Skip to content

Commit

Permalink
chore: Add optional QR code generation
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed Nov 20, 2023
1 parent 9f4eca6 commit 07286fa
Show file tree
Hide file tree
Showing 18 changed files with 420 additions and 140 deletions.
4 changes: 0 additions & 4 deletions packages/callback-example/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @sphereon/oid4vci-callback-example





## [0.7.3](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.2...v0.7.3) (2023-09-30)

**Note:** Version bump only for package @sphereon/oid4vci-callback-example
Expand Down
4 changes: 0 additions & 4 deletions packages/client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @sphereon/oid4vci-client





## [0.7.3](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.2...v0.7.3) (2023-09-30)

**Note:** Version bump only for package @sphereon/oid4vci-client
Expand Down
2 changes: 1 addition & 1 deletion packages/client/lib/__tests__/MattrE2E.spec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const jwk: JWK = {
// priv hex: 913466d1a38d1d8c0d3c0fb0fc3b633075085a31372bbd2a8022215a88d9d1e5
const did = `did:key:z6Mki5ZwZKN1dBQprfJTikUvkDxrHijiiQngkWviMF5gw2Hv`;
const kid = `${did}#z6Mki5ZwZKN1dBQprfJTikUvkDxrHijiiQngkWviMF5gw2Hv`;
describe('OID4VCI-Client using Mattr issuer should', () => {
describe.skip('OID4VCI-Client using Mattr issuer should', () => {
async function test(format: 'ldp_vc' | 'jwt_vc_json') {
const offer = await getCredentialOffer(format);
const client = await OpenID4VCIClient.fromURI({
Expand Down
148 changes: 73 additions & 75 deletions packages/client/lib/__tests__/SphereonE2E.spec.test.ts
Original file line number Diff line number Diff line change
@@ -1,171 +1,169 @@
import * as crypto from 'crypto'
import * as crypto from 'crypto';

import { Alg, Jwt, ProofOfPossessionCallbacks } from '@sphereon/oid4vci-common'
import { CredentialMapper } from '@sphereon/ssi-types'
import * as didts from '@transmute/did-key.js'
import { fetch } from 'cross-fetch'
import debug from 'debug'
import { importJWK, JWK, SignJWT } from 'jose'
import { v4 } from 'uuid'
import { Alg, Jwt, ProofOfPossessionCallbacks } from '@sphereon/oid4vci-common';
import { CredentialMapper } from '@sphereon/ssi-types';
import * as didts from '@transmute/did-key.js';
import { fetch } from 'cross-fetch';
import debug from 'debug';
import { importJWK, JWK, SignJWT } from 'jose';
import { v4 } from 'uuid';

import { OpenID4VCIClient } from '..';

import { OpenID4VCIClient } from '..'
export const UNIT_TEST_TIMEOUT = 30000;

export const UNIT_TEST_TIMEOUT = 30000

const ISSUER_URL = 'https://ssi.sphereon.com/pf3'
const ISSUER_URL = 'https://ssi.sphereon.com/pf3';

const jwk: JWK = {
crv: 'Ed25519',
d: 'kTRm0aONHYwNPA-w_DtjMHUIWjE3K70qgCIhWojZ0eU',
x: 'NeA0d8sp86xRh3DczU4m5wPNIbl0HCSwOBcMN3sNmdk',
kty: 'OKP'
}
kty: 'OKP',
};

// pub hex: 35e03477cb29f3ac518770dccd4e26e703cd21b9741c24b038170c377b0d99d9
// priv hex: 913466d1a38d1d8c0d3c0fb0fc3b633075085a31372bbd2a8022215a88d9d1e5
const did = `did:key:z6Mki5ZwZKN1dBQprfJTikUvkDxrHijiiQngkWviMF5gw2Hv`;
const kid = `${did}#z6Mki5ZwZKN1dBQprfJTikUvkDxrHijiiQngkWviMF5gw2Hv`
const kid = `${did}#z6Mki5ZwZKN1dBQprfJTikUvkDxrHijiiQngkWviMF5gw2Hv`;
describe('OID4VCI-Client using Sphereon issuer should', () => {
async function test(format: 'ldp_vc' | 'jwt_vc_json') {
debug.enable('*')
const offer = await getCredentialOffer(format)
debug.enable('*');
const offer = await getCredentialOffer(format);
const client = await OpenID4VCIClient.fromURI({
uri: offer.uri,
kid,
alg: Alg.EdDSA
})
expect(client.credentialOffer).toBeDefined()
expect(client.endpointMetadata).toBeDefined()
expect(client.getCredentialEndpoint()).toEqual(`${ISSUER_URL}/credentials`)
expect(client.getAccessTokenEndpoint()).toEqual(`${ISSUER_URL}/token`)

const accessToken = await client.acquireAccessToken()
alg: Alg.EdDSA,
});
expect(client.credentialOffer).toBeDefined();
expect(client.endpointMetadata).toBeDefined();
expect(client.getCredentialEndpoint()).toEqual(`${ISSUER_URL}/credentials`);
expect(client.getAccessTokenEndpoint()).toEqual(`${ISSUER_URL}/token`);

const accessToken = await client.acquireAccessToken();
// console.log(accessToken);
expect(accessToken).toMatchObject({
expires_in: 300,
// scope: 'GuestCredential',
token_type: 'bearer'
})
token_type: 'bearer',
});

const credentialResponse = await client.acquireCredentials({
credentialTypes: 'GuestCredential',
format,
proofCallbacks: {
signCallback: proofOfPossessionCallbackFunction
}
})
expect(credentialResponse.credential).toBeDefined()
const wrappedVC = CredentialMapper.toWrappedVerifiableCredential(credentialResponse.credential!)
expect(format.startsWith(wrappedVC.format)).toEqual(true)
signCallback: proofOfPossessionCallbackFunction,
},
});
expect(credentialResponse.credential).toBeDefined();
const wrappedVC = CredentialMapper.toWrappedVerifiableCredential(credentialResponse.credential!);
expect(format.startsWith(wrappedVC.format)).toEqual(true);
}

xit(
'succeed in a full flow with the client using OpenID4VCI version 11 and ldp_vc',
async () => {
await test('ldp_vc')
await test('ldp_vc');
},
UNIT_TEST_TIMEOUT
)
UNIT_TEST_TIMEOUT,
);
it(
'succeed in a full flow with the client using OpenID4VCI version 11 and jwt_vc_json',
async () => {
await test('jwt_vc_json')
await test('jwt_vc_json');
},
UNIT_TEST_TIMEOUT
)
})
UNIT_TEST_TIMEOUT,
);
});

