diff --git a/doc/swagger.yaml b/doc/swagger.yaml index a4c41cebe..112a1a96d 100644 --- a/doc/swagger.yaml +++ b/doc/swagger.yaml @@ -89,7 +89,7 @@ definitions: - issuer - type type: object - cryptosuite.PublicKeyJWK: + crypto.PublicKeyJWK: properties: alg: type: string @@ -151,9 +151,33 @@ definitions: type: array type: object did.Service: + properties: + accept: + items: + type: string + type: array + id: + type: string + routingKeys: + items: + type: string + type: array + serviceEndpoint: + description: |- + A string, map, or set composed of one or more strings and/or maps + All string values must be valid URIs + type: + type: string + required: + - id + - serviceEndpoint + - type type: object did.VerificationMethod: properties: + blockchainAccountId: + description: for PKH DIDs - https://github.com/w3c-ccg/did-pkh/blob/90b28ad3c18d63822a8aab3c752302aa64fc9382/did-pkh-method-draft.md + type: string controller: type: string id: @@ -161,7 +185,7 @@ definitions: publicKeyBase58: type: string publicKeyJwk: - $ref: '#/definitions/cryptosuite.PublicKeyJWK' + $ref: '#/definitions/crypto.PublicKeyJWK' description: must conform to https://datatracker.ietf.org/doc/html/rfc7517 publicKeyMultibase: description: https://datatracker.ietf.org/doc/html/draft-multiformats-multibase-03 @@ -173,6 +197,253 @@ definitions: - id - type type: object + dwn.DWNPublishManifestResponse: + properties: + response: + type: string + status: + type: integer + required: + - response + - status + type: object + exchange.ClaimFormat: + properties: + jwt: + $ref: '#/definitions/exchange.JWTType' + jwt_vc: + $ref: '#/definitions/exchange.JWTType' + jwt_vp: + $ref: '#/definitions/exchange.JWTType' + ldp: + $ref: '#/definitions/exchange.LDPType' + ldp_vc: + $ref: '#/definitions/exchange.LDPType' + ldp_vp: + $ref: '#/definitions/exchange.LDPType' + type: object + exchange.Constraints: + properties: + fields: + items: + $ref: '#/definitions/exchange.Field' + type: array + is_holder: + $ref: '#/definitions/exchange.RelationalConstraint' + limit_disclosure: + description: |- + If a predicate property is present, filter must be too + https://identity.foundation/presentation-exchange/#predicate-feature + type: string + same_subject: + $ref: '#/definitions/exchange.RelationalConstraint' + statuses: + $ref: '#/definitions/exchange.CredentialStatus' + description: https://identity.foundation/presentation-exchange/#credential-status-constraint-feature + subject_is_issuer: + description: https://identity.foundation/presentation-exchange/#relational-constraint-feature + type: string + type: object + exchange.CredentialStatus: + properties: + active: + properties: + directive: + description: https://identity.foundation/presentation-exchange/#relational-constraint-feature + type: string + type: object + revoked: + properties: + directive: + description: https://identity.foundation/presentation-exchange/#relational-constraint-feature + type: string + type: object + suspended: + properties: + directive: + description: https://identity.foundation/presentation-exchange/#relational-constraint-feature + type: string + type: object + type: object + exchange.Field: + properties: + filter: + $ref: '#/definitions/exchange.Filter' + id: + type: string + path: + items: + type: string + type: array + predicate: + description: |- + If a predicate property is present, filter must be too + https://identity.foundation/presentation-exchange/#predicate-feature + type: string + purpose: + type: string + required: + - path + type: object + exchange.Filter: + properties: + allOf: {} + const: {} + enum: + items: {} + type: array + exclusiveMaximum: {} + exclusiveMinimum: {} + format: + type: string + formatMaximum: {} + formatMinimum: + description: TODO(gabe) these may not be valid https://github.com/decentralized-identity/presentation-exchange/issues/312 + maxLength: + type: integer + maximum: {} + minLength: + type: integer + minimum: {} + not: {} + oneOf: {} + pattern: + type: string + type: + type: string + type: object + exchange.InputDescriptor: + properties: + constraints: + $ref: '#/definitions/exchange.Constraints' + format: + $ref: '#/definitions/exchange.ClaimFormat' + group: + description: Must match a grouping strings listed in the `from` values of + a submission requirement rule + items: + type: string + type: array + id: + description: Must be unique within the Presentation Definition + type: string + name: + type: string + purpose: + description: Purpose for which claim's data is being requested + type: string + required: + - constraints + - id + type: object + exchange.JWTType: + properties: + alg: + items: + type: string + type: array + required: + - alg + type: object + exchange.LDPType: + properties: + proof_type: + items: + type: string + type: array + required: + - proof_type + type: object + exchange.PresentationDefinition: + properties: + format: + $ref: '#/definitions/exchange.ClaimFormat' + frame: + description: https://identity.foundation/presentation-exchange/#json-ld-framing-feature + id: + type: string + input_descriptors: + items: + $ref: '#/definitions/exchange.InputDescriptor' + type: array + name: + type: string + purpose: + type: string + submission_requirements: + items: + $ref: '#/definitions/exchange.SubmissionRequirement' + type: array + required: + - id + - input_descriptors + type: object + exchange.PresentationSubmission: + properties: + definition_id: + type: string + descriptor_map: + items: + $ref: '#/definitions/exchange.SubmissionDescriptor' + type: array + id: + type: string + required: + - definition_id + - descriptor_map + - id + type: object + exchange.RelationalConstraint: + properties: + directive: + description: https://identity.foundation/presentation-exchange/#relational-constraint-feature + type: string + field_id: + type: string + required: + - directive + - field_id + type: object + exchange.SubmissionDescriptor: + properties: + format: + type: string + id: + description: Must match the `id` property of the corresponding input descriptor + type: string + path: + type: string + path_nested: + $ref: '#/definitions/exchange.SubmissionDescriptor' + required: + - format + - id + - path + type: object + exchange.SubmissionRequirement: + properties: + count: + minimum: 1 + type: integer + from: + type: string + from_nested: + items: + $ref: '#/definitions/exchange.SubmissionRequirement' + type: array + max: + type: integer + min: + type: integer + name: + type: string + purpose: + type: string + rule: + type: string + required: + - rule + type: object github.com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialRequest: properties: '@context': @@ -216,6 +487,18 @@ definitions: privateKeyBase58: type: string type: object + github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest: + properties: + manifest: + $ref: '#/definitions/manifest.CredentialManifest' + required: + - manifest + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestResponse: + properties: + manifest: + $ref: '#/definitions/manifest.CredentialManifest' + type: object github.com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaRequest: properties: author: @@ -236,6 +519,20 @@ definitions: schema: $ref: '#/definitions/schema.VCJSONSchema' type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationResponse: + properties: + application: + $ref: '#/definitions/manifest.CredentialApplication' + id: + type: string + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationsResponse: + properties: + applications: + items: + $ref: '#/definitions/manifest.CredentialApplication' + type: array + type: object github.com_tbd54566975_ssi-service_pkg_server_router.GetCredentialResponse: properties: credential: @@ -262,6 +559,13 @@ definitions: type: string type: array type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDsByMethodResponse: + properties: + dids: + items: + $ref: '#/definitions/did.DIDDocument' + type: array + type: object github.com_tbd54566975_ssi-service_pkg_server_router.GetHealthCheckResponse: properties: status: @@ -278,6 +582,34 @@ definitions: type: type: string type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse: + properties: + id: + type: string + manifest: + $ref: '#/definitions/manifest.CredentialManifest' + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestsResponse: + properties: + manifests: + items: + $ref: '#/definitions/manifest.CredentialManifest' + type: array + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetResponseResponse: + properties: + id: + type: string + response: + $ref: '#/definitions/manifest.CredentialResponse' + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetResponsesResponse: + properties: + responses: + items: + $ref: '#/definitions/manifest.CredentialResponse' + type: array + type: object github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse: properties: schema: @@ -290,6 +622,23 @@ definitions: $ref: '#/definitions/schema.VCJSONSchema' type: array type: object + github.com_tbd54566975_ssi-service_pkg_server_router.PublishManifestRequest: + properties: + manifestId: + type: string + required: + - manifestId + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.PublishManifestResponse: + properties: + dwnResponse: + $ref: '#/definitions/dwn.DWNPublishManifestResponse' + manifest: + $ref: '#/definitions/manifest.CredentialManifest' + required: + - dwnResponse + - manifest + type: object github.com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest: properties: base58PrivateKey: @@ -306,6 +655,138 @@ definitions: - id - type type: object + github.com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationRequest: + properties: + application: + $ref: '#/definitions/manifest.CredentialApplication' + requesterDid: + description: Once we have JWT signed wrapper that can get the did this can + be removed + type: string + required: + - application + - requesterDid + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationResponse: + properties: + credentials: + items: + $ref: '#/definitions/credential.VerifiableCredential' + type: array + response: + $ref: '#/definitions/manifest.CredentialResponse' + type: object + manifest.CredentialApplication: + properties: + format: + $ref: '#/definitions/exchange.ClaimFormat' + id: + type: string + manifest_id: + type: string + presentation_submission: + $ref: '#/definitions/exchange.PresentationSubmission' + description: Must be present if the corresponding manifest contains a presentation_definition + spec_version: + type: string + required: + - format + - id + - manifest_id + - spec_version + type: object + manifest.CredentialManifest: + properties: + format: + $ref: '#/definitions/exchange.ClaimFormat' + id: + type: string + issuer: + $ref: '#/definitions/manifest.Issuer' + output_descriptors: + items: + $ref: '#/definitions/manifest.OutputDescriptor' + type: array + presentation_definition: + $ref: '#/definitions/exchange.PresentationDefinition' + spec_version: + type: string + required: + - id + - issuer + - output_descriptors + - spec_version + type: object + manifest.CredentialResponse: + properties: + application_id: + type: string + denial: + properties: + input_descriptors: + items: + type: string + type: array + reason: + type: string + required: + - reason + type: object + fulfillment: + properties: + descriptor_map: + items: + $ref: '#/definitions/exchange.SubmissionDescriptor' + type: array + required: + - descriptor_map + type: object + id: + type: string + manifest_id: + type: string + spec_version: + type: string + required: + - id + - manifest_id + - spec_version + type: object + manifest.Issuer: + properties: + id: + type: string + name: + type: string + styles: + $ref: '#/definitions/rendering.EntityStyleDescriptor' + description: |- + an object or URI as defined by the DIF Entity Styles specification + https://identity.foundation/wallet-rendering/#entity-styles + required: + - id + type: object + manifest.OutputDescriptor: + properties: + description: + type: string + display: + $ref: '#/definitions/rendering.DataDisplay' + description: 'both below: an object or URI as defined by the DIF Entity Styles + specification' + id: + description: Must be unique within a manifest + type: string + name: + type: string + schema: + type: string + styles: + $ref: '#/definitions/rendering.EntityStyleDescriptor' + required: + - id + - schema + type: object pkg_server_router.CreateCredentialRequest: properties: '@context': @@ -349,6 +830,18 @@ definitions: privateKeyBase58: type: string type: object + pkg_server_router.CreateManifestRequest: + properties: + manifest: + $ref: '#/definitions/manifest.CredentialManifest' + required: + - manifest + type: object + pkg_server_router.CreateManifestResponse: + properties: + manifest: + $ref: '#/definitions/manifest.CredentialManifest' + type: object pkg_server_router.CreateSchemaRequest: properties: author: @@ -369,6 +862,20 @@ definitions: schema: $ref: '#/definitions/schema.VCJSONSchema' type: object + pkg_server_router.GetApplicationResponse: + properties: + application: + $ref: '#/definitions/manifest.CredentialApplication' + id: + type: string + type: object + pkg_server_router.GetApplicationsResponse: + properties: + applications: + items: + $ref: '#/definitions/manifest.CredentialApplication' + type: array + type: object pkg_server_router.GetCredentialResponse: properties: credential: @@ -395,6 +902,13 @@ definitions: type: string type: array type: object + pkg_server_router.GetDIDsByMethodResponse: + properties: + dids: + items: + $ref: '#/definitions/did.DIDDocument' + type: array + type: object pkg_server_router.GetHealthCheckResponse: properties: status: @@ -411,21 +925,66 @@ definitions: type: type: string type: object - pkg_server_router.GetSchemaResponse: + pkg_server_router.GetManifestResponse: properties: - schema: - $ref: '#/definitions/schema.VCJSONSchema' + id: + type: string + manifest: + $ref: '#/definitions/manifest.CredentialManifest' type: object - pkg_server_router.GetSchemasResponse: + pkg_server_router.GetManifestsResponse: properties: - schemas: + manifests: items: - $ref: '#/definitions/schema.VCJSONSchema' + $ref: '#/definitions/manifest.CredentialManifest' type: array type: object - pkg_server_router.StoreKeyRequest: + pkg_server_router.GetResponseResponse: properties: - base58PrivateKey: + id: + type: string + response: + $ref: '#/definitions/manifest.CredentialResponse' + type: object + pkg_server_router.GetResponsesResponse: + properties: + responses: + items: + $ref: '#/definitions/manifest.CredentialResponse' + type: array + type: object + pkg_server_router.GetSchemaResponse: + properties: + schema: + $ref: '#/definitions/schema.VCJSONSchema' + type: object + pkg_server_router.GetSchemasResponse: + properties: + schemas: + items: + $ref: '#/definitions/schema.VCJSONSchema' + type: array + type: object + pkg_server_router.PublishManifestRequest: + properties: + manifestId: + type: string + required: + - manifestId + type: object + pkg_server_router.PublishManifestResponse: + properties: + dwnResponse: + $ref: '#/definitions/dwn.DWNPublishManifestResponse' + manifest: + $ref: '#/definitions/manifest.CredentialManifest' + required: + - dwnResponse + - manifest + type: object + pkg_server_router.StoreKeyRequest: + properties: + base58PrivateKey: type: string controller: type: string @@ -439,6 +998,118 @@ definitions: - id - type type: object + pkg_server_router.SubmitApplicationRequest: + properties: + application: + $ref: '#/definitions/manifest.CredentialApplication' + requesterDid: + description: Once we have JWT signed wrapper that can get the did this can + be removed + type: string + required: + - application + - requesterDid + type: object + pkg_server_router.SubmitApplicationResponse: + properties: + credentials: + items: + $ref: '#/definitions/credential.VerifiableCredential' + type: array + response: + $ref: '#/definitions/manifest.CredentialResponse' + type: object + rendering.ColorResource: + properties: + color: + description: 'a HEX string color value (e.g. #00000)' + type: string + type: object + rendering.DataDisplay: + properties: + description: + $ref: '#/definitions/rendering.DisplayMappingObject' + properties: + items: + $ref: '#/definitions/rendering.LabeledDisplayMappingObject' + type: array + subtitle: + $ref: '#/definitions/rendering.DisplayMappingObject' + title: + $ref: '#/definitions/rendering.DisplayMappingObject' + type: object + rendering.DisplayMappingObject: + properties: + fallback: + type: string + path: + description: |- + Ifa path is present it must be an array of JSON Path string expressions + and the schema property must also be present. + items: + type: string + type: array + schema: + $ref: '#/definitions/rendering.DisplayMappingSchema' + text: + description: If path is not present, the text value is required with no other + properties + type: string + type: object + rendering.DisplayMappingSchema: + properties: + format: + description: Must be present if the value of the type property is "string" + type: string + type: + type: string + required: + - type + type: object + rendering.EntityStyleDescriptor: + properties: + background: + $ref: '#/definitions/rendering.ColorResource' + hero: + $ref: '#/definitions/rendering.ImageResource' + text: + $ref: '#/definitions/rendering.ColorResource' + thumbnail: + $ref: '#/definitions/rendering.ImageResource' + type: object + rendering.ImageResource: + properties: + alt: + description: Describes the alternate text for a logo image + type: string + uri: + description: Must be a valid URI string to an image resource + type: string + required: + - uri + type: object + rendering.LabeledDisplayMappingObject: + properties: + fallback: + type: string + label: + type: string + path: + description: |- + Ifa path is present it must be an array of JSON Path string expressions + and the schema property must also be present. + items: + type: string + type: array + schema: + $ref: '#/definitions/rendering.DisplayMappingSchema' + text: + description: If path is not present, the text value is required with no other + properties + type: string + required: + - label + type: object schema.JSONSchema: additionalProperties: true type: object @@ -634,11 +1305,35 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDMethodsResponse' + $ref: '#/definitions/pkg_server_router.GetDIDMethodsResponse' summary: Get DID Methods tags: - DecentralizedIdentityAPI /v1/dids/{method}: + get: + consumes: + - application/json + description: Get DIDs by method + parameters: + - description: Method + in: path + name: method + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.GetDIDsByMethodResponse' + "400": + description: Bad request + schema: + type: string + summary: Get DIDs + tags: + - DecentralizedIdentityAPI put: consumes: - application/json @@ -649,7 +1344,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodRequest' + $ref: '#/definitions/pkg_server_router.CreateDIDByMethodRequest' - description: Method in: path name: method @@ -661,7 +1356,7 @@ paths: "201": description: Created schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodResponse' + $ref: '#/definitions/pkg_server_router.CreateDIDByMethodResponse' "400": description: Bad request schema: @@ -677,14 +1372,14 @@ paths: get: consumes: - application/json - description: Get DID By Method + description: Get DID by method parameters: - description: request body in: body name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodRequest' + $ref: '#/definitions/pkg_server_router.CreateDIDByMethodRequest' - description: Method in: path name: method @@ -701,7 +1396,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDByMethodResponse' + $ref: '#/definitions/pkg_server_router.GetDIDByMethodResponse' "400": description: Bad request schema: @@ -709,6 +1404,36 @@ paths: summary: Get DID tags: - DecentralizedIdentityAPI + /v1/dwn/manifest: + put: + consumes: + - application/json + description: Public Manifest to DWN + parameters: + - description: request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.PublishManifestRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.PublishManifestResponse' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Public Manifest to DWN + tags: + - DWNAPI /v1/keys: put: consumes: @@ -720,7 +1445,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest' + $ref: '#/definitions/pkg_server_router.StoreKeyRequest' produces: - application/json responses: @@ -754,7 +1479,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetKeyDetailsResponse' + $ref: '#/definitions/pkg_server_router.GetKeyDetailsResponse' "400": description: Bad request schema: @@ -762,6 +1487,308 @@ paths: summary: Get Details For Key tags: - KeyStoreAPI + /v1/manifests: + get: + consumes: + - application/json + description: Checks for the presence of a query parameter and calls the associated + filtered get method + parameters: + - description: string issuer + in: query + name: issuer + type: string + - description: string schema + in: query + name: schema + type: string + - description: string subject + in: query + name: subject + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.GetManifestsResponse' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Get manifests + tags: + - ManifestAPI + put: + consumes: + - application/json + description: Create manifest + parameters: + - description: request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/pkg_server_router.CreateManifestRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/pkg_server_router.CreateManifestResponse' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Create manifest + tags: + - ManifestAPI + /v1/manifests/{id}: + delete: + consumes: + - application/json + description: Delete manifest by ID + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Delete manifests + tags: + - ManifestAPI + get: + consumes: + - application/json + description: Get manifest by id + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.GetManifestResponse' + "400": + description: Bad request + schema: + type: string + summary: Get manifest + tags: + - ManifestAPI + /v1/manifests/applications: + get: + consumes: + - application/json + description: Checks for the presence of a query parameter and calls the associated + filtered get method + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.GetApplicationsResponse' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Get applications + tags: + - ApplicationAPI + put: + consumes: + - application/json + description: Submit application + parameters: + - description: request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/pkg_server_router.SubmitApplicationRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/pkg_server_router.SubmitApplicationResponse' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Submit application + tags: + - ApplicationAPI + /v1/manifests/applications/{id}: + delete: + consumes: + - application/json + description: Delete application by ID + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Delete applications + tags: + - ApplicationAPI + get: + consumes: + - application/json + description: Get application by id + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.GetApplicationResponse' + "400": + description: Bad request + schema: + type: string + summary: Get application + tags: + - ApplicationAPI + /v1/manifests/responses: + get: + consumes: + - application/json + description: Checks for the presence of a query parameter and calls the associated + filtered get method + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.GetResponsesResponse' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Get responses + tags: + - ResponseAPI + /v1/manifests/responses/{id}: + delete: + consumes: + - application/json + description: Delete response by ID + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Delete responses + tags: + - ResponseAPI + get: + consumes: + - application/json + description: Get response by id + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.GetResponseResponse' + "400": + description: Bad request + schema: + type: string + summary: Get response + tags: + - ResponseAPI /v1/schemas: get: consumes: @@ -773,7 +1800,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetSchemasResponse' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemasResponse' "500": description: Internal server error schema: @@ -791,14 +1818,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/pkg_server_router.CreateSchemaRequest' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaRequest' produces: - application/json responses: "201": description: Created schema: - $ref: '#/definitions/pkg_server_router.CreateSchemaResponse' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaResponse' "400": description: Bad request schema: @@ -827,7 +1854,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetSchemaResponse' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse' "400": description: Bad request schema: diff --git a/magefile.go b/magefile.go index ce535b68e..77fefd6df 100644 --- a/magefile.go +++ b/magefile.go @@ -73,7 +73,7 @@ func Spec() error { logrus.Fatal(err) return err } - return sh.Run(swagCommand, "init", "-g", "cmd/main.go", "--pd", "-o", "docs", "-ot", "yaml") + return sh.Run(swagCommand, "init", "-g", "cmd/main.go", "--pd", "-o", "doc", "-ot", "yaml") } func runCITests(extraTestArgs ...string) error { diff --git a/pkg/server/router/did.go b/pkg/server/router/did.go index 94b32ee3b..2bc1702f0 100644 --- a/pkg/server/router/did.go +++ b/pkg/server/router/did.go @@ -152,3 +152,39 @@ func (dr DIDRouter) GetDIDByMethod(ctx context.Context, w http.ResponseWriter, _ resp := GetDIDByMethodResponse{DID: gotDID.DID} return framework.Respond(ctx, w, resp, http.StatusOK) } + +type GetDIDsByMethodResponse struct { + DIDs []didsdk.DIDDocument `json:"dids,omitempty"` +} + +// GetDIDsByMethod godoc +// @Summary Get DIDs +// @Description Get DIDs by method +// @Tags DecentralizedIdentityAPI +// @Accept json +// @Produce json +// @Param method path string true "Method" +// @Success 200 {object} GetDIDsByMethodResponse +// @Failure 400 {string} string "Bad request" +// @Router /v1/dids/{method} [get] +func (dr DIDRouter) GetDIDsByMethod(ctx context.Context, w http.ResponseWriter, _ *http.Request) error { + method := framework.GetParam(ctx, MethodParam) + if method == nil { + errMsg := "get DIDs by method request missing method parameter" + logrus.Error(errMsg) + return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest) + } + + // TODO(gabe) check if the method is supported, to tell whether this is a bad req or internal error + // TODO(gabe) differentiate between internal errors and not found DIDs + getDIDsRequest := did.GetDIDsRequest{Method: did.Method(*method)} + gotDIDs, err := dr.service.GetDIDsByMethod(getDIDsRequest) + if err != nil { + errMsg := fmt.Sprintf("could not get DIDs for method: %s", *method) + logrus.WithError(err).Error(errMsg) + return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest) + } + + resp := GetDIDsByMethodResponse{DIDs: gotDIDs.DIDs} + return framework.Respond(ctx, w, resp, http.StatusOK) +} diff --git a/pkg/server/router/did_test.go b/pkg/server/router/did_test.go index 33c51220e..3799ed9b7 100644 --- a/pkg/server/router/did_test.go +++ b/pkg/server/router/did_test.go @@ -79,5 +79,26 @@ func TestDIDRouter(t *testing.T) { // make sure it's the same value assert.Equal(tt, createDIDResponse.DID.ID, getDIDResponse.DID.ID) + + // create a second DID + createDIDResponse2, err := didService.CreateDIDByMethod(did.CreateDIDRequest{Method: did.KeyMethod, KeyType: crypto.Ed25519}) + assert.NoError(tt, err) + assert.NotEmpty(tt, createDIDResponse2) + + // get all DIDs back + getDIDsResponse, err := didService.GetDIDsByMethod(did.GetDIDsRequest{Method: did.KeyMethod}) + assert.NoError(tt, err) + assert.NotEmpty(tt, getDIDsResponse) + assert.Len(tt, getDIDsResponse.DIDs, 2) + + knownDIDs := map[string]bool{createDIDResponse.DID.ID: true, createDIDResponse2.DID.ID: true} + for _, did := range getDIDsResponse.DIDs { + if _, ok := knownDIDs[did.ID]; !ok { + tt.Error("got unknown DID") + } else { + delete(knownDIDs, did.ID) + } + } + assert.Len(tt, knownDIDs, 0) }) } diff --git a/pkg/server/server.go b/pkg/server/server.go index b9f5c6df3..60267f29f 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -115,6 +115,7 @@ func (s *SSIServer) DecentralizedIdentityAPI(service svcframework.Service) (err s.Handle(http.MethodGet, handlerPath, didRouter.GetDIDMethods) s.Handle(http.MethodPut, path.Join(handlerPath, "/:method"), didRouter.CreateDIDByMethod) + s.Handle(http.MethodGet, path.Join(handlerPath, "/:method"), didRouter.GetDIDsByMethod) s.Handle(http.MethodGet, path.Join(handlerPath, "/:method/:id"), didRouter.GetDIDByMethod) return } diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index b2eaf5513..4dcb68b56 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -146,21 +146,25 @@ func TestDIDAPI(t *testing.T) { assert.Error(tt, err) assert.Contains(tt, err.Error(), "invalid create DID request") + // reset recorder between calls + w.Flush() + // with body, bad key type createDIDRequest := router.CreateDIDByMethodRequest{KeyType: "bad"} requestReader := newRequestValue(tt, createDIDRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/dids/key", requestReader) - w = httptest.NewRecorder() err = didService.CreateDIDByMethod(newRequestContextWithParams(params), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), "could not create DID for method with key type: bad") + // reset recorder between calls + w.Flush() + // with body, good key type createDIDRequest = router.CreateDIDByMethodRequest{KeyType: crypto.Ed25519} requestReader = newRequestValue(tt, createDIDRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/dids/key", requestReader) - w = httptest.NewRecorder() err = didService.CreateDIDByMethod(newRequestContextWithParams(params), w, req) assert.NoError(tt, err) @@ -197,6 +201,9 @@ func TestDIDAPI(t *testing.T) { assert.Error(tt, err) assert.Contains(tt, err.Error(), "could not get DID for method") + // reset recorder between calls + w.Flush() + // good method, bad id badParams1 := map[string]string{ "method": "key", @@ -206,12 +213,13 @@ func TestDIDAPI(t *testing.T) { assert.Error(tt, err) assert.Contains(tt, err.Error(), "could not get DID for method with id: worse") + // reset recorder between calls + w.Flush() // store a DID createDIDRequest := router.CreateDIDByMethodRequest{KeyType: crypto.Ed25519} requestReader := newRequestValue(tt, createDIDRequest) params := map[string]string{"method": "key"} req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/dids/key", requestReader) - w = httptest.NewRecorder() err = didService.CreateDIDByMethod(newRequestContextWithParams(params), w, req) assert.NoError(tt, err) @@ -220,11 +228,13 @@ func TestDIDAPI(t *testing.T) { err = json.NewDecoder(w.Body).Decode(&createdDID) assert.NoError(tt, err) + // reset recorder between calls + w.Flush() + // get it back createdID := createdDID.DID.ID getDIDPath := fmt.Sprintf("https://ssi-service.com/v1/dids/key/%s", createdID) req = httptest.NewRequest(http.MethodGet, getDIDPath, nil) - w = httptest.NewRecorder() // good params goodParams := map[string]string{ @@ -239,6 +249,94 @@ func TestDIDAPI(t *testing.T) { assert.NoError(tt, err) assert.Equal(tt, createdID, resp.DID.ID) }) + + t.Run("Test Get DIDs By Method", func(tt *testing.T) { + bolt, err := storage.NewBoltDB() + + // remove the db file after the test + tt.Cleanup(func() { + _ = bolt.Close() + _ = os.Remove(storage.DBFile) + }) + + _, keyStore := testKeyStore(tt, bolt) + didService := testDIDRouter(tt, bolt, keyStore) + + // get DIDs by method + req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/dids/bad", nil) + w := httptest.NewRecorder() + + // bad params + badParams := map[string]string{ + "method": "bad", + } + err = didService.GetDIDsByMethod(newRequestContextWithParams(badParams), w, req) + assert.Error(tt, err) + assert.Contains(tt, err.Error(), "could not get DIDs for method: bad") + + // good method + goodParams := map[string]string{ + "method": "key", + } + err = didService.GetDIDsByMethod(newRequestContextWithParams(goodParams), w, req) + assert.NoError(tt, err) + var gotDIDs router.GetDIDByMethodResponse + err = json.NewDecoder(w.Body).Decode(&gotDIDs) + assert.NoError(tt, err) + assert.Empty(tt, gotDIDs) + + // reset recorder between calls + w.Flush() + + // store two DIDs + createDIDRequest := router.CreateDIDByMethodRequest{KeyType: crypto.Ed25519} + requestReader := newRequestValue(tt, createDIDRequest) + params := map[string]string{"method": "key"} + req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/dids/key", requestReader) + + err = didService.CreateDIDByMethod(newRequestContextWithParams(params), w, req) + assert.NoError(tt, err) + + var createdDID router.CreateDIDByMethodResponse + err = json.NewDecoder(w.Body).Decode(&createdDID) + assert.NoError(tt, err) + + // reset recorder between calls + w.Flush() + + requestReader = newRequestValue(tt, createDIDRequest) + req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/dids/key", requestReader) + + err = didService.CreateDIDByMethod(newRequestContextWithParams(params), w, req) + assert.NoError(tt, err) + + var createdDID2 router.CreateDIDByMethodResponse + err = json.NewDecoder(w.Body).Decode(&createdDID2) + assert.NoError(tt, err) + + // reset recorder between calls + w.Flush() + + // get all dids for method + + req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/dids/key", requestReader) + err = didService.GetDIDsByMethod(newRequestContextWithParams(params), w, req) + assert.NoError(tt, err) + + var gotDIDsResponse router.GetDIDsByMethodResponse + err = json.NewDecoder(w.Body).Decode(&gotDIDsResponse) + assert.NoError(tt, err) + + knownDIDs := map[string]bool{createdDID.DID.ID: true, createdDID2.DID.ID: true} + for _, did := range gotDIDsResponse.DIDs { + if _, ok := knownDIDs[did.ID]; !ok { + tt.Error("got unknown DID") + } else { + delete(knownDIDs, did.ID) + } + } + assert.Len(tt, knownDIDs, 0) + }) } func TestSchemaAPI(t *testing.T) { diff --git a/pkg/service/did/did.go b/pkg/service/did/did.go index 449732fa6..3571c7d31 100644 --- a/pkg/service/did/did.go +++ b/pkg/service/did/did.go @@ -33,6 +33,7 @@ type Service struct { type MethodHandler interface { CreateDID(request CreateDIDRequest) (*CreateDIDResponse, error) GetDID(request GetDIDRequest) (*GetDIDResponse, error) + GetDIDs(method Method) (*GetDIDsResponse, error) } func NewDIDService(config config.DIDServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) { @@ -116,6 +117,16 @@ func (s *Service) GetDIDByMethod(request GetDIDRequest) (*GetDIDResponse, error) return handler.GetDID(request) } +func (s *Service) GetDIDsByMethod(request GetDIDsRequest) (*GetDIDsResponse, error) { + method := request.Method + handler, err := s.getHandler(method) + if err != nil { + errMsg := fmt.Sprintf("could not get handler for method<%s>", method) + return nil, util.LoggingErrorMsg(err, errMsg) + } + return handler.GetDIDs(method) +} + func (s *Service) getHandler(method Method) (MethodHandler, error) { handler, ok := s.handlers[method] if !ok { diff --git a/pkg/service/did/key.go b/pkg/service/did/key.go index 822a55774..e56de59b5 100644 --- a/pkg/service/did/key.go +++ b/pkg/service/did/key.go @@ -87,6 +87,21 @@ func (h *keyDIDHandler) GetDID(request GetDIDRequest) (*GetDIDResponse, error) { return &GetDIDResponse{DID: gotDID.DID}, nil } +func (h *keyDIDHandler) GetDIDs(method Method) (*GetDIDsResponse, error) { + + logrus.Debugf("getting DIDs for method: %s", method) + + gotDIDs, err := h.storage.GetDIDs(string(method)) + if err != nil { + return nil, fmt.Errorf("error getting DIDs for method: %s", method) + } + var dids []did.DIDDocument + for _, did := range gotDIDs { + dids = append(dids, did.DID) + } + return &GetDIDsResponse{DIDs: dids}, nil +} + func privateKeyToBase58(privKey interface{}) (string, error) { if haveBytes, ok := privKey.([]byte); ok { return base58.Encode(haveBytes), nil diff --git a/pkg/service/did/model.go b/pkg/service/did/model.go index 8625d27df..ea49ec1b0 100644 --- a/pkg/service/did/model.go +++ b/pkg/service/did/model.go @@ -31,3 +31,12 @@ type GetDIDRequest struct { type GetDIDResponse struct { DID didsdk.DIDDocument `json:"did"` } + +type GetDIDsRequest struct { + Method Method `json:"method" validate:"required"` +} + +// GetDIDsResponse is the JSON-serializable response for getting all DIDs for a given method +type GetDIDsResponse struct { + DIDs []didsdk.DIDDocument `json:"dids"` +} diff --git a/pkg/service/did/storage/bolt.go b/pkg/service/did/storage/bolt.go index df2b9b159..2f2604428 100644 --- a/pkg/service/did/storage/bolt.go +++ b/pkg/service/did/storage/bolt.go @@ -5,6 +5,7 @@ import ( "github.com/goccy/go-json" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/tbd54566975/ssi-service/internal/util" "github.com/tbd54566975/ssi-service/pkg/storage" @@ -79,8 +80,8 @@ func (b BoltDIDStorage) GetDIDs(method string) ([]StoredDID, error) { return nil, util.LoggingErrorMsg(err, couldNotGetDIDsErr) } if len(gotDIDs) == 0 { - err := fmt.Errorf("no DIDs found for method: %s", method) - return nil, util.LoggingErrorMsg(err, "could not get stored DIDs") + logrus.Infof("no DIDs found for method: %s", method) + return nil, nil } var stored []StoredDID for _, didBytes := range gotDIDs {