diff --git a/doc/swagger.yaml b/doc/swagger.yaml index 349353965..56298acee 100644 --- a/doc/swagger.yaml +++ b/doc/swagger.yaml @@ -1,16 +1,4 @@ definitions: - credential.Container: - properties: - credential: - $ref: '#/definitions/credential.VerifiableCredential' - credentialJWT: - type: string - id: - description: Credential ID - type: string - revoked: - type: boolean - type: object credential.CredentialSchema: properties: id: @@ -68,7 +56,8 @@ definitions: $ref: '#/definitions/credential.CredentialSchema' credentialStatus: {} credentialSubject: - $ref: '#/definitions/credential.CredentialSubject' + allOf: + - $ref: '#/definitions/credential.CredentialSubject' description: This is where the subject's ID *may* be present evidence: items: {} @@ -101,6 +90,26 @@ definitions: - issuer - type type: object + crypto.KeyType: + enum: + - Ed25519 + - X25519 + - secp256k1 + - P-224 + - P-256 + - P-384 + - P-521 + - RSA + type: string + x-enum-varnames: + - Ed25519 + - X25519 + - SECP256k1 + - P224 + - P256 + - P384 + - P521 + - RSA crypto.PublicKeyJWK: properties: alg: @@ -126,6 +135,20 @@ definitions: required: - kty type: object + crypto.SignatureAlgorithm: + enum: + - EdDSA + - ES256K + - ES256 + - ES384 + - PS256 + type: string + x-enum-varnames: + - EdDSA + - ES256K + - ES256 + - ES384 + - PS256 did.DIDDocument: properties: '@context': {} @@ -155,7 +178,7 @@ definitions: type: array service: items: - $ref: '#/definitions/did.Service' + $ref: '#/definitions/github_com_TBD54566975_ssi-sdk_did.Service' type: array verificationMethod: items: @@ -188,6 +211,18 @@ definitions: error: $ref: '#/definitions/did.ResolutionError' type: object + did.Method: + enum: + - key + - peer + - pkh + - web + type: string + x-enum-varnames: + - KeyMethod + - PeerMethod + - PKHMethod + - WebMethod did.ResolutionError: properties: code: @@ -199,8 +234,6 @@ definitions: representationNotSupported: type: boolean type: object - did.Service: - type: object did.VerificationMethod: properties: blockchainAccountId: @@ -213,7 +246,8 @@ definitions: publicKeyBase58: type: string publicKeyJwk: - $ref: '#/definitions/crypto.PublicKeyJWK' + allOf: + - $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 @@ -249,38 +283,34 @@ definitions: 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 + $ref: '#/definitions/exchange.Preference' same_subject: $ref: '#/definitions/exchange.RelationalConstraint' statuses: - $ref: '#/definitions/exchange.CredentialStatus' + allOf: + - $ref: '#/definitions/exchange.CredentialStatus' description: https://identity.foundation/presentation-exchange/#credential-status-constraint-feature subject_is_issuer: + allOf: + - $ref: '#/definitions/exchange.Preference' 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 + $ref: '#/definitions/exchange.Preference' type: object revoked: properties: directive: - description: https://identity.foundation/presentation-exchange/#relational-constraint-feature - type: string + $ref: '#/definitions/exchange.Preference' type: object suspended: properties: directive: - description: https://identity.foundation/presentation-exchange/#relational-constraint-feature - type: string + $ref: '#/definitions/exchange.Preference' type: object type: object exchange.Field: @@ -300,10 +330,11 @@ definitions: type: string type: array predicate: + allOf: + - $ref: '#/definitions/exchange.Preference' description: |- If a predicate property is present, filter must be too https://identity.foundation/presentation-exchange/#predicate-feature - type: string purpose: type: string required: @@ -368,7 +399,7 @@ definitions: properties: alg: items: - type: string + $ref: '#/definitions/crypto.SignatureAlgorithm' type: array required: - alg @@ -382,6 +413,18 @@ definitions: required: - proof_type type: object + exchange.Preference: + enum: + - required + - preferred + - allowed + - disallowed + type: string + x-enum-varnames: + - Required + - Preferred + - Allowed + - Disallowed exchange.PresentationDefinition: properties: format: @@ -424,14 +467,21 @@ definitions: exchange.RelationalConstraint: properties: directive: - description: https://identity.foundation/presentation-exchange/#relational-constraint-feature - type: string + $ref: '#/definitions/exchange.Preference' field_id: type: string required: - directive - field_id type: object + exchange.Selection: + enum: + - all + - pick + type: string + x-enum-varnames: + - All + - Pick exchange.SubmissionDescriptor: properties: format: @@ -468,11 +518,46 @@ definitions: purpose: type: string rule: - type: string + $ref: '#/definitions/exchange.Selection' required: - rule type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialRequest: + github_com_TBD54566975_ssi-sdk_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 + github_com_tbd54566975_ssi-service_internal_credential.Container: + properties: + credential: + $ref: '#/definitions/credential.VerifiableCredential' + credentialJWT: + type: string + id: + description: Credential ID + type: string + revoked: + type: boolean + type: object + github_com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialRequest: properties: '@context': description: A context is optional. If not present, we'll apply default, required @@ -498,32 +583,32 @@ definitions: - issuer - subject type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialResponse: properties: credential: $ref: '#/definitions/credential.VerifiableCredential' credentialJwt: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodRequest: properties: didWebId: type: string keyType: - type: string + $ref: '#/definitions/crypto.KeyType' required: - keyType type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodResponse: properties: did: $ref: '#/definitions/did.DIDDocument' keyType: - type: string + $ref: '#/definitions/crypto.KeyType' privateKeyBase58: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateIssuanceTemplateRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateIssuanceTemplateRequest: properties: credentialManifest: description: ID of the credential manifest that this template corresponds @@ -532,13 +617,19 @@ definitions: credentials: description: Info required to create a credential from a credential application. items: - $ref: '#/definitions/issuing.CredentialTemplate' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplate' type: array + id: + description: ID of this template. + type: string issuer: description: ID of the issuer that will be issuing the credentials. type: string + required: + - credentialManifest + - issuer type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest: properties: description: type: string @@ -561,14 +652,14 @@ definitions: - issuerDid - outputDescriptors type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateManifestResponse: properties: credential_manifest: $ref: '#/definitions/manifest.CredentialManifest' manifestJwt: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionRequest: properties: format: $ref: '#/definitions/exchange.ClaimFormat' @@ -587,12 +678,12 @@ definitions: required: - inputDescriptors type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionResponse: properties: presentation_definition: $ref: '#/definitions/exchange.PresentationDefinition' type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaRequest: properties: author: type: string @@ -609,7 +700,7 @@ definitions: - name - schema type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaResponse: properties: id: type: string @@ -618,28 +709,28 @@ definitions: schemaJwt: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.CreateSubmissionRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.CreateSubmissionRequest: properties: submissionJwt: type: string required: - submissionJwt type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationResponse: + 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: + 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: + github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialResponse: properties: credential: $ref: '#/definitions/credential.VerifiableCredential' @@ -648,7 +739,7 @@ definitions: id: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusListResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusListResponse: properties: credential: $ref: '#/definitions/credential.VerifiableCredential' @@ -657,43 +748,43 @@ definitions: id: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusResponse: properties: revoked: type: boolean type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetCredentialsResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialsResponse: properties: credentials: items: - $ref: '#/definitions/credential.Container' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_internal_credential.Container' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDByMethodResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetDIDByMethodResponse: properties: did: $ref: '#/definitions/did.DIDDocument' type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDMethodsResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetDIDMethodsResponse: properties: methods: items: - type: string + $ref: '#/definitions/did.Method' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDsByMethodResponse: + 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: + github_com_tbd54566975_ssi-service_pkg_server_router.GetHealthCheckResponse: properties: status: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetKeyDetailsResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetKeyDetailsResponse: properties: controller: type: string @@ -702,9 +793,9 @@ definitions: id: type: string type: - type: string + $ref: '#/definitions/crypto.KeyType' type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse: properties: credential_manifest: $ref: '#/definitions/manifest.CredentialManifest' @@ -713,14 +804,14 @@ definitions: manifestJwt: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestsResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetManifestsResponse: properties: manifests: items: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetOperationsRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.GetOperationsRequest: properties: filter: description: |- @@ -731,47 +822,47 @@ definitions: description: 'The name of the parent''s resource. For example: "/presentation/submissions".' type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetOperationsResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetOperationsResponse: properties: operations: items: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.Operation' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.Operation' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse: properties: presentation_definition: $ref: '#/definitions/exchange.PresentationDefinition' type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetResponseResponse: + 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: + 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: + github_com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse: properties: schema: $ref: '#/definitions/schema.VCJSONSchema' schemaJwt: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemasResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetSchemasResponse: properties: schemas: items: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetSubmissionResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.GetSubmissionResponse: properties: definition_id: type: string @@ -793,14 +884,14 @@ definitions: - id - status type: object - github.com_tbd54566975_ssi-service_pkg_server_router.ListIssuanceTemplatesResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.ListIssuanceTemplatesResponse: properties: issuanceTemplates: items: - $ref: '#/definitions/issuing.IssuanceTemplate' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionRequest: properties: filter: description: |- @@ -808,14 +899,14 @@ definitions: For example: `status = "done"`. type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionResponse: properties: submissions: items: - $ref: '#/definitions/model.Submission' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.Operation: + github_com_tbd54566975_ssi-service_pkg_server_router.Operation: properties: done: description: Whether this operation has finished. @@ -824,10 +915,11 @@ definitions: description: The name of the resource related to this operation. E.g. "presentations/submissions/" type: string result: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.OperationResult' + allOf: + - $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.OperationResult' description: Populated if Done == true. type: object - github.com_tbd54566975_ssi-service_pkg_server_router.OperationResult: + github_com_tbd54566975_ssi-service_pkg_server_router.OperationResult: properties: error: description: Populated when there was an error with the operation. @@ -836,7 +928,7 @@ definitions: description: Populated iff Error == "". The type should be specified in the calling APIs documentation. type: object - github.com_tbd54566975_ssi-service_pkg_server_router.ResolveDIDResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.ResolveDIDResponse: properties: didDocument: $ref: '#/definitions/did.DIDDocument' @@ -845,7 +937,14 @@ definitions: didResolutionMetadata: $ref: '#/definitions/did.DIDResolutionMetadata' type: object - github.com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.ReviewApplicationRequest: + properties: + approved: + type: boolean + reason: + type: string + type: object + github_com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionRequest: properties: approved: type: boolean @@ -854,7 +953,7 @@ definitions: required: - approved type: object - github.com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionResponse: properties: definition_id: type: string @@ -876,7 +975,7 @@ definitions: - id - status type: object - github.com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest: properties: base58PrivateKey: type: string @@ -885,61 +984,71 @@ definitions: id: type: string type: - type: string + $ref: '#/definitions/crypto.KeyType' required: - base58PrivateKey - controller - id - type type: object - github.com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationRequest: properties: applicationJwt: type: string required: - applicationJwt type: object - github.com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationResponse: + properties: + credential_response: + $ref: '#/definitions/manifest.CredentialResponse' + responseJwt: + type: string + verifiableCredentials: + description: this is an interface type to union Data Integrity and JWT style + VCs + type: object + github_com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusRequest: properties: revoked: type: boolean required: - revoked type: object - github.com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusResponse: properties: revoked: type: boolean type: object - github.com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialRequest: properties: credential: $ref: '#/definitions/credential.VerifiableCredential' credentialJwt: type: string type: object - github.com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialResponse: properties: reason: type: string verified: type: boolean type: object - github.com_tbd54566975_ssi-service_pkg_server_router.VerifySchemaRequest: + github_com_tbd54566975_ssi-service_pkg_server_router.VerifySchemaRequest: properties: schemaJwt: type: string required: - schemaJwt type: object - github.com_tbd54566975_ssi-service_pkg_server_router.VerifySchemaResponse: + github_com_tbd54566975_ssi-service_pkg_server_router.VerifySchemaResponse: properties: reason: type: string verified: type: boolean type: object - issuing.ClaimTemplates: + github_com_tbd54566975_ssi-service_pkg_service_issuing.ClaimTemplates: properties: data: additionalProperties: {} @@ -948,13 +1057,15 @@ definitions: claim about the credentialSubject in the credential that will be issued. type: object type: object - issuing.CredentialTemplate: + github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplate: properties: data: - $ref: '#/definitions/issuing.CredentialTemplateData' + allOf: + - $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplateData' description: Date that will be used to determine credential claims. expiry: - $ref: '#/definitions/issuing.TimeLike' + allOf: + - $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.TimeLike' description: Parameter to determine the expiry of the credential. id: description: ID corresponding to an OutputDescriptor.ID from the manifest. @@ -966,24 +1077,19 @@ definitions: description: ID of the CredentialSchema to be used for the issued credential. type: string type: object - issuing.CredentialTemplateData: + github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplateData: properties: claims: - $ref: '#/definitions/issuing.ClaimTemplates' + allOf: + - $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.ClaimTemplates' description: The set of information that will be used to create claims. credentialInputDescriptor: description: |- - ID of the input descriptor in the application. Correponds to one of the + Optional. When present, it's the ID of the input descriptor in the application. Corresponds to one of the PresentationDefinition.InputDescriptors[].ID in the credential manifest. type: string type: object - issuing.GetIssuanceTemplateResponse: - properties: - issuanceTemplate: - $ref: '#/definitions/issuing.IssuanceTemplate' - description: The template that was requested. - type: object - issuing.IssuanceTemplate: + github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate: properties: credentialManifest: description: ID of the credential manifest that this template corresponds @@ -992,19 +1098,49 @@ definitions: credentials: description: Info required to create a credential from a credential application. items: - $ref: '#/definitions/issuing.CredentialTemplate' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplate' type: array + id: + description: ID of this template. + type: string issuer: description: ID of the issuer that will be issuing the credentials. type: string + required: + - credentialManifest + - issuer type: object - issuing.TimeLike: + github_com_tbd54566975_ssi-service_pkg_service_issuing.TimeLike: properties: - time.Duration: + duration: + description: For a fixed offset from when it was issued. type: integer - time.Time: + time: + description: For fixed time in the future. type: string type: object + github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission: + properties: + definition_id: + type: string + descriptor_map: + items: + $ref: '#/definitions/exchange.SubmissionDescriptor' + type: array + id: + type: string + reason: + description: The reason why the submission was approved or denied. + type: string + status: + description: One of {`pending`, `approved`, `denied`, `cancelled`}. + type: string + required: + - definition_id + - descriptor_map + - id + - status + type: object manifest.CredentialApplication: properties: format: @@ -1014,7 +1150,8 @@ definitions: manifest_id: type: string presentation_submission: - $ref: '#/definitions/exchange.PresentationSubmission' + allOf: + - $ref: '#/definitions/exchange.PresentationSubmission' description: Must be present if the corresponding manifest contains a presentation_definition spec_version: type: string @@ -1092,7 +1229,8 @@ definitions: name: type: string styles: - $ref: '#/definitions/rendering.EntityStyleDescriptor' + allOf: + - $ref: '#/definitions/rendering.EntityStyleDescriptor' description: |- an object or URI as defined by the DIF Entity Styles specification https://identity.foundation/wallet-rendering/#entity-styles @@ -1104,7 +1242,8 @@ definitions: description: type: string display: - $ref: '#/definitions/rendering.DataDisplay' + allOf: + - $ref: '#/definitions/rendering.DataDisplay' description: 'both below: an object or URI as defined by the DIF Entity Styles specification' id: @@ -1120,28 +1259,6 @@ definitions: - id - schema type: object - model.Submission: - properties: - definition_id: - type: string - descriptor_map: - items: - $ref: '#/definitions/exchange.SubmissionDescriptor' - type: array - id: - type: string - reason: - description: The reason why the submission was approved or denied. - type: string - status: - description: One of {`pending`, `approved`, `denied`, `cancelled`}. - type: string - required: - - definition_id - - descriptor_map - - id - - status - type: object pkg_server_router.CreateCredentialRequest: properties: '@context': @@ -1180,7 +1297,7 @@ definitions: didWebId: type: string keyType: - type: string + $ref: '#/definitions/crypto.KeyType' required: - keyType type: object @@ -1189,7 +1306,7 @@ definitions: did: $ref: '#/definitions/did.DIDDocument' keyType: - type: string + $ref: '#/definitions/crypto.KeyType' privateKeyBase58: type: string type: object @@ -1202,11 +1319,17 @@ definitions: credentials: description: Info required to create a credential from a credential application. items: - $ref: '#/definitions/issuing.CredentialTemplate' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplate' type: array + id: + description: ID of this template. + type: string issuer: description: ID of the issuer that will be issuing the credentials. type: string + required: + - credentialManifest + - issuer type: object pkg_server_router.CreateManifestRequest: properties: @@ -1336,7 +1459,7 @@ definitions: properties: credentials: items: - $ref: '#/definitions/credential.Container' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_internal_credential.Container' type: array type: object pkg_server_router.GetDIDByMethodResponse: @@ -1348,7 +1471,7 @@ definitions: properties: methods: items: - type: string + $ref: '#/definitions/did.Method' type: array type: object pkg_server_router.GetDIDsByMethodResponse: @@ -1372,7 +1495,7 @@ definitions: id: type: string type: - type: string + $ref: '#/definitions/crypto.KeyType' type: object pkg_server_router.GetManifestResponse: properties: @@ -1467,7 +1590,7 @@ definitions: properties: issuanceTemplates: items: - $ref: '#/definitions/issuing.IssuanceTemplate' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate' type: array type: object pkg_server_router.ListSubmissionRequest: @@ -1482,7 +1605,7 @@ definitions: properties: submissions: items: - $ref: '#/definitions/model.Submission' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission' type: array type: object pkg_server_router.Operation: @@ -1494,7 +1617,8 @@ definitions: description: The name of the resource related to this operation. E.g. "presentations/submissions/" type: string result: - $ref: '#/definitions/pkg_server_router.OperationResult' + allOf: + - $ref: '#/definitions/pkg_server_router.OperationResult' description: Populated if Done == true. type: object pkg_server_router.OperationResult: @@ -1515,6 +1639,13 @@ definitions: didResolutionMetadata: $ref: '#/definitions/did.DIDResolutionMetadata' type: object + pkg_server_router.ReviewApplicationRequest: + properties: + approved: + type: boolean + reason: + type: string + type: object pkg_server_router.ReviewSubmissionRequest: properties: approved: @@ -1555,7 +1686,7 @@ definitions: id: type: string type: - type: string + $ref: '#/definitions/crypto.KeyType' required: - base58PrivateKey - controller @@ -1569,6 +1700,16 @@ definitions: required: - applicationJwt type: object + pkg_server_router.SubmitApplicationResponse: + properties: + credential_response: + $ref: '#/definitions/manifest.CredentialResponse' + responseJwt: + type: string + verifiableCredentials: + description: this is an interface type to union Data Integrity and JWT style + VCs + type: object pkg_server_router.UpdateCredentialStatusRequest: properties: revoked: @@ -1744,7 +1885,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetHealthCheckResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetHealthCheckResponse' summary: Health Check tags: - HealthCheck @@ -1790,7 +1931,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetCredentialsResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialsResponse' "400": description: Bad request schema: @@ -1812,14 +1953,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/pkg_server_router.CreateCredentialRequest' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialRequest' produces: - application/json responses: "201": description: Created schema: - $ref: '#/definitions/pkg_server_router.CreateCredentialResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialResponse' "400": description: Bad request schema: @@ -1876,7 +2017,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetCredentialResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialResponse' "400": description: Bad request schema: @@ -1901,7 +2042,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetCredentialStatusResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusResponse' "400": description: Bad request schema: @@ -1919,14 +2060,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/pkg_server_router.UpdateCredentialStatusRequest' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusRequest' produces: - application/json responses: "201": description: Created schema: - $ref: '#/definitions/pkg_server_router.UpdateCredentialStatusResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusResponse' "400": description: Bad request schema: @@ -1955,7 +2096,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetCredentialStatusListResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusListResponse' "400": description: Bad request schema: @@ -1974,14 +2115,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/pkg_server_router.VerifyCredentialRequest' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialRequest' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.VerifyCredentialResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialResponse' "400": description: Bad request schema: @@ -2135,14 +2276,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/pkg_server_router.CreateIssuanceTemplateRequest' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.CreateIssuanceTemplateRequest' produces: - application/json responses: "201": description: Created schema: - $ref: '#/definitions/issuing.IssuanceTemplate' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate' "400": description: Bad request schema: @@ -2199,7 +2340,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/issuing.GetIssuanceTemplateResponse' + $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate' "400": description: Bad request schema: @@ -2218,7 +2359,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: @@ -2252,7 +2393,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: @@ -2285,7 +2426,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestsResponse' + $ref: '#/definitions/pkg_server_router.GetManifestsResponse' "400": description: Bad request schema: @@ -2307,14 +2448,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest' + $ref: '#/definitions/pkg_server_router.CreateManifestRequest' produces: - application/json responses: "201": description: Created schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestResponse' + $ref: '#/definitions/pkg_server_router.CreateManifestResponse' "400": description: Bad request schema: @@ -2371,7 +2512,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse' + $ref: '#/definitions/pkg_server_router.GetManifestResponse' "400": description: Bad request schema: @@ -2391,7 +2532,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationsResponse' + $ref: '#/definitions/pkg_server_router.GetApplicationsResponse' "400": description: Bad request schema: @@ -2414,7 +2555,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationRequest' + $ref: '#/definitions/pkg_server_router.SubmitApplicationRequest' produces: - application/json responses: @@ -2422,7 +2563,7 @@ paths: description: Operation with a SubmitApplicationResponse type in the `result.response` field. schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.Operation' + $ref: '#/definitions/pkg_server_router.Operation' "400": description: Bad request schema: @@ -2479,7 +2620,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationResponse' + $ref: '#/definitions/pkg_server_router.GetApplicationResponse' "400": description: Bad request schema: @@ -2487,6 +2628,36 @@ paths: summary: Get application tags: - ApplicationAPI + /v1/manifests/applications/{id}/review: + put: + consumes: + - application/json + description: Reviewing an application either fulfills or denies the credential. + parameters: + - description: request body + in: body + name: request + required: true + schema: + $ref: '#/definitions/pkg_server_router.ReviewApplicationRequest' + produces: + - application/json + responses: + "201": + description: Credential Response + schema: + $ref: '#/definitions/pkg_server_router.SubmitApplicationResponse' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Reviews an application + tags: + - ApplicationAPI /v1/manifests/responses: get: consumes: @@ -2499,7 +2670,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetResponsesResponse' + $ref: '#/definitions/pkg_server_router.GetResponsesResponse' "400": description: Bad request schema: @@ -2556,7 +2727,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetResponseResponse' + $ref: '#/definitions/pkg_server_router.GetResponseResponse' "400": description: Bad request schema: @@ -2663,14 +2834,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionRequest' + $ref: '#/definitions/pkg_server_router.CreatePresentationDefinitionRequest' produces: - application/json responses: "201": description: Created schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionResponse' + $ref: '#/definitions/pkg_server_router.CreatePresentationDefinitionResponse' "400": description: Bad request schema: @@ -2727,7 +2898,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse' + $ref: '#/definitions/pkg_server_router.GetPresentationDefinitionResponse' "400": description: Bad request schema: @@ -2747,14 +2918,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionRequest' + $ref: '#/definitions/pkg_server_router.ListSubmissionRequest' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionResponse' + $ref: '#/definitions/pkg_server_router.ListSubmissionResponse' "400": description: Bad request schema: @@ -2776,14 +2947,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateSubmissionRequest' + $ref: '#/definitions/pkg_server_router.CreateSubmissionRequest' produces: - application/json responses: "201": description: The type of response is Submission once the operation has finished. schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.Operation' + $ref: '#/definitions/pkg_server_router.Operation' "400": description: Bad request schema: @@ -2812,7 +2983,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetSubmissionResponse' + $ref: '#/definitions/pkg_server_router.GetSubmissionResponse' "400": description: Bad request schema: @@ -2833,14 +3004,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionRequest' + $ref: '#/definitions/pkg_server_router.ReviewSubmissionRequest' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionResponse' + $ref: '#/definitions/pkg_server_router.ReviewSubmissionResponse' "400": description: Bad request schema: diff --git a/integration/common.go b/integration/common.go index eb9172262..2922e83d9 100644 --- a/integration/common.go +++ b/integration/common.go @@ -307,7 +307,23 @@ func getJSONElement(jsonString string, jsonPath string) (string, error) { return "", errors.Wrap(err, "finding element in json string") } - elementStr := fmt.Sprintf("%v", element) + if element == nil { + return "", nil + } + var elementStr string + switch element.(type) { + case bool: + elementStr = fmt.Sprintf("%v", element) + case string: + elementStr = fmt.Sprintf("%v", element) + case map[string]any: + data, err := json.Marshal(element) + if err != nil { + return "", err + } + elementStr = compactJSONOutput(string(data)) + } + return elementStr, nil } @@ -328,6 +344,7 @@ func get(url string) (string, error) { return "", fmt.Errorf("status code not in the 200s. body: %s", string(body)) } + logrus.Infof("Received: %s", string(body)) return string(body), err } @@ -389,3 +406,23 @@ func getValidApplicationRequest(credAppJSON string, credentialJWT string) manife Credentials: creds, } } + +type reviewApplicationParams struct { + ID string + Approved bool + Reason string +} + +func ReviewApplication(params reviewApplicationParams) (string, error) { + trueApplicationJSON, err := resolveTemplate(params, "review-application-input.json") + if err != nil { + return "", err + } + + output, err := put(endpoint+version+"manifests/applications/"+params.ID+"/review", trueApplicationJSON) + if err != nil { + return "", errors.Wrapf(err, "application endpoint with output: %s", output) + } + + return output, nil +} diff --git a/integration/didweb_integration_test.go b/integration/didweb_integration_test.go index 73ddb9295..54fd74446 100644 --- a/integration/didweb_integration_test.go +++ b/integration/didweb_integration_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" ) var didWebContext = NewTestContext("DIDWeb") @@ -118,7 +119,7 @@ func TestDidWebCreateCredentialManifestIntegration(t *testing.T) { assert.NotEmpty(t, manifestID) } -func TestDidWebSubmitApplicationIntegration(t *testing.T) { +func TestDidWebSubmitAndReviewApplicationIntegration(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } @@ -150,17 +151,39 @@ func TestDidWebSubmitApplicationIntegration(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, credAppJWT) - credentialResponseOutput, err := SubmitApplication(applicationParams{ + submitApplicationOutput, err := SubmitApplication(applicationParams{ ApplicationJWT: credAppJWT, }) assert.NoError(t, err) - assert.NotEmpty(t, credentialResponseOutput) + assert.NotEmpty(t, submitApplicationOutput) - crManifestID, err := getJSONElement(credentialResponseOutput, "$.result.response.credential_response.manifest_id") + isDone, err := getJSONElement(submitApplicationOutput, "$.done") + assert.NoError(t, err) + assert.Equal(t, "false", isDone) + opID, err := getJSONElement(submitApplicationOutput, "$.id") + assert.NoError(t, err) + + reviewApplicationOutput, err := ReviewApplication(reviewApplicationParams{ + ID: storage.StatusObjectID(opID), + Approved: true, + Reason: "oh yeah im testing", + }) + assert.NoError(t, err) + crManifestID, err := getJSONElement(reviewApplicationOutput, "$.credential_response.manifest_id") assert.NoError(t, err) assert.Equal(t, manifestID, crManifestID) - vc, err := getJSONElement(credentialResponseOutput, "$.result.response.verifiableCredentials[0]") + vc, err := getJSONElement(reviewApplicationOutput, "$.verifiableCredentials[0]") assert.NoError(t, err) assert.NotEmpty(t, vc) + + operationOutput, err := get(endpoint + version + "operations/" + opID) + assert.NoError(t, err) + isDone, err = getJSONElement(operationOutput, "$.done") + assert.NoError(t, err) + assert.Equal(t, "true", isDone) + + opCredentialResponse, err := getJSONElement(operationOutput, "$.result.response") + assert.NoError(t, err) + assert.JSONEq(t, reviewApplicationOutput, opCredentialResponse) } diff --git a/integration/steelthread_integration_test.go b/integration/steelthread_integration_test.go index bb718d2e7..b765b3d00 100644 --- a/integration/steelthread_integration_test.go +++ b/integration/steelthread_integration_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" ) var steelThreadContext = NewTestContext("SteelThread") @@ -118,7 +119,7 @@ func TestCreateCredentialManifestIntegration(t *testing.T) { assert.NotEmpty(t, manifestID) } -func TestSubmitApplicationIntegration(t *testing.T) { +func TestSubmitAndReviewApplicationIntegration(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } @@ -150,17 +151,40 @@ func TestSubmitApplicationIntegration(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, credAppJWT) - credentialResponseOutput, err := SubmitApplication(applicationParams{ + submitApplicationOutput, err := SubmitApplication(applicationParams{ ApplicationJWT: credAppJWT, }) assert.NoError(t, err) - assert.NotEmpty(t, credentialResponseOutput) + assert.NotEmpty(t, submitApplicationOutput) - crManifestID, err := getJSONElement(credentialResponseOutput, "$.result.response.credential_response.manifest_id") + isDone, err := getJSONElement(submitApplicationOutput, "$.done") + assert.NoError(t, err) + assert.Equal(t, "false", isDone) + opID, err := getJSONElement(submitApplicationOutput, "$.id") + assert.NoError(t, err) + + reviewApplicationOutput, err := ReviewApplication(reviewApplicationParams{ + ID: storage.StatusObjectID(opID), + Approved: true, + Reason: "oh yeah im testing", + }) + assert.NoError(t, err) + + crManifestID, err := getJSONElement(reviewApplicationOutput, "$.credential_response.manifest_id") assert.NoError(t, err) assert.Equal(t, manifestID, crManifestID) - vc, err := getJSONElement(credentialResponseOutput, "$.result.response.verifiableCredentials[0]") + vc, err := getJSONElement(reviewApplicationOutput, "$.verifiableCredentials[0]") assert.NoError(t, err) assert.NotEmpty(t, vc) + + operationOutput, err := get(endpoint + version + "operations/" + opID) + assert.NoError(t, err) + isDone, err = getJSONElement(operationOutput, "$.done") + assert.NoError(t, err) + assert.Equal(t, "true", isDone) + + opCredentialResponse, err := getJSONElement(operationOutput, "$.result.response") + assert.NoError(t, err) + assert.JSONEq(t, reviewApplicationOutput, opCredentialResponse) } diff --git a/integration/testdata/review-application-input.json b/integration/testdata/review-application-input.json new file mode 100644 index 000000000..305d0f8ca --- /dev/null +++ b/integration/testdata/review-application-input.json @@ -0,0 +1,4 @@ +{ + "approved": {{.Approved}}, + "reason": "{{.Reason}}" +} \ No newline at end of file diff --git a/pkg/server/router/manifest.go b/pkg/server/router/manifest.go index 105638061..113a31789 100644 --- a/pkg/server/router/manifest.go +++ b/pkg/server/router/manifest.go @@ -283,7 +283,7 @@ func (sar SubmitApplicationRequest) ToServiceRequest() (*model.SubmitApplication type SubmitApplicationResponse struct { Response manifestsdk.CredentialResponse `json:"credential_response"` // this is an interface type to union Data Integrity and JWT style VCs - Credentials []any `json:"verifiableCredentials,omitempty"` + Credentials any `json:"verifiableCredentials,omitempty"` ResponseJWT keyaccess.JWT `json:"responseJwt,omitempty"` } @@ -513,3 +513,52 @@ func (mr ManifestRouter) DeleteResponse(ctx context.Context, w http.ResponseWrit return framework.Respond(ctx, w, nil, http.StatusOK) } + +type ReviewApplicationRequest struct { + Approved bool `json:"approved"` + Reason string `json:"reason"` +} + +func (r ReviewApplicationRequest) toServiceRequest(id string) model.ReviewApplicationRequest { + return model.ReviewApplicationRequest{ + ID: id, + Approved: r.Approved, + Reason: r.Reason, + } +} + +// ReviewApplication godoc +// @Summary Reviews an application +// @Description Reviewing an application either fulfills or denies the credential. +// @Tags ApplicationAPI +// @Accept json +// @Produce json +// @Param request body ReviewApplicationRequest true "request body" +// @Success 201 {object} SubmitApplicationResponse "Credential Response" +// @Failure 400 {string} string "Bad request" +// @Failure 500 {string} string "Internal server error" +// @Router /v1/manifests/applications/{id}/review [put] +func (mr ManifestRouter) ReviewApplication(ctx context.Context, w http.ResponseWriter, r *http.Request) error { + id := framework.GetParam(ctx, IDParam) + if id == nil { + return framework.NewRequestError( + util.LoggingNewError("review application request requires id"), http.StatusBadRequest) + } + + var request ReviewApplicationRequest + if err := framework.Decode(r, &request); err != nil { + return framework.NewRequestError( + util.LoggingErrorMsg(err, "invalid review application request"), http.StatusBadRequest) + } + + applicationResponse, err := mr.service.ReviewApplication(request.toServiceRequest(*id)) + if err != nil { + return framework.NewRequestError( + util.LoggingErrorMsg(err, "failed reviewing application"), http.StatusInternalServerError) + } + return framework.Respond(ctx, w, SubmitApplicationResponse{ + Response: applicationResponse.Response, + Credentials: applicationResponse.Credentials, + ResponseJWT: applicationResponse.ResponseJWT, + }, http.StatusOK) +} diff --git a/pkg/server/router/manifest_test.go b/pkg/server/router/manifest_test.go index db1742731..dd88b47ef 100644 --- a/pkg/server/router/manifest_test.go +++ b/pkg/server/router/manifest_test.go @@ -10,8 +10,8 @@ import ( "github.com/google/uuid" "github.com/mr-tron/base58" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/tbd54566975/ssi-service/pkg/service/manifest/model" + "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" credmodel "github.com/tbd54566975/ssi-service/internal/credential" "github.com/tbd54566975/ssi-service/internal/keyaccess" @@ -125,8 +125,14 @@ func TestManifestRouter(t *testing.T) { assert.NoError(tt, err) createdApplicationResponseOp, err := manifestService.ProcessApplicationSubmission(*sar) assert.NoError(tt, err) - createdApplicationResponse, ok := createdApplicationResponseOp.Result.Response.(model.SubmitApplicationResponse) - require.True(tt, ok) + assert.False(tt, createdApplicationResponseOp.Done) + + createdApplicationResponse, err := manifestService.ReviewApplication(model.ReviewApplicationRequest{ + ID: storage.StatusObjectID(createdApplicationResponseOp.ID), + Approved: true, + Reason: "ApprovalMan is here", + }) + assert.NoError(tt, err) assert.NotEmpty(tt, createdManifest) assert.NotEmpty(tt, createdApplicationResponse.Response.ID) assert.NotEmpty(tt, createdApplicationResponse.Response.Fulfillment) diff --git a/pkg/server/server.go b/pkg/server/server.go index d68bc5894..64918cace 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -245,6 +245,7 @@ func (s *SSIServer) ManifestAPI(service svcframework.Service) (err error) { s.Handle(http.MethodGet, applicationsHandlerPath, manifestRouter.GetApplications) s.Handle(http.MethodGet, path.Join(applicationsHandlerPath, "/:id"), manifestRouter.GetApplication) s.Handle(http.MethodDelete, path.Join(applicationsHandlerPath, "/:id"), manifestRouter.DeleteApplication) + s.Handle(http.MethodPut, path.Join(applicationsHandlerPath, "/:id", "/review"), manifestRouter.ReviewApplication) s.Handle(http.MethodGet, responsesHandlerPath, manifestRouter.GetResponses) s.Handle(http.MethodGet, path.Join(responsesHandlerPath, "/:id"), manifestRouter.GetResponse) diff --git a/pkg/server/server_manifest_test.go b/pkg/server/server_manifest_test.go index f15f0359f..c4d812971 100644 --- a/pkg/server/server_manifest_test.go +++ b/pkg/server/server_manifest_test.go @@ -12,13 +12,13 @@ import ( "github.com/mr-tron/base58" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - manifestsvc "github.com/tbd54566975/ssi-service/pkg/service/manifest/model" - credmodel "github.com/tbd54566975/ssi-service/internal/credential" "github.com/tbd54566975/ssi-service/internal/keyaccess" "github.com/tbd54566975/ssi-service/pkg/server/router" "github.com/tbd54566975/ssi-service/pkg/service/credential" "github.com/tbd54566975/ssi-service/pkg/service/did" + manifestsvc "github.com/tbd54566975/ssi-service/pkg/service/manifest/model" + "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" "github.com/tbd54566975/ssi-service/pkg/service/schema" ) @@ -416,10 +416,18 @@ func TestManifestAPI(t *testing.T) { err = json.NewDecoder(w.Body).Decode(&op) assert.NoError(tt, err) - var appResp router.SubmitApplicationResponse - respData, err := json.Marshal(op.Result.Response) + assert.False(tt, op.Done) + assert.Contains(tt, op.ID, "credentials/responses/") + + // review application + reviewApplicationRequestValue := newRequestValue(tt, router.ReviewApplicationRequest{Approved: true, Reason: "I'm the almighty approver"}) + applicationID := storage.StatusObjectID(op.ID) + req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications/"+applicationID+"/review", reviewApplicationRequestValue) + err = manifestRouter.ReviewApplication(newRequestContextWithParams(map[string]string{"id": applicationID}), w, req) assert.NoError(tt, err) - err = json.Unmarshal(respData, &appResp) + + var appResp router.SubmitApplicationResponse + err = json.NewDecoder(w.Body).Decode(&appResp) assert.NoError(tt, err) assert.NotEmpty(tt, appResp.Response) @@ -685,10 +693,15 @@ func TestManifestAPI(t *testing.T) { err = json.NewDecoder(w.Body).Decode(&op) assert.NoError(tt, err) - var appResp router.SubmitApplicationResponse - respData, err := json.Marshal(op.Result.Response) + // review application + reviewApplicationRequestValue := newRequestValue(tt, router.ReviewApplicationRequest{Approved: true, Reason: "I'm the almighty approver"}) + applicationID := storage.StatusObjectID(op.ID) + req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications/"+applicationID+"/review", reviewApplicationRequestValue) + err = manifestRouter.ReviewApplication(newRequestContextWithParams(map[string]string{"id": applicationID}), w, req) assert.NoError(tt, err) - err = json.Unmarshal(respData, &appResp) + + var appResp router.SubmitApplicationResponse + err = json.NewDecoder(w.Body).Decode(&appResp) assert.NoError(tt, err) assert.NotEmpty(tt, appResp.Response.Fulfillment) diff --git a/pkg/service/manifest/model/model.go b/pkg/service/manifest/model/model.go index 30c49bd04..bf50625c2 100644 --- a/pkg/service/manifest/model/model.go +++ b/pkg/service/manifest/model/model.go @@ -87,6 +87,14 @@ type DeleteApplicationRequest struct { ID string `json:"id,omitempty" validate:"required"` } +// ReviewApplicationRequest is something foobar +type ReviewApplicationRequest struct { + // ID of the application. + ID string `json:"id" validate:"required"` + Approved bool `json:"approved"` + Reason string `json:"reason"` +} + // Response type GetResponseRequest struct { diff --git a/pkg/service/manifest/response.go b/pkg/service/manifest/response.go index c3b8b0b4a..96db6e984 100644 --- a/pkg/service/manifest/response.go +++ b/pkg/service/manifest/response.go @@ -6,6 +6,7 @@ import ( "github.com/TBD54566975/ssi-sdk/credential/exchange" "github.com/TBD54566975/ssi-sdk/credential/manifest" errresp "github.com/TBD54566975/ssi-sdk/error" + "github.com/pkg/errors" cred "github.com/tbd54566975/ssi-service/internal/credential" "github.com/tbd54566975/ssi-service/internal/keyaccess" @@ -37,7 +38,7 @@ func (s Service) signCredentialResponseJWT(signingDID string, r CredentialRespon return responseToken, nil } -func (s Service) buildCredentialResponse(applicantDID, manifestID, applicationID string, credManifest manifest.CredentialManifest) (*manifest.CredentialResponse, []cred.Container, error) { +func (s Service) buildCredentialResponse(applicantDID, manifestID, applicationID string, credManifest manifest.CredentialManifest, approved bool, reason string) (*manifest.CredentialResponse, []cred.Container, error) { // TODO(gabe) need to check if this can be fulfilled and conditionally return success/denial responseBuilder := manifest.NewCredentialResponseBuilder(manifestID) if err := responseBuilder.SetApplicationID(applicationID); err != nil { @@ -80,8 +81,14 @@ func (s Service) buildCredentialResponse(applicantDID, manifestID, applicationID } // set the information for the fulfilled credentials in the response - if err := responseBuilder.SetFulfillment(descriptors); err != nil { - return nil, nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set fulfillment") + if approved { + if err := responseBuilder.SetFulfillment(descriptors); err != nil { + return nil, nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set fulfillment") + } + } else { + if err := responseBuilder.SetDenial(reason); err != nil { + return nil, nil, errors.Wrap(err, "setting denial") + } } credRes, err := responseBuilder.Build() if err != nil { diff --git a/pkg/service/manifest/service.go b/pkg/service/manifest/service.go index c42d19da4..60d57f316 100644 --- a/pkg/service/manifest/service.go +++ b/pkg/service/manifest/service.go @@ -10,18 +10,17 @@ import ( "github.com/goccy/go-json" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "github.com/tbd54566975/ssi-service/pkg/service/manifest/model" - manifeststg "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage" - "github.com/tbd54566975/ssi-service/pkg/service/operation" - opcredential "github.com/tbd54566975/ssi-service/pkg/service/operation/credential" - opstorage "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" - "github.com/tbd54566975/ssi-service/config" credint "github.com/tbd54566975/ssi-service/internal/credential" "github.com/tbd54566975/ssi-service/internal/util" "github.com/tbd54566975/ssi-service/pkg/service/credential" "github.com/tbd54566975/ssi-service/pkg/service/framework" "github.com/tbd54566975/ssi-service/pkg/service/keystore" + "github.com/tbd54566975/ssi-service/pkg/service/manifest/model" + manifeststg "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage" + "github.com/tbd54566975/ssi-service/pkg/service/operation" + opcredential "github.com/tbd54566975/ssi-service/pkg/service/operation/credential" + opstorage "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" "github.com/tbd54566975/ssi-service/pkg/storage" ) @@ -227,6 +226,11 @@ type CredentialResponseContainer struct { Credentials []any `json:"verifiableCredentials,omitempty"` } +// ProcessApplicationSubmission stores the application in a pending state, along with an operation. Once the operation +// is done, the Operation.Response field will be of type model.SubmitApplicationResponse. +// Invalid applications return an operation marked as done, with Response that represents denial. +// The state of the application can be updated by calling CancelOperation, or by calling ReviewApplicationSubmission. +// When the state is updated, the operation is marked as done. func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationRequest) (*operation.Operation, error) { // get the manifest associated with the application manifestID := request.Application.ManifestID @@ -238,7 +242,6 @@ func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationReq if gotManifest == nil { return nil, util.LoggingNewErrorf("application<%s> is not valid; a manifest does not exist with id: %s", applicationID, manifestID) } - credManifest := gotManifest.Manifest opID := opcredential.IDFromResponseID(applicationID) // validate the application @@ -271,7 +274,7 @@ func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationReq applicantDID := request.ApplicantDID storageRequest := manifeststg.StoredApplication{ ID: applicationID, - Status: opcredential.StatusFulfilled, + Status: opcredential.StatusPending, ManifestID: manifestID, ApplicantDID: applicantDID, Application: request.Application, @@ -282,8 +285,37 @@ func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationReq return nil, util.LoggingErrorMsg(err, "could not store application") } + storedOp := opstorage.StoredOperation{ + ID: opID, + } + if err = s.opsStorage.StoreOperation(storedOp); err != nil { + return nil, errors.Wrap(err, "storing operation") + } + return operation.ServiceModel(storedOp) +} + +// ReviewApplication moves an application state and marks the operation associated with it as done. A credential +// response is stored. +func (s Service) ReviewApplication(request model.ReviewApplicationRequest) (*model.SubmitApplicationResponse, error) { + application, err := s.storage.GetApplication(request.ID) + if err != nil { + return nil, errors.Wrap(err, "fetching application") + } + + manifestID := application.ManifestID + gotManifest, err := s.storage.GetManifest(manifestID) + if err != nil { + return nil, errors.Wrap(err, "fetching manifest") + } + applicationID := application.ID + if gotManifest == nil { + return nil, util.LoggingNewErrorf("application<%s> is not valid; a manifest does not exist with id: %s", applicationID, manifestID) + } + credManifest := gotManifest.Manifest + applicantDID := application.ApplicantDID + // build the credential response - credResp, creds, err := s.buildCredentialResponse(applicantDID, manifestID, applicationID, credManifest) + credResp, creds, err := s.buildCredentialResponse(applicantDID, manifestID, applicationID, credManifest, request.Approved, request.Reason) if err != nil { return nil, util.LoggingErrorMsg(err, "could not build credential response") } @@ -309,23 +341,13 @@ func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationReq Credentials: creds, ResponseJWT: *responseJWT, } - if err = s.storage.StoreResponse(storeResponseRequest); err != nil { - return nil, util.LoggingErrorMsg(err, "could not store manifest response") - } - - sarData, err := json.Marshal(storeResponseRequest) + storedResponse, _, err := s.storage.ReviewApplication(request.ID, request.Approved, request.Reason, opcredential.IDFromResponseID(request.ID), storeResponseRequest) if err != nil { - return nil, errors.Wrap(err, "marshalling response") - } - storedOp := opstorage.StoredOperation{ - ID: opID, - Done: true, - Response: sarData, + return nil, errors.Wrap(err, "updating submission") } - if err = s.opsStorage.StoreOperation(storedOp); err != nil { - return nil, errors.Wrap(err, "storing operation") - } - return operation.ServiceModel(storedOp) + + m := model.ServiceModel(storedResponse) + return &m, nil } func (s Service) GetApplication(request model.GetApplicationRequest) (*model.GetApplicationResponse, error) { diff --git a/pkg/service/manifest/storage/storage.go b/pkg/service/manifest/storage/storage.go index 2c0bfdbbf..b51ca8254 100644 --- a/pkg/service/manifest/storage/storage.go +++ b/pkg/service/manifest/storage/storage.go @@ -3,16 +3,17 @@ package storage import ( "fmt" + "github.com/TBD54566975/ssi-sdk/credential/manifest" "github.com/goccy/go-json" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "github.com/tbd54566975/ssi-service/pkg/service/operation/credential" - - "github.com/TBD54566975/ssi-sdk/credential/manifest" - cred "github.com/tbd54566975/ssi-service/internal/credential" "github.com/tbd54566975/ssi-service/internal/keyaccess" "github.com/tbd54566975/ssi-service/internal/util" + "github.com/tbd54566975/ssi-service/pkg/service/operation/credential" + opstorage "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" + "github.com/tbd54566975/ssi-service/pkg/service/operation/storage/namespace" + opsubmission "github.com/tbd54566975/ssi-service/pkg/service/operation/submission" "github.com/tbd54566975/ssi-service/pkg/storage" ) @@ -237,3 +238,54 @@ func (ms *Storage) DeleteResponse(id string) error { } return nil } + +// ReviewApplication does the following: +// 1. Updates the application status according to the approved parameter. +// 2. Creates a Credential Response corresponding to the approved parameter and with the given reason. +// 3. Marks the operation with id == opID as done, and sets operation.Response to the StoredResponse from the object +// creates in step 2. +// +// The operation and it's response (from 3) are returned. +func (ms *Storage) ReviewApplication(id string, approved bool, reason string, opID string, response StoredResponse) (*StoredResponse, *opstorage.StoredOperation, error) { + // TODO: everything should be in a single Tx. + m := map[string]any{ + "status": opsubmission.StatusDenied, + "reason": reason, + } + if approved { + m["status"] = opsubmission.StatusApproved + } + if _, err := ms.db.Update(credential.ApplicationNamespace, id, m); err != nil { + return nil, nil, errors.Wrap(err, "updating application") + } + + if err := ms.StoreResponse(response); err != nil { + return nil, nil, errors.Wrap(err, "storing credential response") + } + + responseData, operationData, err := ms.db.UpdateValueAndOperation( + responseNamespace, + response.ID, + storage.NewUpdater(m), + namespace.FromID(opID), + opID, + opsubmission.OperationUpdater{ + UpdaterWithMap: storage.NewUpdater(map[string]any{ + "done": true, + }), + }) + if err != nil { + return nil, nil, errors.Wrap(err, "updating value and operation") + } + + var s StoredResponse + if err = json.Unmarshal(responseData, &s); err != nil { + return nil, nil, errors.Wrap(err, "unmarshalling written credential response") + } + var op opstorage.StoredOperation + if err = json.Unmarshal(operationData, &op); err != nil { + return nil, nil, errors.Wrap(err, "unmarshalling written operation") + } + + return &s, &op, nil +}