interface CreateCredentialOfferResponse {
uri: string,
userPinRequired: boolean
uri: string;
userPinRequired: boolean;
}

async function getCredentialOffer(format: 'ldp_vc' | 'jwt_vc_json'): Promise<CreateCredentialOfferResponse> {
const credentialOffer = await fetch('https://ssi.sphereon.com/pf3/webapp/credential-offers', {
method: 'post',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
'Content-Type': 'application/json',
},

//make sure to serialize your JSON body
body: JSON.stringify({
'credentials': ['GuestCredential'],
'grants': {
credentials: ['GuestCredential'],
grants: {
'urn:ietf:params:oauth:grant-type:pre-authorized_code': {
'pre-authorized_code': v4().substring(0, 10),
'user_pin_required': false
}
user_pin_required: false,
},
},
'credentialDataSupplierInput': { 'firstName': 'Hello', 'lastName': 'World', 'email': '[email protected]' }
})
})
credentialDataSupplierInput: { firstName: 'Hello', lastName: 'World', email: '[email protected]' },
}),
});

return (await credentialOffer.json()) as CreateCredentialOfferResponse
return (await credentialOffer.json()) as CreateCredentialOfferResponse;
}

async function proofOfPossessionCallbackFunction(args: Jwt, kid?: string): Promise<string> {
const importedJwk = await importJWK(jwk, 'EdDSA')
const importedJwk = await importJWK(jwk, 'EdDSA');
return await new SignJWT({ ...args.payload })
.setProtectedHeader({ ...args.header, kid: kid! })
.setIssuer(kid!)
.setIssuedAt()
.setExpirationTime('2h')
.sign(importedJwk)
.sign(importedJwk);
}


