Closed xabierXercode closed 9 months ago
Well, UserInfo
does not support the field library
, only id
, email
and name
:
https://github.com/readium/readium-lcp-server/blob/c72c003c861c70f66fbc12d3745ff78a79ea98d0/license/license.go#L62-L67
That being said, the LCP specification allows arbitrary vendor extensions (i.e. custom JSON fields / properties / keys): https://readium.org/technical/readium-lcp-specification/#37-identifying-the-user-the-user-object
...so your library
field should in fact be a URI (am I right, @HadrienGardeur @llemeurfr ?).
More importantly, the Go server code should be capable of handling these arbitrary keys, notably when there is a request to encrypt them in the generated license JSON. See the getField
function:
https://github.com/readium/readium-lcp-server/blob/c72c003c861c70f66fbc12d3745ff78a79ea98d0/license/license.go#L245-L248
So based on my quick investigation, I would say "thank you for the bug report!" :) but I would also say "let's not use the suggested if (!field.IsValid())
check, instead let's fix this properly by implementing support for encrypting vendor extension URIs / custom fields".
What do you think @xabierXercode ?
@danielweck I agree that we should implement support for support to encrypt URI of provider extension / custom fields.
I think we must also make the server more robust. We must not allow fields in the petition that do not adhere to the specification. I think we should also send some kind of error when this occurs. Maybe the right place to do this will be in: https://github.com/readium/readium-lcp-server/blob/c72c003c861c70f66fbc12d3745ff78a79ea98d0/lcpserver/api/license.go#L82
What do you think?
I agree that this will have to be fixed properly to allow provider extensions and trap the kind of error you've encountered.
Since that time, the code was hardened to accept a partial license with unknown fields. But the convertion from JSON to an object is still strict and unknown fields are lost during the process.
The issue appears to still be occurring. The error:
[negroni] PANIC: reflect: call of reflect.Value.Set on zero Value
goroutine 167 [running]:
github.com/urfave/negroni.(*Recovery).ServeHTTP.func1()
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/recovery.go:159 +0xad
panic({0x7ff6dead5840?, 0xc000538528?})
C:/Program Files/Go/src/runtime/panic.go:914 +0x21f
reflect.flag.mustBeAssignableSlow(0x7ff6dea98da0?)
C:/Program Files/Go/src/reflect/value.go:265 +0x105
reflect.flag.mustBeAssignable(...)
C:/Program Files/Go/src/reflect/value.go:259
reflect.Value.Set({0x0?, 0x0?, 0x20?}, {0x7ff6dea98720?, 0xc000037220?, 0xc0000f4d80?})
C:/Program Files/Go/src/reflect/value.go:2254 +0x65
github.com/readium/readium-lcp-server/license.encryptFields({0x7ff6deea0e00, 0x7ff6df481440}, 0xc0000b6840, {0xc0005305c0, 0x20, 0x40})
C:/Users/matthew.dunlop/go/pkg/mod/github.com/readium/readium-lcp-server@v0.0.0-20230809161937-3d23a1331703/license/license.go:348 +0x85
github.com/readium/readium-lcp-server/license.EncryptLicenseFields(0xc0000b6840, {{0xc00000b588, 0x8}, {0xc000020520, 0x20, 0x20}, {0xc000024320, 0x3e}, 0xcc8ac, {0xc000024370, ...}, ...})
C:/Users/matthew.dunlop/go/pkg/mod/github.com/readium/readium-lcp-server@v0.0.0-20230809161937-3d23a1331703/license/license.go:319 +0x1b9
github.com/readium/readium-lcp-server/lcpserver/api.buildLicense(0xc0000b6840, {0x7ff6deea25c0, 0xc0000d6120}, 0x0)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/readium/readium-lcp-server@v0.0.0-20230809161937-3d23a1331703/lcpserver/api/license.go:138 +0x205
github.com/readium/readium-lcp-server/lcpserver/api.GenerateLicense({0x241f5fe57f8?, 0xc000520020}, 0xc000520020?, {0x7ff6deea25c0?, 0xc0000d6120})
C:/Users/matthew.dunlop/go/pkg/mod/github.com/readium/readium-lcp-server@v0.0.0-20230809161937-3d23a1331703/lcpserver/api/license.go:366 +0x11b
github.com/readium/readium-lcp-server/lcpserver/server.New.(*Server).handlePrivateFunc.func5({0x241f5fe57f8, 0xc000520020}, 0xc0000f49f0?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/readium/readium-lcp-server@v0.0.0-20230809161937-3d23a1331703/lcpserver/server/server.go:156 +0x6f
net/http.HandlerFunc.ServeHTTP(0xc00007ca00?, {0x241f5fe57f8?, 0xc000520020?}, 0x7ff6de28ce65?)
C:/Program Files/Go/src/net/http/server.go:2136 +0x29
github.com/gorilla/mux.(*Router).ServeHTTP(0xc0000d2000, {0x241f5fe57f8, 0xc000520020}, 0xc00007c900)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1c5
github.com/urfave/negroni.(*Negroni).UseHandler.Wrap.func1({0x241f5fe57f8, 0xc000520020}, 0x7ff6deb0f460?, 0xc000065120)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:46 +0x45
github.com/urfave/negroni.HandlerFunc.ServeHTTP(0x7ff6de189628?, {0x241f5fe57f8?, 0xc000520020?}, 0x0?, 0x7ff6de3f19b9?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:29 +0x2d
github.com/urfave/negroni.middleware.ServeHTTP({{0x7ff6dee9cae0?, 0xc000538300?}, 0xc000538378?}, {0x241f5fe57f8, 0xc000520020}, 0xc0000b6768?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38 +0xa8
github.com/rs/cors.(*Cors).ServeHTTP(0xc0000d20c0, {0x241f5fe57f8, 0xc000520020}, 0xc00007c900, 0xc000065100)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/rs/cors@v1.8.2/cors.go:266 +0x17e
github.com/urfave/negroni.middleware.ServeHTTP({{0x7ff6dee9c2e0?, 0xc0000d20c0?}, 0xc000538360?}, {0x241f5fe57f8, 0xc000520020}, 0x7ff6de25c68f?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38 +0xa8
github.com/urfave/negroni.(*Logger).ServeHTTP(0xc00009a8a0, {0x241f5fe57f8?, 0xc000520020}, 0xc00007c900, 0xc0000650e0)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/logger.go:62 +0x83
github.com/urfave/negroni.middleware.ServeHTTP({{0x7ff6dee9c2a0?, 0xc00009a8a0?}, 0xc000538348?}, {0x241f5fe57f8, 0xc000520020}, 0x7ff6deb0f460?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38 +0xa8
github.com/urfave/negroni.(*Recovery).ServeHTTP(0xc0004c19a0?, {0x241f5fe57f8?, 0xc000520020?}, 0x5007ff6de465b8e?, 0xc13dbaf4234a38f0?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/recovery.go:193 +0x7b
github.com/urfave/negroni.middleware.ServeHTTP({{0x7ff6dee9c280?, 0xc000526690?}, 0xc000538330?}, {0x241f5fe57f8, 0xc000520020}, 0xb?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38 +0xa8
github.com/jeffbmartinez/delay.Middleware.ServeHTTP({}, {0x241f5fe57f8, 0xc000520020}, 0xc00007c900, 0xc000065080)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/jeffbmartinez/delay@v0.0.0-20150608194421-e1b689d78b33/delay.go:23 +0x68
github.com/urfave/negroni.middleware.ServeHTTP({{0x7ff6dee9c260?, 0x7ff6df481440?}, 0xc000538318?}, {0x241f5fe57f8, 0xc000520020}, 0x7ff6deb0d2e0?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:38 +0xa8
github.com/urfave/negroni.(*Negroni).ServeHTTP(0xc00009a810, {0x7ff6deea1410?, 0xc0000b21c0}, 0xc0000b2101?)
C:/Users/matthew.dunlop/go/pkg/mod/github.com/urfave/negroni@v1.0.0/negroni.go:96 +0x114
net/http.serverHandler.ServeHTTP({0x7ff6dee9d9b0?}, {0x7ff6deea1410?, 0xc0000b21c0?}, 0x6?)
C:/Program Files/Go/src/net/http/server.go:2938 +0x8e
net/http.(*conn).serve(0xc0001be000, {0x7ff6deea1d70, 0xc0000f4390})
C:/Program Files/Go/src/net/http/server.go:2009 +0x5f4
created by net/http.(*Server).Serve in goroutine 1
C:/Program Files/Go/src/net/http/server.go:3086 +0x5cb
The request:
{
"provider": "http://www.imaginaryebookretailer.com",
"user": {
"id": "d9f298a7-7f34-49e7-8aae-4378ecb1d597",
"email": "user@imaginaryebookretailer.com",
"http://www.imaginaryebookretailer.com/lcp/vendorspecificvalue": "f7a02b00-952e-44d9-a952-6b2c553f5242",
"encrypted": [
"email",
"http://www.imaginaryebookretailer.com/lcp/vendorspecificvalue"
]
},
"encryption": {
"user_key": {
"text_hint": "The title of the first book you ever read",
"hex_value": "4981AA0A50D563040519E9032B5D74367B1D129E239A1BA82667A57333866494"
}
},
"rights": {
"print": 10,
"copy": 2048
}
}
lcpserver can accept partial licenses with unknown fields but can't deal with encrypting them, instead printing an exception to console and returning the stack trace in the response body.
That's right: the custom field is filtered during json unmarshaling, but its reference in the encrypted
array attribute is kept in the resulting array. At the time the fields are encrypted, a null pointer is generated and processed without care.
At this point in the development of the LCP Server v1, allowing custom fields in partial licenses seems a bit complex, as we'd need to code a custom JSON decoder working on random JSON fields. It should be simpler in the LCP Server v2 by creating an extension point in license requests, a generic meta field with name and value attributes, and some custom json marshalling code for the license.
For now I'll create a fix where the custom field is removed from both the user
array and the encrypted
property in the returned license.
Fixed in e0d40746470c9f2cee03b23b4755af24f03702dd
When create a partial license with user encrypted field different of name or email the server throws error:
The request:
The error occurs in : https://github.com/readium/readium-lcp-server/blob/master/license/license.go#L235
The solution to this problem is easy: