diff --git a/apps/agent/jest.config.ts b/apps/agent/jest.config.ts index e197b225b1a32705e4be680d15e4f25aedef1667..bebc00f141a0ce141371b15823924155ce801953 100644 --- a/apps/agent/jest.config.ts +++ b/apps/agent/jest.config.ts @@ -9,5 +9,5 @@ export default { moduleFileExtensions: ["ts", "js", "html"], coverageDirectory: "../../coverage/apps/agent", collectCoverage: true, - verbose: true + verbose: true, }; diff --git a/apps/dashboard/src/components/ConnectionItem/index.tsx b/apps/dashboard/src/components/ConnectionItem/index.tsx index c246be7caa89f8d4d77ae0826f1be0e8a42b6d76..2c7c5ea5d15c1daaa4aaf629d45d4458ce8cc66a 100644 --- a/apps/dashboard/src/components/ConnectionItem/index.tsx +++ b/apps/dashboard/src/components/ConnectionItem/index.tsx @@ -30,7 +30,8 @@ const ConnectionItem = observer(({ item, onClick }: ConnectionItemProps) => { item.theirDid ) : ( <span className={s.warn}> - This connection is no longer active. Messages sent here will not be received. + This connection is no longer active. Messages sent here will not be + received. </span> )} </div> diff --git a/apps/dashboard/src/modals/NewCredentialDefDialog/index.tsx b/apps/dashboard/src/modals/NewCredentialDefDialog/index.tsx index 49d8835b756d1e8dff1c688e943dcc67ea2f6c00..e33c25a8265390f45bb374fae0d0e8952faa7315 100644 --- a/apps/dashboard/src/modals/NewCredentialDefDialog/index.tsx +++ b/apps/dashboard/src/modals/NewCredentialDefDialog/index.tsx @@ -35,7 +35,7 @@ const NewCredentialDefDialog = observer( const credDef = await api.createCredentialDefinition({ schemaId, tag, - supportRevocation: false + supportRevocation: false, }); console.log(credDef); toast.success(`New credential definition created`); diff --git a/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/CustomForm.tsx b/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/CustomForm.tsx index 1797365ad48a9bcb6a8ea98e0ffc76eced18f98a..711be29f54cefc445a80ae718327e82b3d169771 100644 --- a/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/CustomForm.tsx +++ b/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/CustomForm.tsx @@ -11,7 +11,7 @@ export interface CustomFormProps { onSignJsonLd: (doc: unknown) => void; } -const selectOptions = examples.map(p => ({ +const selectOptions = examples.map((p) => ({ value: p.name, label: p.name, })); diff --git a/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/Intro.tsx b/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/Intro.tsx index 9ddadd470bad310ca20209597e1ac1e2bfa2616b..b035d361d89fdd1c598d2de229d51fb9c7f0d298 100644 --- a/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/Intro.tsx +++ b/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/Intro.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Button, Space} from "antd"; +import { Button, Space } from "antd"; import { FormType } from "../interfaces"; export interface IntroProps { diff --git a/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/examples.ts b/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/examples.ts index 5a51eea38b721064b8303f770c22faa650a707ae..ad2349d51026ff8d3e54d1c50db29dc25c8d6698 100644 --- a/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/examples.ts +++ b/apps/dashboard/src/modals/OfferJsonLdCredentialDialog/forms/examples.ts @@ -1,47 +1,43 @@ const examples = [ { - "name": "Vereign - PrivatePerson", - "doc": { + name: "Vereign - PrivatePerson", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://www.vereign.com/.well-known/vereign-schema" + "https://www.vereign.com/.well-known/vereign-schema", ], - "id": "", - "issuer": "", - "issuanceDate": "", - "type": [ - "VerifiableCredential" - ], - "credentialSubject": { - "type": "vereign:PrivatePerson", + id: "", + issuer: "", + issuanceDate: "", + type: ["VerifiableCredential"], + credentialSubject: { + type: "vereign:PrivatePerson", "vereign:name": "Evelyn Parker", "vereign:dateOfBirth": "12.06.1990", "vereign:address": { "vereign:street": "154 Maple Street, Apartment 3B", "vereign:building": "154", "vereign:city": "Sofia", - "vereign:country": "Bulgaria" - } - } - } + "vereign:country": "Bulgaria", + }, + }, + }, }, { - "name": "Vereign - LegalParticipant", - "doc": { + name: "Vereign - LegalParticipant", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://www.vereign.com/.well-known/vereign-schema" + "https://www.vereign.com/.well-known/vereign-schema", ], - "type": [ - "VerifiableCredential" - ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { - "type": "vereign:LegalParticipant", + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { + type: "vereign:LegalParticipant", "vereign:companyName": "SolarTech Dynamics Inc.", "vereign:taxID": "123-456-7890", "vereign:gleiCode": "5500Z99QKFTV873N4X35", @@ -49,144 +45,143 @@ const examples = [ "vereign:street": "Innovation Boulevard", "vereign:building": "No. 202", "vereign:city": "New Eden", - "vereign:country": "Atlantis" - } - } - } + "vereign:country": "Atlantis", + }, + }, + }, }, { - "name": "XFSC - participant", - "doc": { + name: "XFSC - participant", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" - ], - "type": [ - "VerifiableCredential" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { - "type": "gx:LegalParticipant", + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { + type: "gx:LegalParticipant", "gx:legalName": "Gaia-X European Association for Data and Cloud AISBL", "gx:legalRegistrationNumber": { - "id": "https://gaia-x.eu/legalRegistrationNumberVC.json" + id: "https://gaia-x.eu/legalRegistrationNumberVC.json", }, "gx:headquarterAddress": { - "gx:countrySubdivisionCode": "BE-BRU" + "gx:countrySubdivisionCode": "BE-BRU", }, "gx:legalAddress": { - "gx:countrySubdivisionCode": "BE-BRU" + "gx:countrySubdivisionCode": "BE-BRU", }, - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - service", - "doc": { + name: "XFSC - service", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": ["VerifiableCredential"], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { - "type": "gx:ServiceOffering", + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { + type: "gx:ServiceOffering", "gx:providedBy": { - "id": "https://wizard.lab.gaia-x.eu/api/credentials/2d37wbGvQzbAQ84yRouh2m2vBKkN8s5AfH9Q75HZRCUQmJW7yAVSNKzjJj6gcjE2mDNDUHCichXWdMH3S2c8AaDLm3kXmf5R8DFPWTYo5iRYkn8kvgU3AjMXc2qTbhuMHCpucKGgT1ZMkcHUygZkt11iD3T8VJNKYwsdk4MGoZwdqoFUuTKVcsXVTBA4ofD1Dtqzjavyng5WUpvJf4gRyfGkMvYYuHCgay8TK8Dayt6Rhcs3r2d1gRCg2UV419S9CpWZGwKQNEXdYbaB2eTiNbQ83KMd4mj1oSJgF7LLDZLJtKJbhwLzR3x35QUqEGevRxnRDKoPdHrEZN7r9TVAmvr9rt7Xq8eB4zGMTza59hisEAUaHsmWQNaVDorqFyZgN5bXswMK1irVQ5SVR9osCCRrKUKkntxfakjmSqapPfveMP39vkgTXfEhsfLUZXGwFcpgLpWxWRn1QLnJY11BVymS7DyaSvbSKotNFQxyV6vghfM2Jetw1mLxU5qsQqDYnDYJjPZQSmkwxjX3yenPVCz6N2ox83tj9AuuQrzg5p2iukNdunDd2QCsHaMEtTq9JVLzXtWs2eZbPkxCBEQwoKTGGVhKu5yxZjCtQGc#9894e9b0a38aa105b50bb9f4e7d0975641273416e70f166f4bd9fd1b00dfe81d" + id: "https://wizard.lab.gaia-x.eu/api/credentials/2d37wbGvQzbAQ84yRouh2m2vBKkN8s5AfH9Q75HZRCUQmJW7yAVSNKzjJj6gcjE2mDNDUHCichXWdMH3S2c8AaDLm3kXmf5R8DFPWTYo5iRYkn8kvgU3AjMXc2qTbhuMHCpucKGgT1ZMkcHUygZkt11iD3T8VJNKYwsdk4MGoZwdqoFUuTKVcsXVTBA4ofD1Dtqzjavyng5WUpvJf4gRyfGkMvYYuHCgay8TK8Dayt6Rhcs3r2d1gRCg2UV419S9CpWZGwKQNEXdYbaB2eTiNbQ83KMd4mj1oSJgF7LLDZLJtKJbhwLzR3x35QUqEGevRxnRDKoPdHrEZN7r9TVAmvr9rt7Xq8eB4zGMTza59hisEAUaHsmWQNaVDorqFyZgN5bXswMK1irVQ5SVR9osCCRrKUKkntxfakjmSqapPfveMP39vkgTXfEhsfLUZXGwFcpgLpWxWRn1QLnJY11BVymS7DyaSvbSKotNFQxyV6vghfM2Jetw1mLxU5qsQqDYnDYJjPZQSmkwxjX3yenPVCz6N2ox83tj9AuuQrzg5p2iukNdunDd2QCsHaMEtTq9JVLzXtWs2eZbPkxCBEQwoKTGGVhKu5yxZjCtQGc#9894e9b0a38aa105b50bb9f4e7d0975641273416e70f166f4bd9fd1b00dfe81d", }, "gx:policy": "", "gx:termsAndConditions": { "gx:URL": "http://termsandconds.com", - "gx:hash": "d8402a23de560f5ab34b22d1a142feb9e13b3143" + "gx:hash": "d8402a23de560f5ab34b22d1a142feb9e13b3143", }, "gx:dataAccountExport": { "gx:requestType": "API", "gx:accessType": "digital", - "gx:formatType": "application/json" + "gx:formatType": "application/json", }, - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - serviceLabelLevel1", - "doc": { - "credentialSubject": { - "id": "" + name: "XFSC - serviceLabelLevel1", + doc: { + credentialSubject: { + id: "", }, - "id": "", - "issuanceDate": "", - "issuer": "" - } + id: "", + issuanceDate: "", + issuer: "", + }, }, { - "name": "XFSC - termsAndConditions", - "doc": { + name: "XFSC - termsAndConditions", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": ["VerifiableCredential"], - "issuanceDate": "", - "credentialSubject": { - "@context": "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", - "type": "gx:GaiaXTermsAndConditions", - "gx:termsAndConditions": "The PARTICIPANT signing the Self-Description agrees as follows:\n- to update its descriptions about any changes, be it technical, organizational, or legal - especially but not limited to contractual in regards to the indicated attributes present in the descriptions.\n\nThe keypair used to sign Verifiable Credentials will be revoked where Gaia-X Association becomes aware of any inaccurate statements in regards to the claims which result in a non-compliance with the Trust Framework and policy rules defined in the Policy Rules and Labelling Document (PRLD).", - "id": "" + type: ["VerifiableCredential"], + issuanceDate: "", + credentialSubject: { + "@context": + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", + type: "gx:GaiaXTermsAndConditions", + "gx:termsAndConditions": + "The PARTICIPANT signing the Self-Description agrees as follows:\n- to update its descriptions about any changes, be it technical, organizational, or legal - especially but not limited to contractual in regards to the indicated attributes present in the descriptions.\n\nThe keypair used to sign Verifiable Credentials will be revoked where Gaia-X Association becomes aware of any inaccurate statements in regards to the claims which result in a non-compliance with the Trust Framework and policy rules defined in the Policy Rules and Labelling Document (PRLD).", + id: "", }, - "issuer": "", - "id": "" - } + issuer: "", + id: "", + }, }, { - "name": "XFSC - serviceWithResources", - "doc": { + name: "XFSC - serviceWithResources", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": [ - "VerifiableCredential" - ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": [ + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: [ { "@type": "gx:ServiceOffering", "@id": "https://lab.gaia-x.eu/lab.json", "gx:providedBy": { - "@id": "did:web:wizard.lab.gaia-x.eu:development:api:credentials:2d37wbGvQzbAQ84yRouh2m2vBKkN8s5AfH9Q75HZRCUQmJW7yAVSNKzjJj6gcjE2mDNDUHCichXWdMH3S2c8AaDLm3kXmf5R8DQsEb24sbSenY4QHNVyrwjRTCZtrPHzTxGiHVtFohMXnmyScNcZHwcGDpEARdWXMVaVfmbfCfcmypHbC7Pxa8zzEtVtJyemWZyvsU66ndiqrg5b7a4VWUyvG8kh5ckH385QyL5i9vWL6w4rEM3rD56ZFzjKrRrZ8wz2nEQFfTFcFKD3mZdZrfnLntaQz6y7daWs9xX2dJ5d65EewDskcoXHuC3QqBJru45sHMjDBv5AAVopWg6sPdNPDdVPhk8ToPVtUzWnSEfqirHzzgrrGFvXuJ2PFV1h5RFWDvP6yFxn6dtcCdYVbqt45c8BH6zR7YrxZqhLNV7j9voKE6HdYMgz7NyeQ3mCYENAF2qtf6gHHx41Bu7ApSbQcNFCoEapFQaowg1rsU3L3oUxC51zT47wPoNU4sG71uKrLyuz56sH3fmx4wGCCPZsuqQNXH3brnubcYfdG39Rg2A89yawAN1g42kUMiuMcgL5Cu5L2TZtq9XhSRsV6gwYPW5g2FLoFSyNhxp#7eb7b2675ecb358920f8fba55e2445f547ea2a251d8eee50c9fb2a60bf6a7441" + "@id": + "did:web:wizard.lab.gaia-x.eu:development:api:credentials:2d37wbGvQzbAQ84yRouh2m2vBKkN8s5AfH9Q75HZRCUQmJW7yAVSNKzjJj6gcjE2mDNDUHCichXWdMH3S2c8AaDLm3kXmf5R8DQsEb24sbSenY4QHNVyrwjRTCZtrPHzTxGiHVtFohMXnmyScNcZHwcGDpEARdWXMVaVfmbfCfcmypHbC7Pxa8zzEtVtJyemWZyvsU66ndiqrg5b7a4VWUyvG8kh5ckH385QyL5i9vWL6w4rEM3rD56ZFzjKrRrZ8wz2nEQFfTFcFKD3mZdZrfnLntaQz6y7daWs9xX2dJ5d65EewDskcoXHuC3QqBJru45sHMjDBv5AAVopWg6sPdNPDdVPhk8ToPVtUzWnSEfqirHzzgrrGFvXuJ2PFV1h5RFWDvP6yFxn6dtcCdYVbqt45c8BH6zR7YrxZqhLNV7j9voKE6HdYMgz7NyeQ3mCYENAF2qtf6gHHx41Bu7ApSbQcNFCoEapFQaowg1rsU3L3oUxC51zT47wPoNU4sG71uKrLyuz56sH3fmx4wGCCPZsuqQNXH3brnubcYfdG39Rg2A89yawAN1g42kUMiuMcgL5Cu5L2TZtq9XhSRsV6gwYPW5g2FLoFSyNhxp#7eb7b2675ecb358920f8fba55e2445f547ea2a251d8eee50c9fb2a60bf6a7441", }, "gx:termsAndConditions": { "@id": "https://lab.gaia-x.eu/soterms.json", "@type": "gx:SOTermsAndConditions", "gx:URL": "", - "gx:hash": "" + "gx:hash": "", }, "gx:policy": "", "gx:dataAccountExport": { "gx:requestType": "API", "gx:accessType": "digital", - "gx:formatType": "application/json" + "gx:formatType": "application/json", }, "gx:aggregationOf": [ { - "@id": "https://lab.gaia-x.eu/ces-software.json" + "@id": "https://lab.gaia-x.eu/ces-software.json", }, { - "@id": "https://lab.gaia-x.eu/ovh-k8s.json" - } - ] + "@id": "https://lab.gaia-x.eu/ovh-k8s.json", + }, + ], }, { "@id": "https://lab.gaia-x.eu/cesDataResource.json", @@ -198,43 +193,46 @@ const examples = [ "gx:license": "EPL-2.0", "gx:copyrightOwnedBy": "original owner", "gx:producedBy": { - "@id": "did:web:wizard.lab.gaia-x.eu:development:api:credentials:2d37wbGvQzbAQ84yRouh2m2vBKkN8s5AfH9Q75HZRCUQmJW7yAVSNKzjJj6gcjE2mDNDUHCichXWdMH3S2c8AaDLm3kXmf5R8DQsEb24sbSenY4QHNVyrwjRTCZtrPHzTxGiHVtFohMXnmyScNcZHwcGDpEARdWXMVaVfmbfCfcmypHbC7Pxa8zzEtVtJyemWZyvsU66ndiqrg5b7a4VWUyvG8kh5ckH385QyL5i9vWL6w4rEM3rD56ZFzjKrRrZ8wz2nEQFfTFcFKD3mZdZrfnLntaQz6y7daWs9xX2dJ5d65EewDskcoXHuC3QqBJru45sHMjDBv5AAVopWg6sPdNPDdVPhk8ToPVtUzWnSEfqirHzzgrrGFvXuJ2PFV1h5RFWDvP6yFxn6dtcCdYVbqt45c8BH6zR7YrxZqhLNV7j9voKE6HdYMgz7NyeQ3mCYENAF2qtf6gHHx41Bu7ApSbQcNFCoEapFQaowg1rsU3L3oUxC51zT47wPoNU4sG71uKrLyuz56sH3fmx4wGCCPZsuqQNXH3brnubcYfdG39Rg2A89yawAN1g42kUMiuMcgL5Cu5L2TZtq9XhSRsV6gwYPW5g2FLoFSyNhxp#7eb7b2675ecb358920f8fba55e2445f547ea2a251d8eee50c9fb2a60bf6a7441" + "@id": + "did:web:wizard.lab.gaia-x.eu:development:api:credentials:2d37wbGvQzbAQ84yRouh2m2vBKkN8s5AfH9Q75HZRCUQmJW7yAVSNKzjJj6gcjE2mDNDUHCichXWdMH3S2c8AaDLm3kXmf5R8DQsEb24sbSenY4QHNVyrwjRTCZtrPHzTxGiHVtFohMXnmyScNcZHwcGDpEARdWXMVaVfmbfCfcmypHbC7Pxa8zzEtVtJyemWZyvsU66ndiqrg5b7a4VWUyvG8kh5ckH385QyL5i9vWL6w4rEM3rD56ZFzjKrRrZ8wz2nEQFfTFcFKD3mZdZrfnLntaQz6y7daWs9xX2dJ5d65EewDskcoXHuC3QqBJru45sHMjDBv5AAVopWg6sPdNPDdVPhk8ToPVtUzWnSEfqirHzzgrrGFvXuJ2PFV1h5RFWDvP6yFxn6dtcCdYVbqt45c8BH6zR7YrxZqhLNV7j9voKE6HdYMgz7NyeQ3mCYENAF2qtf6gHHx41Bu7ApSbQcNFCoEapFQaowg1rsU3L3oUxC51zT47wPoNU4sG71uKrLyuz56sH3fmx4wGCCPZsuqQNXH3brnubcYfdG39Rg2A89yawAN1g42kUMiuMcgL5Cu5L2TZtq9XhSRsV6gwYPW5g2FLoFSyNhxp#7eb7b2675ecb358920f8fba55e2445f547ea2a251d8eee50c9fb2a60bf6a7441", }, "gx:exposedThrough": { - "@id": "https://lab.gaia-x.eu/lab.json" - } + "@id": "https://lab.gaia-x.eu/lab.json", + }, }, { "@type": "gx:SoftwareResource", "@id": "https://lab.gaia-x.eu/ces-software.json", "gx:policy": "default: allow", "gx:license": "EPL-2.0", - "gx:copyrightOwnedBy": "original owner" + "gx:copyrightOwnedBy": "original owner", }, { "@type": "gx:SoftwareResource", "@id": "https://lab.gaia-x.eu/ovh-k8s.json", "gx:policy": "default: allow", - "gx:license": "https://www.ovh.com/fr/support/documents_legaux/conditions%20generales%20de%20service.pdf", - "gx:copyrightOwnedBy": "OVH" + "gx:license": + "https://www.ovh.com/fr/support/documents_legaux/conditions%20generales%20de%20service.pdf", + "gx:copyrightOwnedBy": "OVH", }, { "@type": "gx:InstantiatedVirtualResource", "@id": "https://lab.gaia-x.eu/cesDevInstance.json", "gx:instanceOf": { - "@id": "https://lab.gaia-x.eu/ces-software.json" + "@id": "https://lab.gaia-x.eu/ces-software.json", }, "gx:hostedOn": { - "@id": "https://lab.gaia-x.eu/ovh-k8s.json" + "@id": "https://lab.gaia-x.eu/ovh-k8s.json", }, "gx:maintainedBy": { - "@id": "did:web:wizard.lab.gaia-x.eu:development:api:credentials:2d37wbGvQzbAQ84yRouh2m2vBKkN8s5AfH9Q75HZRCUQmJW7yAVSNKzjJj6gcjE2mDNDUHCichXWdMH3S2c8AaDLm3kXmf5R8DQsEb24sbSenY4QHNVyrwjRTCZtrPHzTxGiHVtFohMXnmyScNcZHwcGDpEARdWXMVaVfmbfCfcmypHbC7Pxa8zzEtVtJyemWZyvsU66ndiqrg5b7a4VWUyvG8kh5ckH385QyL5i9vWL6w4rEM3rD56ZFzjKrRrZ8wz2nEQFfTFcFKD3mZdZrfnLntaQz6y7daWs9xX2dJ5d65EewDskcoXHuC3QqBJru45sHMjDBv5AAVopWg6sPdNPDdVPhk8ToPVtUzWnSEfqirHzzgrrGFvXuJ2PFV1h5RFWDvP6yFxn6dtcCdYVbqt45c8BH6zR7YrxZqhLNV7j9voKE6HdYMgz7NyeQ3mCYENAF2qtf6gHHx41Bu7ApSbQcNFCoEapFQaowg1rsU3L3oUxC51zT47wPoNU4sG71uKrLyuz56sH3fmx4wGCCPZsuqQNXH3brnubcYfdG39Rg2A89yawAN1g42kUMiuMcgL5Cu5L2TZtq9XhSRsV6gwYPW5g2FLoFSyNhxp#7eb7b2675ecb358920f8fba55e2445f547ea2a251d8eee50c9fb2a60bf6a7441" + "@id": + "did:web:wizard.lab.gaia-x.eu:development:api:credentials:2d37wbGvQzbAQ84yRouh2m2vBKkN8s5AfH9Q75HZRCUQmJW7yAVSNKzjJj6gcjE2mDNDUHCichXWdMH3S2c8AaDLm3kXmf5R8DQsEb24sbSenY4QHNVyrwjRTCZtrPHzTxGiHVtFohMXnmyScNcZHwcGDpEARdWXMVaVfmbfCfcmypHbC7Pxa8zzEtVtJyemWZyvsU66ndiqrg5b7a4VWUyvG8kh5ckH385QyL5i9vWL6w4rEM3rD56ZFzjKrRrZ8wz2nEQFfTFcFKD3mZdZrfnLntaQz6y7daWs9xX2dJ5d65EewDskcoXHuC3QqBJru45sHMjDBv5AAVopWg6sPdNPDdVPhk8ToPVtUzWnSEfqirHzzgrrGFvXuJ2PFV1h5RFWDvP6yFxn6dtcCdYVbqt45c8BH6zR7YrxZqhLNV7j9voKE6HdYMgz7NyeQ3mCYENAF2qtf6gHHx41Bu7ApSbQcNFCoEapFQaowg1rsU3L3oUxC51zT47wPoNU4sG71uKrLyuz56sH3fmx4wGCCPZsuqQNXH3brnubcYfdG39Rg2A89yawAN1g42kUMiuMcgL5Cu5L2TZtq9XhSRsV6gwYPW5g2FLoFSyNhxp#7eb7b2675ecb358920f8fba55e2445f547ea2a251d8eee50c9fb2a60bf6a7441", }, "gx:serviceAccessPoint": [ { - "@id": "https://lab.gaia-x.eu/cesDevInstanceAP.json" - } - ] + "@id": "https://lab.gaia-x.eu/cesDevInstanceAP.json", + }, + ], }, { "@type": "gx:ServiceAccessPoint", @@ -243,55 +241,51 @@ const examples = [ "gx:port": "443", "gx:protocol": "https", "gx:version": "1.0.0", - "gx:openAPI": "https://ces-development.lab.gaia-x.eu/q/swagger-ui" + "gx:openAPI": "https://ces-development.lab.gaia-x.eu/q/swagger-ui", }, { "@type": "gx:LegitimateInterest", "@id": "https://lab.gaia-x.eu/ces-interest.json", "gx:legalBasis": "GDPR-6-1-a", - "gx:dataProtectionContact": "https://gaia-x.eu/privacy-policy/" - } - ] - } + "gx:dataProtectionContact": "https://gaia-x.eu/privacy-policy/", + }, + ], + }, }, { - "name": "XFSC - sOTermsAndConditions", - "doc": { + name: "XFSC - sOTermsAndConditions", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" - ], - "type": [ - "VerifiableCredential" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { "@id": "https://lab.gaia-x.eu/soterms.json", "@type": "gx:SOTermsAndConditions", "gx:URL": "", "gx:hash": "", - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - dataResource", - "doc": { + name: "XFSC - dataResource", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" - ], - "type": [ - "VerifiableCredential" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { "@id": "https://lab.gaia-x.eu/cesDataResource.json", "@type": "gx:DataResource", "gx:name": "CES Data", @@ -301,30 +295,28 @@ const examples = [ "gx:license": "EPL-2.0", "gx:copyrightOwnedBy": "original owner", "gx:producedBy": { - "@id": "__id of the data provider participant CS__" + "@id": "__id of the data provider participant CS__", }, "gx:exposedThrough": { - "@id": "__id of the service offering exposing this data__" + "@id": "__id of the service offering exposing this data__", }, - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - physicalResource", - "doc": { + name: "XFSC - physicalResource", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": [ - "VerifiableCredential" - ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { "@type": "gx:PhysicalResource", "@id": "https://lab.gaia-x.eu/ces-physical.json", "gx:policy": "default: allow", @@ -336,99 +328,91 @@ const examples = [ "@type": "vcard:Address", "vcard:postal-code": "12345", "vcard:street-address": "123 Main St", - "gx:countryCode": "US" + "gx:countryCode": "US", }, "gx:location": "35.89421911 139.94637467", - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - softwareResource", - "doc": { + name: "XFSC - softwareResource", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": [ - "VerifiableCredential" - ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { "@type": "gx:SoftwareResource", "@id": "https://lab.gaia-x.eu/ces-software.json", "gx:policy": "default: allow", "gx:license": "EPL-2.0", "gx:copyrightOwnedBy": "original owner", - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - virtualResource", - "doc": { + name: "XFSC - virtualResource", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": [ - "VerifiableCredential" - ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { "@type": "gx:VirtualResource", "@id": "https://lab.gaia-x.eu/ces-software.json", "gx:policy": "default: allow", "gx:license": "EPL-2.0", "gx:copyrightOwnedBy": "original owner", - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - legitimateInterest", - "doc": { + name: "XFSC - legitimateInterest", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": [ - "VerifiableCredential" - ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { "@type": "gx:LegitimateInterest", "@id": "https://lab.gaia-x.eu/ces-interest.json", "gx:legalBasis": "GDPR-6-1-a", "gx:dataProtectionContact": "https://gaia-x.eu/privacy-policy/", - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - serviceAccessPoint", - "doc": { + name: "XFSC - serviceAccessPoint", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": [ - "VerifiableCredential" - ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { "@type": "gx:ServiceAccessPoint", "@id": "https://lab.gaia-x.eu/cesDevInstanceAP.json", "gx:host": "ces-development.lab.gaia-x.eu", @@ -436,45 +420,44 @@ const examples = [ "gx:protocol": "https", "gx:version": "1.0.0", "gx:openAPI": "https://ces-development.lab.gaia-x.eu/q/swagger-ui", - "id": "" - } - } + id: "", + }, + }, }, { - "name": "XFSC - instantiatedVirtualResource", - "doc": { + name: "XFSC - instantiatedVirtualResource", + doc: { "@context": [ "https://www.w3.org/2018/credentials/v1", "https://w3id.org/security/suites/jws-2020/v1", - "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#" + "https://registry.lab.gaia-x.eu/development/api/trusted-shape-registry/v1/shapes/jsonld/trustframework#", ], - "type": [ - "VerifiableCredential" - ], - "id": "", - "issuer": "", - "issuanceDate": "", - "credentialSubject": { + type: ["VerifiableCredential"], + id: "", + issuer: "", + issuanceDate: "", + credentialSubject: { "@type": "gx:InstantiatedVirtualResource", "@id": "https://lab.gaia-x.eu/cesDevInstance.json", "gx:instanceOf": { - "@id": "__id of the cs of software resource this is an instance of__" + "@id": "__id of the cs of software resource this is an instance of__", }, "gx:hostedOn": { - "@id": "__id of the cs of the physical or virtual resource hosting this__" + "@id": + "__id of the cs of the physical or virtual resource hosting this__", }, "gx:maintainedBy": { - "@id": "__id of the cs of the participant maintaining this__" + "@id": "__id of the cs of the participant maintaining this__", }, "gx:serviceAccessPoint": [ { - "@id": "__id of the cs of the service access point__" - } + "@id": "__id of the cs of the service access point__", + }, ], - "id": "" - } - } - } -] + id: "", + }, + }, + }, +]; export default examples; diff --git a/apps/dashboard/src/routes/pages/LoginPage/LoginPageStore.ts b/apps/dashboard/src/routes/pages/LoginPage/LoginPageStore.ts index 3a1bc773e17b2bd5238ce7f859aa5a054617ace7..aeb253ec57b85f0ca1264a01aa2c0d802d816589 100644 --- a/apps/dashboard/src/routes/pages/LoginPage/LoginPageStore.ts +++ b/apps/dashboard/src/routes/pages/LoginPage/LoginPageStore.ts @@ -34,7 +34,7 @@ class LoginPageStore { requiredCredDef = await api.createCredentialDefinition({ schemaId: this.schemaId, tag: "Identity", - supportRevocation: false + supportRevocation: false, }); } diff --git a/apps/dashboard/src/routes/pages/RegisterPage/RegisterPageStore.ts b/apps/dashboard/src/routes/pages/RegisterPage/RegisterPageStore.ts index a55db30f6d065c52d2afae22dfbc725c5ae37f97..45ae10217ec1c4da0916d81c64e92b59d342942b 100644 --- a/apps/dashboard/src/routes/pages/RegisterPage/RegisterPageStore.ts +++ b/apps/dashboard/src/routes/pages/RegisterPage/RegisterPageStore.ts @@ -34,7 +34,7 @@ class RegisterPageStore { requiredCredDef = await api.createCredentialDefinition({ schemaId: this.schemaId, tag: "Identity", - supportRevocation: false + supportRevocation: false, }); } diff --git a/libs/askar/src/agent.utils.ts b/libs/askar/src/agent.utils.ts index 0e257348321ede2e466d43c018cf3c1cd1fb61e0..1f70543daa7d42a4a97bc85848d5d85cfa753471 100644 --- a/libs/askar/src/agent.utils.ts +++ b/libs/askar/src/agent.utils.ts @@ -32,7 +32,7 @@ import { WalletKeyExistsError, WebDidResolver, JwkDidResolver, - TrustPingResponseReceivedEvent, + DidRecord, } from "@credo-ts/core"; import { AnonCredsCredentialFormatService, @@ -47,7 +47,7 @@ import { IndyVdrModule, } from "@credo-ts/indy-vdr"; import { indyVdr } from "@hyperledger/indy-vdr-nodejs"; -import { anoncreds } from '@hyperledger/anoncreds-nodejs' +import { anoncreds } from "@hyperledger/anoncreds-nodejs"; import { AskarModule } from "@credo-ts/askar"; import { ariesAskar } from "@hyperledger/aries-askar-nodejs"; import { Key as AskarKey, KeyAlgs } from "@hyperledger/aries-askar-shared"; @@ -75,6 +75,7 @@ export type SubjectMessage = { import { Request, Response, Express } from "express"; import url from "url"; import { JsonLdCredentialFormatService } from "./credo/JsonLdCredentialFormatService"; +import { EntityNotFoundError } from "@ocm-engine/dtos"; export const importDidsToWallet = async ( agent: Agent, @@ -636,3 +637,15 @@ export const webHookHandler = async <T>( console.log(`Successfully sent web hook to ${url}/topic/${webHookTopic}`); } }; + +export const getFirstDidWebRecord = async ( + agent: Agent, +): Promise<DidRecord> => { + const didWebs = await agent.dids.getCreatedDids({ + method: "web", + }); + if (!didWebs.length) { + throw new EntityNotFoundError("Agent does not have did:web"); + } + return didWebs[0]; +}; diff --git a/libs/askar/src/askar-nats/agent.consumer.service.ts b/libs/askar/src/askar-nats/agent.consumer.service.ts index afa0028c2c9e57ef6a259bba3d0de1f48f97a5a1..0cd2b40ebcd7f223c65f72c263bec003e5d46808 100644 --- a/libs/askar/src/askar-nats/agent.consumer.service.ts +++ b/libs/askar/src/askar-nats/agent.consumer.service.ts @@ -4,7 +4,6 @@ import { OnModuleDestroy, OnModuleInit, } from "@nestjs/common"; -import { AgentService } from "../askar/agent.service"; import { ConsumerService } from "@ocm-engine/nats"; import { ConfigService } from "@nestjs/config"; import { IConfAgent } from "@ocm-engine/config"; @@ -15,7 +14,6 @@ import { EventHandlerService } from "./event.handler.service"; export class AgentConsumerService implements OnModuleInit, OnModuleDestroy { private readonly logger = new Logger(AgentConsumerService.name); constructor( - private readonly agentService: AgentService, private readonly consumerService: ConsumerService, private readonly configService: ConfigService, private readonly gatewayClient: GatewayClient, diff --git a/libs/askar/src/askar-nats/askar.nats.module.ts b/libs/askar/src/askar-nats/askar.nats.module.ts index bf6bc7af41ecac01c32c6461a6974c162e13a223..49b7913835848bd4d80667b95538b8e919d9d2c5 100644 --- a/libs/askar/src/askar-nats/askar.nats.module.ts +++ b/libs/askar/src/askar-nats/askar.nats.module.ts @@ -3,7 +3,14 @@ import { ConfigModule } from "@nestjs/config"; import { LedgersModule } from "@ocm-engine/ledgers"; import { APP_PIPE } from "@nestjs/core"; import { AgentConsumerService } from "./agent.consumer.service"; -import { AgentService } from "../askar/agent.service"; +import { AgentAnoncredsService } from "../askar/services/agent.anoncreds.service"; +import { AgentBasicMessagesService } from "../askar/services/agent.basicMessages.service"; +import { AgentConnectionsService } from "../askar/services/agent.connections.service"; +import { AgentCredentialsService } from "../askar/services/agent.credentials.service"; +import { AgentDidsService } from "../askar/services/agent.dids.service"; +import { AgentJsonldService } from "../askar/services/agent.jsonld.service"; +import { AgentOobService } from "../askar/services/agent.oob.service"; +import { AgentProofsService } from "../askar/services/agent.proofs.service"; import { ConsumerService } from "@ocm-engine/nats"; import { GatewayClient } from "@ocm-engine/clients"; import { EventHandlerService } from "./event.handler.service"; @@ -13,7 +20,14 @@ import { EventHandlerService } from "./event.handler.service"; providers: [ ConsumerService, AgentConsumerService, - AgentService, + AgentAnoncredsService, + AgentBasicMessagesService, + AgentConnectionsService, + AgentCredentialsService, + AgentDidsService, + AgentJsonldService, + AgentOobService, + AgentProofsService, GatewayClient, EventHandlerService, { diff --git a/libs/askar/src/askar-nats/event.handler.service.ts b/libs/askar/src/askar-nats/event.handler.service.ts index e563f4479ccbb79f0583ce581641637c2231a986..aaff61b75ef8ba7a1cc761fe0603999a34420628 100644 --- a/libs/askar/src/askar-nats/event.handler.service.ts +++ b/libs/askar/src/askar-nats/event.handler.service.ts @@ -1,5 +1,12 @@ import { Injectable, Logger } from "@nestjs/common"; -import { AgentService } from "../askar/agent.service"; +import { AgentAnoncredsService } from "../askar/services/agent.anoncreds.service"; +import { AgentBasicMessagesService } from "../askar/services/agent.basicMessages.service"; +import { AgentConnectionsService } from "../askar/services/agent.connections.service"; +import { AgentCredentialsService } from "../askar/services/agent.credentials.service"; +import { AgentDidsService } from "../askar/services/agent.dids.service"; +import { AgentJsonldService } from "../askar/services/agent.jsonld.service"; +import { AgentOobService } from "../askar/services/agent.oob.service"; +import { AgentProofsService } from "../askar/services/agent.proofs.service"; import { AcceptProofDto, CloudEventDto, @@ -47,140 +54,151 @@ import { export class EventHandlerService { private readonly logger = new Logger(EventHandlerService.name); - constructor(private readonly agentService: AgentService) {} + constructor( + private readonly agentAnoncredsService: AgentAnoncredsService, + private readonly agentBasicMessagesService: AgentBasicMessagesService, + private readonly agentConnectionsService: AgentConnectionsService, + private readonly agentCredentialsService: AgentCredentialsService, + private readonly agentDidsService: AgentDidsService, + private readonly agentJsonldService: AgentJsonldService, + private readonly agentOobService: AgentOobService, + private readonly agentProofsService: AgentProofsService, + ) {} async handle<T>(event: CloudEventDto<T>) { let data: unknown; let dto; switch (event.type) { case CONNECTION_CREATE: - data = await this.agentService.createInvitation(); + data = await this.agentOobService.createInvitation(); break; case CONNECTION_ACCEPT: dto = event.data as AcceptInvitationRequestDto; - data = await this.agentService.acceptInvitation(dto.invitationUrl); + data = await this.agentOobService.acceptInvitation(dto.invitationUrl); break; case CONNECTION_LIST: - data = await this.agentService.fetchConnections(); + data = await this.agentConnectionsService.fetchConnections(); break; case CONNECTION_GET: dto = event.data as IdReqDto; - data = await this.agentService.getConnectionById(dto.id); + data = await this.agentConnectionsService.getConnectionById(dto.id); break; case CONNECTION_DELETE: dto = event.data as IdReqDto; - data = await this.agentService.deleteConnectionById(dto.id); + data = await this.agentConnectionsService.deleteConnectionById(dto.id); break; case SCHEMA_CREATE: dto = event.data as CreateSchemaRequestDto; - data = await this.agentService.createSchema(dto); + data = await this.agentAnoncredsService.createSchema(dto); break; case SCHEMA_LIST: - data = await this.agentService.fetchSchemas(); + data = await this.agentAnoncredsService.fetchSchemas(); break; case SCHEMA_GET: dto = event.data as IdReqDto; - data = await this.agentService.getSchemaById(dto.id); + data = await this.agentAnoncredsService.getSchemaById(dto.id); break; case CRED_DEF_CREATE: - data = await this.agentService.createCredentialDefinition( + data = await this.agentAnoncredsService.createCredentialDefinition( event.data as CreateCredentialDefinitionRequestDto, ); break; case CRED_DEF_LIST: - data = await this.agentService.fetchCredentialDefinitions(); + data = await this.agentAnoncredsService.fetchCredentialDefinitions(); break; case CRED_DEF_GET: dto = event.data as IdReqDto; - data = await this.agentService.getCredentialDefinitionById(dto.id); + data = await this.agentAnoncredsService.getCredentialDefinitionById( + dto.id, + ); break; case CRED_SEND_OFFER: - data = await this.agentService.offerCredential( + data = await this.agentCredentialsService.offerCredential( event.data as OfferCredentialRequestDto, ); break; case CRED_LIST: dto = event.data as CredentialFilterDto; - data = await this.agentService.fetchCredentials(dto); + data = await this.agentCredentialsService.fetchCredentials(dto); break; case CRED_GET: dto = event.data as IdReqDto; - data = await this.agentService.getCredentialById(dto.id); + data = await this.agentCredentialsService.getCredentialById(dto.id); break; case CRED_OFFER_ACCEPT: - data = await this.agentService.acceptCredential( + data = await this.agentCredentialsService.acceptCredential( event.data as AcceptCredentialDto, ); break; case CRED_OFFER_DECLINE: dto = event.data as IdReqDto; - data = await this.agentService.declineCredential(dto.id); + data = await this.agentCredentialsService.declineCredential(dto.id); break; case CRED_DELETE: dto = event.data as IdReqDto; - data = await this.agentService.deleteCredentialById(dto.id); + data = await this.agentCredentialsService.deleteCredentialById(dto.id); break; case PROOF_REQUEST: dto = event.data as RequestProofDto; - data = await this.agentService.requestProof(dto); + data = await this.agentProofsService.requestProof(dto); break; case PROOF_LIST: dto = event.data as ProofFilterDto; - data = await this.agentService.fetchProofs(dto); + data = await this.agentProofsService.fetchProofs(dto); break; case PROOF_GET: dto = event.data as IdReqDto; - data = await this.agentService.getProofById(dto.id); + data = await this.agentProofsService.getProofById(dto.id); break; case PROOF_ACCEPT: - data = await this.agentService.acceptProof( + data = await this.agentProofsService.acceptProof( event.data as AcceptProofDto, ); break; case PROOF_DECLINE: dto = event.data as IdReqDto; - data = await this.agentService.declineProofRequest(dto.id); + data = await this.agentProofsService.declineProofRequest(dto.id); break; case PROOF_DELETE: dto = event.data as IdReqDto; - data = await this.agentService.deleteProofById(dto.id); + data = await this.agentProofsService.deleteProofById(dto.id); break; case MESSAGE_MAKE: dto = event.data as MakeBasicMessageRequestDto; - data = await this.agentService.sendMessage(dto); + data = await this.agentBasicMessagesService.sendMessage(dto); break; case MESSAGE_LIST: dto = event.data as MessageFilterDto; - data = await this.agentService.fetchBasicMessages(dto); + data = await this.agentBasicMessagesService.fetchBasicMessages(dto); break; case MESSAGE_DELETE: dto = event.data as IdReqDto; - data = await this.agentService.deleteMessageById(dto.id); + data = await this.agentBasicMessagesService.deleteMessageById(dto.id); break; } diff --git a/libs/askar/src/askar-rest/askar.rest.module.ts b/libs/askar/src/askar-rest/askar.rest.module.ts index 6a320c0fde2e48e4775bcda5c88ff6a9bf2787b5..b68904ff287db8d43ccced196bb0ddf3df40e50d 100644 --- a/libs/askar/src/askar-rest/askar.rest.module.ts +++ b/libs/askar/src/askar-rest/askar.rest.module.ts @@ -1,5 +1,12 @@ import { Module, ValidationPipe } from "@nestjs/common"; -import { AgentService } from "../askar/agent.service"; +import { AgentAnoncredsService } from "../askar/services/agent.anoncreds.service"; +import { AgentBasicMessagesService } from "../askar/services/agent.basicMessages.service"; +import { AgentConnectionsService } from "../askar/services/agent.connections.service"; +import { AgentCredentialsService } from "../askar/services/agent.credentials.service"; +import { AgentDidsService } from "../askar/services/agent.dids.service"; +import { AgentJsonldService } from "../askar/services/agent.jsonld.service"; +import { AgentOobService } from "../askar/services/agent.oob.service"; +import { AgentProofsService } from "../askar/services/agent.proofs.service"; import { ConfigModule } from "@nestjs/config"; import { LedgersModule } from "@ocm-engine/ledgers"; import { APP_PIPE } from "@nestjs/core"; @@ -17,7 +24,14 @@ import { JwtModule } from "@nestjs/jwt"; }), ], providers: [ - AgentService, + AgentAnoncredsService, + AgentBasicMessagesService, + AgentConnectionsService, + AgentCredentialsService, + AgentDidsService, + AgentJsonldService, + AgentOobService, + AgentProofsService, { provide: APP_PIPE, useValue: new ValidationPipe({ diff --git a/libs/askar/src/askar-rest/exception.handler.ts b/libs/askar/src/askar-rest/exception.handler.ts index 4847f4cc1065679581ab4d77244f7a604a74cc92..5846d3c1af2c18853d5e7aae48ede753336b0b17 100644 --- a/libs/askar/src/askar-rest/exception.handler.ts +++ b/libs/askar/src/askar-rest/exception.handler.ts @@ -6,10 +6,7 @@ import { HttpStatus, BadRequestException, } from "@nestjs/common"; -import { - CredoError, - RecordNotFoundError, -} from "@credo-ts/core"; +import { CredoError, RecordNotFoundError } from "@credo-ts/core"; import { EntityNotFoundError } from "@ocm-engine/dtos"; @Catch() diff --git a/libs/askar/src/askar-rest/rest.controller.ts b/libs/askar/src/askar-rest/rest.controller.ts index dfffbdc404afe832a78b24d39f2facc4fff72eda..c2d8a349c05b68c332b62fe7af8cbe629fe795eb 100644 --- a/libs/askar/src/askar-rest/rest.controller.ts +++ b/libs/askar/src/askar-rest/rest.controller.ts @@ -9,8 +9,14 @@ import { UseFilters, UseGuards, } from "@nestjs/common"; - -import { AgentService } from "../askar/agent.service"; +import { AgentAnoncredsService } from "../askar/services/agent.anoncreds.service"; +import { AgentBasicMessagesService } from "../askar/services/agent.basicMessages.service"; +import { AgentConnectionsService } from "../askar/services/agent.connections.service"; +import { AgentCredentialsService } from "../askar/services/agent.credentials.service"; +import { AgentDidsService } from "../askar/services/agent.dids.service"; +import { AgentJsonldService } from "../askar/services/agent.jsonld.service"; +import { AgentOobService } from "../askar/services/agent.oob.service"; +import { AgentProofsService } from "../askar/services/agent.proofs.service"; import { CreateCredentialDefinitionRequestDto, OfferCredentialRequestDto, @@ -38,28 +44,37 @@ import { AuthGuard } from "./auth/auth.guard"; @Controller("v1") @UseGuards(AuthGuard) export class RestController { - constructor(private readonly agentService: AgentService) {} + constructor( + private readonly agentAnoncredsService: AgentAnoncredsService, + private readonly agentBasicMessagesService: AgentBasicMessagesService, + private readonly agentConnectionsService: AgentConnectionsService, + private readonly agentCredentialsService: AgentCredentialsService, + private readonly agentDidsService: AgentDidsService, + private readonly agentJsonldService: AgentJsonldService, + private readonly agentOobService: AgentOobService, + private readonly agentProofsService: AgentProofsService, + ) {} @Get("/invitations") async fetchInvitations(@Query() filter: InvitationFilterDto) { - return this.agentService.fetchInvitations(filter); + return this.agentOobService.fetchInvitations(filter); } @Post("/invitations") createInvitation( @Body() createInvitationRequestDto: CreateInvitationRequestDto, ) { - return this.agentService.createInvitation(createInvitationRequestDto); + return this.agentOobService.createInvitation(createInvitationRequestDto); } @Get("/invitations/:id") getInvitationById(@Param("id") id: string) { - return this.agentService.getInvitationById(id); + return this.agentOobService.getInvitationById(id); } @Delete("/invitations/:id") deleteInvitationById(@Param("id") id: string) { - return this.agentService.deleteInvitationById(id); + return this.agentOobService.deleteInvitationById(id); } @Post("/invitations/accept") @@ -70,186 +85,191 @@ export class RestController { createInvitationDto.invitationUrl || createInvitationDto.shortInvitationUrl; - return this.agentService.acceptInvitation(url); + return this.agentOobService.acceptInvitation(url); } @Get("/connections") async fetchConnections() { - return this.agentService.fetchConnections(); + return this.agentConnectionsService.fetchConnections(); } @Get("/connections/:id") async getConnectionById(@Param("id") id: string) { - return this.agentService.getConnectionById(id); + return this.agentConnectionsService.getConnectionById(id); } @Delete("/connections/:id") async deleteConnectionById(@Param("id") id: string) { - return this.agentService.deleteConnectionById(id); + return this.agentConnectionsService.deleteConnectionById(id); } @Get("/connections/oob/:id") async getConnectionByOobId(@Param("id") id: string) { - return this.agentService.getConnectionByOobId(id); + return this.agentConnectionsService.getConnectionByOobId(id); } @Post("/connections/ping/:id") async pingConnection(@Param("id") id: string) { - return this.agentService.trustPingToConnection(id); + return this.agentConnectionsService.trustPingToConnection(id); } @Post("/schemas") async createSchema(@Body() schemaDto: CreateSchemaRequestDto) { - return this.agentService.createSchema(schemaDto); + return this.agentAnoncredsService.createSchema(schemaDto); } @Post("/schemas/get-by-id") async getSchemaById(@Body() dto: IdReqDto) { - return this.agentService.getSchemaById(dto.id); + return this.agentAnoncredsService.getSchemaById(dto.id); } @Get("/schemas") async fetchSchemas() { - return this.agentService.fetchSchemas(); + return this.agentAnoncredsService.fetchSchemas(); } @Get("/definitions") async fetchCredentialDefinitions() { - return this.agentService.fetchCredentialDefinitions(); + return this.agentAnoncredsService.fetchCredentialDefinitions(); } @Post("/definitions/get-by-id") async getCredentialDefinitionById(@Body() dto: IdReqDto) { - return this.agentService.getCredentialDefinitionById(dto.id); + return this.agentAnoncredsService.getCredentialDefinitionById(dto.id); } @Post("/definitions") async createCredentialDefinition( @Body() credentialDefinitionDto: CreateCredentialDefinitionRequestDto, ) { - return this.agentService.createCredentialDefinition( + return this.agentAnoncredsService.createCredentialDefinition( credentialDefinitionDto, ); } @Post("/credentials/offers") async offerCredential(@Body() dto: OfferCredentialRequestDto) { - return this.agentService.offerCredential(dto); + return this.agentCredentialsService.offerCredential(dto); } @Post("/credentials/jsonld/offers") async offerJsonLdCredential(@Body() data: OfferJsonCredentialRequests) { - return this.agentService.offerJsonLdCredential(data.connectionId, data.doc); + return this.agentJsonldService.offerJsonLdCredential( + data.connectionId, + data.doc, + ); } @Post("/jsonld/sign") async signJsonLdCredential(@Body() data: SignJsonCredentialRequests) { - return this.agentService.signJsonLdCredential(data.doc); + return this.agentJsonldService.signJsonLdCredential(data.doc); } @Post("/jsonld/credentials/:cred_id/prepare-verifiable-presentation") async signJsonLdPresentationByCredId(@Param("cred_id") credentialId: string) { - return this.agentService.prepareVerifiablePresentationByJsonLdCredId( + return this.agentJsonldService.prepareVerifiablePresentationByJsonLdCredId( credentialId, ); } @Get("/credentials") async fetchCredentials(@Query() credentialFilterDto: CredentialFilterDto) { - return this.agentService.fetchCredentials(credentialFilterDto); + return this.agentCredentialsService.fetchCredentials(credentialFilterDto); } @Get("/credentials/:id") async getCredentialById(@Param("id") credentialId: string) { - return this.agentService.getCredentialById(credentialId); + return this.agentCredentialsService.getCredentialById(credentialId); } @Get("/credentials/:id/format-data") async getCredentialFormatDataById(@Param("id") credentialId: string) { - return this.agentService.getCredentialFormatDataById(credentialId); + return this.agentCredentialsService.getCredentialFormatDataById( + credentialId, + ); } @Post("/credentials/offers/accept") async acceptCredential(@Body() dto: AcceptCredentialDto) { - return this.agentService.acceptCredential(dto); + return this.agentCredentialsService.acceptCredential(dto); } @Post("/credentials/offers/:credential_record_id/decline") async declineCredential( @Param("credential_record_id") credentialRecordId: string, ) { - return this.agentService.declineCredential(credentialRecordId); + return this.agentCredentialsService.declineCredential(credentialRecordId); } @Delete("/credentials/:id") async deleteCredentialById(@Param("id") credentialId: string) { - return this.agentService.deleteCredentialById(credentialId); + return this.agentCredentialsService.deleteCredentialById(credentialId); } @Post("/messages") async sendMessage(@Body() message: MakeBasicMessageRequestDto) { - return this.agentService.sendMessage(message); + return this.agentBasicMessagesService.sendMessage(message); } @Get("/messages") async fetchBasicMessages(@Query() filter: MessageFilterDto) { - return this.agentService.fetchBasicMessages(filter); + return this.agentBasicMessagesService.fetchBasicMessages(filter); } @Delete("/messages/:id") async deleteBasicMessage(@Param("id") messageId: string) { - return this.agentService.deleteMessageById(messageId); + return this.agentBasicMessagesService.deleteMessageById(messageId); } @Get("/proofs") async fetchProofs(@Query() proofFilterDto: ProofFilterDto) { - return this.agentService.fetchProofs(proofFilterDto); + return this.agentProofsService.fetchProofs(proofFilterDto); } @Get("/proofs/:proof_record_id") async getProofById(@Param("proof_record_id") proofRecordId: string) { - return this.agentService.getProofById(proofRecordId); + return this.agentProofsService.getProofById(proofRecordId); } @Get("/proofs/:proof_record_id/format-data") async getProofFormatDataById( @Param("proof_record_id") proofRecordId: string, ) { - return this.agentService.getProofFormatDataById(proofRecordId); + return this.agentProofsService.getProofFormatDataById(proofRecordId); } @Post("/proofs/:proof_record_id/acceptance-wait") async proofAcceptanceWait(@Param("proof_record_id") proofRecordId: string) { - return this.agentService.proofAcceptanceWait(proofRecordId); + return this.agentProofsService.proofAcceptanceWait(proofRecordId); } @Post("/proofs/request") async requestProof(@Body() requestProofDto: RequestProofDto) { - return this.agentService.requestProof(requestProofDto); + return this.agentProofsService.requestProof(requestProofDto); } @Post(`/proofs/accept`) async acceptProof(@Body() acceptProofRequestDto: AcceptProofDto) { - return this.agentService.acceptProof(acceptProofRequestDto); + return this.agentProofsService.acceptProof(acceptProofRequestDto); } @Post("/proofs/:proof_record_id/decline") async declineProofRequest(@Param("proof_record_id") proofRecordId: string) { - return this.agentService.declineProofRequest(proofRecordId); + return this.agentProofsService.declineProofRequest(proofRecordId); } @Delete("/proofs/:proof_record_id") async deleteProofById(@Param("proof_record_id") proofRecordId: string) { - return this.agentService.deleteProofById(proofRecordId); + return this.agentProofsService.deleteProofById(proofRecordId); } @Get("/created-dids") async getCreatedDids(): Promise<DidRecordDto[]> { - return this.agentService.getCreatedDids(); + return this.agentDidsService.getCreatedDids(); } @Post("/resolve-did") async resolveDid(@Body() dto: IdReqDto): Promise<DidResolutionResult> { - return this.agentService.resolve(dto.id); + return this.agentDidsService.resolve(dto.id); } } diff --git a/libs/askar/src/askar/agent.service.ts b/libs/askar/src/askar/agent.service.ts deleted file mode 100644 index 38caf855474b90dd74ef9eb0c55c545b4076a493..0000000000000000000000000000000000000000 --- a/libs/askar/src/askar/agent.service.ts +++ /dev/null @@ -1,1333 +0,0 @@ -import { Injectable, Logger } from "@nestjs/common"; -import { AskarService } from "./askar.service"; -import { - ConnectionRecordDto, - AcceptProofDto, - CreateCredentialDefinitionRequestDto, - CreddefRecordDto, - CreateInvitationResponseDto, - CreateSchemaRequestDto, - SchemaRecordDto, - CredentialNotCreatedError, - OfferCredentialRequestDto, - CredentialRecordDto, - RequestProofDto, - ProofRecordDto, - MakeBasicMessageRequestDto, - MessageRecordDto, - SchemaNotCreatedError, - CredentialFilterDto, - ProofFilterDto, - MessageFilterDto, - RequestProofResponseDto, - CredentialOfferResponseDto, - EntityNotFoundError, - AcceptCredentialDto, - CredentialFormatDataDto, - ProofFormatDataDto, - CreateInvitationRequestDto, - InvitationFilterDto, - DidRecordDto, - OcmError, - W3cCredentialDto, - BaseRecordDto, - W3cJsonLdVerifiableCredentialDto, - W3cJsonLdVerifiablePresentationDto, -} from "@ocm-engine/dtos"; -import { - AutoAcceptCredential, - BasicMessageRecord, - BasicMessageRole, - ClaimFormat, - ConnectionRecord, - CredentialExchangeRecord, - JsonTransformer, - CredentialState, - ProofState, - Query, - ProofExchangeRecord, - OutOfBandRecord, - W3cCredential, - W3cCredentialService, - DidRecord, - JsonCredential, - W3cJsonLdVerifiableCredential, -} from "@credo-ts/core"; -import { AnonCredsRequestedAttribute } from "@credo-ts/anoncreds"; -import { uuid } from "@credo-ts/core/build/utils/uuid"; -import { - waitForCredentialExchangeRecordSubject, - waitForProofExchangeRecordSubject, -} from "../agent.utils"; - -@Injectable() -export class AgentService { - private readonly logger = new Logger(AgentService.name); - constructor(private readonly askar: AskarService) {} - - createInvitation = async ( - createInvitationRequestDto?: CreateInvitationRequestDto, - ) => { - const outOfBoundRecord = await this.askar.agent.oob.createInvitation( - createInvitationRequestDto, - ); - - const response = new CreateInvitationResponseDto(); - - let longUrl = outOfBoundRecord.outOfBandInvitation.toUrl({ - domain: this.askar.agentConfig.agentPeerAddress, - }); - - if (this.askar.agentConfig.agentOobUrl) { - longUrl = longUrl.replace( - this.askar.agentConfig.agentPeerAddress, - this.askar.agentConfig.agentOobUrl, - ); - } - - //TODO: should we replace the short url with agentOobUrl if we do this we should have a redirect in ingress - response.shortInvitationUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBoundRecord.outOfBandInvitation.id}`; - response.outOfBandId = outOfBoundRecord.id; - response.createdAt = outOfBoundRecord.createdAt; - response.updatedAt = outOfBoundRecord.updatedAt; - response.role = outOfBoundRecord.role; - response.state = outOfBoundRecord.state; - response.invitationUrl = longUrl; - - return response; - }; - - acceptInvitation = async ( - invitationUrl: string, - ): Promise<ConnectionRecordDto> => { - const { connectionRecord } = - await this.askar.agent.oob.receiveInvitationFromUrl(invitationUrl); - - if (typeof connectionRecord === "undefined") { - throw new EntityNotFoundError(); - } - - const response = new ConnectionRecordDto(); - response.connectionName = connectionRecord.theirLabel; - response.state = connectionRecord.state; - response.id = connectionRecord.id; - response.did = connectionRecord.did; - response.theirDid = connectionRecord.theirDid; - response.invitationDid = connectionRecord.invitationDid; - response.outOfBandId = connectionRecord.outOfBandId; - response.createdAt = connectionRecord.createdAt; - response.updatedAt = connectionRecord.updatedAt; - response.imageUrl = connectionRecord.imageUrl; - - return response; - }; - - deleteInvitationById = async (id: string) => { - return this.askar.agent.oob.deleteById(id); - }; - - fetchInvitations = async (filter: InvitationFilterDto) => { - const query: Query<OutOfBandRecord>[] = []; - - if (filter.states) { - const stateQuery: Query<OutOfBandRecord> = { - $or: filter.states.map((state) => ({ state })), - }; - query.push(stateQuery); - } - - if (filter.roles) { - const roleQuery: Query<OutOfBandRecord> = { - $or: filter.roles.map((role) => ({ role })), - }; - - query.push(roleQuery); - } - - let invitations = await this.askar.agent.oob.findAllByQuery({ - $and: query, - }); - invitations = invitations.sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ); - - const invitationsResponse = invitations.map((invitation) => { - const response = new CreateInvitationResponseDto(); - response.invitationUrl = invitation.outOfBandInvitation.toUrl({ - domain: this.askar.agentConfig.agentPeerAddress, - }); - response.shortInvitationUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${invitation.outOfBandInvitation.id}`; - response.outOfBandId = invitation.id; - response.createdAt = invitation.createdAt; - response.updatedAt = invitation.updatedAt; - response.role = invitation.role; - response.state = invitation.state; - return response; - }); - - return invitationsResponse; - }; - - getInvitationById = async (oobId: string) => { - const invitation = await this.askar.agent.oob.getById(oobId); - - const response = new CreateInvitationResponseDto(); - response.invitationUrl = invitation.outOfBandInvitation.toUrl({ - domain: this.askar.agentConfig.agentPeerAddress, - }); - response.shortInvitationUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${invitation.outOfBandInvitation.id}`; - response.outOfBandId = invitation.id; - response.createdAt = invitation.createdAt; - response.updatedAt = invitation.updatedAt; - response.role = invitation.role; - response.state = invitation.state; - return response; - }; - - async fetchConnections(): Promise<ConnectionRecordDto[]> { - //TODO: no ordering in findAllByQuery - const agentResponse = (await this.askar.agent.connections.getAll()).sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ); - - const connectionArray = agentResponse.map((singleConnectionRes) => { - const connectionResponse = new ConnectionRecordDto(); - connectionResponse.id = singleConnectionRes.id; - connectionResponse.state = singleConnectionRes.state; - connectionResponse.connectionName = singleConnectionRes.theirLabel; - connectionResponse.alias = singleConnectionRes.alias; - connectionResponse.did = singleConnectionRes.did; - connectionResponse.theirDid = singleConnectionRes.theirDid; - connectionResponse.invitationDid = singleConnectionRes.invitationDid; - connectionResponse.outOfBandId = singleConnectionRes.outOfBandId; - connectionResponse.createdAt = singleConnectionRes.createdAt; - connectionResponse.updatedAt = singleConnectionRes.updatedAt; - connectionResponse.imageUrl = singleConnectionRes.imageUrl; - - return connectionResponse; - }); - - return connectionArray; - } - - getConnectionByOobId = async (oobId: string) => { - const connectionRecords = - await this.askar.agent.connections.findAllByOutOfBandId(oobId); - - const connectionArray = connectionRecords.map((singleConnectionRes) => { - const connectionResponse = new ConnectionRecordDto(); - connectionResponse.id = singleConnectionRes.id; - connectionResponse.state = singleConnectionRes.state; - connectionResponse.connectionName = singleConnectionRes.theirLabel; - connectionResponse.alias = singleConnectionRes.alias; - connectionResponse.did = singleConnectionRes.did; - connectionResponse.theirDid = singleConnectionRes.theirDid; - connectionResponse.invitationDid = singleConnectionRes.invitationDid; - connectionResponse.outOfBandId = singleConnectionRes.outOfBandId; - connectionResponse.createdAt = singleConnectionRes.createdAt; - connectionResponse.updatedAt = singleConnectionRes.updatedAt; - connectionResponse.imageUrl = singleConnectionRes.imageUrl; - - return connectionResponse; - }); - - return connectionArray; - }; - - getConnectionById = async (id: string): Promise<ConnectionRecordDto> => { - const agentResponse = await this.askar.agent.connections.findById(id); - - if (!agentResponse) { - throw new EntityNotFoundError(); - } - - const connectionResponse = new ConnectionRecordDto(); - connectionResponse.id = agentResponse.id; - connectionResponse.state = agentResponse.state; - connectionResponse.connectionName = agentResponse.theirLabel; - connectionResponse.alias = agentResponse.alias; - connectionResponse.did = agentResponse.did; - connectionResponse.theirDid = agentResponse.theirDid; - connectionResponse.invitationDid = agentResponse.invitationDid; - connectionResponse.outOfBandId = agentResponse.outOfBandId; - connectionResponse.createdAt = agentResponse.createdAt; - connectionResponse.updatedAt = agentResponse.updatedAt; - connectionResponse.imageUrl = agentResponse.imageUrl; - - return connectionResponse; - }; - - deleteConnectionById = async (id: string): Promise<void> => { - await this.askar.agent.connections.hangup({ - connectionId: id, - deleteAfterHangup: true - }); - }; - - fetchSchemas = async (): Promise<SchemaRecordDto[]> => { - let schemaRecords = - await this.askar.agent.modules.anoncreds.getCreatedSchemas({}); - schemaRecords = schemaRecords.sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ); - - const schemaResponses = schemaRecords.map((singleSchemaRes) => { - const schemaResponse = new SchemaRecordDto(); - schemaResponse.id = singleSchemaRes.schemaId; - schemaResponse.createdAt = singleSchemaRes.createdAt; - schemaResponse.updatedAt = singleSchemaRes.updatedAt; - schemaResponse.name = singleSchemaRes.schema.name; - schemaResponse.attributes = singleSchemaRes.schema.attrNames; - schemaResponse.version = singleSchemaRes.schema.version; - schemaResponse.issuerId = singleSchemaRes.schema.issuerId; - schemaResponse.methodName = singleSchemaRes.methodName; - - return schemaResponse; - }); - - return schemaResponses; - }; - - getSchemaById = async (schemaId: string): Promise<SchemaRecordDto> => { - const agentResponse = await this.askar.agent.modules.anoncreds.getSchema( - schemaId, - ); - - if (!agentResponse || !agentResponse.schema) { - throw new EntityNotFoundError(); - } - - const schemaResponse = new SchemaRecordDto(); - schemaResponse.id = agentResponse.schemaId; - schemaResponse.name = agentResponse.schema.name; - schemaResponse.attributes = agentResponse.schema.attrNames; - schemaResponse.version = agentResponse.schema.version; - schemaResponse.issuerId = agentResponse.schema.issuerId; - - return schemaResponse; - }; - - createSchema = async ( - schema: CreateSchemaRequestDto, - ): Promise<SchemaRecordDto> => { - const dids = await this.askar.agent.dids.getCreatedDids({ method: "indy" }); - - const schemaResult = - await this.askar.agent.modules.anoncreds.registerSchema({ - schema: { - name: schema.name, - issuerId: dids[0].did, - attrNames: schema.attributes, - version: schema.version, - }, - options: {}, - }); - - if (schemaResult.schemaState.state !== "finished") { - throw new SchemaNotCreatedError(); - } - - const response = new SchemaRecordDto(); - - response.name = schemaResult.schemaState.schema.name; - response.id = schemaResult.schemaState.schemaId; - response.issuerId = schemaResult.schemaState.schema.issuerId; - response.version = schemaResult.schemaState.schema.version; - response.attributes = schemaResult.schemaState.schema.attrNames; - - return response; - }; - - fetchCredentialDefinitions = async (): Promise<CreddefRecordDto[]> => { - let credentialDefinitions = - await this.askar.agent.modules.anoncreds.getCreatedCredentialDefinitions( - {}, - ); - credentialDefinitions = credentialDefinitions.sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ); - - const response: Array<CreddefRecordDto> = []; - for (const credDef of credentialDefinitions) { - const cd = new CreddefRecordDto(); - cd.id = credDef.credentialDefinitionId; - cd.createdAt = credDef.createdAt; - cd.updatedAt = credDef.updatedAt; - cd.schemaId = credDef.credentialDefinition.schemaId; - cd.issuerId = credDef.credentialDefinition.issuerId; - cd.tag = credDef.credentialDefinition.tag; - response.push(cd); - } - - return response; - }; - - getCredentialDefinitionById = async ( - credentialDefinitionId: string, - ): Promise<CreddefRecordDto> => { - const credDefs = - await this.askar.agent.modules.anoncreds.getCreatedCredentialDefinitions({ - credentialDefinitionId, - }); - - const credDef = credDefs[0] || null; - if (!credDef) { - throw new EntityNotFoundError(); - } - - const cd = new CreddefRecordDto(); - cd.id = credDef.credentialDefinitionId; - cd.createdAt = credDef.createdAt; - cd.updatedAt = credDef.updatedAt; - cd.schemaId = credDef.credentialDefinition.schemaId; - cd.issuerId = credDef.credentialDefinition.issuerId; - cd.tag = credDef.credentialDefinition.tag; - - return cd; - }; - - createCredentialDefinition = async ( - credentialDefinitionDto: CreateCredentialDefinitionRequestDto, - ): Promise<CreddefRecordDto> => { - const dids = await this.askar.agent.dids.getCreatedDids({ method: "indy" }); - - const credDef = - await this.askar.agent.modules.anoncreds.registerCredentialDefinition({ - credentialDefinition: { - tag: credentialDefinitionDto.tag, - issuerId: dids[0].did, - schemaId: credentialDefinitionDto.schemaId, - }, - options: { - supportRevocation: credentialDefinitionDto.supportRevocation ?? false, - }, - }); - - if (credDef.credentialDefinitionState.state !== "finished") { - throw new CredentialNotCreatedError(); - } - - const response = new CreddefRecordDto(); - response.id = credDef.credentialDefinitionState.credentialDefinitionId; - response.schemaId = - credDef.credentialDefinitionState.credentialDefinition.schemaId; - response.issuerId = - credDef.credentialDefinitionState.credentialDefinition.issuerId; - response.tag = credDef.credentialDefinitionState.credentialDefinition.tag; - - return response; - }; - - signJsonLdCredential = async ( - credToSign: W3cCredentialDto, - ): Promise<W3cJsonLdVerifiableCredentialDto> => { - this.logger.log("Sign json ld credentials"); - - const didRecord = await this.getFirstDidWebRecord(); - const verificationMethodList = - didRecord.didDocument?.verificationMethod || []; - if (!verificationMethodList.length) { - throw new EntityNotFoundError( - "DidDocument does not exists or contains no verification methods", - ); - } - - const verificationMethod = verificationMethodList[0]; - - const w3cServ = - this.askar.agent.context.dependencyManager.resolve(W3cCredentialService); - - credToSign.id = didRecord.did + "?uuid=" + uuid(); - if (credToSign.credentialSubject) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - credToSign.credentialSubject.id = credToSign.id; - } - credToSign.issuer = didRecord.did; - credToSign.issuanceDate = new Date().toISOString(); - let credential: W3cCredential; - try { - credential = JsonTransformer.fromJSON(credToSign, W3cCredential); - } catch (e) { - this.logger.log("Incorrect request parameter", e); - throw new OcmError( - "Invalid JSON-LD data format. Please ensure that your JSON-LD contains the following properties: @context, id, type, issuer, issuanceDate, expirationDate, and credentialSubject.", - ); - } - - const vc = await w3cServ.signCredential(this.askar.agent.context, { - format: ClaimFormat.LdpVc, - credential, - proofType: "Ed25519Signature2018", - verificationMethod: verificationMethod.id, - }); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const jsonVC = vc.toJson() as W3cJsonLdVerifiableCredentialDto; - this.logger.debug(JSON.stringify(jsonVC, null, 2)); - - return jsonVC; - }; - - prepareVerifiablePresentationByJsonLdCredId = async ( - credentialRecordId: string, - ): Promise<W3cJsonLdVerifiablePresentationDto> => { - const didRecord = await this.getFirstDidWebRecord(); - const verificationMethodList = - didRecord.didDocument?.verificationMethod || []; - if (!verificationMethodList.length) { - throw new EntityNotFoundError( - "DidDocument does not exists or contains no verification methods", - ); - } - - const verificationMethod = verificationMethodList[0]; - - const credFormatData = await this.askar.agent.credentials.getFormatData( - credentialRecordId, - ); - if (!credFormatData.credential?.jsonld) { - throw new OcmError( - "The JSON-LD credential is either not in your wallet, pending approval, or not in the JSON-LD format.", - ); - } - - const jsonLd = credFormatData.credential.jsonld; - const vc = JsonTransformer.fromJSON(jsonLd, W3cJsonLdVerifiableCredential); - - const w3cServ = - this.askar.agent.context.dependencyManager.resolve(W3cCredentialService); - const presentation = await w3cServ.createPresentation({ - credentials: [vc], - id: didRecord.did + "?uuid=" + uuid(), - }); - - const vp = await w3cServ.signPresentation(this.askar.agent.context, { - format: ClaimFormat.LdpVp, - presentation, - proofPurpose: null, - proofType: "Ed25519Signature2018", - challenge: uuid(), - verificationMethod: verificationMethod.id, - }); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const jsonVP = vp.toJson() as W3cJsonLdVerifiablePresentationDto; - this.logger.debug(JSON.stringify(jsonVP, null, 2)); - - return jsonVP; - }; - - offerJsonLdCredential = async ( - connectionId: string | undefined, - credToSign: W3cCredentialDto, - ): Promise<CredentialOfferResponseDto> => { - this.logger.log("offerJsonLdCredential", connectionId); - - const didRecord = await this.getFirstDidWebRecord(); - const verificationMethodList = - didRecord.didDocument?.verificationMethod || []; - if (!verificationMethodList.length) { - throw new EntityNotFoundError( - "DidDocument does not exists or contains no verification methods", - ); - } - - const verificationMethod = verificationMethodList[0]; - - const w3cServ = - this.askar.agent.context.dependencyManager.resolve(W3cCredentialService); - - credToSign.id = didRecord.did + "?uuid=" + uuid(); - if (credToSign.credentialSubject) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - credToSign.credentialSubject.id = credToSign.id; - } - credToSign.issuer = didRecord.did; - credToSign.issuanceDate = new Date().toISOString(); - let credential: W3cCredential; - try { - credential = JsonTransformer.fromJSON(credToSign, W3cCredential); - } catch (e) { - this.logger.log("Incorrect request parameter", e); - throw new OcmError( - "Invalid JSON-LD data format. Please ensure that your JSON-LD contains the following properties: @context, id, type, issuer, issuanceDate, expirationDate, and credentialSubject.", - ); - } - - const vc = await w3cServ.signCredential(this.askar.agent.context, { - format: ClaimFormat.LdpVc, - credential, - proofType: "Ed25519Signature2018", - verificationMethod: verificationMethod.id, - }); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const jsonVC = vc.toJson() as JsonCredential; - - if (!connectionId) { - // create connection less credential - const { credentialRecord, message } = - await this.askar.agent.credentials.createOffer({ - protocolVersion: "v2", - credentialFormats: { - jsonld: { - credential: jsonVC, - options: { - proofType: "Ed25519Signature2018", - proofPurpose: "assertionMethod", - }, - }, - }, - autoAcceptCredential: AutoAcceptCredential.ContentApproved, - }); - - credentialRecord.setTag("xRole", "issuer"); - await this.askar.agent.credentials.update(credentialRecord); - - const outOfBandRecord = await this.askar.agent.oob.createInvitation({ - messages: [message], - handshake: false, - }); - - const credentialUrl = outOfBandRecord.outOfBandInvitation.toUrl({ - domain: this.askar.agentConfig.agentPeerAddress, - }); - - const shortCredentialUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBandRecord.outOfBandInvitation.id}`; - - const dto = new CredentialRecordDto(); - dto.id = credentialRecord.id; - dto.state = credentialRecord.state; - dto.connectionId = credentialRecord.connectionId; - dto.attributes = credentialRecord.credentialAttributes; - dto.createdAt = credentialRecord.createdAt; - dto.tags = credentialRecord.getTags(); - - return { - credentialUrl: credentialUrl, - shortCredentialUrl: shortCredentialUrl, - credentialRecord: dto, - }; - } - - const credentialExchangeRecord = - await this.askar.agent.credentials.offerCredential({ - connectionId: connectionId, - protocolVersion: "v2", - credentialFormats: { - jsonld: { - credential: jsonVC, - options: { - proofType: "Ed25519Signature2018", - proofPurpose: "assertionMethod", - }, - }, - }, - autoAcceptCredential: AutoAcceptCredential.ContentApproved, - }); - - this.logger.log(credentialExchangeRecord); - - credentialExchangeRecord.setTag("xRole", "issuer"); - await this.askar.agent.credentials.update(credentialExchangeRecord); - - const dto = new CredentialRecordDto(); - dto.id = credentialExchangeRecord.id; - dto.state = credentialExchangeRecord.state; - dto.connectionId = credentialExchangeRecord.connectionId; - dto.attributes = credentialExchangeRecord.credentialAttributes; - dto.createdAt = credentialExchangeRecord.createdAt; - dto.tags = credentialExchangeRecord.getTags(); - - return { - credentialUrl: null, - shortCredentialUrl: null, - credentialRecord: dto, - }; - }; - - offerCredential = async ( - offerCredentialDto: OfferCredentialRequestDto, - ): Promise<CredentialOfferResponseDto> => { - this.logger.log( - "Incoming request", - JSON.stringify(offerCredentialDto, null, 2), - ); - - if (!offerCredentialDto.connectionId) { - const { credentialRecord, message } = - await this.askar.agent.credentials.createOffer({ - protocolVersion: "v2", - credentialFormats: { - anoncreds: { - credentialDefinitionId: offerCredentialDto.credentialDefinitionId, - attributes: offerCredentialDto.attributes, - }, - }, - autoAcceptCredential: AutoAcceptCredential.ContentApproved, - }); - - credentialRecord.setTag("xRole", "issuer"); - await this.askar.agent.credentials.update(credentialRecord); - - const outOfBandRecord = await this.askar.agent.oob.createInvitation({ - messages: [message], - handshake: false, - }); - - const credentialUrl = outOfBandRecord.outOfBandInvitation.toUrl({ - domain: this.askar.agentConfig.agentPeerAddress, - }); - - const shortCredentialUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBandRecord.outOfBandInvitation.id}`; - - const dto = new CredentialRecordDto(); - dto.id = credentialRecord.id; - dto.state = credentialRecord.state; - dto.connectionId = credentialRecord.connectionId; - dto.attributes = credentialRecord.credentialAttributes; - dto.createdAt = credentialRecord.createdAt; - dto.tags = credentialRecord.getTags(); - - return { - credentialUrl: credentialUrl, - shortCredentialUrl: shortCredentialUrl, - credentialRecord: dto, - }; - } - const credentialExchangeRecord = - await this.askar.agent.credentials.offerCredential({ - protocolVersion: "v2", - connectionId: offerCredentialDto.connectionId, - credentialFormats: { - anoncreds: { - credentialDefinitionId: offerCredentialDto.credentialDefinitionId, - attributes: offerCredentialDto.attributes, - }, - }, - }); - - credentialExchangeRecord.setTag("xRole", "issuer"); - await this.askar.agent.credentials.update(credentialExchangeRecord); - - const dto = new CredentialRecordDto(); - dto.id = credentialExchangeRecord.id; - dto.state = credentialExchangeRecord.state; - dto.connectionId = credentialExchangeRecord.connectionId; - dto.attributes = credentialExchangeRecord.credentialAttributes; - dto.createdAt = credentialExchangeRecord.createdAt; - dto.tags = credentialExchangeRecord.getTags(); - - return { - credentialUrl: null, - shortCredentialUrl: null, - credentialRecord: dto, - }; - }; - - acceptCredential = async ( - acceptCredentialDto: AcceptCredentialDto, - ): Promise<CredentialRecordDto> => { - if (acceptCredentialDto.credentialUrl) { - return this.acceptOobCredentials(acceptCredentialDto.credentialUrl); - } - return this.acceptConnectionCredential(acceptCredentialDto.credentialId); - }; - - acceptOobCredentials = async (url: string): Promise<CredentialRecordDto> => { - // omit await in order to catch received record in the next line - setTimeout(() => { - this.askar.agent.oob.receiveInvitationFromUrl(url, { - autoAcceptConnection: false, - autoAcceptInvitation: true, - // reuseConnection: true, - }); - }, 20); - - const record = await waitForCredentialExchangeRecordSubject( - this.askar.agentB, - { - state: CredentialState.OfferReceived, - }, - ); - - const acceptedRecord = await this.askar.agent.credentials.acceptOffer({ - credentialRecordId: record.id, - }); - - const response = new CredentialRecordDto(); - response.id = acceptedRecord.id; - response.state = acceptedRecord.state; - response.connectionId = acceptedRecord.connectionId; - response.attributes = acceptedRecord.credentialAttributes; - response.createdAt = acceptedRecord.createdAt; - response.tags = acceptedRecord.getTags(); - - return response; - }; - - acceptConnectionCredential = async ( - credentialRecordId: string, - ): Promise<CredentialRecordDto> => { - const credentialExchangeRecord = - await this.askar.agent.credentials.acceptOffer({ - credentialRecordId, - }); - - const response = new CredentialRecordDto(); - response.id = credentialExchangeRecord.id; - response.state = credentialExchangeRecord.state; - response.connectionId = credentialExchangeRecord.connectionId; - response.attributes = credentialExchangeRecord.credentialAttributes; - response.createdAt = credentialExchangeRecord.createdAt; - response.tags = credentialExchangeRecord.getTags(); - - return response; - }; - - declineCredential = async ( - credentialRecordId: string, - ): Promise<CredentialRecordDto> => { - const credentialExchangeRecord = - await this.askar.agent.credentials.declineOffer(credentialRecordId); - - // send request to the issuer that the request is declined, to mark it as Abondoned - await this.askar.agent.credentials.sendProblemReport({ - credentialRecordId: credentialRecordId, - description: "Decline offer", - }); - - const response = new CredentialRecordDto(); - response.id = credentialExchangeRecord.id; - response.state = credentialExchangeRecord.state; - response.connectionId = credentialExchangeRecord.connectionId; - response.attributes = credentialExchangeRecord.credentialAttributes; - response.createdAt = credentialExchangeRecord.createdAt; - response.tags = credentialExchangeRecord.getTags(); - - return response; - }; - - fetchCredentials = async ( - filter: CredentialFilterDto, - ): Promise<CredentialRecordDto[]> => { - const query: Query<CredentialExchangeRecord>[] = []; - - if (filter.states) { - const stateQuery: Query<CredentialExchangeRecord> = { - $or: filter.states.map((state) => ({ state })), - }; - query.push(stateQuery); - } - - if (filter.connectionId) { - const connectionQuery: Query<CredentialExchangeRecord> = { - connectionId: filter.connectionId, - }; - query.push(connectionQuery); - } - - let credentials = await this.askar.agent.credentials.findAllByQuery({ - $and: query, - }); - credentials = credentials.sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ); - - const response: CredentialRecordDto[] = []; - for (const offer of credentials) { - const t = new CredentialRecordDto(); - t.id = offer.id; - t.state = offer.state; - t.connectionId = offer.connectionId; - t.createdAt = offer.createdAt; - t.attributes = offer.credentialAttributes; - t.tags = offer.getTags(); - response.push(t); - } - - return response; - }; - - getCredentialById = async ( - credentialId: string, - ): Promise<CredentialRecordDto> => { - const credentialRecord = await this.askar.agent.credentials.findById( - credentialId, - ); - - if (!credentialRecord) { - throw new EntityNotFoundError(); - } - - const credential = new CredentialRecordDto(); - credential.id = credentialRecord.id; - credential.state = credentialRecord.state; - credential.connectionId = credentialRecord.connectionId; - credential.createdAt = credentialRecord.createdAt; - credential.attributes = credentialRecord.credentialAttributes; - credential.tags = credentialRecord.getTags(); - - return credential; - }; - - getCredentialFormatDataById = async ( - credentialId: string, - ): Promise<CredentialFormatDataDto> => { - - const formatData = await this.askar.agent.credentials.getFormatData( - credentialId, - ); - - if (!formatData) { - throw new EntityNotFoundError(); - } - - const dto = new CredentialFormatDataDto(); - dto.proposalAttributes = formatData.proposalAttributes; - dto.offerAttributes = formatData.offerAttributes; - dto.anoncredsProposal = formatData.proposal?.anoncreds; - dto.anoncredsOffer = formatData.offer?.anoncreds; - dto.anoncredsRequest = formatData.request?.anoncreds; - dto.anoncredsCredential = formatData.credential?.anoncreds; - - dto.all = formatData; - - return dto; - }; - - requestProof = async ( - requestProofDto: RequestProofDto, - ): Promise<RequestProofResponseDto> => { - this.logger.log(JSON.stringify(requestProofDto, null, 2)); - const requestedAttributes: Record<string, AnonCredsRequestedAttribute> = {}; - - for (const attr of requestProofDto.attributes) { - requestedAttributes[uuid()] = { - name: attr.attributeName, - restrictions: [ - { - schema_id: attr.schemaId, - cred_def_id: attr.credentialDefinitionId, - }, - ], - }; - } - - if (!requestProofDto.connectionId) { - this.logger.log("connection Id not detected, creating oob proof"); - const { proofRecord, message } = - await this.askar.agent.proofs.createRequest({ - protocolVersion: "v2", - proofFormats: { - anoncreds: { - name: "proof-request", - version: "1.0", - requested_attributes: requestedAttributes, - }, - }, - }); - - proofRecord.setTag("xRole", "requester"); - await this.askar.agent.proofs.update(proofRecord); - - const outOfBandRecord = await this.askar.agent.oob.createInvitation({ - messages: [message], - handshake: false, - }); - - const proofUrl = outOfBandRecord.outOfBandInvitation.toUrl({ - domain: this.askar.agentConfig.agentPeerAddress, - }); - const shortProofUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBandRecord.outOfBandInvitation.id}`; - - const dto = new ProofRecordDto(); - dto.id = proofRecord.id; - dto.connectionId = proofRecord.connectionId; - dto.state = proofRecord.state; - dto.updatedAt = proofRecord.updatedAt; - dto.createdAt = proofRecord.createdAt; - dto.tags = proofRecord.getTags(); - - return { - proofUrl: proofUrl, - shortProofUrl: shortProofUrl, - proofRecord: dto, - }; - } - - this.logger.log(`${requestProofDto.connectionId} detected, issuing proof`); - - const exchangeRecord = await this.askar.agent.proofs.requestProof({ - protocolVersion: "v2", - connectionId: requestProofDto.connectionId, - proofFormats: { - anoncreds: { - name: "proof-request", - version: "1.0", - requested_attributes: requestedAttributes, - }, - }, - }); - - exchangeRecord.setTag("xRole", "requester"); - await this.askar.agent.proofs.update(exchangeRecord); - - const response = new ProofRecordDto(); - response.id = exchangeRecord.id; - response.connectionId = exchangeRecord.connectionId; - response.state = exchangeRecord.state; - response.updatedAt = exchangeRecord.updatedAt; - response.createdAt = exchangeRecord.createdAt; - response.tags = exchangeRecord.getTags(); - - return { - proofUrl: null, - shortProofUrl: null, - proofRecord: response, - }; - }; - - deleteCredentialById = async (id: string): Promise<void> => { - await this.askar.agent.credentials.deleteById(id); - }; - - fetchProofs = async (filter: ProofFilterDto): Promise<ProofRecordDto[]> => { - const query: Query<ProofExchangeRecord>[] = []; - - if (filter.states) { - const stateQuery: Query<ProofExchangeRecord> = { - $or: filter.states.map((state) => ({ state })), - }; - query.push(stateQuery); - } - - if (filter.connectionId) { - const connectionQuery: Query<ProofExchangeRecord> = { - connectionId: filter.connectionId, - }; - query.push(connectionQuery); - } - - let proofs = await this.askar.agent.proofs.findAllByQuery({ - $and: query, - }); - proofs = proofs.sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ); - - const response: ProofRecordDto[] = []; - for (const proof of proofs) { - const t = new ProofRecordDto(); - t.id = proof.id; - t.connectionId = proof.connectionId; - t.state = proof.state; - t.updatedAt = proof.updatedAt; - t.createdAt = proof.createdAt; - t.tags = proof.getTags(); - - response.push(t); - } - - return response; - }; - - getProofById = async (proofRecordId: string): Promise<ProofRecordDto> => { - const proofRecord = await this.askar.agent.proofs.findById(proofRecordId); - - if (!proofRecord) { - throw new EntityNotFoundError(); - } - - const proofResponse = new ProofRecordDto(); - - proofResponse.id = proofRecord.id; - proofResponse.connectionId = proofRecord.connectionId; - proofResponse.state = proofRecord.state; - proofResponse.updatedAt = proofRecord.updatedAt; - proofResponse.createdAt = proofRecord.createdAt; - proofResponse.tags = proofRecord.getTags(); - - return proofResponse; - }; - - getProofFormatDataById = async ( - proofRecordId: string, - ): Promise<ProofFormatDataDto> => { - const formatData = await this.askar.agent.proofs.getFormatData( - proofRecordId, - ); - - if (!formatData) { - throw new EntityNotFoundError(); - } - - const dto = new ProofFormatDataDto(); - dto.anoncredsProposal = formatData.proposal?.anoncreds; - dto.anoncredsRequest = formatData.request?.anoncreds; - dto.anoncredsPresentation = formatData.presentation?.anoncreds; - return dto; - }; - - proofAcceptanceWait = async ( - proofRecordId: string, - ): Promise<ProofFormatDataDto> => { - const proofRecord = await this.askar.agent.proofs.findById(proofRecordId); - - if (!proofRecord) { - throw new EntityNotFoundError(); - } - - if (proofRecord.state === ProofState.Done) { - return this.getProofFormatDataById(proofRecordId); - } - - await waitForProofExchangeRecordSubject(this.askar.agentB, { - proofRecordId, - state: ProofState.Done, - timeoutMs: 3 * 60 * 1000, // 3 minutes - }); - - return this.getProofFormatDataById(proofRecordId); - }; - - acceptProof = async ( - acceptProofDto: AcceptProofDto, - ): Promise<ProofRecordDto> => { - if (acceptProofDto.proofUrl) { - return this.acceptOobProof(acceptProofDto.proofUrl); - } - return this.acceptConnectionProof(acceptProofDto.proofId); - }; - - acceptOobProof = async (url: string): Promise<ProofRecordDto> => { - // omit await in order to catch received record in the next line - setTimeout(() => { - this.askar.agent.oob.receiveInvitationFromUrl(url, { - autoAcceptConnection: false, - autoAcceptInvitation: true, - // reuseConnection: true, - }); - }, 20); - - const record = await waitForProofExchangeRecordSubject(this.askar.agentB, { - state: ProofState.RequestReceived, - }); - - const requestedCredentials = - await this.askar.agent.proofs.selectCredentialsForRequest({ - proofRecordId: record.id, - }); - - const acceptedRecord = await this.askar.agent.proofs.acceptRequest({ - proofRecordId: record.id, - proofFormats: requestedCredentials.proofFormats, - }); - - const response = new ProofRecordDto(); - - response.id = acceptedRecord.id; - response.connectionId = acceptedRecord.connectionId; - response.state = acceptedRecord.state; - response.updatedAt = acceptedRecord.updatedAt; - response.createdAt = acceptedRecord.createdAt; - response.tags = acceptedRecord.getTags(); - - return response; - }; - - acceptConnectionProof = async ( - proofRecordId: string, - ): Promise<ProofRecordDto> => { - this.logger.log(`accepting proof request for ${proofRecordId}`); - const requestedCredentials = - await this.askar.agent.proofs.selectCredentialsForRequest({ - proofRecordId, - }); - - this.logger.log(JSON.stringify(requestedCredentials, null, 2)); - - const proof = await this.askar.agent.proofs.acceptRequest({ - proofRecordId, - proofFormats: requestedCredentials.proofFormats, - }); - - this.logger.log(JSON.stringify(proof, null, 2)); - - const response = new ProofRecordDto(); - response.id = proof.id; - response.connectionId = proof.connectionId; - response.state = proof.state; - response.updatedAt = proof.updatedAt; - response.createdAt = proof.createdAt; - response.tags = proof.getTags(); - - return response; - }; - - declineProofRequest = async ( - proofRecordId: string, - ): Promise<ProofRecordDto> => { - const resultFromDecline = await this.askar.agent.proofs.declineRequest({ - proofRecordId, - sendProblemReport: true, - }); - - const declineResponse = new ProofRecordDto(); - declineResponse.id = resultFromDecline.id; - declineResponse.connectionId = resultFromDecline.connectionId; - declineResponse.state = resultFromDecline.state; - declineResponse.updatedAt = resultFromDecline.updatedAt; - declineResponse.createdAt = resultFromDecline.createdAt; - declineResponse.tags = resultFromDecline.getTags(); - - return declineResponse; - }; - - deleteProofById = async (id: string): Promise<void> => { - await this.askar.agent.proofs.deleteById(id); - }; - - resolve = async (did: string) => { - return this.askar.agent.dids.resolve(did); - }; - - fetchBasicMessages = async ( - filter: MessageFilterDto, - ): Promise<MessageRecordDto[]> => { - const query: Query<BasicMessageRecord>[] = []; - - if (filter.role) { - const roleQuery: Query<BasicMessageRecord> = { - role: filter.role, - }; - query.push(roleQuery); - } - - if (filter.connectionId) { - const connectionQuery: Query<BasicMessageRecord> = { - connectionId: filter.connectionId, - }; - query.push(connectionQuery); - } - - let messages = await this.askar.agent.basicMessages.findAllByQuery({ - $and: query, - }); - messages = messages.sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ); - - const connectionIds = messages.map((message) => message.connectionId); - - const connections = await this.askar.agent.connections.findAllByQuery({ - $or: connectionIds.map((p) => ({ id: p })), - }); - const grouppedConnections = connections.reduce( - (acc: { [connId: string]: ConnectionRecord }, conn) => { - acc[conn.id] = conn; - return acc; - }, - {}, - ); - - const response: MessageRecordDto[] = []; - for (const message of messages) { - const connection = grouppedConnections[message.connectionId]; - const label = connection?.theirLabel || ""; - - const t = new MessageRecordDto(); - t.id = message.id; - t.createdAt = message.createdAt; - t.updatedAt = message.updatedAt; - t.connectionId = message.connectionId; - t.role = message.role; - t.content = message.content; - t.sentTime = message.sentTime; - t.from = message.role === BasicMessageRole.Receiver ? label : ""; - t.to = message.role === BasicMessageRole.Sender ? label : ""; - - response.push(t); - } - - return response; - }; - - sendMessage = async ( - dto: MakeBasicMessageRequestDto, - ): Promise<MessageRecordDto> => { - const messageRecord = await this.askar.agent.basicMessages.sendMessage( - dto.connectionId, - dto.message, - ); - - const connRecord = await this.askar.agent.connections.findById( - dto.connectionId, - ); - - const response = new MessageRecordDto(); - response.id = messageRecord.id; - response.createdAt = messageRecord.createdAt; - response.updatedAt = messageRecord.updatedAt; - response.connectionId = messageRecord.connectionId; - response.role = messageRecord.role; - response.content = messageRecord.content; - response.sentTime = messageRecord.sentTime; - response.from = ""; - response.to = connRecord?.theirLabel || ""; - - return response; - }; - - deleteMessageById = async (id: string): Promise<void> => { - await this.askar.agent.basicMessages.deleteById(id); - }; - - getCreatedDids = async (): Promise<DidRecordDto[]> => { - const didRecords = await this.askar.agent.dids.getCreatedDids(); - return didRecords.map((p) => { - const dto = new DidRecordDto(); - const tags = p.getTags(); - - dto.did = p.did; - dto.role = p.role; - dto.method = tags.method; - dto.tags = tags; - - return dto; - }); - }; - - trustPingToConnection = async (connectionId: string) => { - const msg = await this.askar.agent.connections.sendPing(connectionId, { - responseRequested: true, - withReturnRouting: false, - }); - - const response = new BaseRecordDto(); - response.id = msg.toJSON()["@id"]; - - return response; - }; - - private getFirstDidWebRecord = async (): Promise<DidRecord> => { - const didWebs = await this.askar.agent.dids.getCreatedDids({ - method: "web", - }); - if (!didWebs.length) { - throw new EntityNotFoundError("Agent does not have did:web"); - } - return didWebs[0]; - }; -} diff --git a/libs/askar/src/askar/askar.module.ts b/libs/askar/src/askar/askar.module.ts index c2f542cef457dd735b3ff5514299703b737bf903..44dc10a3af3f5c9e330c39637fa28e7f4c5a2b9d 100644 --- a/libs/askar/src/askar/askar.module.ts +++ b/libs/askar/src/askar/askar.module.ts @@ -1,20 +1,44 @@ import { Module, Global } from "@nestjs/common"; -import { AskarService } from "./askar.service"; -import { AgentService } from "./agent.service"; +import { AskarService } from "./services/askar.service"; +import { AgentAnoncredsService } from "./services/agent.anoncreds.service"; +import { AgentBasicMessagesService } from "./services/agent.basicMessages.service"; +import { AgentConnectionsService } from "./services/agent.connections.service"; +import { AgentCredentialsService } from "./services/agent.credentials.service"; +import { AgentDidsService } from "./services/agent.dids.service"; +import { AgentJsonldService } from "./services/agent.jsonld.service"; +import { AgentOobService } from "./services/agent.oob.service"; +import { AgentProofsService } from "./services/agent.proofs.service"; import { ConfigModule } from "@nestjs/config"; import { LedgersModule } from "@ocm-engine/ledgers"; -import { AgentEventListenerService } from "./agent-event-listener.service"; +import { AgentEventListenerService } from "./services/agent-event-listener.service"; import { GatewayClient } from "@ocm-engine/clients"; @Global() @Module({ imports: [ConfigModule, LedgersModule], providers: [ - AgentService, + AgentAnoncredsService, + AgentBasicMessagesService, + AgentConnectionsService, + AgentCredentialsService, + AgentDidsService, + AgentJsonldService, + AgentOobService, + AgentProofsService, AskarService, AgentEventListenerService, GatewayClient, ], - exports: [AgentService, AskarService], + exports: [ + AgentAnoncredsService, + AgentBasicMessagesService, + AgentConnectionsService, + AgentCredentialsService, + AgentDidsService, + AgentJsonldService, + AgentOobService, + AgentProofsService, + AskarService, + ], }) export class AskarModule {} diff --git a/libs/askar/src/askar/agent-event-listener.service.ts b/libs/askar/src/askar/services/agent-event-listener.service.ts similarity index 99% rename from libs/askar/src/askar/agent-event-listener.service.ts rename to libs/askar/src/askar/services/agent-event-listener.service.ts index 64977822ee80e6ab0382ca46ef06a845db5e72de..d1dde4d69b17da2853996b292f759a7bee8bd43d 100644 --- a/libs/askar/src/askar/agent-event-listener.service.ts +++ b/libs/askar/src/askar/services/agent-event-listener.service.ts @@ -19,7 +19,7 @@ import { svdxConnectionStateChangeHandler, svdxProofStateChangeHandler, webHookHandler, -} from "../agent.utils"; +} from "../../agent.utils"; @Injectable() export class AgentEventListenerService implements OnModuleInit { diff --git a/libs/askar/src/askar/services/agent.anoncreds.service.ts b/libs/askar/src/askar/services/agent.anoncreds.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..34a454dcfe8c1221cb3f427b377c43c178068de3 --- /dev/null +++ b/libs/askar/src/askar/services/agent.anoncreds.service.ts @@ -0,0 +1,173 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { AskarService } from "./askar.service"; +import { + CreateCredentialDefinitionRequestDto, + CreddefRecordDto, + CreateSchemaRequestDto, + SchemaRecordDto, + CredentialNotCreatedError, + SchemaNotCreatedError, + EntityNotFoundError, +} from "@ocm-engine/dtos"; + +@Injectable() +export class AgentAnoncredsService { + private readonly logger = new Logger(AgentAnoncredsService.name); + constructor(private readonly askar: AskarService) {} + + fetchSchemas = async (): Promise<SchemaRecordDto[]> => { + let schemaRecords = + await this.askar.agent.modules.anoncreds.getCreatedSchemas({}); + schemaRecords = schemaRecords.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + + const schemaResponses = schemaRecords.map((singleSchemaRes) => { + const schemaResponse = new SchemaRecordDto(); + schemaResponse.id = singleSchemaRes.schemaId; + schemaResponse.createdAt = singleSchemaRes.createdAt; + schemaResponse.updatedAt = singleSchemaRes.updatedAt; + schemaResponse.name = singleSchemaRes.schema.name; + schemaResponse.attributes = singleSchemaRes.schema.attrNames; + schemaResponse.version = singleSchemaRes.schema.version; + schemaResponse.issuerId = singleSchemaRes.schema.issuerId; + schemaResponse.methodName = singleSchemaRes.methodName; + + return schemaResponse; + }); + + return schemaResponses; + }; + + getSchemaById = async (schemaId: string): Promise<SchemaRecordDto> => { + const agentResponse = await this.askar.agent.modules.anoncreds.getSchema( + schemaId, + ); + + if (!agentResponse || !agentResponse.schema) { + throw new EntityNotFoundError(); + } + + const schemaResponse = new SchemaRecordDto(); + schemaResponse.id = agentResponse.schemaId; + schemaResponse.name = agentResponse.schema.name; + schemaResponse.attributes = agentResponse.schema.attrNames; + schemaResponse.version = agentResponse.schema.version; + schemaResponse.issuerId = agentResponse.schema.issuerId; + + return schemaResponse; + }; + + createSchema = async ( + schema: CreateSchemaRequestDto, + ): Promise<SchemaRecordDto> => { + const dids = await this.askar.agent.dids.getCreatedDids({ method: "indy" }); + + const schemaResult = + await this.askar.agent.modules.anoncreds.registerSchema({ + schema: { + name: schema.name, + issuerId: dids[0].did, + attrNames: schema.attributes, + version: schema.version, + }, + options: {}, + }); + + if (schemaResult.schemaState.state !== "finished") { + throw new SchemaNotCreatedError(); + } + + const response = new SchemaRecordDto(); + + response.name = schemaResult.schemaState.schema.name; + response.id = schemaResult.schemaState.schemaId; + response.issuerId = schemaResult.schemaState.schema.issuerId; + response.version = schemaResult.schemaState.schema.version; + response.attributes = schemaResult.schemaState.schema.attrNames; + + return response; + }; + + fetchCredentialDefinitions = async (): Promise<CreddefRecordDto[]> => { + let credentialDefinitions = + await this.askar.agent.modules.anoncreds.getCreatedCredentialDefinitions( + {}, + ); + credentialDefinitions = credentialDefinitions.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + + const response: Array<CreddefRecordDto> = []; + for (const credDef of credentialDefinitions) { + const cd = new CreddefRecordDto(); + cd.id = credDef.credentialDefinitionId; + cd.createdAt = credDef.createdAt; + cd.updatedAt = credDef.updatedAt; + cd.schemaId = credDef.credentialDefinition.schemaId; + cd.issuerId = credDef.credentialDefinition.issuerId; + cd.tag = credDef.credentialDefinition.tag; + response.push(cd); + } + + return response; + }; + + getCredentialDefinitionById = async ( + credentialDefinitionId: string, + ): Promise<CreddefRecordDto> => { + const credDefs = + await this.askar.agent.modules.anoncreds.getCreatedCredentialDefinitions({ + credentialDefinitionId, + }); + + const credDef = credDefs[0] || null; + if (!credDef) { + throw new EntityNotFoundError(); + } + + const cd = new CreddefRecordDto(); + cd.id = credDef.credentialDefinitionId; + cd.createdAt = credDef.createdAt; + cd.updatedAt = credDef.updatedAt; + cd.schemaId = credDef.credentialDefinition.schemaId; + cd.issuerId = credDef.credentialDefinition.issuerId; + cd.tag = credDef.credentialDefinition.tag; + + return cd; + }; + + createCredentialDefinition = async ( + credentialDefinitionDto: CreateCredentialDefinitionRequestDto, + ): Promise<CreddefRecordDto> => { + const dids = await this.askar.agent.dids.getCreatedDids({ method: "indy" }); + + const credDef = + await this.askar.agent.modules.anoncreds.registerCredentialDefinition({ + credentialDefinition: { + tag: credentialDefinitionDto.tag, + issuerId: dids[0].did, + schemaId: credentialDefinitionDto.schemaId, + }, + options: { + supportRevocation: credentialDefinitionDto.supportRevocation ?? false, + }, + }); + + if (credDef.credentialDefinitionState.state !== "finished") { + throw new CredentialNotCreatedError(); + } + + const response = new CreddefRecordDto(); + response.id = credDef.credentialDefinitionState.credentialDefinitionId; + response.schemaId = + credDef.credentialDefinitionState.credentialDefinition.schemaId; + response.issuerId = + credDef.credentialDefinitionState.credentialDefinition.issuerId; + response.tag = credDef.credentialDefinitionState.credentialDefinition.tag; + + return response; + }; +} diff --git a/libs/askar/src/askar/services/agent.basicMessages.service.ts b/libs/askar/src/askar/services/agent.basicMessages.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..5f9454ea8a107799322aa48f00b1e08333d10740 --- /dev/null +++ b/libs/askar/src/askar/services/agent.basicMessages.service.ts @@ -0,0 +1,111 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { AskarService } from "./askar.service"; +import { + MakeBasicMessageRequestDto, + MessageRecordDto, + MessageFilterDto, +} from "@ocm-engine/dtos"; +import { + BasicMessageRecord, + BasicMessageRole, + ConnectionRecord, + Query, +} from "@credo-ts/core"; + +@Injectable() +export class AgentBasicMessagesService { + private readonly logger = new Logger(AgentBasicMessagesService.name); + constructor(private readonly askar: AskarService) {} + + fetchBasicMessages = async ( + filter: MessageFilterDto, + ): Promise<MessageRecordDto[]> => { + const query: Query<BasicMessageRecord>[] = []; + + if (filter.role) { + const roleQuery: Query<BasicMessageRecord> = { + role: filter.role, + }; + query.push(roleQuery); + } + + if (filter.connectionId) { + const connectionQuery: Query<BasicMessageRecord> = { + connectionId: filter.connectionId, + }; + query.push(connectionQuery); + } + + let messages = await this.askar.agent.basicMessages.findAllByQuery({ + $and: query, + }); + messages = messages.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + + const connectionIds = messages.map((message) => message.connectionId); + + const connections = await this.askar.agent.connections.findAllByQuery({ + $or: connectionIds.map((p) => ({ id: p })), + }); + const grouppedConnections = connections.reduce( + (acc: { [connId: string]: ConnectionRecord }, conn) => { + acc[conn.id] = conn; + return acc; + }, + {}, + ); + + const response: MessageRecordDto[] = []; + for (const message of messages) { + const connection = grouppedConnections[message.connectionId]; + const label = connection?.theirLabel || ""; + + const t = new MessageRecordDto(); + t.id = message.id; + t.createdAt = message.createdAt; + t.updatedAt = message.updatedAt; + t.connectionId = message.connectionId; + t.role = message.role; + t.content = message.content; + t.sentTime = message.sentTime; + t.from = message.role === BasicMessageRole.Receiver ? label : ""; + t.to = message.role === BasicMessageRole.Sender ? label : ""; + + response.push(t); + } + + return response; + }; + + sendMessage = async ( + dto: MakeBasicMessageRequestDto, + ): Promise<MessageRecordDto> => { + const messageRecord = await this.askar.agent.basicMessages.sendMessage( + dto.connectionId, + dto.message, + ); + + const connRecord = await this.askar.agent.connections.findById( + dto.connectionId, + ); + + const response = new MessageRecordDto(); + response.id = messageRecord.id; + response.createdAt = messageRecord.createdAt; + response.updatedAt = messageRecord.updatedAt; + response.connectionId = messageRecord.connectionId; + response.role = messageRecord.role; + response.content = messageRecord.content; + response.sentTime = messageRecord.sentTime; + response.from = ""; + response.to = connRecord?.theirLabel || ""; + + return response; + }; + + deleteMessageById = async (id: string): Promise<void> => { + await this.askar.agent.basicMessages.deleteById(id); + }; +} diff --git a/libs/askar/src/askar/services/agent.connections.service.ts b/libs/askar/src/askar/services/agent.connections.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e389e872edb836852cc7458e41baa4831aec23c --- /dev/null +++ b/libs/askar/src/askar/services/agent.connections.service.ts @@ -0,0 +1,106 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { AskarService } from "./askar.service"; +import { + ConnectionRecordDto, + EntityNotFoundError, + BaseRecordDto, +} from "@ocm-engine/dtos"; + +@Injectable() +export class AgentConnectionsService { + private readonly logger = new Logger(AgentConnectionsService.name); + constructor(private readonly askar: AskarService) {} + + async fetchConnections(): Promise<ConnectionRecordDto[]> { + //TODO: no ordering in findAllByQuery + const agentResponse = (await this.askar.agent.connections.getAll()).sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + + const connectionArray = agentResponse.map((singleConnectionRes) => { + const connectionResponse = new ConnectionRecordDto(); + connectionResponse.id = singleConnectionRes.id; + connectionResponse.state = singleConnectionRes.state; + connectionResponse.connectionName = singleConnectionRes.theirLabel; + connectionResponse.alias = singleConnectionRes.alias; + connectionResponse.did = singleConnectionRes.did; + connectionResponse.theirDid = singleConnectionRes.theirDid; + connectionResponse.invitationDid = singleConnectionRes.invitationDid; + connectionResponse.outOfBandId = singleConnectionRes.outOfBandId; + connectionResponse.createdAt = singleConnectionRes.createdAt; + connectionResponse.updatedAt = singleConnectionRes.updatedAt; + connectionResponse.imageUrl = singleConnectionRes.imageUrl; + + return connectionResponse; + }); + + return connectionArray; + } + + getConnectionByOobId = async (oobId: string) => { + const connectionRecords = + await this.askar.agent.connections.findAllByOutOfBandId(oobId); + + const connectionArray = connectionRecords.map((singleConnectionRes) => { + const connectionResponse = new ConnectionRecordDto(); + connectionResponse.id = singleConnectionRes.id; + connectionResponse.state = singleConnectionRes.state; + connectionResponse.connectionName = singleConnectionRes.theirLabel; + connectionResponse.alias = singleConnectionRes.alias; + connectionResponse.did = singleConnectionRes.did; + connectionResponse.theirDid = singleConnectionRes.theirDid; + connectionResponse.invitationDid = singleConnectionRes.invitationDid; + connectionResponse.outOfBandId = singleConnectionRes.outOfBandId; + connectionResponse.createdAt = singleConnectionRes.createdAt; + connectionResponse.updatedAt = singleConnectionRes.updatedAt; + connectionResponse.imageUrl = singleConnectionRes.imageUrl; + + return connectionResponse; + }); + + return connectionArray; + }; + + getConnectionById = async (id: string): Promise<ConnectionRecordDto> => { + const agentResponse = await this.askar.agent.connections.findById(id); + + if (!agentResponse) { + throw new EntityNotFoundError(); + } + + const connectionResponse = new ConnectionRecordDto(); + connectionResponse.id = agentResponse.id; + connectionResponse.state = agentResponse.state; + connectionResponse.connectionName = agentResponse.theirLabel; + connectionResponse.alias = agentResponse.alias; + connectionResponse.did = agentResponse.did; + connectionResponse.theirDid = agentResponse.theirDid; + connectionResponse.invitationDid = agentResponse.invitationDid; + connectionResponse.outOfBandId = agentResponse.outOfBandId; + connectionResponse.createdAt = agentResponse.createdAt; + connectionResponse.updatedAt = agentResponse.updatedAt; + connectionResponse.imageUrl = agentResponse.imageUrl; + + return connectionResponse; + }; + + deleteConnectionById = async (id: string): Promise<void> => { + await this.askar.agent.connections.hangup({ + connectionId: id, + deleteAfterHangup: true, + }); + }; + + trustPingToConnection = async (connectionId: string) => { + const msg = await this.askar.agent.connections.sendPing(connectionId, { + responseRequested: true, + withReturnRouting: false, + }); + + const response = new BaseRecordDto(); + response.id = msg.toJSON()["@id"]; + + return response; + }; +} diff --git a/libs/askar/src/askar/services/agent.credentials.service.ts b/libs/askar/src/askar/services/agent.credentials.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..8cfbbbadbea8f75e120584a3309d0ef0417a52d5 --- /dev/null +++ b/libs/askar/src/askar/services/agent.credentials.service.ts @@ -0,0 +1,278 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { AskarService } from "./askar.service"; +import { + OfferCredentialRequestDto, + CredentialRecordDto, + CredentialFilterDto, + CredentialOfferResponseDto, + EntityNotFoundError, + AcceptCredentialDto, + CredentialFormatDataDto, +} from "@ocm-engine/dtos"; +import { + AutoAcceptCredential, + CredentialExchangeRecord, + CredentialState, + Query, +} from "@credo-ts/core"; +import { waitForCredentialExchangeRecordSubject } from "../../agent.utils"; + +@Injectable() +export class AgentCredentialsService { + private readonly logger = new Logger(AgentCredentialsService.name); + constructor(private readonly askar: AskarService) {} + + offerCredential = async ( + offerCredentialDto: OfferCredentialRequestDto, + ): Promise<CredentialOfferResponseDto> => { + this.logger.log( + "Incoming request", + JSON.stringify(offerCredentialDto, null, 2), + ); + + if (!offerCredentialDto.connectionId) { + const { credentialRecord, message } = + await this.askar.agent.credentials.createOffer({ + protocolVersion: "v2", + credentialFormats: { + anoncreds: { + credentialDefinitionId: offerCredentialDto.credentialDefinitionId, + attributes: offerCredentialDto.attributes, + }, + }, + autoAcceptCredential: AutoAcceptCredential.ContentApproved, + }); + + credentialRecord.setTag("xRole", "issuer"); + await this.askar.agent.credentials.update(credentialRecord); + + const outOfBandRecord = await this.askar.agent.oob.createInvitation({ + messages: [message], + handshake: false, + }); + + const credentialUrl = outOfBandRecord.outOfBandInvitation.toUrl({ + domain: this.askar.agentConfig.agentPeerAddress, + }); + + const shortCredentialUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBandRecord.outOfBandInvitation.id}`; + + const dto = new CredentialRecordDto(); + dto.id = credentialRecord.id; + dto.state = credentialRecord.state; + dto.connectionId = credentialRecord.connectionId; + dto.attributes = credentialRecord.credentialAttributes; + dto.createdAt = credentialRecord.createdAt; + dto.tags = credentialRecord.getTags(); + + return { + credentialUrl: credentialUrl, + shortCredentialUrl: shortCredentialUrl, + credentialRecord: dto, + }; + } + const credentialExchangeRecord = + await this.askar.agent.credentials.offerCredential({ + protocolVersion: "v2", + connectionId: offerCredentialDto.connectionId, + credentialFormats: { + anoncreds: { + credentialDefinitionId: offerCredentialDto.credentialDefinitionId, + attributes: offerCredentialDto.attributes, + }, + }, + }); + + credentialExchangeRecord.setTag("xRole", "issuer"); + await this.askar.agent.credentials.update(credentialExchangeRecord); + + const dto = new CredentialRecordDto(); + dto.id = credentialExchangeRecord.id; + dto.state = credentialExchangeRecord.state; + dto.connectionId = credentialExchangeRecord.connectionId; + dto.attributes = credentialExchangeRecord.credentialAttributes; + dto.createdAt = credentialExchangeRecord.createdAt; + dto.tags = credentialExchangeRecord.getTags(); + + return { + credentialUrl: null, + shortCredentialUrl: null, + credentialRecord: dto, + }; + }; + + acceptCredential = async ( + acceptCredentialDto: AcceptCredentialDto, + ): Promise<CredentialRecordDto> => { + if (acceptCredentialDto.credentialUrl) { + return this.acceptOobCredentials(acceptCredentialDto.credentialUrl); + } + return this.acceptConnectionCredential(acceptCredentialDto.credentialId); + }; + + acceptOobCredentials = async (url: string): Promise<CredentialRecordDto> => { + // omit await in order to catch received record in the next line + setTimeout(() => { + this.askar.agent.oob.receiveInvitationFromUrl(url, { + autoAcceptConnection: false, + autoAcceptInvitation: true, + // reuseConnection: true, + }); + }, 20); + + const record = await waitForCredentialExchangeRecordSubject( + this.askar.agentB, + { + state: CredentialState.OfferReceived, + }, + ); + + const acceptedRecord = await this.askar.agent.credentials.acceptOffer({ + credentialRecordId: record.id, + }); + + const response = new CredentialRecordDto(); + response.id = acceptedRecord.id; + response.state = acceptedRecord.state; + response.connectionId = acceptedRecord.connectionId; + response.attributes = acceptedRecord.credentialAttributes; + response.createdAt = acceptedRecord.createdAt; + response.tags = acceptedRecord.getTags(); + + return response; + }; + + acceptConnectionCredential = async ( + credentialRecordId: string, + ): Promise<CredentialRecordDto> => { + const credentialExchangeRecord = + await this.askar.agent.credentials.acceptOffer({ + credentialRecordId, + }); + + const response = new CredentialRecordDto(); + response.id = credentialExchangeRecord.id; + response.state = credentialExchangeRecord.state; + response.connectionId = credentialExchangeRecord.connectionId; + response.attributes = credentialExchangeRecord.credentialAttributes; + response.createdAt = credentialExchangeRecord.createdAt; + response.tags = credentialExchangeRecord.getTags(); + + return response; + }; + + declineCredential = async ( + credentialRecordId: string, + ): Promise<CredentialRecordDto> => { + const credentialExchangeRecord = + await this.askar.agent.credentials.declineOffer(credentialRecordId); + + // send request to the issuer that the request is declined, to mark it as Abondoned + await this.askar.agent.credentials.sendProblemReport({ + credentialRecordId: credentialRecordId, + description: "Decline offer", + }); + + const response = new CredentialRecordDto(); + response.id = credentialExchangeRecord.id; + response.state = credentialExchangeRecord.state; + response.connectionId = credentialExchangeRecord.connectionId; + response.attributes = credentialExchangeRecord.credentialAttributes; + response.createdAt = credentialExchangeRecord.createdAt; + response.tags = credentialExchangeRecord.getTags(); + + return response; + }; + + fetchCredentials = async ( + filter: CredentialFilterDto, + ): Promise<CredentialRecordDto[]> => { + const query: Query<CredentialExchangeRecord>[] = []; + + if (filter.states) { + const stateQuery: Query<CredentialExchangeRecord> = { + $or: filter.states.map((state) => ({ state })), + }; + query.push(stateQuery); + } + + if (filter.connectionId) { + const connectionQuery: Query<CredentialExchangeRecord> = { + connectionId: filter.connectionId, + }; + query.push(connectionQuery); + } + + let credentials = await this.askar.agent.credentials.findAllByQuery({ + $and: query, + }); + credentials = credentials.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + + const response: CredentialRecordDto[] = []; + for (const offer of credentials) { + const t = new CredentialRecordDto(); + t.id = offer.id; + t.state = offer.state; + t.connectionId = offer.connectionId; + t.createdAt = offer.createdAt; + t.attributes = offer.credentialAttributes; + t.tags = offer.getTags(); + response.push(t); + } + + return response; + }; + + getCredentialById = async ( + credentialId: string, + ): Promise<CredentialRecordDto> => { + const credentialRecord = await this.askar.agent.credentials.findById( + credentialId, + ); + + if (!credentialRecord) { + throw new EntityNotFoundError(); + } + + const credential = new CredentialRecordDto(); + credential.id = credentialRecord.id; + credential.state = credentialRecord.state; + credential.connectionId = credentialRecord.connectionId; + credential.createdAt = credentialRecord.createdAt; + credential.attributes = credentialRecord.credentialAttributes; + credential.tags = credentialRecord.getTags(); + + return credential; + }; + + getCredentialFormatDataById = async ( + credentialId: string, + ): Promise<CredentialFormatDataDto> => { + const formatData = await this.askar.agent.credentials.getFormatData( + credentialId, + ); + + if (!formatData) { + throw new EntityNotFoundError(); + } + + const dto = new CredentialFormatDataDto(); + dto.proposalAttributes = formatData.proposalAttributes; + dto.offerAttributes = formatData.offerAttributes; + dto.anoncredsProposal = formatData.proposal?.anoncreds; + dto.anoncredsOffer = formatData.offer?.anoncreds; + dto.anoncredsRequest = formatData.request?.anoncreds; + dto.anoncredsCredential = formatData.credential?.anoncreds; + + dto.all = formatData; + + return dto; + }; + + deleteCredentialById = async (id: string): Promise<void> => { + await this.askar.agent.credentials.deleteById(id); + }; +} diff --git a/libs/askar/src/askar/services/agent.dids.service.ts b/libs/askar/src/askar/services/agent.dids.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..7cb1cf0bef380edf6f33d0fe90dfd8ab045b81f5 --- /dev/null +++ b/libs/askar/src/askar/services/agent.dids.service.ts @@ -0,0 +1,28 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { AskarService } from "./askar.service"; +import { DidRecordDto } from "@ocm-engine/dtos"; + +@Injectable() +export class AgentDidsService { + private readonly logger = new Logger(AgentDidsService.name); + constructor(private readonly askar: AskarService) {} + + resolve = async (did: string) => { + return this.askar.agent.dids.resolve(did); + }; + + getCreatedDids = async (): Promise<DidRecordDto[]> => { + const didRecords = await this.askar.agent.dids.getCreatedDids(); + return didRecords.map((p) => { + const dto = new DidRecordDto(); + const tags = p.getTags(); + + dto.did = p.did; + dto.role = p.role; + dto.method = tags.method; + dto.tags = tags; + + return dto; + }); + }; +} diff --git a/libs/askar/src/askar/services/agent.jsonld.service.ts b/libs/askar/src/askar/services/agent.jsonld.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0f8029e9f4a5e8d87dcdd3a0e1370e48b20a80a --- /dev/null +++ b/libs/askar/src/askar/services/agent.jsonld.service.ts @@ -0,0 +1,260 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { AskarService } from "./askar.service"; +import { + CredentialRecordDto, + CredentialOfferResponseDto, + EntityNotFoundError, + OcmError, + W3cCredentialDto, + W3cJsonLdVerifiableCredentialDto, + W3cJsonLdVerifiablePresentationDto, +} from "@ocm-engine/dtos"; +import { + AutoAcceptCredential, + ClaimFormat, + JsonTransformer, + W3cCredential, + W3cCredentialService, + JsonCredential, + W3cJsonLdVerifiableCredential, +} from "@credo-ts/core"; +import { uuid } from "@credo-ts/core/build/utils/uuid"; +import { getFirstDidWebRecord } from "../../agent.utils"; + +@Injectable() +export class AgentJsonldService { + private readonly logger = new Logger(AgentJsonldService.name); + constructor(private readonly askar: AskarService) {} + + signJsonLdCredential = async ( + credToSign: W3cCredentialDto, + ): Promise<W3cJsonLdVerifiableCredentialDto> => { + this.logger.log("Sign json ld credentials"); + + const didRecord = await getFirstDidWebRecord(this.askar.agent); + const verificationMethodList = + didRecord.didDocument?.verificationMethod || []; + if (!verificationMethodList.length) { + throw new EntityNotFoundError( + "DidDocument does not exists or contains no verification methods", + ); + } + + const verificationMethod = verificationMethodList[0]; + + const w3cServ = + this.askar.agent.context.dependencyManager.resolve(W3cCredentialService); + + credToSign.id = didRecord.did + "?uuid=" + uuid(); + if (credToSign.credentialSubject) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + credToSign.credentialSubject.id = credToSign.id; + } + credToSign.issuer = didRecord.did; + credToSign.issuanceDate = new Date().toISOString(); + let credential: W3cCredential; + try { + credential = JsonTransformer.fromJSON(credToSign, W3cCredential); + } catch (e) { + this.logger.log("Incorrect request parameter", e); + throw new OcmError( + "Invalid JSON-LD data format. Please ensure that your JSON-LD contains the following properties: @context, id, type, issuer, issuanceDate, expirationDate, and credentialSubject.", + ); + } + + const vc = await w3cServ.signCredential(this.askar.agent.context, { + format: ClaimFormat.LdpVc, + credential, + proofType: "Ed25519Signature2018", + verificationMethod: verificationMethod.id, + }); + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const jsonVC = vc.toJson() as W3cJsonLdVerifiableCredentialDto; + this.logger.debug(JSON.stringify(jsonVC, null, 2)); + + return jsonVC; + }; + + prepareVerifiablePresentationByJsonLdCredId = async ( + credentialRecordId: string, + ): Promise<W3cJsonLdVerifiablePresentationDto> => { + const didRecord = await getFirstDidWebRecord(this.askar.agent); + const verificationMethodList = + didRecord.didDocument?.verificationMethod || []; + if (!verificationMethodList.length) { + throw new EntityNotFoundError( + "DidDocument does not exists or contains no verification methods", + ); + } + + const verificationMethod = verificationMethodList[0]; + + const credFormatData = await this.askar.agent.credentials.getFormatData( + credentialRecordId, + ); + if (!credFormatData.credential?.jsonld) { + throw new OcmError( + "The JSON-LD credential is either not in your wallet, pending approval, or not in the JSON-LD format.", + ); + } + + const jsonLd = credFormatData.credential.jsonld; + const vc = JsonTransformer.fromJSON(jsonLd, W3cJsonLdVerifiableCredential); + + const w3cServ = + this.askar.agent.context.dependencyManager.resolve(W3cCredentialService); + const presentation = await w3cServ.createPresentation({ + credentials: [vc], + id: didRecord.did + "?uuid=" + uuid(), + }); + + const vp = await w3cServ.signPresentation(this.askar.agent.context, { + format: ClaimFormat.LdpVp, + presentation, + proofPurpose: null, + proofType: "Ed25519Signature2018", + challenge: uuid(), + verificationMethod: verificationMethod.id, + }); + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const jsonVP = vp.toJson() as W3cJsonLdVerifiablePresentationDto; + this.logger.debug(JSON.stringify(jsonVP, null, 2)); + + return jsonVP; + }; + + offerJsonLdCredential = async ( + connectionId: string | undefined, + credToSign: W3cCredentialDto, + ): Promise<CredentialOfferResponseDto> => { + this.logger.log("offerJsonLdCredential", connectionId); + + const didRecord = await getFirstDidWebRecord(this.askar.agent); + const verificationMethodList = + didRecord.didDocument?.verificationMethod || []; + if (!verificationMethodList.length) { + throw new EntityNotFoundError( + "DidDocument does not exists or contains no verification methods", + ); + } + + const verificationMethod = verificationMethodList[0]; + + const w3cServ = + this.askar.agent.context.dependencyManager.resolve(W3cCredentialService); + + credToSign.id = didRecord.did + "?uuid=" + uuid(); + if (credToSign.credentialSubject) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + credToSign.credentialSubject.id = credToSign.id; + } + credToSign.issuer = didRecord.did; + credToSign.issuanceDate = new Date().toISOString(); + let credential: W3cCredential; + try { + credential = JsonTransformer.fromJSON(credToSign, W3cCredential); + } catch (e) { + this.logger.log("Incorrect request parameter", e); + throw new OcmError( + "Invalid JSON-LD data format. Please ensure that your JSON-LD contains the following properties: @context, id, type, issuer, issuanceDate, expirationDate, and credentialSubject.", + ); + } + + const vc = await w3cServ.signCredential(this.askar.agent.context, { + format: ClaimFormat.LdpVc, + credential, + proofType: "Ed25519Signature2018", + verificationMethod: verificationMethod.id, + }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const jsonVC = vc.toJson() as JsonCredential; + + if (!connectionId) { + // create connection less credential + const { credentialRecord, message } = + await this.askar.agent.credentials.createOffer({ + protocolVersion: "v2", + credentialFormats: { + jsonld: { + credential: jsonVC, + options: { + proofType: "Ed25519Signature2018", + proofPurpose: "assertionMethod", + }, + }, + }, + autoAcceptCredential: AutoAcceptCredential.ContentApproved, + }); + + credentialRecord.setTag("xRole", "issuer"); + await this.askar.agent.credentials.update(credentialRecord); + + const outOfBandRecord = await this.askar.agent.oob.createInvitation({ + messages: [message], + handshake: false, + }); + + const credentialUrl = outOfBandRecord.outOfBandInvitation.toUrl({ + domain: this.askar.agentConfig.agentPeerAddress, + }); + + const shortCredentialUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBandRecord.outOfBandInvitation.id}`; + + const dto = new CredentialRecordDto(); + dto.id = credentialRecord.id; + dto.state = credentialRecord.state; + dto.connectionId = credentialRecord.connectionId; + dto.attributes = credentialRecord.credentialAttributes; + dto.createdAt = credentialRecord.createdAt; + dto.tags = credentialRecord.getTags(); + + return { + credentialUrl: credentialUrl, + shortCredentialUrl: shortCredentialUrl, + credentialRecord: dto, + }; + } + + const credentialExchangeRecord = + await this.askar.agent.credentials.offerCredential({ + connectionId: connectionId, + protocolVersion: "v2", + credentialFormats: { + jsonld: { + credential: jsonVC, + options: { + proofType: "Ed25519Signature2018", + proofPurpose: "assertionMethod", + }, + }, + }, + autoAcceptCredential: AutoAcceptCredential.ContentApproved, + }); + + this.logger.log(credentialExchangeRecord); + + credentialExchangeRecord.setTag("xRole", "issuer"); + await this.askar.agent.credentials.update(credentialExchangeRecord); + + const dto = new CredentialRecordDto(); + dto.id = credentialExchangeRecord.id; + dto.state = credentialExchangeRecord.state; + dto.connectionId = credentialExchangeRecord.connectionId; + dto.attributes = credentialExchangeRecord.credentialAttributes; + dto.createdAt = credentialExchangeRecord.createdAt; + dto.tags = credentialExchangeRecord.getTags(); + + return { + credentialUrl: null, + shortCredentialUrl: null, + credentialRecord: dto, + }; + }; +} diff --git a/libs/askar/src/askar/services/agent.oob.service.ts b/libs/askar/src/askar/services/agent.oob.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..03beebd5462c9e149b2cfef39b8525b24b97a1e1 --- /dev/null +++ b/libs/askar/src/askar/services/agent.oob.service.ts @@ -0,0 +1,136 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { AskarService } from "./askar.service"; +import { + ConnectionRecordDto, + CreateInvitationResponseDto, + EntityNotFoundError, + CreateInvitationRequestDto, + InvitationFilterDto, +} from "@ocm-engine/dtos"; +import { Query, OutOfBandRecord } from "@credo-ts/core"; + +@Injectable() +export class AgentOobService { + private readonly logger = new Logger(AgentOobService.name); + constructor(private readonly askar: AskarService) {} + + createInvitation = async ( + createInvitationRequestDto?: CreateInvitationRequestDto, + ) => { + const outOfBoundRecord = await this.askar.agent.oob.createInvitation( + createInvitationRequestDto, + ); + + const response = new CreateInvitationResponseDto(); + + let longUrl = outOfBoundRecord.outOfBandInvitation.toUrl({ + domain: this.askar.agentConfig.agentPeerAddress, + }); + + if (this.askar.agentConfig.agentOobUrl) { + longUrl = longUrl.replace( + this.askar.agentConfig.agentPeerAddress, + this.askar.agentConfig.agentOobUrl, + ); + } + + //TODO: should we replace the short url with agentOobUrl if we do this we should have a redirect in ingress + response.shortInvitationUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBoundRecord.outOfBandInvitation.id}`; + response.outOfBandId = outOfBoundRecord.id; + response.createdAt = outOfBoundRecord.createdAt; + response.updatedAt = outOfBoundRecord.updatedAt; + response.role = outOfBoundRecord.role; + response.state = outOfBoundRecord.state; + response.invitationUrl = longUrl; + + return response; + }; + + acceptInvitation = async ( + invitationUrl: string, + ): Promise<ConnectionRecordDto> => { + const { connectionRecord } = + await this.askar.agent.oob.receiveInvitationFromUrl(invitationUrl); + + if (typeof connectionRecord === "undefined") { + throw new EntityNotFoundError(); + } + + const response = new ConnectionRecordDto(); + response.connectionName = connectionRecord.theirLabel; + response.state = connectionRecord.state; + response.id = connectionRecord.id; + response.did = connectionRecord.did; + response.theirDid = connectionRecord.theirDid; + response.invitationDid = connectionRecord.invitationDid; + response.outOfBandId = connectionRecord.outOfBandId; + response.createdAt = connectionRecord.createdAt; + response.updatedAt = connectionRecord.updatedAt; + response.imageUrl = connectionRecord.imageUrl; + + return response; + }; + + deleteInvitationById = async (id: string) => { + return this.askar.agent.oob.deleteById(id); + }; + + fetchInvitations = async (filter: InvitationFilterDto) => { + const query: Query<OutOfBandRecord>[] = []; + + if (filter.states) { + const stateQuery: Query<OutOfBandRecord> = { + $or: filter.states.map((state) => ({ state })), + }; + query.push(stateQuery); + } + + if (filter.roles) { + const roleQuery: Query<OutOfBandRecord> = { + $or: filter.roles.map((role) => ({ role })), + }; + + query.push(roleQuery); + } + + let invitations = await this.askar.agent.oob.findAllByQuery({ + $and: query, + }); + invitations = invitations.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + + const invitationsResponse = invitations.map((invitation) => { + const response = new CreateInvitationResponseDto(); + response.invitationUrl = invitation.outOfBandInvitation.toUrl({ + domain: this.askar.agentConfig.agentPeerAddress, + }); + response.shortInvitationUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${invitation.outOfBandInvitation.id}`; + response.outOfBandId = invitation.id; + response.createdAt = invitation.createdAt; + response.updatedAt = invitation.updatedAt; + response.role = invitation.role; + response.state = invitation.state; + return response; + }); + + return invitationsResponse; + }; + + getInvitationById = async (oobId: string) => { + const invitation = await this.askar.agent.oob.getById(oobId); + + const response = new CreateInvitationResponseDto(); + response.invitationUrl = invitation.outOfBandInvitation.toUrl({ + domain: this.askar.agentConfig.agentPeerAddress, + }); + response.shortInvitationUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${invitation.outOfBandInvitation.id}`; + response.outOfBandId = invitation.id; + response.createdAt = invitation.createdAt; + response.updatedAt = invitation.updatedAt; + response.role = invitation.role; + response.state = invitation.state; + return response; + }; +} diff --git a/libs/askar/src/askar/services/agent.proofs.service.ts b/libs/askar/src/askar/services/agent.proofs.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa4c5f3c672d7bdfe5844f9f7623b455ced34573 --- /dev/null +++ b/libs/askar/src/askar/services/agent.proofs.service.ts @@ -0,0 +1,310 @@ +import { Injectable, Logger } from "@nestjs/common"; +import { AskarService } from "./askar.service"; +import { + AcceptProofDto, + RequestProofDto, + ProofRecordDto, + ProofFilterDto, + RequestProofResponseDto, + EntityNotFoundError, + ProofFormatDataDto, +} from "@ocm-engine/dtos"; +import { ProofState, Query, ProofExchangeRecord } from "@credo-ts/core"; +import { AnonCredsRequestedAttribute } from "@credo-ts/anoncreds"; +import { uuid } from "@credo-ts/core/build/utils/uuid"; +import { waitForProofExchangeRecordSubject } from "../../agent.utils"; + +@Injectable() +export class AgentProofsService { + private readonly logger = new Logger(AgentProofsService.name); + constructor(private readonly askar: AskarService) {} + + requestProof = async ( + requestProofDto: RequestProofDto, + ): Promise<RequestProofResponseDto> => { + this.logger.log(JSON.stringify(requestProofDto, null, 2)); + const requestedAttributes: Record<string, AnonCredsRequestedAttribute> = {}; + + for (const attr of requestProofDto.attributes) { + requestedAttributes[uuid()] = { + name: attr.attributeName, + restrictions: [ + { + schema_id: attr.schemaId, + cred_def_id: attr.credentialDefinitionId, + }, + ], + }; + } + + if (!requestProofDto.connectionId) { + this.logger.log("connection Id not detected, creating oob proof"); + const { proofRecord, message } = + await this.askar.agent.proofs.createRequest({ + protocolVersion: "v2", + proofFormats: { + anoncreds: { + name: "proof-request", + version: "1.0", + requested_attributes: requestedAttributes, + }, + }, + }); + + proofRecord.setTag("xRole", "requester"); + await this.askar.agent.proofs.update(proofRecord); + + const outOfBandRecord = await this.askar.agent.oob.createInvitation({ + messages: [message], + handshake: false, + }); + + const proofUrl = outOfBandRecord.outOfBandInvitation.toUrl({ + domain: this.askar.agentConfig.agentPeerAddress, + }); + const shortProofUrl = `${this.askar.agentConfig.agentPeerAddress}/invitations/${outOfBandRecord.outOfBandInvitation.id}`; + + const dto = new ProofRecordDto(); + dto.id = proofRecord.id; + dto.connectionId = proofRecord.connectionId; + dto.state = proofRecord.state; + dto.updatedAt = proofRecord.updatedAt; + dto.createdAt = proofRecord.createdAt; + dto.tags = proofRecord.getTags(); + + return { + proofUrl: proofUrl, + shortProofUrl: shortProofUrl, + proofRecord: dto, + }; + } + + this.logger.log(`${requestProofDto.connectionId} detected, issuing proof`); + + const exchangeRecord = await this.askar.agent.proofs.requestProof({ + protocolVersion: "v2", + connectionId: requestProofDto.connectionId, + proofFormats: { + anoncreds: { + name: "proof-request", + version: "1.0", + requested_attributes: requestedAttributes, + }, + }, + }); + + exchangeRecord.setTag("xRole", "requester"); + await this.askar.agent.proofs.update(exchangeRecord); + + const response = new ProofRecordDto(); + response.id = exchangeRecord.id; + response.connectionId = exchangeRecord.connectionId; + response.state = exchangeRecord.state; + response.updatedAt = exchangeRecord.updatedAt; + response.createdAt = exchangeRecord.createdAt; + response.tags = exchangeRecord.getTags(); + + return { + proofUrl: null, + shortProofUrl: null, + proofRecord: response, + }; + }; + + fetchProofs = async (filter: ProofFilterDto): Promise<ProofRecordDto[]> => { + const query: Query<ProofExchangeRecord>[] = []; + + if (filter.states) { + const stateQuery: Query<ProofExchangeRecord> = { + $or: filter.states.map((state) => ({ state })), + }; + query.push(stateQuery); + } + + if (filter.connectionId) { + const connectionQuery: Query<ProofExchangeRecord> = { + connectionId: filter.connectionId, + }; + query.push(connectionQuery); + } + + let proofs = await this.askar.agent.proofs.findAllByQuery({ + $and: query, + }); + proofs = proofs.sort( + (a, b) => + new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + ); + + const response: ProofRecordDto[] = []; + for (const proof of proofs) { + const t = new ProofRecordDto(); + t.id = proof.id; + t.connectionId = proof.connectionId; + t.state = proof.state; + t.updatedAt = proof.updatedAt; + t.createdAt = proof.createdAt; + t.tags = proof.getTags(); + + response.push(t); + } + + return response; + }; + + getProofById = async (proofRecordId: string): Promise<ProofRecordDto> => { + const proofRecord = await this.askar.agent.proofs.findById(proofRecordId); + + if (!proofRecord) { + throw new EntityNotFoundError(); + } + + const proofResponse = new ProofRecordDto(); + + proofResponse.id = proofRecord.id; + proofResponse.connectionId = proofRecord.connectionId; + proofResponse.state = proofRecord.state; + proofResponse.updatedAt = proofRecord.updatedAt; + proofResponse.createdAt = proofRecord.createdAt; + proofResponse.tags = proofRecord.getTags(); + + return proofResponse; + }; + + getProofFormatDataById = async ( + proofRecordId: string, + ): Promise<ProofFormatDataDto> => { + const formatData = await this.askar.agent.proofs.getFormatData( + proofRecordId, + ); + + if (!formatData) { + throw new EntityNotFoundError(); + } + + const dto = new ProofFormatDataDto(); + dto.anoncredsProposal = formatData.proposal?.anoncreds; + dto.anoncredsRequest = formatData.request?.anoncreds; + dto.anoncredsPresentation = formatData.presentation?.anoncreds; + return dto; + }; + + proofAcceptanceWait = async ( + proofRecordId: string, + ): Promise<ProofFormatDataDto> => { + const proofRecord = await this.askar.agent.proofs.findById(proofRecordId); + + if (!proofRecord) { + throw new EntityNotFoundError(); + } + + if (proofRecord.state === ProofState.Done) { + return this.getProofFormatDataById(proofRecordId); + } + + await waitForProofExchangeRecordSubject(this.askar.agentB, { + proofRecordId, + state: ProofState.Done, + timeoutMs: 3 * 60 * 1000, // 3 minutes + }); + + return this.getProofFormatDataById(proofRecordId); + }; + + acceptProof = async ( + acceptProofDto: AcceptProofDto, + ): Promise<ProofRecordDto> => { + if (acceptProofDto.proofUrl) { + return this.acceptOobProof(acceptProofDto.proofUrl); + } + return this.acceptConnectionProof(acceptProofDto.proofId); + }; + + acceptOobProof = async (url: string): Promise<ProofRecordDto> => { + // omit await in order to catch received record in the next line + setTimeout(() => { + this.askar.agent.oob.receiveInvitationFromUrl(url, { + autoAcceptConnection: false, + autoAcceptInvitation: true, + // reuseConnection: true, + }); + }, 20); + + const record = await waitForProofExchangeRecordSubject(this.askar.agentB, { + state: ProofState.RequestReceived, + }); + + const requestedCredentials = + await this.askar.agent.proofs.selectCredentialsForRequest({ + proofRecordId: record.id, + }); + + const acceptedRecord = await this.askar.agent.proofs.acceptRequest({ + proofRecordId: record.id, + proofFormats: requestedCredentials.proofFormats, + }); + + const response = new ProofRecordDto(); + + response.id = acceptedRecord.id; + response.connectionId = acceptedRecord.connectionId; + response.state = acceptedRecord.state; + response.updatedAt = acceptedRecord.updatedAt; + response.createdAt = acceptedRecord.createdAt; + response.tags = acceptedRecord.getTags(); + + return response; + }; + + acceptConnectionProof = async ( + proofRecordId: string, + ): Promise<ProofRecordDto> => { + this.logger.log(`accepting proof request for ${proofRecordId}`); + const requestedCredentials = + await this.askar.agent.proofs.selectCredentialsForRequest({ + proofRecordId, + }); + + this.logger.log(JSON.stringify(requestedCredentials, null, 2)); + + const proof = await this.askar.agent.proofs.acceptRequest({ + proofRecordId, + proofFormats: requestedCredentials.proofFormats, + }); + + this.logger.log(JSON.stringify(proof, null, 2)); + + const response = new ProofRecordDto(); + response.id = proof.id; + response.connectionId = proof.connectionId; + response.state = proof.state; + response.updatedAt = proof.updatedAt; + response.createdAt = proof.createdAt; + response.tags = proof.getTags(); + + return response; + }; + + declineProofRequest = async ( + proofRecordId: string, + ): Promise<ProofRecordDto> => { + const resultFromDecline = await this.askar.agent.proofs.declineRequest({ + proofRecordId, + sendProblemReport: true, + }); + + const declineResponse = new ProofRecordDto(); + declineResponse.id = resultFromDecline.id; + declineResponse.connectionId = resultFromDecline.connectionId; + declineResponse.state = resultFromDecline.state; + declineResponse.updatedAt = resultFromDecline.updatedAt; + declineResponse.createdAt = resultFromDecline.createdAt; + declineResponse.tags = resultFromDecline.getTags(); + + return declineResponse; + }; + + deleteProofById = async (id: string): Promise<void> => { + await this.askar.agent.proofs.deleteById(id); + }; +} diff --git a/libs/askar/src/askar/askar.service.ts b/libs/askar/src/askar/services/askar.service.ts similarity index 99% rename from libs/askar/src/askar/askar.service.ts rename to libs/askar/src/askar/services/askar.service.ts index facf24316a14d64954e789697e2ae26d6ec26dea..84819cf912afdf37b47f6e1cee576e3ac97d2923 100644 --- a/libs/askar/src/askar/askar.service.ts +++ b/libs/askar/src/askar/services/askar.service.ts @@ -29,7 +29,7 @@ import { setupEventBehaviorSubjects, setupSubjectTransports, generateDidWeb, -} from "../agent.utils"; +} from "../../agent.utils"; import { IConfAgent } from "@ocm-engine/config"; import { BehaviorSubject } from "rxjs"; import express from "express"; diff --git a/libs/askar/src/askar/transports/agent.subject.outbound.transport.ts b/libs/askar/src/askar/transports/agent.subject.outbound.transport.ts index 9954ab3b43497f9f37846e91eb003f36fff32cb1..446b8cdcaa24722ea84ce0ea959046fe73486609 100644 --- a/libs/askar/src/askar/transports/agent.subject.outbound.transport.ts +++ b/libs/askar/src/askar/transports/agent.subject.outbound.transport.ts @@ -47,17 +47,13 @@ export class SubjectOutboundTransport implements OutboundTransport { const { payload, endpoint } = outboundPackage; if (!endpoint) { - throw new CredoError( - "Cannot send message to subject without endpoint", - ); + throw new CredoError("Cannot send message to subject without endpoint"); } const subject = this.subjectMap[endpoint]; if (!subject) { - throw new CredoError( - `No subject found for endpoint ${endpoint}`, - ); + throw new CredoError(`No subject found for endpoint ${endpoint}`); } // Create a replySubject just for this session. Both ends will be able to close it, diff --git a/libs/askar/src/credo/JsonLdCredentialFormatService.ts b/libs/askar/src/credo/JsonLdCredentialFormatService.ts index 96f7e0060654ed8b508e3fe8ceff52a9e000e3f8..7bbc4cd943317a9aad7d8bce863de5dde68bc3a8 100644 --- a/libs/askar/src/credo/JsonLdCredentialFormatService.ts +++ b/libs/askar/src/credo/JsonLdCredentialFormatService.ts @@ -90,9 +90,7 @@ export class JsonLdCredentialFormatService attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>(); if (!credProposalJson) { - throw new CredoError( - "Missing jsonld credential proposal data payload", - ); + throw new CredoError("Missing jsonld credential proposal data payload"); } // validation is done in here @@ -164,9 +162,7 @@ export class JsonLdCredentialFormatService attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>(); if (!credentialOfferJson) { - throw new CredoError( - "Missing jsonld credential offer data payload", - ); + throw new CredoError("Missing jsonld credential offer data payload"); } JsonTransformer.fromJSON(credentialOfferJson, JsonLdCredentialDetail); @@ -233,9 +229,7 @@ export class JsonLdCredentialFormatService attachment.getDataAsJson<JsonLdFormatDataCredentialDetail>(); if (!requestJson) { - throw new CredoError( - "Missing jsonld credential request data payload", - ); + throw new CredoError("Missing jsonld credential request data payload"); } // validate @@ -268,9 +262,7 @@ export class JsonLdCredentialFormatService )); if (!verificationMethod) { - throw new CredoError( - "Missing verification method in credential data", - ); + throw new CredoError("Missing verification method in credential data"); } const format = new CredentialFormatSpec({ attachmentId, @@ -361,9 +353,7 @@ export class JsonLdCredentialFormatService ); if (!keyType || keyType.length === 0) { - throw new CredoError( - `No Key Type found for proofType ${proofType}`, - ); + throw new CredoError(`No Key Type found for proofType ${proofType}`); } const verificationMethod = await findVerificationMethodByKeyType( diff --git a/libs/askar/src/index.ts b/libs/askar/src/index.ts index 5fb756c0f59cf5403e52175ae5134ced9232a5ea..c9a560b5d869bf040a97e7a452cdc39e11e675fa 100644 --- a/libs/askar/src/index.ts +++ b/libs/askar/src/index.ts @@ -1,5 +1,12 @@ export * from "./askar/askar.module"; -export * from "./askar/agent.service"; -export * from "./askar/askar.service"; +export * from "./askar/services/agent.anoncreds.service"; +export * from "./askar/services/agent.basicMessages.service"; +export * from "./askar/services/agent.connections.service"; +export * from "./askar/services/agent.credentials.service"; +export * from "./askar/services/agent.dids.service"; +export * from "./askar/services/agent.jsonld.service"; +export * from "./askar/services/agent.oob.service"; +export * from "./askar/services/agent.proofs.service"; +export * from "./askar/services/askar.service"; export * from "./askar.dynamic.module"; export * from "./askar-rest/askar.rest.module"; diff --git a/libs/dtos/src/dtos/generics/proof.formatData.dto.ts b/libs/dtos/src/dtos/generics/proof.formatData.dto.ts index 427a6d3993a7518f1d7ae9150efef621932f3464..fb0e74d36dd24c93760ea1dbd43b4d930a72bda9 100644 --- a/libs/dtos/src/dtos/generics/proof.formatData.dto.ts +++ b/libs/dtos/src/dtos/generics/proof.formatData.dto.ts @@ -1,7 +1,4 @@ -import { - AnonCredsProof, - AnonCredsProofRequest, -} from "@credo-ts/anoncreds"; +import { AnonCredsProof, AnonCredsProofRequest } from "@credo-ts/anoncreds"; export class ProofFormatDataDto { public anoncredsProposal?: AnonCredsProofRequest;