Skip to content

Commit

Permalink
feat: EBSI DID registraiton/management
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed Jul 2, 2024
1 parent 70e41d7 commit 7195786
Show file tree
Hide file tree
Showing 57 changed files with 1,622 additions and 1,195 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,4 @@ test/*.js
**/.env.local
/packages/web3-provider-headless/__tests__/config.json
/packages/event-logger/plugin.schema.json
/packages/public-key-hosting/__tests__/database/test.sqlite
4 changes: 2 additions & 2 deletions packages/contact-manager-rest-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
},
"dependencies": {
"@sphereon/ssi-express-support": "workspace:*",
"@sphereon/ssi-sdk-ext.key-manager": "0.21.1-next.16",
"@sphereon/ssi-sdk-ext.key-utils": "0.21.1-next.16",
"@sphereon/ssi-sdk-ext.key-manager": "0.21.1-next.19",
"@sphereon/ssi-sdk-ext.key-utils": "0.21.1-next.19",
"@sphereon/ssi-sdk.contact-manager": "workspace:*",
"@sphereon/ssi-sdk.core": "workspace:*",
"@sphereon/ssi-sdk.data-store": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion packages/data-store/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@sphereon/pex": "^3.3.3",
"@sphereon/ssi-sdk.core": "workspace:*",
"@sphereon/ssi-types": "workspace:*",
"@sphereon/ssi-sdk-ext.did-utils": "^0.21.0",
"@sphereon/ssi-sdk-ext.did-utils": "0.21.1-next.19",
"@veramo/core": "4.2.0",
"@veramo/utils": "4.2.0",
"blakejs": "^1.1.1",
Expand Down
304 changes: 186 additions & 118 deletions packages/ebsi-support/__tests__/attestation.test.ts
Original file line number Diff line number Diff line change
@@ -1,147 +1,215 @@
import {CreateRequestObjectMode} from '@sphereon/oid4vci-common'
import {toJwk} from '@sphereon/ssi-sdk-ext.key-utils'
import {createObjects, getConfig} from '@sphereon/ssi-sdk.agent-config'
import {IContactManager} from '@sphereon/ssi-sdk.contact-manager'
import {IOID4VCIHolder} from '@sphereon/ssi-sdk.oid4vci-holder'
import {IPresentationExchange} from '@sphereon/ssi-sdk.presentation-exchange'
import {IDidAuthSiopOpAuthenticator} from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
import {IDIDManager, IIdentifier, IKeyManager, IResolver, MinimalImportableKey, TAgent} from '@veramo/core'
import { ExpressBuilder } from '@sphereon/ssi-express-support'
import { createObjects, getConfig } from '@sphereon/ssi-sdk.agent-config'
import { IContactManager } from '@sphereon/ssi-sdk.contact-manager'
import { IOID4VCIHolder } from '@sphereon/ssi-sdk.oid4vci-holder'
import { IPresentationExchange } from '@sphereon/ssi-sdk.presentation-exchange'
import { PublicKeyHosting } from '@sphereon/ssi-sdk.public-key-hosting'
import { jwksURIFromIdentifier } from '@sphereon/ssi-sdk.public-key-hosting/dist/functions'
import { IDidAuthSiopOpAuthenticator } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
import { IDIDManager, IIdentifier, IKeyManager, IResolver, MinimalImportableKey, TAgent } from '@veramo/core'
// @ts-ignore
import cors from 'cors'

// @ts-ignore
import express, {Express} from 'express'
import {Server} from 'http'
import {DataSource} from 'typeorm'
import {IEbsiSupport} from '../src'
import {AttestationAuthRequestUrlResult} from '../src/functions'
import express, { Express } from 'express'
import { DataSource } from 'typeorm'
import { IEbsiSupport } from '../src'
import { ebsiCreateDidOnLedger } from '../src/did'
// import { AttestationAuthRequestUrlResult } from '../src/functions'

let dbConnection: Promise<DataSource>
let agent: TAgent<
IKeyManager & IDIDManager & IDidAuthSiopOpAuthenticator & IPresentationExchange & IOID4VCIHolder & IResolver & IContactManager & IEbsiSupport
IKeyManager & IDIDManager & IDidAuthSiopOpAuthenticator & IPresentationExchange & IOID4VCIHolder & IResolver & IContactManager & IEbsiSupport
>
let app: Express | undefined
/*let app: Express | undefined
let server: Server<any, any> | undefined
const port = 3333
const port = 3333*/
const secp256k1PrivateKey: MinimalImportableKey = {
privateKeyHex: '6e491660cf923f7d9ce4a03401444b361817df9e76b926b55e21ffe7144d2ee6',
kms: 'local',
type: 'Secp256k1',
meta: {
purposes: ['capabilityInvocation'],
},
privateKeyHex: '6e491660cf923f7d9ce4a03401444b361817df9e76b926b55e21ffe7144d2ee6',
kms: 'local',
type: 'Secp256k1',
meta: {
purposes: ['capabilityInvocation'],
},
}
const secp256k1Jwk = toJwk(secp256k1PrivateKey.privateKeyHex, 'Secp256k1', {isPrivateKey: true})
// const secp256k1Jwk = toJwk(secp256k1PrivateKey.privateKeyHex, 'Secp256k1', {isPrivateKey: true})

const secp256r1PrivateKey: MinimalImportableKey = {
privateKeyHex: 'f0710a0bb80c28a14ae62831bfe7f90a6937d006295fad6115e5539e7e314ee4',
kms: 'local',
type: 'Secp256r1',
meta: {
purposes: ['assertionMethod', 'authentication'],
},
privateKeyHex: 'f0710a0bb80c28a14ae62831bfe7f90a6937d006295fad6115e5539e7e314ee4',
kms: 'local',
type: 'Secp256r1',
meta: {
purposes: ['assertionMethod', 'authentication'],
},
}

const secp256r1Jwk = toJwk(secp256r1PrivateKey.privateKeyHex, 'Secp256r1', {isPrivateKey: true})
let authReqResult: AttestationAuthRequestUrlResult
// const secp256r1Jwk = toJwk(secp256r1PrivateKey.privateKeyHex, 'Secp256r1', { isPrivateKey: true })
// let authReqResult: AttestationAuthRequestUrlResult
const MOCK_BASE_URL = 'https://ebsi-sphereon.ngrok.dev' // `http://localhost:${port}`
jest.setTimeout(600000)

const setup = async (): Promise<boolean> => {
const config = await getConfig('packages/ebsi-support/agent.yml')
const {localAgent, db} = await createObjects(config, {localAgent: '/agent', db: '/dbConnection'})
agent = localAgent as TAgent<
IKeyManager & IDIDManager & IDidAuthSiopOpAuthenticator & IPresentationExchange & IOID4VCIHolder & IResolver & IContactManager & IEbsiSupport
>
dbConnection = db

app = express()
app.use(
cors({
origin: ['*'],
}),
)
app.use(express.json())

app.get('/', async (req: express.Request, res: express.Response) => {
res.send({hello: 'world'})
})

app.get('/.well-known/jwks', async (req: express.Request, res: express.Response) => {
res.send({keys: [{...secp256k1Jwk}, {...secp256r1Jwk}]})
})

console.log(`########## $${MOCK_BASE_URL}`)

server = app.listen(port, () => {
console.log(`Mock server is listening to port ${port}`)
})

return true
const config = await getConfig('packages/ebsi-support/agent.yml')
const { localAgent, db } = await createObjects(config, { localAgent: '/agent', db: '/dbConnection' })
agent = localAgent as TAgent<
IKeyManager & IDIDManager & IDidAuthSiopOpAuthenticator & IPresentationExchange & IOID4VCIHolder & IResolver & IContactManager & IEbsiSupport
>
dbConnection = db

/*
app = express()
app.use(
cors({
origin: ['*'],
}),
)
app.use(express.json())
app.get('/', async (req: express.Request, res: express.Response) => {
res.send({hello: 'world'})
})
app.get('/.well-known/jwks', async (req: express.Request, res: express.Response) => {
res.send({keys: [{...secp256k1Jwk}, {...secp256r1Jwk}]})
})
*/
console.log(`########## $${MOCK_BASE_URL}`)

/*server = app.listen(port, () => {
console.log(`Mock server is listening to port ${port}`)
})*/

return true
}

const tearDown = async (): Promise<boolean> => {
if (server) {
server.closeAllConnections()
}

if (dbConnection && false) {
;(await dbConnection)?.close()
}
return true
/* if (server) {
server.closeAllConnections()
}*/

if (dbConnection && false) {
;(await dbConnection)?.close()
}
return true
}

describe('attestation client should', () => {
let identifier: IIdentifier

beforeAll(async (): Promise<void> => {
await setup()
identifier = await agent.didManagerCreate({
provider: 'did:ebsi',
options: {secp256k1Key: secp256k1PrivateKey, secp256r1Key: secp256r1PrivateKey},
})
console.log(identifier.did)
})

afterAll(async (): Promise<void> => {
await tearDown()
let identifier: IIdentifier

beforeAll(async (): Promise<void> => {
await setup()
const builder = ExpressBuilder.fromServerOpts({
port: 3333,
envVarPrefix: 'PK_HOSTING_',
hostname: '0.0.0.0',
})

it('get attestation to onboard', async () => {
const clientId = MOCK_BASE_URL
authReqResult = await agent.ebsiCreateAttestationAuthRequestURL({
credentialType: 'VerifiableAuthorisationToOnboard',
formats: ['jwt_vc_json'],
redirectUri: `${MOCK_BASE_URL}`,
clientId,
idOpts: {identifier},
// credentialIssuer: 'http://192.168.2.90:3000/conformance/v3/issuer-mock',
credentialIssuer: 'https://api-conformance.ebsi.eu/conformance/v3/issuer-mock',
requestObjectOpts: {
iss: clientId,
requestObjectMode: CreateRequestObjectMode.REQUEST_OBJECT,
jwksUri: `${MOCK_BASE_URL}/.well-known/jwks`,
.withMorganLogging({ format: 'dev' })
.withPassportAuth(false)
const expressSupport = builder.build()

new PublicKeyHosting({
opts: {
endpointOpts: {
globalAuth: {
authentication: {
enabled: false,
},
})
const attestationResult = await agent.ebsiGetAttestation({clientId, authReqResult})

console.log('=========== CREDENTIALS:')
console.log(attestationResult.credentials)

console.log('=========== CONTEXT CREDS TO ACCEPT:')
console.log(attestationResult)


const accessToken = await agent.ebsiAccessTokenGet({
// attestationCredential: CredentialMapper.storedCredentialToOriginalFormat(attestationResult.credentials[0].rawVerifiableCredential as OriginalVerifiableCredential),
jwksUri: `${MOCK_BASE_URL}/.well-known/jwks`,
scope: 'didr_invite',
idOpts: {identifier, kid: secp256r1Jwk.kid},
redirectUri: `${MOCK_BASE_URL}`,
credentialIssuer: 'https://api-conformance.ebsi.eu/conformance/v3/issuer-mock',
clientId,
apiOpts: {environment: "conformance", mock: 'auth-mock', type: 'openid-configuration'}
})
console.log(JSON.stringify(accessToken))
},
},
hostingOpts: {
enableFeatures: ['did-jwks'],
},
},
expressSupport,
agent,
})
expressSupport.start()

try {
identifier = await agent.didManagerCreate({
provider: 'did:ebsi',
options: { secp256k1Key: secp256k1PrivateKey, secp256r1Key: secp256r1PrivateKey },
})
console.log(`WE CREATED DID:`)
console.log(identifier.did)
} catch (e) {
console.log(`###########WHOOPS:`, e)
}
})

afterAll(async (): Promise<void> => {
await tearDown()
})

it('get attestation to onboard', async () => {
const clientId = MOCK_BASE_URL
/*
authReqResult = await agent.ebsiCreateAttestationAuthRequestURL({
credentialType: 'VerifiableAuthorisationToOnboard',
formats: ['jwt_vc_json'],
redirectUri: `${MOCK_BASE_URL}`,
clientId,
idOpts: {identifier},
// credentialIssuer: 'http://192.168.2.90:3000/conformance/v3/issuer-mock',
credentialIssuer: 'https://api-conformance.ebsi.eu/conformance/v3/issuer-mock',
requestObjectOpts: {
iss: clientId,
requestObjectMode: CreateRequestObjectMode.REQUEST_OBJECT,
jwksUri: `${MOCK_BASE_URL}/.well-known/jwks`,
},
})
const attestationResult = await agent.ebsiGetAttestation({clientId, authReqResult})
console.log('=========== CREDENTIALS:')
console.log(attestationResult.credentials)
console.log('=========== CONTEXT CREDS TO ACCEPT:')
console.log(attestationResult)
*/

const jwksUri = `${MOCK_BASE_URL}/.well-known/jwks/dids/${jwksURIFromIdentifier({
identifier,
onlyEncodeDid: true,
})}`
console.log('========================')
console.log('========================')
console.log('JWKS URI:', jwksUri)
console.log('========================')
console.log('========================')
/* const accessToken = await agent.ebsiAccessTokenGet({
// attestationCredential: CredentialMapper.storedCredentialToOriginalFormat(attestationResult.credentials[0].rawVerifiableCredential as OriginalVerifiableCredential),
jwksUri,
scope: 'didr_invite',
idOpts: {identifier, kid: secp256r1Jwk.kid},
redirectUri: jwksUri, //`${MOCK_BASE_URL}`,
credentialIssuer: 'https://api-conformance.ebsi.eu/conformance/v3/issuer-mock',
clientId,
environment: 'conformance',
})
console.log(JSON.stringify(accessToken))*/

const ledgerResult = await ebsiCreateDidOnLedger(
{
identifier,
accessTokenOpts: {
clientId,
redirectUri: jwksUri,
credentialIssuer: 'https://api-conformance.ebsi.eu/conformance/v3/issuer-mock',
// credentialIssuer: 'http://192.168.2.90:3000/conformance/v3/issuer-mock',
environment: 'conformance',
jwksUri,
},
/*// bearerToken: accessToken.accessTokenResponse.access_token,
apiOpts: {
environment: 'conformance',
version: 'v5'
},*/
},
{ agent },
)

console.log(JSON.stringify(ledgerResult, null, 2))
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { IDIDManager, IIdentifier, IKeyManager, MinimalImportableKey, TAgent } f
import { fetch } from 'cross-fetch'
//@ts-ignore
import express, { Application, NextFunction, Request, Response } from 'express'
import { Server, createServer } from 'http'
import { createServer, Server } from 'http'
import { importJWK, SignJWT } from 'jose'
import { IEbsiSupport, ScopeByDefinition } from '../../src'
import { IEbsiSupport } from '../../src'

type ConfiguredAgent = TAgent<IKeyManager & IDIDManager & IDidAuthSiopOpAuthenticator & IEbsiSupport>

Expand Down Expand Up @@ -345,11 +345,11 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro
attestationCredential:
'eyJ0eXAiOiJKV1QiLCJraWQiOiIxODNkY2E4NDRiNzM5OGM4MTQ0ZTJiMzk5OWM3MzA2Y2I3OTYzMDJhZWQxNDdkNjY4ZmI2ZmI5YmE0OTZkNTBkIiwiYWxnIjoiRVMyNTZLIn0.eyJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aURuaW94WVlMVzFhM3FVYnFURno0VyIsImlhdCI6MTcxNDQxMzA4OCwianRpIjoidXJuOnV1aWQ6NWZiN2Q5OGItMTA4Yy00YmMwLTlmZmMtYzY5Zjg0ZWQ3ODhmIiwibmJmIjoxNzE0NDEzMDg4LCJleHAiOjE3NDU5NDkwODgsInN1YiI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDo1ZmI3ZDk4Yi0xMDhjLTRiYzAtOWZmYy1jNjlmODRlZDc4OGYiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZUF1dGhvcmlzYXRpb25Ub09uYm9hcmQiXSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNC0yOVQxNzo1MToyOFoiLCJpc3N1ZWQiOiIyMDI0LTA0LTI5VDE3OjUxOjI4WiIsInZhbGlkRnJvbSI6IjIwMjQtMDQtMjlUMTc6NTE6MjhaIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTA0LTI5VDE3OjUxOjI4WiIsImlzc3VlciI6ImRpZDplYnNpOnppRG5pb3hZWUxXMWEzcVVicVRGejRXIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZWJzaTp6ZXliQWlKeHpVVXJXUTFZTTUxU1kzNSIsImFjY3JlZGl0ZWRGb3IiOltdfSwidGVybXNPZlVzZSI6eyJpZCI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidHlwZSI6Iklzc3VhbmNlQ2VydGlmaWNhdGUifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLXBpbG90LmVic2kuZXUvdHJ1c3RlZC1zY2hlbWFzLXJlZ2lzdHJ5L3YyL3NjaGVtYXMvejNNZ1VGVWtiNzIydXE0eDNkdjV5QUptbk5tekRGZUs1VUM4eDgzUW9lTEpNIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fX0.QWNWTWlrbUpLcFJaLVBGczQ0U3Mxb200Mk4yb3JzWndsTXp3REpHTTMxSUM2WG5ZVXJ0ZlY4RHFTbVQtaXBIMEdLSDZhclFEcGtrbXZTTy1NenYxWEE',
// definitionId: ScopeByDefinition.didr_invite_presentation,
idOpts: {identifier},
/* did: identifier.did,
idOpts: { identifier },
/* did: identifier.did,
kid: `${identifier.did}#${id.keys[1].kid}`,*/
scope: 'didr_invite',
apiOpts: { environment: 'conformance-test', type: 'openid-configuration' },
environment: 'conformance-test',
}),
).resolves.toEqual({})
})
Expand Down
Loading

0 comments on commit 7195786

Please sign in to comment.