describe('ismapolis bug report #63, https://github.com/Sphereon-Opensource/OID4VC-demo/issues/63, should', () => {
it('work as expected provided a correct JWT is supplied', async () => {
debug.enable('*')
const { uri } = await getCredentialOffer('jwt_vc_json')
const client = await OpenID4VCIClient.fromURI({ uri: uri, clientId: 'test-clientID' })
const metadata = await client.retrieveServerMetadata()
console.log(JSON.stringify(metadata))
debug.enable('*');
const { uri } = await getCredentialOffer('jwt_vc_json');
const client = await OpenID4VCIClient.fromURI({ uri: uri, clientId: 'test-clientID' });
const metadata = await client.retrieveServerMetadata();
console.log(JSON.stringify(metadata));

//2. Adquire acces token from authorization server endpoint

const accessToken = await client.acquireAccessToken({})
console.log(`Access token: ${JSON.stringify(accessToken)}`)
const accessToken = await client.acquireAccessToken({});
console.log(`Access token: ${JSON.stringify(accessToken)}`);

//3. Create DID needed for later proof of possession
const { keys, didDocument } = await didts.jwk.generate({
type: 'secp256k1', // 'P-256', 'P-384', 'X25519', 'secp256k1'
accept: 'application/did+json',
secureRandom: () => {
return crypto.randomBytes(32)
}
})
const edPrivateKey = await importJWK(keys[0].privateKeyJwk)
return crypto.randomBytes(32);
},
});
const edPrivateKey = await importJWK(keys[0].privateKeyJwk);

async function signCallback(args: Jwt, kid?: string): Promise<string> {
if (!args.payload.aud) {
throw Error('aud required')
throw Error('aud required');
} else if (!kid) {
throw Error('kid required')
throw Error('kid required');
}
return await new SignJWT({ ...args.payload })
.setProtectedHeader({ alg: args.header.alg, kid, typ: 'openid4vci-proof+jwt' })
.setIssuedAt()
.setIssuer(kid)
.setAudience(args.payload.aud)
.setExpirationTime('2h')
.sign(edPrivateKey)
.sign(edPrivateKey);
}

const callbacks: ProofOfPossessionCallbacks<never> = {
signCallback: signCallback
}
signCallback: signCallback,
};

const credentialResponse = await client.acquireCredentials({
credentialTypes: 'GuestCredential',
proofCallbacks: callbacks,
format: 'jwt_vc_json',
alg: Alg.ES256K,
kid: didDocument.verificationMethod[0].id,
jti: v4()
})
console.log(JSON.stringify(credentialResponse.credential))
})
})
jti: v4(),
});
console.log(JSON.stringify(credentialResponse.credential));
});
});
4 changes: 0 additions & 4 deletions packages/common/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @sphereon/oid4vci-common





## [0.7.3](https://github.com/Sphereon-Opensource/OID4VCI/compare/v0.7.2...v0.7.3) (2023-09-30)

**Note:** Version bump only for package @sphereon/oid4vci-common
Expand Down
1 change: 1 addition & 0 deletions packages/common/lib/types/Generic.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export type CredentialDataSupplierInput = any;

export type CreateCredentialOfferURIResult = {
uri: string;
qrCodeDataUri?: string;
session: CredentialOfferSession;
userPin?: string;
userPinLength?: number;
Expand Down
Loading

0 comments on commit 07286fa

Please sign in to comment.