From 1f48d2aa58c785dce6c9277fad4142835dff400e Mon Sep 17 00:00:00 2001 From: Michael Avoyan Date: Wed, 10 Jul 2024 22:11:05 +0300 Subject: [PATCH] cont --- .../repositories/CheckForOffersRepository.ts | 21 +++ .../repositories/FinalizeOffersRepository.ts | 21 +++ .../repositories/GenerateDidJwkRepository.ts | 18 +++ .../repositories/GenerateOffersRepository.ts | 20 +++ ...tCredentialManifestByDeepLinkRepository.ts | 6 +- ...etCredentialManifestByServiceRepository.ts | 20 +++ .../PresentationRequestRepository.ts | 6 +- .../SearchForOrganizationsRepository.ts | 20 +++ .../SubmitPresentationRepository.ts | 4 +- packages/sample-app/src/repositories/index.ts | 16 ++- .../sample-app/src/screens/MeinScreen.tsx | 124 ++++++++++++++---- packages/sample-app/src/utils/Utils.ts | 35 +++++ .../src/controllers/CheckForOffers.ts | 2 +- .../src/controllers/FinalizeOffers.ts | 4 +- .../src/controllers/GenerateOffers.ts | 2 +- .../src/test-apis/GenerateDidJwkTest.http | 2 +- 16 files changed, 287 insertions(+), 34 deletions(-) create mode 100644 packages/sample-app/src/repositories/CheckForOffersRepository.ts create mode 100644 packages/sample-app/src/repositories/FinalizeOffersRepository.ts create mode 100644 packages/sample-app/src/repositories/GenerateDidJwkRepository.ts create mode 100644 packages/sample-app/src/repositories/GenerateOffersRepository.ts create mode 100644 packages/sample-app/src/repositories/GetCredentialManifestByServiceRepository.ts create mode 100644 packages/sample-app/src/repositories/SearchForOrganizationsRepository.ts create mode 100644 packages/sample-app/src/utils/Utils.ts diff --git a/packages/sample-app/src/repositories/CheckForOffersRepository.ts b/packages/sample-app/src/repositories/CheckForOffersRepository.ts new file mode 100644 index 0000000..2a894ac --- /dev/null +++ b/packages/sample-app/src/repositories/CheckForOffersRepository.ts @@ -0,0 +1,21 @@ +/** + * Created by Michael Avoyan on 10/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 checkOffers = async ( + generateOffersDescriptor: Dictionary, + sessionToken: Dictionary, +): Promise> => { + const config = { + url: Urls.checkOffers, + method: 'POST', + data: { generateOffersDescriptor, sessionToken } + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/FinalizeOffersRepository.ts b/packages/sample-app/src/repositories/FinalizeOffersRepository.ts new file mode 100644 index 0000000..d7ed4aa --- /dev/null +++ b/packages/sample-app/src/repositories/FinalizeOffersRepository.ts @@ -0,0 +1,21 @@ +/** + * Created by Michael Avoyan on 10/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 finalizeOffers = async ( + finalizeOffersDescriptor: Dictionary, + sessionToken: Dictionary, +): Promise> => { + const config = { + url: Urls.finalizeOffers, + method: 'POST', + data: { finalizeOffersDescriptor, sessionToken }, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/GenerateDidJwkRepository.ts b/packages/sample-app/src/repositories/GenerateDidJwkRepository.ts new file mode 100644 index 0000000..11d2320 --- /dev/null +++ b/packages/sample-app/src/repositories/GenerateDidJwkRepository.ts @@ -0,0 +1,18 @@ +/** + * Created by Michael Avoyan on 10/07/2024. + * + * Copyright 2022 Velocity Career Labs inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import Urls from "../network/Urls"; +import { Dictionary } from "../Types"; +import fetcher from "../network/Fetcher"; + +export const generateDidJwk = async (generateDidJwkDescriptor: Dictionary): Promise> => { + const config = { + url: Urls.generateDidJwk, + method: 'POST', + data: generateDidJwkDescriptor, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/GenerateOffersRepository.ts b/packages/sample-app/src/repositories/GenerateOffersRepository.ts new file mode 100644 index 0000000..4ce61a2 --- /dev/null +++ b/packages/sample-app/src/repositories/GenerateOffersRepository.ts @@ -0,0 +1,20 @@ +/** + * Created by Michael Avoyan on 09/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 generateOffers = async ( + generateOffersDescriptor: Dictionary +): Promise> => { + const config = { + url: Urls.generateOffers, + method: 'POST', + data: { generateOffersDescriptor }, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/GetCredentialManifestByDeepLinkRepository.ts b/packages/sample-app/src/repositories/GetCredentialManifestByDeepLinkRepository.ts index 1aa349d..72aea97 100644 --- a/packages/sample-app/src/repositories/GetCredentialManifestByDeepLinkRepository.ts +++ b/packages/sample-app/src/repositories/GetCredentialManifestByDeepLinkRepository.ts @@ -8,11 +8,13 @@ import Urls from "../network/Urls"; import fetcher from "../network/Fetcher"; import { Dictionary } from "../Types"; -export const getCredentialManifest = async (deepLink: string): Promise> => { +export const getCredentialManifestByDeepLink = async ( + deepLink: Dictionary +): Promise> => { const config = { url: Urls.getCredentialManifest, method: 'POST', - data: { "value": deepLink }, + data: deepLink, }; return await fetcher(config); } \ No newline at end of file diff --git a/packages/sample-app/src/repositories/GetCredentialManifestByServiceRepository.ts b/packages/sample-app/src/repositories/GetCredentialManifestByServiceRepository.ts new file mode 100644 index 0000000..7d63e72 --- /dev/null +++ b/packages/sample-app/src/repositories/GetCredentialManifestByServiceRepository.ts @@ -0,0 +1,20 @@ +/** + * Created by Michael Avoyan on 10/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 getCredentialManifestByService = async ( + credentialManifestDescriptorByService: Dictionary +): Promise> => { + const config = { + url: Urls.getCredentialManifest, + method: 'POST', + data: credentialManifestDescriptorByService, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/PresentationRequestRepository.ts b/packages/sample-app/src/repositories/PresentationRequestRepository.ts index 26053f0..7f74d10 100644 --- a/packages/sample-app/src/repositories/PresentationRequestRepository.ts +++ b/packages/sample-app/src/repositories/PresentationRequestRepository.ts @@ -8,11 +8,13 @@ import { Dictionary } from "@velocitycareerlabs/vnf-nodejs-wallet-sdk/src"; import fetcher from "../network/Fetcher"; import Urls from "../network/Urls"; -export const getPresentationRequest = async (deepLink: string): Promise> => { +export const getPresentationRequest = async ( + deepLink: Dictionary +): Promise> => { const config = { url: Urls.getPresentationRequest, method: 'POST', - data: { "value": deepLink }, + data: deepLink, }; return await fetcher(config); } \ No newline at end of file diff --git a/packages/sample-app/src/repositories/SearchForOrganizationsRepository.ts b/packages/sample-app/src/repositories/SearchForOrganizationsRepository.ts new file mode 100644 index 0000000..de03104 --- /dev/null +++ b/packages/sample-app/src/repositories/SearchForOrganizationsRepository.ts @@ -0,0 +1,20 @@ +/** + * Created by Michael Avoyan on 09/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 searchForOrganizations = async ( + organizationDescriptor: Dictionary +): Promise => { + const config = { + url: Urls.searchForOrganizations, + method: 'POST', + data: organizationDescriptor, + }; + return await fetcher(config); +} \ No newline at end of file diff --git a/packages/sample-app/src/repositories/SubmitPresentationRepository.ts b/packages/sample-app/src/repositories/SubmitPresentationRepository.ts index 7e9f8fa..a66e959 100644 --- a/packages/sample-app/src/repositories/SubmitPresentationRepository.ts +++ b/packages/sample-app/src/repositories/SubmitPresentationRepository.ts @@ -8,7 +8,9 @@ import { Dictionary } from "@velocitycareerlabs/vnf-nodejs-wallet-sdk/src"; import Urls from "../network/Urls"; import fetcher from "../network/Fetcher"; -export const submitPresentation = async (presentationSubmission: Dictionary): Promise> => { +export const submitPresentation = async ( + presentationSubmission: Dictionary +): Promise> => { const config = { url: Urls.submitPresentation, method: 'POST', diff --git a/packages/sample-app/src/repositories/index.ts b/packages/sample-app/src/repositories/index.ts index 312e349..4387ad7 100644 --- a/packages/sample-app/src/repositories/index.ts +++ b/packages/sample-app/src/repositories/index.ts @@ -10,7 +10,13 @@ import { getCredentialTypes } from "./CredentialTypesRepository"; import { getCredentialTypeSchemas } from "./CredentialTypeSchemasRepository"; import { getPresentationRequest } from "./PresentationRequestRepository"; import { submitPresentation } from "./SubmitPresentationRepository"; -import { getCredentialManifest } from "./GetCredentialManifestByDeepLinkRepository"; +import { getCredentialManifestByDeepLink } from "./GetCredentialManifestByDeepLinkRepository"; +import { getCredentialManifestByService } from "./GetCredentialManifestByServiceRepository"; +import { generateOffers } from "./GenerateOffersRepository"; +import { checkOffers } from "./CheckForOffersRepository"; +import { finalizeOffers } from "./FinalizeOffersRepository"; +import { searchForOrganizations } from "./SearchForOrganizationsRepository"; +import { generateDidJwk } from "./GenerateDidJwkRepository"; export { getCountries, @@ -18,5 +24,11 @@ export { getCredentialTypeSchemas, getPresentationRequest, submitPresentation, - getCredentialManifest + getCredentialManifestByDeepLink, + getCredentialManifestByService, + generateOffers, + finalizeOffers, + checkOffers, + searchForOrganizations, + generateDidJwk }; \ No newline at end of file diff --git a/packages/sample-app/src/screens/MeinScreen.tsx b/packages/sample-app/src/screens/MeinScreen.tsx index 2a45b16..e319e81 100644 --- a/packages/sample-app/src/screens/MeinScreen.tsx +++ b/packages/sample-app/src/screens/MeinScreen.tsx @@ -11,36 +11,59 @@ import { getCredentialTypeSchemas, getCredentialTypes, getPresentationRequest, - submitPresentation, getCredentialManifest + submitPresentation, + getCredentialManifestByDeepLink, + getCredentialManifestByService, + generateOffers, + searchForOrganizations, + generateDidJwk, finalizeOffers, checkOffers } from "../repositories"; import { Constants } from "./Constants"; import { Dictionary } from "../Types"; +import { getApprovedRejectedOfferIdsMock } from "../utils/Utils"; + +let didJwk: Dictionary; +const initialization = async () => { + if (!didJwk) { + didJwk = await generateDidJwk({ + signatureAlgorithm: "P-256", + remoteCryptoServicesToken: null + }); + } + console.log('didJwk: ', didJwk); +}; + +// @ts-ignore +await initialization(); const onGetCountries = () => { - getCountries().then((response) => { - console.log(response); + getCountries().then((countries) => { + console.log('countries: ', countries); }).catch((error) => { console.log(error); }); }; + const onGetCredentialTypes = () => { - getCredentialTypes().then((response) => { - console.log(response); + getCredentialTypes().then((credentialTypes) => { + console.log('credential types: ', credentialTypes); }).catch((error) => { console.log(error); }); }; + const onGetCredentialTypeSchemas = () => { - getCredentialTypeSchemas().then((response) => { - console.log(response); + getCredentialTypeSchemas().then((credentialTypeSchemas) => { + console.log('credential typeSchemas: ', credentialTypeSchemas); }).catch((error) => { console.log(error); }); }; + const onGetPresentationRequest = () => { - getPresentationRequest(Constants.PresentationRequestDeepLinkStrDev) + getPresentationRequest({value: Constants.PresentationRequestDeepLinkStrDev} ) .then((presentationRequest) => { - console.log("Presentation Request received: ", presentationRequest); + console.log('presentation request: ', presentationRequest); onSubmitPresentation(presentationRequest); }) .catch((error) => { @@ -50,30 +73,87 @@ const onGetPresentationRequest = () => { const onSubmitPresentation = (presentationRequest: Dictionary) => { submitPresentation({ - 'verifiableCredentials': Constants.PresentationSelectionsList, - 'presentationRequest': presentationRequest + verifiableCredentials: Constants.PresentationSelectionsList, + presentationRequest: presentationRequest } - ).then((response) => { - console.log(response); + ).then((submissionResult) => { + console.log('submission result: ', submissionResult); }).catch((error) => { console.log(error); }); -} +}; const onGetCredentialManifestByDeepLink = () => { - getCredentialManifest(Constants.CredentialManifestDeepLinkStrDev).then((credentialManifest) => { - console.log(credentialManifest); + getCredentialManifestByDeepLink( + { value: Constants.CredentialManifestDeepLinkStrDev } + ).then((credentialManifest) => { + console.log('credential manifest: ', credentialManifest); + onGenerateOffers(credentialManifest); }).catch((error) => { console.log(error); }); -} - -const gonGetCredentialManifestByDeepLink = () => { - onGetCredentialManifestByDeepLink() }; + const onGetOrganizationsThenCredentialManifestByService = () => { - alert(`You clicked on getOrganizationsThenCredentialManifestByService`); + searchForOrganizations({ + filter: { 'did': Constants.DidDev } + }).then((organizations) => { + console.log('organizations: ', organizations); + const serviceCredentialAgentIssuer = organizations.all[0].payload.service[0]; + getCredentialManifestByService({ + service: serviceCredentialAgentIssuer, + issuingType: 'Career', + credentialTypes: [serviceCredentialAgentIssuer.type], // Can come from any where + didJwk: didJwk + }).then((credentialManifest) => { + console.log('credential manifest: ', credentialManifest); + onGenerateOffers(credentialManifest); + }).catch((error) => { + console.log(error); + }); + }).catch((error) => { + console.log(error); + }); +} + +const onGenerateOffers = (credentialManifest: Dictionary) => { + const generateOffersDescriptor = { + credentialManifest: credentialManifest, + types: Constants.CredentialTypes, + identificationVerifiableCredentials: Constants.IdentificationList + } + generateOffers(generateOffersDescriptor).then((offers) => { + console.log('generate offers: ', offers); + onCheckOffers(generateOffersDescriptor, offers.sessionToken) + }).catch((error) => { + console.log(error); + }) }; + +const onCheckOffers = (generateOffersDescriptor: Dictionary, sessionToken: Dictionary) => { + checkOffers(generateOffersDescriptor, sessionToken).then((offers) => { + console.log('check offers: ', offers); + onFinalizeOffers(generateOffersDescriptor.credentialManifest, offers); + }).catch((error) => { + console.log(error); + }); +} + +const onFinalizeOffers = (credentialManifest: Dictionary, offers: Dictionary) => { + const approvedRejectedOfferIds = getApprovedRejectedOfferIdsMock(offers) + const finalizeOffersDescriptor = { + credentialManifest: credentialManifest, + challenge: offers.challenge, + approvedOfferIds: approvedRejectedOfferIds[0], + rejectedOfferIds: approvedRejectedOfferIds[1] + } + finalizeOffers(finalizeOffersDescriptor, offers.sessionToken).then((credentials) => { + console.log('credentials: ', credentials); + }).catch((error) => { + console.log(error); + }); +} + const onGetCredentialTypesUIFormSchema = () => { alert(`You clicked on getCredentialTypesUIFormSchema`); }; @@ -99,7 +179,7 @@ const MeinScreen: React.FC = () => { 'Get Credential Types': onGetCredentialTypes, 'Get Credential Type Schemas': onGetCredentialTypeSchemas, 'Disclosing Credentials (aka Inspection)': onGetPresentationRequest, - 'Receiving Credentials (aka Issuing) By Deeplink': gonGetCredentialManifestByDeepLink, + 'Receiving Credentials (aka Issuing) By Deeplink': onGetCredentialManifestByDeepLink, 'Receiving Credentials (aka Issuing) By Services': onGetOrganizationsThenCredentialManifestByService, 'Self Reporting Credentials (aka Self Attested)': onGetCredentialTypesUIFormSchema, 'Refresh Credentials': onRefreshCredentials, diff --git a/packages/sample-app/src/utils/Utils.ts b/packages/sample-app/src/utils/Utils.ts new file mode 100644 index 0000000..e49b912 --- /dev/null +++ b/packages/sample-app/src/utils/Utils.ts @@ -0,0 +1,35 @@ +/** + * Created by Michael Avoyan on 10/07/2024. + * + * Copyright 2022 Velocity Career Labs inc. + * SPDX-License-Identifier: Apache-2.0 + */ +import { Dictionary } from "../Types"; + +export const getApprovedRejectedOfferIdsMock = (offers: Dictionary): [string[], string[]] => { + const approvedOfferIds: string[] = []; + const rejectedOfferIds: string[] = []; + let offer1: string | null = null; + let offer2: string | null = null; + let offer3: string | null = null; + + if (offers.all.length > 0) { + offer1 = offers.all[0].payload.id; + } + if (offers.all.length > 1) { + offer2 = offers.all[1].payload.id; + } + if (offers.all.length > 2) { + offer3 = offers.all[2].payload.id; + } + if (offer1 !== null) { + approvedOfferIds.push(offer1); + } + if (offer2 !== null) { + approvedOfferIds.push(offer2); + } + if (offer3 !== null) { + rejectedOfferIds.push(offer3); + } + return [approvedOfferIds, rejectedOfferIds]; +}; diff --git a/packages/sample-server/src/controllers/CheckForOffers.ts b/packages/sample-server/src/controllers/CheckForOffers.ts index 40dfd9b..0ab38b6 100644 --- a/packages/sample-server/src/controllers/CheckForOffers.ts +++ b/packages/sample-server/src/controllers/CheckForOffers.ts @@ -10,7 +10,7 @@ import { generateOffersDescriptorFromJson, tokenFromString } from "../utils/Conv export async function checkForOffers(req, reply) { try { const offers = await req.vclSdk.checkForOffers( - generateOffersDescriptorFromJson(req.body), + generateOffersDescriptorFromJson(req.body.generateOffersDescriptor), tokenFromString(req.body.sessionToken.value) ); reply.send(offers); diff --git a/packages/sample-server/src/controllers/FinalizeOffers.ts b/packages/sample-server/src/controllers/FinalizeOffers.ts index b6c0c2a..e03a469 100644 --- a/packages/sample-server/src/controllers/FinalizeOffers.ts +++ b/packages/sample-server/src/controllers/FinalizeOffers.ts @@ -10,8 +10,8 @@ import { finalizeOffersDescriptorFromJson, tokenFromString } from "../utils/Conv export async function finalizeOffers(req, reply) { try { const jwtVerifiableCredentials = await req.vclSdk.finalizeOffers( - finalizeOffersDescriptorFromJson(req.body), - tokenFromString(req.body.sessionToken) + finalizeOffersDescriptorFromJson(req.body.finalizeOffersDescriptor), + tokenFromString(req.body.sessionToken.value) ); reply.send(jwtVerifiableCredentials); } catch (e: any) { diff --git a/packages/sample-server/src/controllers/GenerateOffers.ts b/packages/sample-server/src/controllers/GenerateOffers.ts index 155b11d..6b00174 100644 --- a/packages/sample-server/src/controllers/GenerateOffers.ts +++ b/packages/sample-server/src/controllers/GenerateOffers.ts @@ -9,7 +9,7 @@ import { generateOffersDescriptorFromJson } from "../utils/Converter"; export async function generateOffers(req, reply) { try { const offers = await req.vclSdk.generateOffers( - generateOffersDescriptorFromJson(req.body), + generateOffersDescriptorFromJson(req.body.generateOffersDescriptor), ); reply.send(offers); } catch (e: any) { diff --git a/packages/sample-server/src/test-apis/GenerateDidJwkTest.http b/packages/sample-server/src/test-apis/GenerateDidJwkTest.http index 9a0697f..74b141c 100644 --- a/packages/sample-server/src/test-apis/GenerateDidJwkTest.http +++ b/packages/sample-server/src/test-apis/GenerateDidJwkTest.http @@ -3,7 +3,7 @@ POST http://localhost:5000/generateDidJwk HTTP/1.1 Content-Type: application/json { - "jwkDescriptor": { + "didJwkDescriptor": { "signatureAlgorithm": "P-256", "remoteCryptoServicesToken": null }