Skip to content

Commit

Permalink
cont
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelavoyan committed Jul 11, 2024
1 parent 9b6f2cb commit 8b821f3
Show file tree
Hide file tree
Showing 14 changed files with 298 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -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<any>,
didJwk: Dictionary<any>
): Promise<any> => {
const config = {
url: Urls.generateSignedJwt,
method: 'POST',
data: { jwtDescriptor, didJwk },
};
return await fetcher(config);
}
Original file line number Diff line number Diff line change
@@ -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<any>
): Promise<Dictionary<any>> => {
const config = {
url: Urls.getCredentialManifest,
method: 'POST',
data: credentialManifestDescriptorRefresh,
};
return await fetcher(config);
}
Original file line number Diff line number Diff line change
@@ -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<any>
): Promise<any> => {
const config = {
url: Urls.getCredentialTypesUIFormSchema,
method: 'POST',
data: credentialTypesUIFormSchemaDescriptor,
};
return await fetcher(config);
}
Original file line number Diff line number Diff line change
@@ -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<any>
): Promise<any> => {
const config = {
url: Urls.getVerifiedProfile,
method: 'POST',
data: verifiedProfileDescriptor,
};
return await fetcher(config);
}
21 changes: 21 additions & 0 deletions packages/sample-app/src/repositories/VerifyJwtRepository.ts
Original file line number Diff line number Diff line change
@@ -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<any>,
publicJwk: Dictionary<any>
): Promise<any> => {
const config = {
url: Urls.verifyJwt,
method: 'POST',
data: { jwt, publicJwk },
};
return await fetcher(config);
}
12 changes: 11 additions & 1 deletion packages/sample-app/src/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -26,9 +31,14 @@ export {
submitPresentation,
getCredentialManifestByDeepLink,
getCredentialManifestByService,
getCredentialManifestToRefreshCredentials,
generateOffers,
finalizeOffers,
checkOffers,
searchForOrganizations,
generateDidJwk
generateDidJwk,
getCredentialTypesUIFormSchema,
getVerifiedProfile,
verifyJwt,
generateSignedJwt
};
4 changes: 2 additions & 2 deletions packages/sample-app/src/screens/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down Expand Up @@ -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" }',
};
Expand Down
70 changes: 62 additions & 8 deletions packages/sample-app/src/screens/MeinScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -155,22 +162,69 @@ const onFinalizeOffers = (credentialManifest: Dictionary<any>, 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 = () => {
Expand Down
5 changes: 3 additions & 2 deletions packages/sample-server/src/routes/Routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
jwtFromJson,
organizationsSearchDescriptorFrom,
presentationRequestDescriptorFrom,
presentationSubmissionFrom, publicJwkFrom,
presentationSubmissionFrom,
publicJwkFrom,
submissionResultFrom,
tokenFrom,
verifiedProfileDescriptorFrom
Expand Down Expand Up @@ -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)
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -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"
}
}
Loading

0 comments on commit 8b821f3

Please sign in to comment.