diff --git a/README.md b/README.md index 4c9c80617f0a6e96dcf0b334bee7888db099527d..ed8047d9d9088c9db17c68b8c7c7bdd690f8684f 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,6 @@ TODO - how key is selected if the request doesn't mention explicit key TODO - how signature suite is constructed based on key type +### Counterfeiter + +TODO - how to use it for generating fake implementations of interfaces \ No newline at end of file diff --git a/cmd/signer/main.go b/cmd/signer/main.go index 9f2727ee17be5a3bd0e6826870e8d99f90e9d913..a11b6d61916e33776261c703e8bc5b41e1002e6a 100644 --- a/cmd/signer/main.go +++ b/cmd/signer/main.go @@ -105,6 +105,8 @@ func main() { openapiServer = goaopenapisrv.New(openapiEndpoints, mux, dec, enc, nil, errFormatter, nil, nil) } + // set custom request decoder, so that request body bytes are simply + // read and not decoded in some other way signerServer.CredentialProof = goasignersrv.NewCredentialProofHandler( signerEndpoints.CredentialProof, mux, @@ -114,6 +116,17 @@ func main() { errFormatter, ) + // set custom request decoder, so that request body bytes are simply + // read and not decoded in some other way + signerServer.PresentationProof = goasignersrv.NewPresentationProofHandler( + signerEndpoints.PresentationProof, + mux, + decoder.RequestDecoder, + enc, + nil, + errFormatter, + ) + // Configure the mux. goasignersrv.Mount(mux, signerServer) goahealthsrv.Mount(mux, healthServer) diff --git a/design/design.go b/design/design.go index b8901caa239339617dfce98522e5947a9e74a592..2698af26a264baa3e77647bbe7c2aa39bc85b1bb 100644 --- a/design/design.go +++ b/design/design.go @@ -30,6 +30,19 @@ var _ = Service("signer", func() { Response(StatusOK) }) }) + + Method("PresentationProof", func() { + Description("PresentationProof adds a proof to a given Verifiable Presentation.") + Payload(PresentationProofRequest) + Result(Any) + HTTP(func() { + POST("/v1/presentation/proof") + Param("key") + Body("presentation") + + Response(StatusOK) + }) + }) }) var _ = Service("health", func() { diff --git a/design/types.go b/design/types.go index af9095942aeb78527c59fb31e9da0d0604116a3b..bfa43f588f926a4a1caaa26db7b19ff957cd6033 100644 --- a/design/types.go +++ b/design/types.go @@ -10,3 +10,11 @@ var CredentialProofRequest = Type("CredentialProofRequest", func() { Field(2, "credential", Bytes, "Verifiable Credential in JSON format.") Required("credential") }) + +var PresentationProofRequest = Type("PresentationProofRequest", func() { + Field(1, "key", String, "Key to use for the proof signature (optional).", func() { + Example("key1") + }) + Field(2, "presentation", Bytes, "Verifiable Presentation in JSON format.") + Required("presentation") +}) diff --git a/gen/http/cli/signer/cli.go b/gen/http/cli/signer/cli.go index 3a001251c39473c6f2b6302d265e3c7b4ab7324c..e79126c525d60bc8f83ace826365b1998cc62fb6 100644 --- a/gen/http/cli/signer/cli.go +++ b/gen/http/cli/signer/cli.go @@ -25,14 +25,14 @@ import ( // func UsageCommands() string { return `health (liveness|readiness) -signer credential-proof +signer (credential-proof|presentation-proof) ` } // UsageExamples produces an example of a valid invocation of the CLI tool. func UsageExamples() string { return os.Args[0] + ` health liveness` + "\n" + - os.Args[0] + ` signer credential-proof --body "QXV0IGZ1Z2lhdCBoYXJ1bS4=" --key "key1"` + "\n" + + os.Args[0] + ` signer credential-proof --body "SXRhcXVlIG9mZmljaWEgY29tbW9kaSBhdXRlbSBhdCBiZWF0YWUu" --key "key1"` + "\n" + "" } @@ -57,6 +57,10 @@ func ParseEndpoint( signerCredentialProofFlags = flag.NewFlagSet("credential-proof", flag.ExitOnError) signerCredentialProofBodyFlag = signerCredentialProofFlags.String("body", "REQUIRED", "") signerCredentialProofKeyFlag = signerCredentialProofFlags.String("key", "", "") + + signerPresentationProofFlags = flag.NewFlagSet("presentation-proof", flag.ExitOnError) + signerPresentationProofBodyFlag = signerPresentationProofFlags.String("body", "REQUIRED", "") + signerPresentationProofKeyFlag = signerPresentationProofFlags.String("key", "", "") ) healthFlags.Usage = healthUsage healthLivenessFlags.Usage = healthLivenessUsage @@ -64,6 +68,7 @@ func ParseEndpoint( signerFlags.Usage = signerUsage signerCredentialProofFlags.Usage = signerCredentialProofUsage + signerPresentationProofFlags.Usage = signerPresentationProofUsage if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { return nil, nil, err @@ -114,6 +119,9 @@ func ParseEndpoint( case "credential-proof": epf = signerCredentialProofFlags + case "presentation-proof": + epf = signerPresentationProofFlags + } } @@ -152,6 +160,9 @@ func ParseEndpoint( case "credential-proof": endpoint = c.CredentialProof() data, err = signerc.BuildCredentialProofPayload(*signerCredentialProofBodyFlag, *signerCredentialProofKeyFlag) + case "presentation-proof": + endpoint = c.PresentationProof() + data, err = signerc.BuildPresentationProofPayload(*signerPresentationProofBodyFlag, *signerPresentationProofKeyFlag) } } } @@ -204,6 +215,7 @@ Usage: COMMAND: credential-proof: CredentialProof adds a proof to a given Verifiable Credential. + presentation-proof: PresentationProof adds a proof to a given Verifiable Presentation. Additional help: %[1]s signer COMMAND --help @@ -217,6 +229,18 @@ CredentialProof adds a proof to a given Verifiable Credential. -key STRING: Example: - %[1]s signer credential-proof --body "QXV0IGZ1Z2lhdCBoYXJ1bS4=" --key "key1" + %[1]s signer credential-proof --body "SXRhcXVlIG9mZmljaWEgY29tbW9kaSBhdXRlbSBhdCBiZWF0YWUu" --key "key1" +`, os.Args[0]) +} + +func signerPresentationProofUsage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] signer presentation-proof -body STRING -key STRING + +PresentationProof adds a proof to a given Verifiable Presentation. + -body STRING: + -key STRING: + +Example: + %[1]s signer presentation-proof --body "QXBlcmlhbSBxdWlhIGNvbnNlcXVhdHVyIGRvbG9yZW0u" --key "key1" `, os.Args[0]) } diff --git a/gen/http/openapi.json b/gen/http/openapi.json index 57e248fc2ea0f20cdc1ee0c75b257f137c392287..fa70d6c891e58cc66f5c4667cb9180bdbaad02d5 100644 --- a/gen/http/openapi.json +++ b/gen/http/openapi.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Signer Service","description":"The signer service exposes HTTP API for creating and verifying digital signatures.","version":""},"host":"localhost:8085","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/credential/proof":{"post":{"tags":["signer"],"summary":"CredentialProof signer","description":"CredentialProof adds a proof to a given Verifiable Credential.","operationId":"signer#CredentialProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","required":false,"type":"string"},{"name":"bytes","in":"body","description":"Verifiable Credential in JSON format.","required":true,"schema":{"type":"string","format":"byte"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Signer Service","description":"The signer service exposes HTTP API for creating and verifying digital signatures.","version":""},"host":"localhost:8085","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/credential/proof":{"post":{"tags":["signer"],"summary":"CredentialProof signer","description":"CredentialProof adds a proof to a given Verifiable Credential.","operationId":"signer#CredentialProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","required":false,"type":"string"},{"name":"bytes","in":"body","description":"Verifiable Credential in JSON format.","required":true,"schema":{"type":"string","format":"byte"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}},"/v1/presentation/proof":{"post":{"tags":["signer"],"summary":"PresentationProof signer","description":"PresentationProof adds a proof to a given Verifiable Presentation.","operationId":"signer#PresentationProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","required":false,"type":"string"},{"name":"bytes","in":"body","description":"Verifiable Presentation in JSON format.","required":true,"schema":{"type":"string","format":"byte"}}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}}}} \ No newline at end of file diff --git a/gen/http/openapi.yaml b/gen/http/openapi.yaml index 07ccef65ab32cc3a75e540e390d0837f2c1873b2..9de69bf02efee965db05769aafbdf9f488b426ce 100644 --- a/gen/http/openapi.yaml +++ b/gen/http/openapi.yaml @@ -63,3 +63,31 @@ paths: format: binary schemes: - http + /v1/presentation/proof: + post: + tags: + - signer + summary: PresentationProof signer + description: PresentationProof adds a proof to a given Verifiable Presentation. + operationId: signer#PresentationProof + parameters: + - name: key + in: query + description: Key to use for the proof signature (optional). + required: false + type: string + - name: bytes + in: body + description: Verifiable Presentation in JSON format. + required: true + schema: + type: string + format: byte + responses: + "200": + description: OK response. + schema: + type: string + format: binary + schemes: + - http diff --git a/gen/http/openapi3.json b/gen/http/openapi3.json index 7aef9891518bbd1b3525c9dbb0126ee7ab9abca3..44444084b6b678b58c927432dea8a4b8fdee84d0 100644 --- a/gen/http/openapi3.json +++ b/gen/http/openapi3.json @@ -1 +1 @@ -{"openapi":"3.0.3","info":{"title":"Signer Service","description":"The signer service exposes HTTP API for creating and verifying digital signatures.","version":"1.0"},"servers":[{"url":"http://localhost:8085","description":"Signer Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/credential/proof":{"post":{"tags":["signer"],"summary":"CredentialProof signer","description":"CredentialProof adds a proof to a given Verifiable Credential.","operationId":"signer#CredentialProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","allowEmptyValue":true,"schema":{"type":"string","description":"Key to use for the proof signature (optional).","example":"key1"},"example":"key1"}],"requestBody":{"description":"Verifiable Credential in JSON format.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Verifiable Credential in JSON format.","example":"RXVtIGl1cmUgbmVtby4=","format":"binary"},"example":"VmVuaWFtIHF1aWEu"}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Ut voluptas sed.","format":"binary"},"example":"Ad magni."}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"signer","description":"Sign service provides endpoints for making digital signatures and proofs for verifiable credentials and presentations."}]} \ No newline at end of file +{"openapi":"3.0.3","info":{"title":"Signer Service","description":"The signer service exposes HTTP API for creating and verifying digital signatures.","version":"1.0"},"servers":[{"url":"http://localhost:8085","description":"Signer Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/credential/proof":{"post":{"tags":["signer"],"summary":"CredentialProof signer","description":"CredentialProof adds a proof to a given Verifiable Credential.","operationId":"signer#CredentialProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","allowEmptyValue":true,"schema":{"type":"string","description":"Key to use for the proof signature (optional).","example":"key1"},"example":"key1"}],"requestBody":{"description":"Verifiable Credential in JSON format.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Verifiable Credential in JSON format.","example":"Q3VscGEgb2NjYWVjYXRpIGRvbG9ydW0gcXVpIGVuaW0gaW5jaWR1bnQu","format":"binary"},"example":"SXRhcXVlIGFkaXBpc2NpIHZvbHVwdGFzLg=="}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Ipsam facere.","format":"binary"},"example":"Asperiores molestias qui."}}}}}},"/v1/presentation/proof":{"post":{"tags":["signer"],"summary":"PresentationProof signer","description":"PresentationProof adds a proof to a given Verifiable Presentation.","operationId":"signer#PresentationProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","allowEmptyValue":true,"schema":{"type":"string","description":"Key to use for the proof signature (optional).","example":"key1"},"example":"key1"}],"requestBody":{"description":"Verifiable Presentation in JSON format.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Verifiable Presentation in JSON format.","example":"RXN0IHF1aWRlbSBoYXJ1bSB2ZXJvLg==","format":"binary"},"example":"SXBzYSB2ZWwgaW4gcmVwdWRpYW5kYWUgcmVwZWxsYXQu"}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Deleniti ipsa.","format":"binary"},"example":"Laudantium exercitationem quis sunt eos."}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"signer","description":"Sign service provides endpoints for making digital signatures and proofs for verifiable credentials and presentations."}]} \ No newline at end of file diff --git a/gen/http/openapi3.yaml b/gen/http/openapi3.yaml index 49ea7ab38506b3ccb2e51145e8e1f5b7cbc9017c..502993a6ed52590afccf536b71251a91d0810839 100644 --- a/gen/http/openapi3.yaml +++ b/gen/http/openapi3.yaml @@ -51,33 +51,167 @@ paths: type: string description: Verifiable Credential in JSON format. example: - - 69 + - 67 - 117 - - 109 + - 108 + - 112 + - 97 - 32 + - 111 + - 99 + - 99 + - 97 + - 101 + - 99 + - 97 + - 116 - 105 - - 117 + - 32 + - 100 + - 111 + - 108 + - 111 - 114 + - 117 + - 109 + - 32 + - 113 + - 117 + - 105 + - 32 - 101 + - 110 + - 105 + - 109 - 32 + - 105 - 110 + - 99 + - 105 + - 100 + - 117 + - 110 + - 116 + - 46 + format: binary + example: + - 73 + - 116 + - 97 + - 113 + - 117 + - 101 + - 32 + - 97 + - 100 + - 105 + - 112 + - 105 + - 115 + - 99 + - 105 + - 32 + - 118 + - 111 + - 108 + - 117 + - 112 + - 116 + - 97 + - 115 + - 46 + responses: + "200": + description: OK response. + content: + application/json: + schema: + type: string + example: Ipsam facere. + format: binary + example: Asperiores molestias qui. + /v1/presentation/proof: + post: + tags: + - signer + summary: PresentationProof signer + description: PresentationProof adds a proof to a given Verifiable Presentation. + operationId: signer#PresentationProof + parameters: + - name: key + in: query + description: Key to use for the proof signature (optional). + allowEmptyValue: true + schema: + type: string + description: Key to use for the proof signature (optional). + example: key1 + example: key1 + requestBody: + description: Verifiable Presentation in JSON format. + required: true + content: + application/json: + schema: + type: string + description: Verifiable Presentation in JSON format. + example: + - 69 + - 115 + - 116 + - 32 + - 113 + - 117 + - 105 + - 100 - 101 - 109 + - 32 + - 104 + - 97 + - 114 + - 117 + - 109 + - 32 + - 118 + - 101 + - 114 - 111 - 46 format: binary example: - - 86 + - 73 + - 112 + - 115 + - 97 + - 32 + - 118 - 101 - - 110 + - 108 + - 32 - 105 - - 97 - - 109 + - 110 - 32 - - 113 + - 114 + - 101 + - 112 - 117 + - 100 - 105 - 97 + - 110 + - 100 + - 97 + - 101 + - 32 + - 114 + - 101 + - 112 + - 101 + - 108 + - 108 + - 97 + - 116 - 46 responses: "200": @@ -86,9 +220,9 @@ paths: application/json: schema: type: string - example: Ut voluptas sed. + example: Deleniti ipsa. format: binary - example: Ad magni. + example: Laudantium exercitationem quis sunt eos. components: {} tags: - name: health diff --git a/gen/http/signer/client/cli.go b/gen/http/signer/client/cli.go index 97328cbcd385969b78fee31b9abb9ef68d8a67c3..007efc105b2105801f3f2f75c4cb3d48e32679f3 100644 --- a/gen/http/signer/client/cli.go +++ b/gen/http/signer/client/cli.go @@ -32,3 +32,25 @@ func BuildCredentialProofPayload(signerCredentialProofBody string, signerCredent return res, nil } + +// BuildPresentationProofPayload builds the payload for the signer +// PresentationProof endpoint from CLI flags. +func BuildPresentationProofPayload(signerPresentationProofBody string, signerPresentationProofKey string) (*signer.PresentationProofRequest, error) { + var body []byte + { + body = []byte(signerPresentationProofBody) + } + var key *string + { + if signerPresentationProofKey != "" { + key = &signerPresentationProofKey + } + } + v := body + res := &signer.PresentationProofRequest{ + Presentation: v, + } + res.Key = key + + return res, nil +} diff --git a/gen/http/signer/client/client.go b/gen/http/signer/client/client.go index 60ea86188d3a49a09d7d6f37d18c538c9e8ffae8..8088ebd580ccc0e5d098a0ce900c6ef0e72da7c2 100644 --- a/gen/http/signer/client/client.go +++ b/gen/http/signer/client/client.go @@ -21,6 +21,10 @@ type Client struct { // CredentialProof endpoint. CredentialProofDoer goahttp.Doer + // PresentationProof Doer is the HTTP client used to make requests to the + // PresentationProof endpoint. + PresentationProofDoer goahttp.Doer + // RestoreResponseBody controls whether the response bodies are reset after // decoding so they can be read again. RestoreResponseBody bool @@ -41,12 +45,13 @@ func NewClient( restoreBody bool, ) *Client { return &Client{ - CredentialProofDoer: doer, - RestoreResponseBody: restoreBody, - scheme: scheme, - host: host, - decoder: dec, - encoder: enc, + CredentialProofDoer: doer, + PresentationProofDoer: doer, + RestoreResponseBody: restoreBody, + scheme: scheme, + host: host, + decoder: dec, + encoder: enc, } } @@ -73,3 +78,27 @@ func (c *Client) CredentialProof() goa.Endpoint { return decodeResponse(resp) } } + +// PresentationProof returns an endpoint that makes HTTP requests to the signer +// service PresentationProof server. +func (c *Client) PresentationProof() goa.Endpoint { + var ( + encodeRequest = EncodePresentationProofRequest(c.encoder) + decodeResponse = DecodePresentationProofResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v interface{}) (interface{}, error) { + req, err := c.BuildPresentationProofRequest(ctx, v) + if err != nil { + return nil, err + } + err = encodeRequest(req, v) + if err != nil { + return nil, err + } + resp, err := c.PresentationProofDoer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("signer", "PresentationProof", err) + } + return decodeResponse(resp) + } +} diff --git a/gen/http/signer/client/encode_decode.go b/gen/http/signer/client/encode_decode.go index 1c7b6dc7315717d711f68de3e7330309dff2f745..004dc905c53bbbdec5abc8fa6e3a5cd81ab04e02 100644 --- a/gen/http/signer/client/encode_decode.go +++ b/gen/http/signer/client/encode_decode.go @@ -88,3 +88,74 @@ func DecodeCredentialProofResponse(decoder func(*http.Response) goahttp.Decoder, } } } + +// BuildPresentationProofRequest instantiates a HTTP request object with method +// and path set to call the "signer" service "PresentationProof" endpoint +func (c *Client) BuildPresentationProofRequest(ctx context.Context, v interface{}) (*http.Request, error) { + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: PresentationProofSignerPath()} + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("signer", "PresentationProof", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// EncodePresentationProofRequest returns an encoder for requests sent to the +// signer PresentationProof server. +func EncodePresentationProofRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error { + return func(req *http.Request, v interface{}) error { + p, ok := v.(*signer.PresentationProofRequest) + if !ok { + return goahttp.ErrInvalidType("signer", "PresentationProof", "*signer.PresentationProofRequest", v) + } + values := req.URL.Query() + if p.Key != nil { + values.Add("key", *p.Key) + } + req.URL.RawQuery = values.Encode() + body := p.Presentation + if err := encoder(req).Encode(&body); err != nil { + return goahttp.ErrEncodingError("signer", "PresentationProof", err) + } + return nil + } +} + +// DecodePresentationProofResponse returns a decoder for responses returned by +// the signer PresentationProof endpoint. restoreBody controls whether the +// response body should be restored after having been read. +func DecodePresentationProofResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) { + return func(resp *http.Response) (interface{}, error) { + if restoreBody { + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + body interface{} + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("signer", "PresentationProof", err) + } + return body, nil + default: + body, _ := ioutil.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("signer", "PresentationProof", resp.StatusCode, string(body)) + } + } +} diff --git a/gen/http/signer/client/paths.go b/gen/http/signer/client/paths.go index 0463734d1169ebe2de2866026f8d6b41416b2e23..308da7a1f7119f5a91820ab7c227fd5ee0256886 100644 --- a/gen/http/signer/client/paths.go +++ b/gen/http/signer/client/paths.go @@ -11,3 +11,8 @@ package client func CredentialProofSignerPath() string { return "/v1/credential/proof" } + +// PresentationProofSignerPath returns the URL path to the signer service PresentationProof HTTP endpoint. +func PresentationProofSignerPath() string { + return "/v1/presentation/proof" +} diff --git a/gen/http/signer/server/encode_decode.go b/gen/http/signer/server/encode_decode.go index 884453d5d0c71cae1239fb66713587752ce90b32..558cd47c13782e5c835412d2fb7997d02cf88765 100644 --- a/gen/http/signer/server/encode_decode.go +++ b/gen/http/signer/server/encode_decode.go @@ -56,3 +56,44 @@ func DecodeCredentialProofRequest(mux goahttp.Muxer, decoder func(*http.Request) return payload, nil } } + +// EncodePresentationProofResponse returns an encoder for responses returned by +// the signer PresentationProof endpoint. +func EncodePresentationProofResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error { + return func(ctx context.Context, w http.ResponseWriter, v interface{}) error { + res, _ := v.(interface{}) + enc := encoder(ctx, w) + body := res + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodePresentationProofRequest returns a decoder for requests sent to the +// signer PresentationProof endpoint. +func DecodePresentationProofRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) { + return func(r *http.Request) (interface{}, error) { + var ( + body []byte + err error + ) + err = decoder(r).Decode(&body) + if err != nil { + if err == io.EOF { + return nil, goa.MissingPayloadError() + } + return nil, goa.DecodePayloadError(err.Error()) + } + + var ( + key *string + ) + keyRaw := r.URL.Query().Get("key") + if keyRaw != "" { + key = &keyRaw + } + payload := NewPresentationProofRequest(body, key) + + return payload, nil + } +} diff --git a/gen/http/signer/server/paths.go b/gen/http/signer/server/paths.go index 1135f5a1767e41fe5c61016576b93a0f5e9442b4..7bc55146b94c7fe8a6283513609f4cf569538492 100644 --- a/gen/http/signer/server/paths.go +++ b/gen/http/signer/server/paths.go @@ -11,3 +11,8 @@ package server func CredentialProofSignerPath() string { return "/v1/credential/proof" } + +// PresentationProofSignerPath returns the URL path to the signer service PresentationProof HTTP endpoint. +func PresentationProofSignerPath() string { + return "/v1/presentation/proof" +} diff --git a/gen/http/signer/server/server.go b/gen/http/signer/server/server.go index 35cb6d56490b195c66a323f91a3c4a8cc4518c66..350a87ef40e9c4260e0ded1c602bbd35a81e5b8a 100644 --- a/gen/http/signer/server/server.go +++ b/gen/http/signer/server/server.go @@ -18,8 +18,9 @@ import ( // Server lists the signer service endpoint HTTP handlers. type Server struct { - Mounts []*MountPoint - CredentialProof http.Handler + Mounts []*MountPoint + CredentialProof http.Handler + PresentationProof http.Handler } // ErrorNamer is an interface implemented by generated error structs that @@ -56,8 +57,10 @@ func New( return &Server{ Mounts: []*MountPoint{ {"CredentialProof", "POST", "/v1/credential/proof"}, + {"PresentationProof", "POST", "/v1/presentation/proof"}, }, - CredentialProof: NewCredentialProofHandler(e.CredentialProof, mux, decoder, encoder, errhandler, formatter), + CredentialProof: NewCredentialProofHandler(e.CredentialProof, mux, decoder, encoder, errhandler, formatter), + PresentationProof: NewPresentationProofHandler(e.PresentationProof, mux, decoder, encoder, errhandler, formatter), } } @@ -67,11 +70,13 @@ func (s *Server) Service() string { return "signer" } // Use wraps the server handlers with the given middleware. func (s *Server) Use(m func(http.Handler) http.Handler) { s.CredentialProof = m(s.CredentialProof) + s.PresentationProof = m(s.PresentationProof) } // Mount configures the mux to serve the signer endpoints. func Mount(mux goahttp.Muxer, h *Server) { MountCredentialProofHandler(mux, h.CredentialProof) + MountPresentationProofHandler(mux, h.PresentationProof) } // Mount configures the mux to serve the signer endpoints. @@ -129,3 +134,54 @@ func NewCredentialProofHandler( } }) } + +// MountPresentationProofHandler configures the mux to serve the "signer" +// service "PresentationProof" endpoint. +func MountPresentationProofHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("POST", "/v1/presentation/proof", f) +} + +// NewPresentationProofHandler creates a HTTP handler which loads the HTTP +// request and calls the "signer" service "PresentationProof" endpoint. +func NewPresentationProofHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(err error) goahttp.Statuser, +) http.Handler { + var ( + decodeRequest = DecodePresentationProofRequest(mux, decoder) + encodeResponse = EncodePresentationProofResponse(encoder) + encodeError = goahttp.ErrorEncoder(encoder, formatter) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "PresentationProof") + ctx = context.WithValue(ctx, goa.ServiceKey, "signer") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + res, err := endpoint(ctx, payload) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + errhandler(ctx, w, err) + } + }) +} diff --git a/gen/http/signer/server/types.go b/gen/http/signer/server/types.go index 7643f58d008578a4943a5c1e22cbdb743d681793..c86ba033b724cc98e99410669edf69c1ff8c44e6 100644 --- a/gen/http/signer/server/types.go +++ b/gen/http/signer/server/types.go @@ -22,3 +22,15 @@ func NewCredentialProofRequest(body []byte, key *string) *signer.CredentialProof return res } + +// NewPresentationProofRequest builds a signer service PresentationProof +// endpoint payload. +func NewPresentationProofRequest(body []byte, key *string) *signer.PresentationProofRequest { + v := body + res := &signer.PresentationProofRequest{ + Presentation: v, + } + res.Key = key + + return res +} diff --git a/gen/signer/client.go b/gen/signer/client.go index b8f9199fd437235d7a492790c91543ad8297fd66..033d69f43c586f8c1450c8eed9afa39088a8f98a 100644 --- a/gen/signer/client.go +++ b/gen/signer/client.go @@ -15,13 +15,15 @@ import ( // Client is the "signer" service client. type Client struct { - CredentialProofEndpoint goa.Endpoint + CredentialProofEndpoint goa.Endpoint + PresentationProofEndpoint goa.Endpoint } // NewClient initializes a "signer" service client given the endpoints. -func NewClient(credentialProof goa.Endpoint) *Client { +func NewClient(credentialProof, presentationProof goa.Endpoint) *Client { return &Client{ - CredentialProofEndpoint: credentialProof, + CredentialProofEndpoint: credentialProof, + PresentationProofEndpoint: presentationProof, } } @@ -34,3 +36,14 @@ func (c *Client) CredentialProof(ctx context.Context, p *CredentialProofRequest) } return ires.(interface{}), nil } + +// PresentationProof calls the "PresentationProof" endpoint of the "signer" +// service. +func (c *Client) PresentationProof(ctx context.Context, p *PresentationProofRequest) (res interface{}, err error) { + var ires interface{} + ires, err = c.PresentationProofEndpoint(ctx, p) + if err != nil { + return + } + return ires.(interface{}), nil +} diff --git a/gen/signer/endpoints.go b/gen/signer/endpoints.go index 9b81418a13992d8dad28b0a52af5db9c20fd907e..a5ebf6c81a72589682f2394ffc8489988a662534 100644 --- a/gen/signer/endpoints.go +++ b/gen/signer/endpoints.go @@ -15,19 +15,22 @@ import ( // Endpoints wraps the "signer" service endpoints. type Endpoints struct { - CredentialProof goa.Endpoint + CredentialProof goa.Endpoint + PresentationProof goa.Endpoint } // NewEndpoints wraps the methods of the "signer" service with endpoints. func NewEndpoints(s Service) *Endpoints { return &Endpoints{ - CredentialProof: NewCredentialProofEndpoint(s), + CredentialProof: NewCredentialProofEndpoint(s), + PresentationProof: NewPresentationProofEndpoint(s), } } // Use applies the given middleware to all the "signer" service endpoints. func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { e.CredentialProof = m(e.CredentialProof) + e.PresentationProof = m(e.PresentationProof) } // NewCredentialProofEndpoint returns an endpoint function that calls the @@ -38,3 +41,12 @@ func NewCredentialProofEndpoint(s Service) goa.Endpoint { return s.CredentialProof(ctx, p) } } + +// NewPresentationProofEndpoint returns an endpoint function that calls the +// method "PresentationProof" of service "signer". +func NewPresentationProofEndpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req interface{}) (interface{}, error) { + p := req.(*PresentationProofRequest) + return s.PresentationProof(ctx, p) + } +} diff --git a/gen/signer/service.go b/gen/signer/service.go index c64308776d773296f054b546b547c51bf6844db1..a1c7d2c184985bf5cc7f5eadb09848e84e4a9684 100644 --- a/gen/signer/service.go +++ b/gen/signer/service.go @@ -16,6 +16,8 @@ import ( type Service interface { // CredentialProof adds a proof to a given Verifiable Credential. CredentialProof(context.Context, *CredentialProofRequest) (res interface{}, err error) + // PresentationProof adds a proof to a given Verifiable Presentation. + PresentationProof(context.Context, *PresentationProofRequest) (res interface{}, err error) } // ServiceName is the name of the service as defined in the design. This is the @@ -26,7 +28,7 @@ const ServiceName = "signer" // MethodNames lists the service method names as defined in the design. These // are the same values that are set in the endpoint request contexts under the // MethodKey key. -var MethodNames = [1]string{"CredentialProof"} +var MethodNames = [2]string{"CredentialProof", "PresentationProof"} // CredentialProofRequest is the payload type of the signer service // CredentialProof method. @@ -36,3 +38,12 @@ type CredentialProofRequest struct { // Verifiable Credential in JSON format. Credential []byte } + +// PresentationProofRequest is the payload type of the signer service +// PresentationProof method. +type PresentationProofRequest struct { + // Key to use for the proof signature (optional). + Key *string + // Verifiable Presentation in JSON format. + Presentation []byte +} diff --git a/internal/service/signer/service.go b/internal/service/signer/service.go index f216f1a8f39627221e3c8598ef02bfb7a9b8eb46..06755754577a21cf4db4c77c181f216d651783c6 100644 --- a/internal/service/signer/service.go +++ b/internal/service/signer/service.go @@ -50,9 +50,11 @@ func New(signer Signer, defaultKey string, httpClient *http.Client, logger *zap. // CredentialProof adds a proof to a given Verifiable Credential. func (s *Service) CredentialProof(ctx context.Context, req *signer.CredentialProofRequest) (interface{}, error) { + logger := s.logger.With(zap.String("operation", "credentialProof")) + vc, err := verifiable.ParseCredential(req.Credential, verifiable.WithJSONLDDocumentLoader(s.docLoader)) if err != nil { - s.logger.Error("error parsing credential", zap.Error(err)) + logger.Error("error parsing verifiable credential", zap.Error(err)) return nil, err } @@ -63,24 +65,60 @@ func (s *Service) CredentialProof(ctx context.Context, req *signer.CredentialPro key, err := s.signer.Key(keyname) if err != nil { - s.logger.Error("error getting signing key", zap.String("key", keyname), zap.Error(err)) + logger.Error("error getting signing key", zap.String("key", keyname), zap.Error(err)) return nil, errors.New("error getting signing key", err) } proofContext, err := s.proofContext(key.Name, key.Type) if err != nil { - s.logger.Error("error building proof context", zap.Error(err)) + logger.Error("error building proof context", zap.Error(err)) return nil, err } if err := vc.AddLinkedDataProof(proofContext, jsonld.WithDocumentLoader(s.docLoader)); err != nil { - s.logger.Error("error adding linked data proof", zap.Error(err)) + logger.Error("error adding linked data proof", zap.Error(err)) return nil, err } return vc, nil } +// PresentationProof adds a proof to a given Verifiable Presentation. +func (s *Service) PresentationProof(ctx context.Context, req *signer.PresentationProofRequest) (interface{}, error) { + logger := s.logger.With(zap.String("operation", "presentationProof")) + + vp, err := verifiable.ParsePresentation(req.Presentation, verifiable.WithPresJSONLDDocumentLoader(s.docLoader)) + if err != nil { + logger.Error("error parsing verifiable presentation", zap.Error(err)) + return nil, err + } + + keyname := s.defaultKey + if req.Key != nil && *req.Key != "" { + keyname = *req.Key + } + + key, err := s.signer.Key(keyname) + if err != nil { + logger.Error("error getting signing key", zap.String("key", keyname), zap.Error(err)) + return nil, errors.New("error getting signing key", err) + } + + proofContext, err := s.proofContext(key.Name, key.Type) + if err != nil { + logger.Error("error building proof context", zap.Error(err)) + return nil, err + } + + if err := vp.AddLinkedDataProof(proofContext, jsonld.WithDocumentLoader(s.docLoader)); err != nil { + logger.Error("error adding linked data proof", zap.Error(err)) + return nil, err + } + + return vp, nil +} + +// proofContext is used to create proofs. func (s *Service) proofContext(key string, keyType string) (*verifiable.LinkedDataProofContext, error) { sigSuite, sigType, err := s.signatureSuite(key, keyType) if err != nil { @@ -97,6 +135,7 @@ func (s *Service) proofContext(key string, keyType string) (*verifiable.LinkedDa return proofContext, nil } +// signatureSuite is used to create digital signatures on proofs. func (s *Service) signatureSuite(key string, keyType string) (sigSuite ariesigner.SignatureSuite, sigType string, err error) { signer := s.signer.WithKey(key) diff --git a/internal/service/signer/service_test.go b/internal/service/signer/service_test.go index 19b47e2e3dab68ea8693c2ed45de86ae2a6972ef..9a44fb3b27cf0dc41b44aafb7340c34a9693d682 100644 --- a/internal/service/signer/service_test.go +++ b/internal/service/signer/service_test.go @@ -17,47 +17,6 @@ import ( "code.vereign.com/gaiax/tsa/signer/internal/service/signer/signerfakes" ) -//nolint:gosec -var validCredential = `{ - "@context": [ - "https://www.w3.org/2018/credentials/v1" - ], - "credentialSubject": { - "hello": "world" - }, - "issuanceDate": "2022-06-02T17:24:05.032533+03:00", - "issuer": "https://example.com", - "type": "VerifiableCredential" -}` - -//nolint:gosec -var invalidCredential = `{"invalid":"credential"}` - -//nolint:gosec -var invalidCredentialContexts = `{ - "@context": ["https://www.w3.org/2018/credentials/v123"], - "credentialSubject": { - "hello": "world" - }, - "issuanceDate": "2022-06-02T17:24:05.032533+03:00", - "issuer": "https://example.com", - "type": "VerifiableCredential" -}` - -//nolint:gosec -var nonExistingCredentialContexts = `{ - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://no-schema-here.com/credentials/context" - ], - "credentialSubject": { - "hello": "world" - }, - "issuanceDate": "2022-06-02T17:24:05.032533+03:00", - "issuer": "https://example.com", - "type": "VerifiableCredential" -}` - func TestService_CredentialProof(t *testing.T) { tests := []struct { name string @@ -191,6 +150,7 @@ func TestService_CredentialProof(t *testing.T) { contexts: []string{"https://www.w3.org/2018/credentials/v1"}, subject: []verifiable.Subject{{CustomFields: verifiable.CustomFields{"hello": "world"}}}, issuer: verifiable.Issuer{ID: "https://example.com"}, + types: []string{verifiable.VCType}, proofPurpose: "assertionMethod", proofType: "Ed25519Signature2018", proofValue: base64.RawURLEncoding.EncodeToString([]byte("test signature")), @@ -223,6 +183,7 @@ func TestService_CredentialProof(t *testing.T) { contexts: []string{"https://www.w3.org/2018/credentials/v1"}, subject: []verifiable.Subject{{CustomFields: verifiable.CustomFields{"hello": "world"}}}, issuer: verifiable.Issuer{ID: "https://example.com"}, + types: []string{verifiable.VCType}, proofPurpose: "assertionMethod", proofType: "EcdsaSecp256k1Signature2019", proofValue: base64.RawURLEncoding.EncodeToString([]byte("test signature")), @@ -253,6 +214,7 @@ func TestService_CredentialProof(t *testing.T) { assert.Equal(t, test.contexts, vc.Context) assert.Equal(t, test.subject, vc.Subject) assert.Equal(t, test.issuer, vc.Issuer) + assert.Equal(t, test.types, vc.Types) assert.Equal(t, test.proofPurpose, vc.Proofs[0]["proofPurpose"]) assert.Equal(t, test.proofType, vc.Proofs[0]["type"]) assert.Equal(t, test.proofValue, vc.Proofs[0]["proofValue"]) @@ -261,3 +223,368 @@ func TestService_CredentialProof(t *testing.T) { }) } } + +func TestService_PresentationProof(t *testing.T) { + tests := []struct { + name string + signer *signerfakes.FakeSigner + defaultKey string + req *goasigner.PresentationProofRequest + + errkind errors.Kind + errtext string + + contexts []string + types []string + proofPurpose string + proofValue string + proofType string + proofVerificationMethod string + }{ + { + name: "invalid verifiable presentation", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Presentation: []byte(invalidPresentation), + }, + errtext: "verifiable presentation is not valid", + }, + { + name: "invalid presentation contexts", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Presentation: []byte(invalidPresentationContexts), + }, + errtext: "verifiable presentation is not valid", + }, + { + name: "non-existing presentation contexts", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Presentation: []byte(nonExistingPresentationContexts), + }, + errtext: "Dereferencing a URL did not result in a valid JSON-LD context", + }, + { + name: "valid presentation but signer cannot find key", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Key: ptr.String("key2"), + Presentation: []byte(validPresentation), + }, + signer: &signerfakes.FakeSigner{ + KeyStub: func(key string) (*signer.SignKey, error) { + return nil, errors.New(errors.NotFound) + }, + }, + errkind: errors.NotFound, + errtext: "error getting signing key", + }, + { + name: "valid presentation but signer returns internal error", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Key: ptr.String("key2"), + Presentation: []byte(validPresentation), + }, + signer: &signerfakes.FakeSigner{ + KeyStub: func(key string) (*signer.SignKey, error) { + return nil, errors.New(errors.Internal) + }, + }, + errkind: errors.Internal, + errtext: "error getting signing key", + }, + { + name: "valid presentation but signer returns internal error", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Key: ptr.String("key2"), + Presentation: []byte(validPresentation), + }, + signer: &signerfakes.FakeSigner{ + KeyStub: func(key string) (*signer.SignKey, error) { + return nil, errors.New(errors.Internal) + }, + }, + errkind: errors.Internal, + errtext: "error getting signing key", + }, + { + name: "valid presentation but signer returns unsupported key type", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Key: ptr.String("key2"), + Presentation: []byte(validPresentation), + }, + signer: &signerfakes.FakeSigner{ + KeyStub: func(key string) (*signer.SignKey, error) { + return &signer.SignKey{ + Name: "key23", + Type: "rsa4096", + }, nil + }, + }, + errkind: errors.Unknown, + errtext: "unsupported key type", + }, + { + name: "valid presentation and signer key type ed25519", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Key: ptr.String("key2"), + Presentation: []byte(validPresentation), + }, + signer: &signerfakes.FakeSigner{ + KeyStub: func(key string) (*signer.SignKey, error) { + return &signer.SignKey{ + Name: "key123", + Type: "ed25519", + }, nil + }, + WithKeyStub: func(key string) signer.Signer { + return &signerfakes.FakeSigner{ + SignStub: func(data []byte) ([]byte, error) { + return []byte("test signature"), nil + }, + } + }, + }, + + // expected attributes the VC must have + contexts: []string{"https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"}, + types: []string{verifiable.VPType}, + proofPurpose: "assertionMethod", + proofType: "Ed25519Signature2018", + proofValue: base64.RawURLEncoding.EncodeToString([]byte("test signature")), + proofVerificationMethod: "key123", + }, + { + name: "valid presentation and signer key type ecdsa-p256", + defaultKey: "key1", + req: &goasigner.PresentationProofRequest{ + Key: ptr.String("key2"), + Presentation: []byte(validPresentation), + }, + signer: &signerfakes.FakeSigner{ + KeyStub: func(key string) (*signer.SignKey, error) { + return &signer.SignKey{ + Name: "key123", + Type: "ecdsa-p256", + }, nil + }, + WithKeyStub: func(key string) signer.Signer { + return &signerfakes.FakeSigner{ + SignStub: func(data []byte) ([]byte, error) { + return []byte("test signature"), nil + }, + } + }, + }, + + // expected attributes the VC must have + contexts: []string{"https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"}, + types: []string{verifiable.VPType}, + proofPurpose: "assertionMethod", + proofType: "EcdsaSecp256k1Signature2019", + proofValue: base64.RawURLEncoding.EncodeToString([]byte("test signature")), + proofVerificationMethod: "key123", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + svc := signer.New(test.signer, test.defaultKey, http.DefaultClient, zap.NewNop()) + res, err := svc.PresentationProof(context.Background(), test.req) + if err != nil { + assert.Nil(t, res) + assert.NotEmpty(t, test.errtext) + if e, ok := err.(*errors.Error); ok { + assert.Equal(t, test.errkind, e.Kind) + assert.Contains(t, e.Message, test.errtext) + } else { + assert.Contains(t, err.Error(), test.errtext) + } + } else { + assert.Empty(t, test.errtext) + assert.NotNil(t, res) + + vp, ok := res.(*verifiable.Presentation) + assert.True(t, ok) + + assert.Equal(t, test.contexts, vp.Context) + assert.Equal(t, test.types, vp.Type) + assert.Equal(t, test.proofPurpose, vp.Proofs[0]["proofPurpose"]) + assert.Equal(t, test.proofType, vp.Proofs[0]["type"]) + assert.Equal(t, test.proofValue, vp.Proofs[0]["proofValue"]) + assert.Equal(t, test.proofVerificationMethod, vp.Proofs[0]["verificationMethod"]) + } + }) + } +} + +// ---------- Verifiable Credentials ---------- // + +//nolint:gosec +var validCredential = `{ + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "credentialSubject": { + "hello": "world" + }, + "issuanceDate": "2022-06-02T17:24:05.032533+03:00", + "issuer": "https://example.com", + "type": "VerifiableCredential" +}` + +//nolint:gosec +var invalidCredential = `{"invalid":"credential"}` + +//nolint:gosec +var invalidCredentialContexts = `{ + "@context": ["https://www.w3.org/2018/credentials/v123"], + "credentialSubject": { + "hello": "world" + }, + "issuanceDate": "2022-06-02T17:24:05.032533+03:00", + "issuer": "https://example.com", + "type": "VerifiableCredential" +}` + +//nolint:gosec +var nonExistingCredentialContexts = `{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://no-schema-here.com/credentials/context" + ], + "credentialSubject": { + "hello": "world" + }, + "issuanceDate": "2022-06-02T17:24:05.032533+03:00", + "issuer": "https://example.com", + "type": "VerifiableCredential" +}` + +// ---------- Verifiable Presentations ---------- // + +var validPresentation = `{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "id": "did:123", + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "credentialSubject": { + "allow": true, + "id": "example/example/1.0", + "taskID": "0123456789abcdef" + }, + "issuanceDate": "2022-06-14T08:43:22.78309334Z", + "issuer": "https://example.com", + "type": "VerifiableCredential" + }, + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "credentialSubject": { + "id": "example/example/2.0", + "result": { + "hello": "world" + } + }, + "issuanceDate": "2022-06-14T08:43:22.783102173Z", + "issuer": "https://example.com", + "type": "VerifiableCredential" + } + ] +}` + +var invalidPresentation = `{"invalid":"presentation"}` + +var invalidPresentationContexts = `{ + "@context": [ + "https://www.w3.org/2018/credentials/v123" + ], + "id": "did:123", + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "credentialSubject": { + "allow": true, + "id": "example/example/1.0", + "taskID": "0123456789abcdef" + }, + "issuanceDate": "2022-06-14T08:43:22.78309334Z", + "issuer": "https://example.com", + "type": "VerifiableCredential" + }, + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "credentialSubject": { + "id": "example/example/2.0", + "result": { + "hello": "world" + } + }, + "issuanceDate": "2022-06-14T08:43:22.783102173Z", + "issuer": "https://example.com", + "type": "VerifiableCredential" + } + ] +}` + +var nonExistingPresentationContexts = `{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.nonexistingschema.org" + ], + "id": "did:123", + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "credentialSubject": { + "allow": true, + "id": "example/example/1.0", + "taskID": "0123456789abcdef" + }, + "issuanceDate": "2022-06-14T08:43:22.78309334Z", + "issuer": "https://example.com", + "type": "VerifiableCredential" + }, + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "credentialSubject": { + "id": "example/example/2.0", + "result": { + "hello": "world" + } + }, + "issuanceDate": "2022-06-14T08:43:22.783102173Z", + "issuer": "https://example.com", + "type": "VerifiableCredential" + } + ] +}`