From 8b821f3bd37e6be93cee5673740eb6315e95411a Mon Sep 17 00:00:00 2001 From: Michael Avoyan Date: Thu, 11 Jul 2024 20:32:44 +0300 Subject: [PATCH] cont --- .../GenerateSignedJwtRepository.ts | 21 ++++++ ...lManifestToRefreshCredentialsRepository.ts | 20 ++++++ .../GetCredentialTypesUIFormSchema.ts | 20 ++++++ .../GetVerifiedProfileRepository.ts | 20 ++++++ .../src/repositories/VerifyJwtRepository.ts | 21 ++++++ packages/sample-app/src/repositories/index.ts | 12 +++- packages/sample-app/src/screens/Constants.ts | 4 +- .../sample-app/src/screens/MeinScreen.tsx | 70 ++++++++++++++++--- packages/sample-server/src/routes/Routes.ts | 5 +- .../GetCredentialManifestByDeepLinkTest.http | 31 +++++++- .../GetCredentialManifestByServiceTest.http | 27 ++++++- ...redentialManifestToRefreshCredentials.http | 36 ++++++++++ packages/sample-server/src/utils/Converter.ts | 49 +++++++------ packages/sdk/src/impl/VCLImpl.ts | 2 +- 14 files changed, 298 insertions(+), 40 deletions(-) create mode 100644 packages/sample-app/src/repositories/GenerateSignedJwtRepository.ts create mode 100644 packages/sample-app/src/repositories/GetCredentialManifestToRefreshCredentialsRepository.ts create mode 100644 packages/sample-app/src/repositories/GetCredentialTypesUIFormSchema.ts create mode 100644 packages/sample-app/src/repositories/GetVerifiedProfileRepository.ts create mode 100644 packages/sample-app/src/repositories/VerifyJwtRepository.ts create mode 100644 packages/sample-server/src/test-apis/GetCredentialManifestToRefreshCredentials.http diff --git a/packages/sample-app/src/repositories/GenerateSignedJwtRepository.ts b/packages/sample-app/src/repositories/GenerateSignedJwtRepository.ts new file mode 100644 index 0000000..2211539 --- /dev/null +++ b/packages/sample-app/src/repositories/GenerateSignedJwtRepository.ts @@ -0,0 +1,21 @@ +/** + * Created by Michael Avoyan on 11/07/2024. + * + * Copyright 2022 Velocity Career Labs inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import { Dictionary } from "../Types"; +import Urls from "../network/Urls"; +import fetcher from "../network/Fetcher"; + +export const generateSignedJwt = async ( + jwtDescriptor: Dictionary, + didJwk: Dictionary +): Promise => { + const config = { + url: Urls.generateSignedJwt, + method: 'POST', + data: { jwtDescriptor, didJwk }, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/GetCredentialManifestToRefreshCredentialsRepository.ts b/packages/sample-app/src/repositories/GetCredentialManifestToRefreshCredentialsRepository.ts new file mode 100644 index 0000000..fd2470a --- /dev/null +++ b/packages/sample-app/src/repositories/GetCredentialManifestToRefreshCredentialsRepository.ts @@ -0,0 +1,20 @@ +/** + * Created by Michael Avoyan on 11/07/2024. + * + * Copyright 2022 Velocity Career Labs inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import { Dictionary } from "../Types"; +import Urls from "../network/Urls"; +import fetcher from "../network/Fetcher"; + +export const getCredentialManifestToRefreshCredentials = async ( + credentialManifestDescriptorRefresh: Dictionary +): Promise> => { + const config = { + url: Urls.getCredentialManifest, + method: 'POST', + data: credentialManifestDescriptorRefresh, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/GetCredentialTypesUIFormSchema.ts b/packages/sample-app/src/repositories/GetCredentialTypesUIFormSchema.ts new file mode 100644 index 0000000..12eb5cf --- /dev/null +++ b/packages/sample-app/src/repositories/GetCredentialTypesUIFormSchema.ts @@ -0,0 +1,20 @@ +/** + * Created by Michael Avoyan on 11/07/2024. + * + * Copyright 2022 Velocity Career Labs inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import Urls from "../network/Urls"; +import fetcher from "../network/Fetcher"; +import { Dictionary } from "../Types"; + +export const getCredentialTypesUIFormSchema = async ( + credentialTypesUIFormSchemaDescriptor: Dictionary +): Promise => { + const config = { + url: Urls.getCredentialTypesUIFormSchema, + method: 'POST', + data: credentialTypesUIFormSchemaDescriptor, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/GetVerifiedProfileRepository.ts b/packages/sample-app/src/repositories/GetVerifiedProfileRepository.ts new file mode 100644 index 0000000..66a6316 --- /dev/null +++ b/packages/sample-app/src/repositories/GetVerifiedProfileRepository.ts @@ -0,0 +1,20 @@ +/** + * Created by Michael Avoyan on 11/07/2024. + * + * Copyright 2022 Velocity Career Labs inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import { Dictionary } from "../Types"; +import Urls from "../network/Urls"; +import fetcher from "../network/Fetcher"; + +export const getVerifiedProfile = async ( + verifiedProfileDescriptor: Dictionary +): Promise => { + const config = { + url: Urls.getVerifiedProfile, + method: 'POST', + data: verifiedProfileDescriptor, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/VerifyJwtRepository.ts b/packages/sample-app/src/repositories/VerifyJwtRepository.ts new file mode 100644 index 0000000..335153e --- /dev/null +++ b/packages/sample-app/src/repositories/VerifyJwtRepository.ts @@ -0,0 +1,21 @@ +/** + * Created by Michael Avoyan on 11/07/2024. + * + * Copyright 2022 Velocity Career Labs inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import { Dictionary } from "../Types"; +import Urls from "../network/Urls"; +import fetcher from "../network/Fetcher"; + +export const verifyJwt = async ( + jwt: Dictionary, + publicJwk: Dictionary +): Promise => { + const config = { + url: Urls.verifyJwt, + method: 'POST', + data: { jwt, publicJwk }, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/index.ts b/packages/sample-app/src/repositories/index.ts index 4387ad7..da15c8e 100644 --- a/packages/sample-app/src/repositories/index.ts +++ b/packages/sample-app/src/repositories/index.ts @@ -12,11 +12,16 @@ import { getPresentationRequest } from "./PresentationRequestRepository"; import { submitPresentation } from "./SubmitPresentationRepository"; import { getCredentialManifestByDeepLink } from "./GetCredentialManifestByDeepLinkRepository"; import { getCredentialManifestByService } from "./GetCredentialManifestByServiceRepository"; +import { getCredentialManifestToRefreshCredentials } from "./GetCredentialManifestToRefreshCredentialsRepository"; import { generateOffers } from "./GenerateOffersRepository"; import { checkOffers } from "./CheckForOffersRepository"; import { finalizeOffers } from "./FinalizeOffersRepository"; import { searchForOrganizations } from "./SearchForOrganizationsRepository"; import { generateDidJwk } from "./GenerateDidJwkRepository"; +import { getCredentialTypesUIFormSchema } from "./GetCredentialTypesUIFormSchema"; +import { getVerifiedProfile } from "./GetVerifiedProfileRepository"; +import { verifyJwt } from "./VerifyJwtRepository"; +import { generateSignedJwt } from "./GenerateSignedJwtRepository"; export { getCountries, @@ -26,9 +31,14 @@ export { submitPresentation, getCredentialManifestByDeepLink, getCredentialManifestByService, + getCredentialManifestToRefreshCredentials, generateOffers, finalizeOffers, checkOffers, searchForOrganizations, - generateDidJwk + generateDidJwk, + getCredentialTypesUIFormSchema, + getVerifiedProfile, + verifyJwt, + generateSignedJwt }; \ No newline at end of file diff --git a/packages/sample-app/src/screens/Constants.ts b/packages/sample-app/src/screens/Constants.ts index c39341d..e455f15 100644 --- a/packages/sample-app/src/screens/Constants.ts +++ b/packages/sample-app/src/screens/Constants.ts @@ -49,7 +49,7 @@ export abstract class Constants { 'https://devagent.velocitycareerlabs.io/api/holder/v0.6/org/did:ion:EiApMLdMb4NPb8sae9-hXGHP79W1gisApVSE80USPEbtJA/issue/get-credential-manifest'; static readonly IssuingServiceJsonStr = - '{"id":"did:ion:EiApMLdMb4NPb8sae9-hXGHP79W1gisApVSE80USPEbtJA#credential-agent-issuer-1","type":"VelocityCredentialAgentIssuer_v1.0","credentialTypes":["Course","EducationDegree","Badge"],"serviceEndpoint":"$IssuingServiceEndPoint"}'; + `{"id":"did:ion:EiApMLdMb4NPb8sae9-hXGHP79W1gisApVSE80USPEbtJA#credential-agent-issuer-1","type":"VelocityCredentialAgentIssuer_v1.0","credentialTypes":["Course","EducationDegree","Badge"],"serviceEndpoint":"${Constants.IssuingServiceEndPoint}"}`; static readonly PresentationSelectionsList = [ { inputDescriptor: 'PhoneV1.0', jwtVc: Constants.AdamSmithPhoneJwt }, @@ -120,7 +120,7 @@ export abstract class Constants { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksiLCJqd2siOnsia3R5IjoiRUMiLCJjcnYiOiJzZWNwMjU2azEiLCJ4IjoiQ1JFNzc0WV8ydkctdTZka2UwSmQzYVhrd1R4WkE2TV96cDZ2TkR0Vmt5NCIsInkiOiJZLWhIdS1FSXlHSGFRRTdmamxZVVlBZ2lVanFqZFc2VXlIaHI2OVFZTS04IiwidXNlIjoic2lnIn19.eyJwMSI6InYxIiwicDIiOiJ2MTIiLCJuYmYiOjE2OTQ0MzUyMjAsImp0aSI6Ijk4YTc4MGFmLTIyZGYtNGU3ZC1iYTZjLTBmYjE0Njk2Zjg0NSIsImlzcyI6ImlzczEyMyIsInN1YiI6IlpHNXQwT1ZrT08iLCJpYXQiOjE2OTQ0MzUyMjB9.kaEGDsRFjFylIAQ1DDX0GQyWBD1y5rG7WNpFZbrL1DFPrfFgDrydXXOCaBbr8TN81kPrbkscsHUuioY-tGCxMw', }; - static readonly SomeJwkPublic = { + static readonly SomePublicJwk = { valueStr: '{ "kty": "EC", "crv": "secp256k1", "x": "CRE774Y_2vG-u6dke0Jd3aXkwTxZA6M_zp6vNDtVky4", "y": "Y-hHu-EIyGHaQE7fjlYUYAgiUjqjdW6UyHhr69QYM-8", "use": "sig" }', }; diff --git a/packages/sample-app/src/screens/MeinScreen.tsx b/packages/sample-app/src/screens/MeinScreen.tsx index e319e81..f4a1f1e 100644 --- a/packages/sample-app/src/screens/MeinScreen.tsx +++ b/packages/sample-app/src/screens/MeinScreen.tsx @@ -16,7 +16,14 @@ import { getCredentialManifestByService, generateOffers, searchForOrganizations, - generateDidJwk, finalizeOffers, checkOffers + generateDidJwk, + finalizeOffers, + checkOffers, + getCredentialTypesUIFormSchema, + getCredentialManifestToRefreshCredentials, + getVerifiedProfile, + verifyJwt, + generateSignedJwt } from "../repositories"; import { Constants } from "./Constants"; import { Dictionary } from "../Types"; @@ -103,7 +110,7 @@ const onGetOrganizationsThenCredentialManifestByService = () => { getCredentialManifestByService({ service: serviceCredentialAgentIssuer, issuingType: 'Career', - credentialTypes: [serviceCredentialAgentIssuer.type], // Can come from any where + credentialTypes: [serviceCredentialAgentIssuer.type], // Can come from anywhere didJwk: didJwk }).then((credentialManifest) => { console.log('credential manifest: ', credentialManifest); @@ -155,22 +162,69 @@ const onFinalizeOffers = (credentialManifest: Dictionary, offers: Dictionar } const onGetCredentialTypesUIFormSchema = () => { - alert(`You clicked on getCredentialTypesUIFormSchema`); + getCredentialTypesUIFormSchema({ + credentialType: "ResidentPermitV1.0", + countryCode: "US" + }).then((credentialTypesUIFormSchema) => { + console.log('credential types UI form schema: ', credentialTypesUIFormSchema); + }).catch((error) => { + console.log(error); + }); }; + const onRefreshCredentials = () => { - alert(`You clicked on refreshCredentials`); + getCredentialManifestToRefreshCredentials({ + service: JSON.parse(Constants.IssuingServiceJsonStr), + credentialIds: Constants.CredentialIdsToRefresh, + didJwk: didJwk + }).then((credentialManifest) => { + console.log('credential manifest to refresh credentials: ', credentialManifest); + }).catch((error) => { + console.log(error); + }); }; + const onGetVerifiedProfile = () => { - alert(`You clicked on getVerifiedProfile`); + getVerifiedProfile({ + did: Constants.DidDev + }).then((verifiedProfile) => { + console.log('verified profile: ', verifiedProfile); + }).catch((error) => { + console.log(error); + }); }; + const onVerifyJwt = () => { - alert(`You clicked on verifyJwt`); + verifyJwt(Constants.SomeJwt, Constants.SomePublicJwk).then((isVerified) => { + console.log('is verified: ', isVerified); + }).catch((error) => { + console.log(error); + }); }; const onGenerateSignedJwt = () => { - alert(`You clicked on generateSignedJwt`); + generateSignedJwt({ + payload: Constants.SomePayload, + iss: "iss123", + jti: "jti123" + }, + didJwk + ).then((signedJwt) => { + console.log('signed jwt: ', signedJwt); + }).catch((error) => { + console.log(error); + }); }; + const onGenerateDidJwk = () => { - alert(`You clicked on generateDidJwk`); + generateDidJwk({ + signatureAlgorithm: "P-256", + remoteCryptoServicesToken: null + }).then((newDidJwk) => { + console.log('new didJwk: ', newDidJwk); + didJwk = newDidJwk; + }).catch((error) => { + console.log(error); + }); }; const MeinScreen: React.FC = () => { diff --git a/packages/sample-server/src/routes/Routes.ts b/packages/sample-server/src/routes/Routes.ts index b970f39..b547e19 100644 --- a/packages/sample-server/src/routes/Routes.ts +++ b/packages/sample-server/src/routes/Routes.ts @@ -16,7 +16,8 @@ import { jwtFromJson, organizationsSearchDescriptorFrom, presentationRequestDescriptorFrom, - presentationSubmissionFrom, publicJwkFrom, + presentationSubmissionFrom, + publicJwkFrom, submissionResultFrom, tokenFrom, verifiedProfileDescriptorFrom @@ -83,7 +84,7 @@ export default async function routes(fastify) { async (req, reply) => { reply.send( await req.vclSdk.getCredentialManifest( - credentialManifestDescriptorFrom(req.body, req.didJwk) + credentialManifestDescriptorFrom(req.body) ) ) } diff --git a/packages/sample-server/src/test-apis/GetCredentialManifestByDeepLinkTest.http b/packages/sample-server/src/test-apis/GetCredentialManifestByDeepLinkTest.http index ee6d054..a3f530e 100644 --- a/packages/sample-server/src/test-apis/GetCredentialManifestByDeepLinkTest.http +++ b/packages/sample-server/src/test-apis/GetCredentialManifestByDeepLinkTest.http @@ -3,5 +3,32 @@ POST http://localhost:5000/getCredentialManifest HTTP/1.1 Content-Type: application/json { - "value": "velocity-network-devnet://issue?request_uri=https%3A%2F%2Fdevagent.velocitycareerlabs.io%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3AEiApMLdMb4NPb8sae9-hXGHP79W1gisApVSE80USPEbtJA%2Fissue%2Fget-credential-manifest%3Fid%3D6384a3ad148b1991687f67c9%26credential_types%3DEmploymentPastV1.1%26issuerDid%3Ddid%3Aion%3AEiApMLdMb4NPb8sae9-hXGHP79W1gisApVSE80USPEbtJA" -} + "deepLink": { + "value": "velocity-network-devnet://issue?request_uri=https%3A%2F%2Fdevagent.velocitycareerlabs.io%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3AEiApMLdMb4NPb8sae9-hXGHP79W1gisApVSE80USPEbtJA%2Fissue%2Fget-credential-manifest%3Fid%3D6384a3ad148b1991687f67c9%26credential_types%3DEmploymentPastV1.1%26issuerDid%3Ddid%3Aion%3AEiApMLdMb4NPb8sae9-hXGHP79W1gisApVSE80USPEbtJA" + }, + "didJwk": { + "payload": { + "did": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9", + "kid": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9#0", + "keyId": "Iv5pwCQfp6e5FsncVgVX0", + "publicJwk": { + "kty": "EC", + "crv": "P-256", + "y": "c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk", + "x": "AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg" + } + }, + "did": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9", + "publicJwk": { + "valueStr": "{\"kty\":\"EC\",\"crv\":\"P-256\",\"y\":\"c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk\",\"x\":\"AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg\"}", + "valueJson": { + "kty": "EC", + "crv": "P-256", + "y": "c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk", + "x": "AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg" + } + }, + "kid": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9#0", + "keyId": "Iv5pwCQfp6e5FsncVgVX0" + } +} \ No newline at end of file diff --git a/packages/sample-server/src/test-apis/GetCredentialManifestByServiceTest.http b/packages/sample-server/src/test-apis/GetCredentialManifestByServiceTest.http index 17ad716..650fcd2 100644 --- a/packages/sample-server/src/test-apis/GetCredentialManifestByServiceTest.http +++ b/packages/sample-server/src/test-apis/GetCredentialManifestByServiceTest.http @@ -10,5 +10,30 @@ Content-Type: application/json "value": "velocity-network-devnet://inspect?request_uri=https%3A%2F%2Fdevagent.velocitycareerlabs.io%2Fapi%2Fholder%2Fv0.6%2Forg%2Fdid%3Aion%3AEiAbP9xvCYnUOiLwqgbkV4auH_26Pv7BT2pYYT3masvvhw%2Finspect%2Fget-presentation-request%3Fid%3D62d8f05788de05e27930b037&inspectorDid=did%3Aion%3AEiAbP9xvCYnUOiLwqgbkV4auH_26Pv7BT2pYYT3masvvhw", "requestUri": "https://devagent.velocitycareerlabs.io/api/holder/v0.6/org/did:ion:EiAbP9xvCYnUOiLwqgbkV4auH_26Pv7BT2pYYT3masvvhw/inspect/get-presentation-request?id=62d8f05788de05e27930b037&inspectorDid=did%3Aion%3AEiAbP9xvCYnUOiLwqgbkV4auH_26Pv7BT2pYYT3masvvhw" }, - "pushDelegate": null + "pushDelegate": null, + "didJwk": { + "payload": { + "did": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9", + "kid": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9#0", + "keyId": "Iv5pwCQfp6e5FsncVgVX0", + "publicJwk": { + "kty": "EC", + "crv": "P-256", + "y": "c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk", + "x": "AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg" + } + }, + "did": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9", + "publicJwk": { + "valueStr": "{\"kty\":\"EC\",\"crv\":\"P-256\",\"y\":\"c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk\",\"x\":\"AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg\"}", + "valueJson": { + "kty": "EC", + "crv": "P-256", + "y": "c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk", + "x": "AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg" + } + }, + "kid": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9#0", + "keyId": "Iv5pwCQfp6e5FsncVgVX0" + } } diff --git a/packages/sample-server/src/test-apis/GetCredentialManifestToRefreshCredentials.http b/packages/sample-server/src/test-apis/GetCredentialManifestToRefreshCredentials.http new file mode 100644 index 0000000..13aa4fd --- /dev/null +++ b/packages/sample-server/src/test-apis/GetCredentialManifestToRefreshCredentials.http @@ -0,0 +1,36 @@ +### Get Credential Manifest To Refresh Credentials +POST http://localhost:5000/getCredentialManifest HTTP/1.1 +Content-Type: application/json + +{ + "service": {"type":"VlcCareerIssuer_v1","id":"#velocity-issuer-1","serviceEndpoint":"https:\/\/devagent.velocitycareerlabs.io\/api\/holder\/v0.6\/org\/did:ion:EiApMLdMb4NPb8sae9-hXGHP79W1gisApVSE80USPEbtJA\/issue\/get-credential-manifest","credentialTypes":["EducationDegree","EducationDegreeRegistrationV1.0","EducationDegreeStudyV1.0","EducationDegreeGraduationV1.0","EducationDegreeRegistrationV1.1","EducationDegreeStudyV1.1","EducationDegreeGraduationV1.1","PastEmploymentPosition","CurrentEmploymentPosition","EmploymentCurrentV1.0","EmploymentPastV1.0","EmploymentCurrentV1.1","EmploymentPastV1.1","Certification","CertificationV1.0","LicenseV1.0","CertificationV1.1","LicenseV1.1","Course","CourseRegistrationV1.0","CourseCompletionV1.0","CourseAttendanceV1.0","CourseRegistrationV1.1","CourseCompletionV1.1","CourseAttendanceV1.1","AssessmentDec2020","AssessmentV1.0","AssessmentV1.1","Badge","OpenBadgeV1.0"]}, + "credentialIds": [ + "did:velocity:v2:0x2bef092530ccc122f5fe439b78eddf6010685e88:248532930732481:1963", + "did:velocity:v2:0x2bef092530ccc122f5fe439b78eddf6010685e88:248532930732481:1963" + ], + "didJwk": { + "payload": { + "did": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9", + "kid": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9#0", + "keyId": "Iv5pwCQfp6e5FsncVgVX0", + "publicJwk": { + "kty": "EC", + "crv": "P-256", + "y": "c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk", + "x": "AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg" + } + }, + "did": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9", + "publicJwk": { + "valueStr": "{\"kty\":\"EC\",\"crv\":\"P-256\",\"y\":\"c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk\",\"x\":\"AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg\"}", + "valueJson": { + "kty": "EC", + "crv": "P-256", + "y": "c9DTq9qTVQ9QBil-H1tdV7qYdDbspaLnpgAIvDJxJGk", + "x": "AXAlZY8j4hyrmtw0hF3k-2VOO4LvWG0K4AykBXKnGUg" + } + }, + "kid": "did:jwk:eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkFYQWxaWThqNGh5cm10dzBoRjNrLTJWT080THZXRzBLNEF5a0JYS25HVWciLCJ5IjoiYzlEVHE5cVRWUTlRQmlsLUgxdGRWN3FZZERic3BhTG5wZ0FJdkRKeEpHayJ9#0", + "keyId": "Iv5pwCQfp6e5FsncVgVX0" + } +} diff --git a/packages/sample-server/src/utils/Converter.ts b/packages/sample-server/src/utils/Converter.ts index fd68bb6..3d5c319 100644 --- a/packages/sample-server/src/utils/Converter.ts +++ b/packages/sample-server/src/utils/Converter.ts @@ -12,6 +12,7 @@ import { VCLCredentialManifestDescriptor, VCLCredentialManifestDescriptorByDeepLink, VCLCredentialManifestDescriptorByService, + VCLCredentialManifestDescriptorRefresh, VCLDeepLink, VCLDidJwk, VCLExchange, @@ -33,15 +34,15 @@ import { VCLVerifiedProfileDescriptor, VCLPublicJwk, VCLJwtDescriptor, - VCLDidJwkDescriptor + VCLDidJwkDescriptor, Nullish } from "@velocitycareerlabs/vnf-nodejs-wallet-sdk/src"; export const deepLinkFrom = (deepLink: any): VCLDeepLink => { return new VCLDeepLink(deepLink.value ?? deepLink); } -export const tokenFrom = (token: any): VCLToken => { - return new VCLToken(token.value ?? token); +export const tokenFrom = (token: any): Nullish => { + return token? new VCLToken(token.value ?? token) : null; } export const jwtFromJson = (json: Dictionary): VCLJwt => { @@ -49,7 +50,8 @@ export const jwtFromJson = (json: Dictionary): VCLJwt => { } export const publicJwkFrom = (json: Dictionary): VCLPublicJwk => { - return VCLPublicJwk.fromJSON(json); + return json.valueStr ? VCLPublicJwk.fromString(json.valueStr) : + VCLPublicJwk.fromJSON(json.valueJson ?? json); } export const didJwkFrom = (json: Dictionary): VCLDidJwk => { @@ -86,7 +88,7 @@ export const presentationSubmissionFrom = (json: Dictionary): VCLPresentati export const submissionResultFrom = (json: Dictionary): VCLSubmissionResult => { const submissionResultJson = json; return new VCLSubmissionResult( - tokenFrom(submissionResultJson.sessionToken.value), + tokenFrom(submissionResultJson.sessionToken.value) ?? new VCLToken(""), new VCLExchange(submissionResultJson.exchange), submissionResultJson.jti, submissionResultJson.submissionId @@ -99,39 +101,40 @@ export const organizationsSearchDescriptorFrom = (json: Dictionary): VCLOrg ); } -const credentialManifestDescriptorByDeepLinkFrom = ( - json: Dictionary, - didJwk: VCLDidJwk -): VCLCredentialManifestDescriptorByDeepLink => { +const credentialManifestDescriptorByDeepLinkFrom = (json: Dictionary): VCLCredentialManifestDescriptorByDeepLink => { return new VCLCredentialManifestDescriptorByDeepLink( - deepLinkFrom(json), + deepLinkFrom(json.deepLink), VCLIssuingType.Career, null, - didJwk, + didJwkFrom(json.didJwk), + null ); } -const credentialManifestDescriptorByServiceFrom = ( - json: Dictionary, - didJwk: VCLDidJwk -): VCLCredentialManifestDescriptorByService => { +const credentialManifestDescriptorByServiceFrom = (json: Dictionary): VCLCredentialManifestDescriptorByService => { return new VCLCredentialManifestDescriptorByService( new VCLServiceCredentialAgentIssuer(json.service), issuingTypeFromString(json.issuingType), json.credentialTypes, null, - didJwk, + didJwkFrom(json.didJwk), null ); } -export const credentialManifestDescriptorFrom = ( - json: Dictionary, - didJwk: VCLDidJwk -): VCLCredentialManifestDescriptor => { - return json.value ? // deep link - credentialManifestDescriptorByDeepLinkFrom(json, didJwk) : - credentialManifestDescriptorByServiceFrom(json, didJwk) +const credentialManifestDescriptorRefreshFrom = (json: Dictionary): VCLCredentialManifestDescriptor => { + return new VCLCredentialManifestDescriptorRefresh( + json.service, + json.credentialIds, + didJwkFrom(json.didJwk), + json.remoteCryptoServicesToken ? new VCLToken(json.remoteCryptoServicesToken) : null + ); +} + +export const credentialManifestDescriptorFrom = (json: Dictionary): VCLCredentialManifestDescriptor => { + return json.credentialIds ? credentialManifestDescriptorRefreshFrom(json) : ( + json.service ? credentialManifestDescriptorByServiceFrom(json) : credentialManifestDescriptorByDeepLinkFrom(json) + ) } export const credentialManifestFrom = (json: Dictionary): VCLCredentialManifest => { diff --git a/packages/sdk/src/impl/VCLImpl.ts b/packages/sdk/src/impl/VCLImpl.ts index 45da06f..6ab28cf 100644 --- a/packages/sdk/src/impl/VCLImpl.ts +++ b/packages/sdk/src/impl/VCLImpl.ts @@ -304,7 +304,7 @@ export class VCLImpl implements VCL { VCLErrorCode.SdkError.toString(), null ); - logError('', error); + logError(`credentialManifestDescriptor.did doesn't exist`, error); throw VCLError.fromError(error); } let verifiedProfile: VCLVerifiedProfile;