-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Created an issuer verification of an EBSI issued credential #236
base: develop
Are you sure you want to change the base?
Changes from 4 commits
333b395
402e250
cab5464
a55c186
bb7cee0
46624fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import {verifyEBSICredentialIssuer} from "../src/agent/OID4VCIHolder"; | ||
import {CredentialMapper} from "@sphereon/ssi-types"; | ||
|
||
const nock = require("nock") | ||
|
||
const BASE_URL = 'https://api-conformance.ebsi.eu' | ||
const GET_VALID_ISSUER_URI = '/trusted-issuers-registry/v4/issuers/did:ebsi:ziDnioxYYLW1a3qUbqTFz4W' | ||
const GET_INVALID_ISSUER_URI = '/trusted-issuers-registry/v4/issuers/invalid_issuer' | ||
|
||
describe('EBSI Functions', () => { | ||
describe('verifyEBSICredentialIssuer', () => { | ||
|
||
const validIssuerResult = { | ||
did: "did:ebsi:ziDnioxYYLW1a3qUbqTFz4W", | ||
attributes: [{ | ||
hash: "test", | ||
body: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxODNkY2E4NDRiNzM5OGM4MTQ0ZTJiMzk5OWM3MzA2Y2I3OTYzMDJhZWQxNDdkNjY4ZmI2ZmI5YmE0OTZkNTBkIiwiYWxnIjoiRVMyNTZLIn0.eyJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aURuaW94WVlMVzFhM3FVYnFURno0VyIsImlhdCI6MTcxNDQxMzA4OCwianRpIjoidXJuOnV1aWQ6NWZiN2Q5OGItMTA4Yy00YmMwLTlmZmMtYzY5Zjg0ZWQ3ODhmIiwibmJmIjoxNzE0NDEzMDg4LCJleHAiOjE3NDU5NDkwODgsInN1YiI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDo1ZmI3ZDk4Yi0xMDhjLTRiYzAtOWZmYy1jNjlmODRlZDc4OGYiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZUF1dGhvcmlzYXRpb25Ub09uYm9hcmQiXSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNC0yOVQxNzo1MToyOFoiLCJpc3N1ZWQiOiIyMDI0LTA0LTI5VDE3OjUxOjI4WiIsInZhbGlkRnJvbSI6IjIwMjQtMDQtMjlUMTc6NTE6MjhaIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTA0LTI5VDE3OjUxOjI4WiIsImlzc3VlciI6ImRpZDplYnNpOnppRG5pb3hZWUxXMWEzcVVicVRGejRXIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZWJzaTp6ZXliQWlKeHpVVXJXUTFZTTUxU1kzNSIsImFjY3JlZGl0ZWRGb3IiOltdfSwidGVybXNPZlVzZSI6eyJpZCI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidHlwZSI6Iklzc3VhbmNlQ2VydGlmaWNhdGUifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLXBpbG90LmVic2kuZXUvdHJ1c3RlZC1zY2hlbWFzLXJlZ2lzdHJ5L3YyL3NjaGVtYXMvejNNZ1VGVWtiNzIydXE0eDNkdjV5QUptbk5tekRGZUs1VUM4eDgzUW9lTEpNIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fX0.QWNWTWlrbUpLcFJaLVBGczQ0U3Mxb200Mk4yb3JzWndsTXp3REpHTTMxSUM2WG5ZVXJ0ZlY4RHFTbVQtaXBIMEdLSDZhclFEcGtrbXZTTy1NenYxWEE", | ||
issuerType: "RootTAO", | ||
tao: "did:ebsi:zeybAiJxzUUrWQ1YM51SY35", | ||
rootTao: "did:ebsi:ziDnioxYYLW1a3qUbqTFz4W" | ||
}] | ||
} | ||
|
||
const notIssuerResult = { | ||
did: "did:ebsi:ziDnioxYYLW1a3qUbqTFz4W", | ||
attributes: [{ | ||
hash: "test", | ||
body: "eyJ0eXAiOiJKV1QiLCJraWQiOiIxODNkY2E4NDRiNzM5OGM4MTQ0ZTJiMzk5OWM3MzA2Y2I3OTYzMDJhZWQxNDdkNjY4ZmI2ZmI5YmE0OTZkNTBkIiwiYWxnIjoiRVMyNTZLIn0.eyJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aURuaW94WVlMVzFhM3FVYnFURno0VyIsImlhdCI6MTcxNDQxMzA4OCwianRpIjoidXJuOnV1aWQ6NWZiN2Q5OGItMTA4Yy00YmMwLTlmZmMtYzY5Zjg0ZWQ3ODhmIiwibmJmIjoxNzE0NDEzMDg4LCJleHAiOjE3NDU5NDkwODgsInN1YiI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDo1ZmI3ZDk4Yi0xMDhjLTRiYzAtOWZmYy1jNjlmODRlZDc4OGYiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZUF1dGhvcmlzYXRpb25Ub09uYm9hcmQiXSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNC0yOVQxNzo1MToyOFoiLCJpc3N1ZWQiOiIyMDI0LTA0LTI5VDE3OjUxOjI4WiIsInZhbGlkRnJvbSI6IjIwMjQtMDQtMjlUMTc6NTE6MjhaIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTA0LTI5VDE3OjUxOjI4WiIsImlzc3VlciI6ImRpZDplYnNpOnppRG5pb3hZWUxXMWEzcVVicVRGejRXIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZWJzaTp6ZXliQWlKeHpVVXJXUTFZTTUxU1kzNSIsImFjY3JlZGl0ZWRGb3IiOltdfSwidGVybXNPZlVzZSI6eyJpZCI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidHlwZSI6Iklzc3VhbmNlQ2VydGlmaWNhdGUifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLXBpbG90LmVic2kuZXUvdHJ1c3RlZC1zY2hlbWFzLXJlZ2lzdHJ5L3YyL3NjaGVtYXMvejNNZ1VGVWtiNzIydXE0eDNkdjV5QUptbk5tekRGZUs1VUM4eDgzUW9lTEpNIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fX0.QWNWTWlrbUpLcFJaLVBGczQ0U3Mxb200Mk4yb3JzWndsTXp3REpHTTMxSUM2WG5ZVXJ0ZlY4RHFTbVQtaXBIMEdLSDZhclFEcGtrbXZTTy1NenYxWEE", | ||
issuerType: "Revoked or Undefined", | ||
tao: "did:ebsi:zeybAiJxzUUrWQ1YM51SY35", | ||
rootTao: "did:ebsi:ziDnioxYYLW1a3qUbqTFz4W" | ||
}] | ||
} | ||
|
||
it(`should return the issuer's did and attributes if the issuer is valid`, async () => { | ||
nock(BASE_URL) | ||
.get(GET_VALID_ISSUER_URI) | ||
.reply(200, JSON.stringify(validIssuerResult)) | ||
await expect(verifyEBSICredentialIssuer({ | ||
wrappedVc: CredentialMapper.toWrappedVerifiableCredential("eyJ0eXAiOiJKV1QiLCJraWQiOiIxODNkY2E4NDRiNzM5OGM4MTQ0ZTJiMzk5OWM3MzA2Y2I3OTYzMDJhZWQxNDdkNjY4ZmI2ZmI5YmE0OTZkNTBkIiwiYWxnIjoiRVMyNTZLIn0.eyJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aURuaW94WVlMVzFhM3FVYnFURno0VyIsImlhdCI6MTcxNDQxMzA4OCwianRpIjoidXJuOnV1aWQ6NWZiN2Q5OGItMTA4Yy00YmMwLTlmZmMtYzY5Zjg0ZWQ3ODhmIiwibmJmIjoxNzE0NDEzMDg4LCJleHAiOjE3NDU5NDkwODgsInN1YiI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDo1ZmI3ZDk4Yi0xMDhjLTRiYzAtOWZmYy1jNjlmODRlZDc4OGYiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZUF1dGhvcmlzYXRpb25Ub09uYm9hcmQiXSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNC0yOVQxNzo1MToyOFoiLCJpc3N1ZWQiOiIyMDI0LTA0LTI5VDE3OjUxOjI4WiIsInZhbGlkRnJvbSI6IjIwMjQtMDQtMjlUMTc6NTE6MjhaIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTA0LTI5VDE3OjUxOjI4WiIsImlzc3VlciI6ImRpZDplYnNpOnppRG5pb3hZWUxXMWEzcVVicVRGejRXIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZWJzaTp6ZXliQWlKeHpVVXJXUTFZTTUxU1kzNSIsImFjY3JlZGl0ZWRGb3IiOltdfSwidGVybXNPZlVzZSI6eyJpZCI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidHlwZSI6Iklzc3VhbmNlQ2VydGlmaWNhdGUifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLXBpbG90LmVic2kuZXUvdHJ1c3RlZC1zY2hlbWFzLXJlZ2lzdHJ5L3YyL3NjaGVtYXMvejNNZ1VGVWtiNzIydXE0eDNkdjV5QUptbk5tekRGZUs1VUM4eDgzUW9lTEpNIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fX0.QWNWTWlrbUpLcFJaLVBGczQ0U3Mxb200Mk4yb3JzWndsTXp3REpHTTMxSUM2WG5ZVXJ0ZlY4RHFTbVQtaXBIMEdLSDZhclFEcGtrbXZTTy1NenYxWEE") | ||
})).resolves.toEqual(validIssuerResult) | ||
}) | ||
|
||
it(`should return undefined if the issuer type is not RootTAO, TAO or TI`, async () => { | ||
nock(BASE_URL) | ||
.get(GET_VALID_ISSUER_URI) | ||
.reply(200, JSON.stringify(notIssuerResult)) | ||
await expect(verifyEBSICredentialIssuer({ | ||
wrappedVc: CredentialMapper.toWrappedVerifiableCredential("eyJ0eXAiOiJKV1QiLCJraWQiOiIxODNkY2E4NDRiNzM5OGM4MTQ0ZTJiMzk5OWM3MzA2Y2I3OTYzMDJhZWQxNDdkNjY4ZmI2ZmI5YmE0OTZkNTBkIiwiYWxnIjoiRVMyNTZLIn0.eyJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aURuaW94WVlMVzFhM3FVYnFURno0VyIsImlhdCI6MTcxNDQxMzA4OCwianRpIjoidXJuOnV1aWQ6NWZiN2Q5OGItMTA4Yy00YmMwLTlmZmMtYzY5Zjg0ZWQ3ODhmIiwibmJmIjoxNzE0NDEzMDg4LCJleHAiOjE3NDU5NDkwODgsInN1YiI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDo1ZmI3ZDk4Yi0xMDhjLTRiYzAtOWZmYy1jNjlmODRlZDc4OGYiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZUF1dGhvcmlzYXRpb25Ub09uYm9hcmQiXSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNC0yOVQxNzo1MToyOFoiLCJpc3N1ZWQiOiIyMDI0LTA0LTI5VDE3OjUxOjI4WiIsInZhbGlkRnJvbSI6IjIwMjQtMDQtMjlUMTc6NTE6MjhaIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTA0LTI5VDE3OjUxOjI4WiIsImlzc3VlciI6ImRpZDplYnNpOnppRG5pb3hZWUxXMWEzcVVicVRGejRXIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZWJzaTp6ZXliQWlKeHpVVXJXUTFZTTUxU1kzNSIsImFjY3JlZGl0ZWRGb3IiOltdfSwidGVybXNPZlVzZSI6eyJpZCI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidHlwZSI6Iklzc3VhbmNlQ2VydGlmaWNhdGUifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLXBpbG90LmVic2kuZXUvdHJ1c3RlZC1zY2hlbWFzLXJlZ2lzdHJ5L3YyL3NjaGVtYXMvejNNZ1VGVWtiNzIydXE0eDNkdjV5QUptbk5tekRGZUs1VUM4eDgzUW9lTEpNIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fX0.QWNWTWlrbUpLcFJaLVBGczQ0U3Mxb200Mk4yb3JzWndsTXp3REpHTTMxSUM2WG5ZVXJ0ZlY4RHFTbVQtaXBIMEdLSDZhclFEcGtrbXZTTy1NenYxWEE") | ||
})).rejects.toBeUndefined() | ||
}) | ||
|
||
it(`should return undefined if the issuer's did is not provided`, async () => { | ||
await expect(verifyEBSICredentialIssuer({ | ||
wrappedVc: CredentialMapper.toWrappedVerifiableCredential("eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjE4M2RjYTg0NGI3Mzk4YzgxNDRlMmIzOTk5YzczMDZjYjc5NjMwMmFlZDE0N2Q2NjhmYjZmYjliYTQ5NmQ1MGQifQ.eyJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aURuaW94WVlMVzFhM3FVYnFURno0VyIsImlhdCI6MTcxNDQxMzA4OCwianRpIjoidXJuOnV1aWQ6NWZiN2Q5OGItMTA4Yy00YmMwLTlmZmMtYzY5Zjg0ZWQ3ODhmIiwibmJmIjoxNzE0NDEzMDg4LCJleHAiOjE3NDU5NDkwODgsInN1YiI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDo1ZmI3ZDk4Yi0xMDhjLTRiYzAtOWZmYy1jNjlmODRlZDc4OGYiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZUF1dGhvcmlzYXRpb25Ub09uYm9hcmQiXSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNC0yOVQxNzo1MToyOFoiLCJpc3N1ZWQiOiIyMDI0LTA0LTI5VDE3OjUxOjI4WiIsInZhbGlkRnJvbSI6IjIwMjQtMDQtMjlUMTc6NTE6MjhaIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTA0LTI5VDE3OjUxOjI4WiIsImlzc3VlciI6IiIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmVic2k6emV5YkFpSnh6VVVyV1ExWU01MVNZMzUiLCJhY2NyZWRpdGVkRm9yIjpbXX0sInRlcm1zT2ZVc2UiOnsiaWQiOiJkaWQ6ZWJzaTp6ZXliQWlKeHpVVXJXUTFZTTUxU1kzNSIsInR5cGUiOiJJc3N1YW5jZUNlcnRpZmljYXRlIn0sImNyZWRlbnRpYWxTY2hlbWEiOnsiaWQiOiJodHRwczovL2FwaS1waWxvdC5lYnNpLmV1L3RydXN0ZWQtc2NoZW1hcy1yZWdpc3RyeS92Mi9zY2hlbWFzL3ozTWdVRlVrYjcyMnVxNHgzZHY1eUFKbW5ObXpERmVLNVVDOHg4M1FvZUxKTSIsInR5cGUiOiJGdWxsSnNvblNjaGVtYVZhbGlkYXRvcjIwMjEifX19.OFcZ-7iqoP_LmxTWqM9rR4aOK8VPyKyRJ2R8MD6m1jT2LzyqMVKzX__EF6e0ghs73l-nVtJBIu28QFsMFxAODg") | ||
})).rejects.toBeUndefined() | ||
}) | ||
|
||
it(`should return undefined if the issuer's did is invalid`, async () => { | ||
nock(BASE_URL).get(GET_INVALID_ISSUER_URI).reply(400) | ||
await expect(verifyEBSICredentialIssuer({ | ||
wrappedVc: CredentialMapper.toWrappedVerifiableCredential("eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjE4M2RjYTg0NGI3Mzk4YzgxNDRlMmIzOTk5YzczMDZjYjc5NjMwMmFlZDE0N2Q2NjhmYjZmYjliYTQ5NmQ1MGQifQ.eyJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aURuaW94WVlMVzFhM3FVYnFURno0VyIsImlhdCI6MTcxNDQxMzA4OCwianRpIjoidXJuOnV1aWQ6NWZiN2Q5OGItMTA4Yy00YmMwLTlmZmMtYzY5Zjg0ZWQ3ODhmIiwibmJmIjoxNzE0NDEzMDg4LCJleHAiOjE3NDU5NDkwODgsInN1YiI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDo1ZmI3ZDk4Yi0xMDhjLTRiYzAtOWZmYy1jNjlmODRlZDc4OGYiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZUF1dGhvcmlzYXRpb25Ub09uYm9hcmQiXSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNC0yOVQxNzo1MToyOFoiLCJpc3N1ZWQiOiIyMDI0LTA0LTI5VDE3OjUxOjI4WiIsInZhbGlkRnJvbSI6IjIwMjQtMDQtMjlUMTc6NTE6MjhaIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTA0LTI5VDE3OjUxOjI4WiIsImlzc3VlciI6ImludmFsaWRfaXNzdWVyIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZWJzaTp6ZXliQWlKeHpVVXJXUTFZTTUxU1kzNSIsImFjY3JlZGl0ZWRGb3IiOltdfSwidGVybXNPZlVzZSI6eyJpZCI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidHlwZSI6Iklzc3VhbmNlQ2VydGlmaWNhdGUifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLXBpbG90LmVic2kuZXUvdHJ1c3RlZC1zY2hlbWFzLXJlZ2lzdHJ5L3YyL3NjaGVtYXMvejNNZ1VGVWtiNzIydXE0eDNkdjV5QUptbk5tekRGZUs1VUM4eDgzUW9lTEpNIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fX0.r0kAeMRrwn8lQNJakAmfWRtLmRQdRbULNjbbvTPsirpVGmN5O0V9O7eQ7_S4sHTF8p_AShSanv4MLvtRfCvg1A") | ||
})).rejects.toBeUndefined() | ||
}) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,7 +59,7 @@ import { OID4VCIMachine } from '../machine/oid4vciMachine' | |
import { | ||
AddContactIdentityArgs, | ||
AddIssuerBrandingArgs, | ||
AssertValidCredentialsArgs, | ||
AssertValidCredentialsArgs, Attribute, | ||
createCredentialsToSelectFromArgs, | ||
CredentialToAccept, | ||
CredentialToSelectFromResult, | ||
|
@@ -84,7 +84,7 @@ import { | |
StartResult, | ||
StoreCredentialBrandingArgs, | ||
StoreCredentialsArgs, | ||
VerificationResult, | ||
VerificationResult, VerifyEBSICredentialIssuerArgs, VerifyEBSICredentialIssuerResult, | ||
} from '../types/IOID4VCIHolder' | ||
import { | ||
getBasicIssuerLocaleBranding, | ||
|
@@ -97,6 +97,7 @@ import { | |
verifyCredentialToAccept, | ||
} from './OID4VCIHolderService' | ||
|
||
import 'cross-fetch/polyfill' | ||
/** | ||
* {@inheritDoc IOID4VCIHolder} | ||
*/ | ||
|
@@ -189,6 +190,30 @@ export function signCallback( | |
} | ||
} | ||
|
||
export async function verifyEBSICredentialIssuer(args: VerifyEBSICredentialIssuerArgs): Promise<VerifyEBSICredentialIssuerResult | undefined> { | ||
const { wrappedVc } = args | ||
|
||
const issuer = wrappedVc.decoded?.iss ?? (typeof wrappedVc.decoded?.vc?.issuer === 'string' ? wrappedVc.decoded?.vc?.issuer : wrappedVc.decoded?.vc?.issuer?.existingInstanceId) | ||
|
||
if (!issuer) { | ||
return Promise.reject(undefined) | ||
} | ||
|
||
const url = `https://api-conformance.ebsi.eu/trusted-issuers-registry/v4/issuers/${issuer}`; | ||
const response = await fetch(url) | ||
if (response.status !== 200) { | ||
return Promise.reject(undefined) | ||
} | ||
|
||
const payload = await response.json() | ||
|
||
if (!payload.attributes.some((a: Attribute) => ['RootTAO', 'TAO', 'TI'].includes(a.issuerType))) { | ||
return Promise.reject(undefined) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes no sense. Provide a proper error. Also I believe the type should be an optional argument as well. If I want to only verify a party to be a trusted issuer I need to be able to provide TI as a single array value. If I want more types I should be able to provide these as well. The default should be TI and a TI only There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refactored error handling and moved issuer type to a parameter |
||
} | ||
|
||
return payload | ||
} | ||
|
||
export class OID4VCIHolder implements IAgentPlugin { | ||
readonly eventTypes: Array<OID4VCIHolderEvent> = [ | ||
OID4VCIHolderEvent.CONTACT_IDENTITY_CREATED, | ||
|
@@ -235,12 +260,14 @@ export class OID4VCIHolder implements IAgentPlugin { | |
private readonly onContactIdentityCreated?: (args: OnContactIdentityCreatedArgs) => Promise<void> | ||
private readonly onCredentialStored?: (args: OnCredentialStoredArgs) => Promise<void> | ||
private readonly onIdentifierCreated?: (args: OnIdentifierCreatedArgs) => Promise<void> | ||
private readonly onVerifyEBSICredentialIssuer?: (args: VerifyEBSICredentialIssuerArgs) => Promise<VerifyEBSICredentialIssuerResult> | ||
|
||
constructor(options?: OID4VCIHolderOptions) { | ||
const { | ||
onContactIdentityCreated, | ||
onCredentialStored, | ||
onIdentifierCreated, | ||
onVerifyEBSICredentialIssuer, | ||
vcFormatPreferences, | ||
jsonldCryptographicSuitePreferences, | ||
didMethodPreferences, | ||
|
@@ -266,6 +293,7 @@ export class OID4VCIHolder implements IAgentPlugin { | |
this.onContactIdentityCreated = onContactIdentityCreated | ||
this.onCredentialStored = onCredentialStored | ||
this.onIdentifierCreated = onIdentifierCreated | ||
this.onVerifyEBSICredentialIssuer = onVerifyEBSICredentialIssuer | ||
} | ||
|
||
public async onEvent(event: any, context: RequiredContext): Promise<void> { | ||
|
@@ -745,6 +773,7 @@ export class OID4VCIHolder implements IAgentPlugin { | |
credentialsToAccept.map((credentialToAccept) => | ||
verifyCredentialToAccept({ | ||
mappedCredential: credentialToAccept, | ||
onVerifyEBSICredentialIssuer: this.onVerifyEBSICredentialIssuer, | ||
context, | ||
}), | ||
), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -119,7 +119,7 @@ export const selectCredentialLocaleBranding = async ( | |
} | ||
|
||
export const verifyCredentialToAccept = async (args: VerifyCredentialToAcceptArgs): Promise<VerificationResult> => { | ||
const { mappedCredential, hasher, context } = args | ||
const { mappedCredential, hasher, onVerifyEBSICredentialIssuer, context } = args | ||
|
||
const credential = mappedCredential.credentialToAccept.credentialResponse.credential as OriginalVerifiableCredential | ||
if (!credential) { | ||
|
@@ -139,6 +139,15 @@ export const verifyCredentialToAccept = async (args: VerifyCredentialToAcceptArg | |
} | ||
} | ||
|
||
if (onVerifyEBSICredentialIssuer) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And where is the code that only applies this if we encounter actual EBSI issuers? You cannot just assume EBSI and only EBSI or not of course. A wallet or RP can be member of many ecosystems There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved it to the if clause to make sure the code will only execute for an EBSI issuer |
||
const response = await onVerifyEBSICredentialIssuer({ | ||
wrappedVc: wrappedVC | ||
}) | ||
if (!response) { | ||
return Promise.reject(Error('The issuer of the EBSI credential cannot be trusted.')) | ||
} | ||
} | ||
|
||
const verificationResult: VerificationResult = await verifyCredential( | ||
{ | ||
credential, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you using an approach that we have never used?
Return a promise reject with an error so you do not have to list undefined as a result type. Or resolve undefined if that is an okay outcome. Not a reject with undefined. That makes no sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored error handling