Skip to content

Commit

Permalink
chore: merge and reformat
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed Feb 15, 2025
1 parent e3d7189 commit cf38c18
Show file tree
Hide file tree
Showing 23 changed files with 1,793 additions and 1,776 deletions.
36 changes: 19 additions & 17 deletions packages/client/lib/CredentialOfferClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import {
OpenId4VCIVersion,
PRE_AUTH_CODE_LITERAL,
PRE_AUTH_GRANT_LITERAL,
toUniformCredentialOfferRequest
} from '@sphereon/oid4vci-common'
import Debug from 'debug'
toUniformCredentialOfferRequest,
} from '@sphereon/oid4vci-common';
import Debug from 'debug';

import { LOG } from './types'
import { fetch } from 'cross-fetch'
import { isUrlEncoded } from './functions'
import { LOG } from './types';
import { fetch } from 'cross-fetch';
import { isUrlEncoded } from './functions';

const debug = Debug('sphereon:oid4vci:offer');

Expand Down Expand Up @@ -48,29 +48,31 @@ export class CredentialOfferClient {
};
} else {
if (uri.includes('credential_offer_uri')) {
const uriObj = getURIComponentsAsArray(uri) as unknown as Record<string, string> // FIXME
const credentialOfferUri = decodeURIComponent(uriObj['credential_offer_uri'])
const decodedUri = isUrlEncoded(credentialOfferUri) ? decodeURIComponent(credentialOfferUri) : credentialOfferUri
const response = await fetch(decodedUri)
const uriObj = getURIComponentsAsArray(uri) as unknown as Record<string, string>; // FIXME
const credentialOfferUri = decodeURIComponent(uriObj['credential_offer_uri']);
const decodedUri = isUrlEncoded(credentialOfferUri) ? decodeURIComponent(credentialOfferUri) : credentialOfferUri;
const response = await fetch(decodedUri);
if (!(response && response.status >= 200 && response.status < 400)) {
return Promise.reject(`the credential offer URI endpoint call was not successful. http code ${response.status} - reason ${response.statusText}`)
return Promise.reject(
`the credential offer URI endpoint call was not successful. http code ${response.status} - reason ${response.statusText}`,
);
}

if (response.headers.get('Content-Type')?.startsWith('application/json') === false) {
return Promise.reject('the credential offer URI endpoint did not return content type application/json')
return Promise.reject('the credential offer URI endpoint did not return content type application/json');
}
credentialOffer = {
credential_offer: decodeJsonProperties(await response.json())
} as CredentialOfferV1_0_11 | CredentialOfferV1_0_13
credential_offer: decodeJsonProperties(await response.json()),
} as CredentialOfferV1_0_11 | CredentialOfferV1_0_13;
} else {
credentialOffer = convertURIToJsonObject(uri, {
// It must have the '=' sign after credential_offer otherwise the uri will get split at openid_credential_offer
arrayTypeProperties: uri.includes('credential_offer_uri=') ? ['credential_offer_uri='] : ['credential_offer='],
requiredProperties: uri.includes('credential_offer_uri=') ? ['credential_offer_uri='] : ['credential_offer=']
}) as CredentialOfferV1_0_11 | CredentialOfferV1_0_13
requiredProperties: uri.includes('credential_offer_uri=') ? ['credential_offer_uri='] : ['credential_offer='],
}) as CredentialOfferV1_0_11 | CredentialOfferV1_0_13;
}
if (credentialOffer?.credential_offer_uri === undefined && !credentialOffer?.credential_offer) {
throw Error('Either a credential_offer or credential_offer_uri should be present in ' + uri)
throw Error('Either a credential_offer or credential_offer_uri should be present in ' + uri);
}
}

Expand Down
39 changes: 21 additions & 18 deletions packages/client/lib/CredentialOfferClientV1_0_13.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import {
OpenId4VCIVersion,
PRE_AUTH_CODE_LITERAL,
PRE_AUTH_GRANT_LITERAL,
toUniformCredentialOfferRequest
} from '@sphereon/oid4vci-common'
import Debug from 'debug'
import { fetch } from 'cross-fetch'
import { isUrlEncoded } from './functions'
toUniformCredentialOfferRequest,
} from '@sphereon/oid4vci-common';
import Debug from 'debug';
import { fetch } from 'cross-fetch';
import { isUrlEncoded } from './functions';

const debug = Debug('sphereon:oid4vci:offer');

Expand All @@ -29,32 +29,35 @@ export class CredentialOfferClientV1_0_13 {
}
const scheme = uri.split('://')[0];
const baseUrl = uri.split('?')[0];
const version = determineSpecVersionFromURI(uri)
let credentialOffer: CredentialOffer
if (uri.includes('credential_offer_uri')) { // FIXME deduplicate
const uriObj = getURIComponentsAsArray(uri) as unknown as Record<string, string> // FIXME
const credentialOfferUri = decodeURIComponent(uriObj['credential_offer_uri'])
const decodedUri = isUrlEncoded(credentialOfferUri) ? decodeURIComponent(credentialOfferUri) : credentialOfferUri
const response = await fetch(decodedUri)
const version = determineSpecVersionFromURI(uri);
let credentialOffer: CredentialOffer;
if (uri.includes('credential_offer_uri')) {
// FIXME deduplicate
const uriObj = getURIComponentsAsArray(uri) as unknown as Record<string, string>; // FIXME
const credentialOfferUri = decodeURIComponent(uriObj['credential_offer_uri']);
const decodedUri = isUrlEncoded(credentialOfferUri) ? decodeURIComponent(credentialOfferUri) : credentialOfferUri;
const response = await fetch(decodedUri);
if (!(response && response.status >= 200 && response.status < 400)) {
return Promise.reject(`the credential offer URI endpoint call was not successful. http code ${response.status} - reason ${response.statusText}`)
return Promise.reject(
`the credential offer URI endpoint call was not successful. http code ${response.status} - reason ${response.statusText}`,
);
}

if (response.headers.get('Content-Type')?.startsWith('application/json') === false) {
return Promise.reject('the credential offer URI endpoint did not return content type application/json')
return Promise.reject('the credential offer URI endpoint did not return content type application/json');
}
credentialOffer = decodeJsonProperties(await response.json()) as CredentialOfferV1_0_11 | CredentialOfferV1_0_13
credentialOffer = decodeJsonProperties(await response.json()) as CredentialOfferV1_0_11 | CredentialOfferV1_0_13;
} else {
credentialOffer = convertURIToJsonObject(uri, {
// It must have the '=' sign after credential_offer otherwise the uri will get split at openid_credential_offer
arrayTypeProperties: uri.includes('credential_offer_uri=')
? ['credential_configuration_ids', 'credential_offer_uri=']
: ['credential_configuration_ids', 'credential_offer='],
requiredProperties: uri.includes('credential_offer_uri=') ? ['credential_offer_uri='] : ['credential_offer=']
}) as CredentialOfferV1_0_13
requiredProperties: uri.includes('credential_offer_uri=') ? ['credential_offer_uri='] : ['credential_offer='],
}) as CredentialOfferV1_0_13;
}
if (credentialOffer?.credential_offer_uri === undefined && !credentialOffer?.credential_offer) {
throw Error('Either a credential_offer or credential_offer_uri should be present in ' + uri)
throw Error('Either a credential_offer or credential_offer_uri should be present in ' + uri);
}

const request = await toUniformCredentialOfferRequest(credentialOffer, {
Expand Down
22 changes: 10 additions & 12 deletions packages/client/lib/__tests__/MetadataClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {
AuthorizationServerMetadata,
getIssuerFromCredentialOfferPayload,
PRE_AUTH_GRANT_LITERAL,
WellKnownEndpoints
} from '@sphereon/oid4vci-common'
WellKnownEndpoints,
} from '@sphereon/oid4vci-common';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import nock from 'nock';
Expand Down Expand Up @@ -305,23 +305,21 @@ describe.skip('Metadataclient with SpruceId should', () => {

describe('Metadataclient with Credenco should', () => {
beforeEach(() => {
const mockData = getMockData('credenco')
const mockData = getMockData('credenco');
if (!mockData?.metadata?.openid4vci_metadata) {
throw new Error('Credenco mock data not found or invalid structure')
throw new Error('Credenco mock data not found or invalid structure');
}
nock('https://mijnkvk.acc.credenco.com')
.get('/.well-known/openid-credential-issuer')
.reply(200, mockData.metadata.openid4vci_metadata)
nock('https://mijnkvk.acc.credenco.com').get('/.well-known/openid-configuration').reply(404)
nock('https://mijnkvk.acc.credenco.com').get('/.well-known/openid-credential-issuer').reply(200, mockData.metadata.openid4vci_metadata);
nock('https://mijnkvk.acc.credenco.com').get('/.well-known/openid-configuration').reply(404);
const authMetadata: AuthorizationServerMetadata = {
authorization_endpoint: 'https://mijnkvk.acc.credenco.com',
"pre-authorized_grant_anonymous_access_supported": true,
'pre-authorized_grant_anonymous_access_supported': true,
issuer: 'https://issuer.research.identiproof.io',
token_endpoint: 'https://mijnkvk.acc.credenco.com/token',
response_types_supported: ['token']
}
response_types_supported: ['token'],
};
nock('https://mijnkvk.acc.credenco.com').get('/.well-known/oauth-authorization-server').reply(200, JSON.stringify(authMetadata));
})
});

it('succeed without OID4VCI and with OIDC metadata', async () => {
const metadata = await MetadataClient.retrieveAllMetadata('https://mijnkvk.acc.credenco.com/');
Expand Down
10 changes: 5 additions & 5 deletions packages/client/lib/__tests__/OpenID4VCIClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import {
determineSpecVersionFromOffer,
determineSpecVersionFromURI,
OpenId4VCIVersion,
WellKnownEndpoints
} from '@sphereon/oid4vci-common'
WellKnownEndpoints,
} from '@sphereon/oid4vci-common';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import nock from 'nock'
import nock from 'nock';

import { createCredentialOfferURIFromObject } from '../../../issuer/lib'
import { OpenID4VCIClient } from '../OpenID4VCIClient'
import { createCredentialOfferURIFromObject } from '../../../issuer/lib';
import { OpenID4VCIClient } from '../OpenID4VCIClient';

const MOCK_URL = 'https://server.example.com/';

Expand Down
15 changes: 5 additions & 10 deletions packages/client/lib/__tests__/SdJwt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,14 @@ import {
AccessTokenRequest,
CredentialConfigurationSupportedSdJwtVcV1_0_13,
CredentialConfigurationSupportedV1_0_13,
CredentialSupportedSdJwtVc
} from '@sphereon/oid4vci-common'
CredentialSupportedSdJwtVc,
} from '@sphereon/oid4vci-common';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import nock from 'nock'
import nock from 'nock';

import { OpenID4VCIClientV1_0_13 } from '..'
import {
AuthorizationServerMetadataBuilder,
createAccessTokenResponse,
IssuerMetadataBuilderV1_13,
VcIssuerBuilder
} from '../../../issuer'
import { OpenID4VCIClientV1_0_13 } from '..';
import { AuthorizationServerMetadataBuilder, createAccessTokenResponse, IssuerMetadataBuilderV1_13, VcIssuerBuilder } from '../../../issuer';

export const UNIT_TEST_TIMEOUT = 30000;

Expand Down
5 changes: 2 additions & 3 deletions packages/client/lib/functions/UrlUtil.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

export function isUrlEncoded(str: string): boolean {
const pattern = /%[0-9A-F]{2}/i
return pattern.test(str)
const pattern = /%[0-9A-F]{2}/i;
return pattern.test(str);
}
13 changes: 4 additions & 9 deletions packages/issuer-rest/lib/OID4VCIServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@ import {
IssuerCredentialSubjectDisplay,
OID4VCICredentialFormat,
QRCodeOpts,
TxCode
TxCode,
} from '@sphereon/oid4vci-common'
import {
CredentialSupportedBuilderV1_13,
ITokenEndpointOpts,
VcIssuer,
VcIssuerBuilder
} from '@sphereon/oid4vci-issuer'
import { CredentialSupportedBuilderV1_13, ITokenEndpointOpts, VcIssuer, VcIssuerBuilder } from '@sphereon/oid4vci-issuer'
import { ExpressSupport, HasEndpointOpts, ISingleEndpointOpts } from '@sphereon/ssi-express-support'
import express, { Express } from 'express'

Expand All @@ -28,7 +23,7 @@ import {
getIssuePayloadEndpoint,
getIssueStatusEndpoint,
getMetadataEndpoints,
pushedAuthorizationEndpoint
pushedAuthorizationEndpoint,
} from './oid4vci-api-functions'

function buildVCIFromEnvironment() {
Expand Down Expand Up @@ -174,7 +169,7 @@ export class OID4VCIServer {
pushedAuthorizationEndpoint(this.router, this.issuer, this.authRequestsData)
getMetadataEndpoints(this.router, this.issuer)
let issuerPayloadPath: string | undefined
if(this.isGetIssuePayloadEndpointEnabled(opts?.endpointOpts?.getIssuePayloadOpts)) {
if (this.isGetIssuePayloadEndpointEnabled(opts?.endpointOpts?.getIssuePayloadOpts)) {
issuerPayloadPath = getIssuePayloadEndpoint(this.router, this.issuer, { ...opts?.endpointOpts?.getIssuePayloadOpts, baseUrl: this.baseUrl })
}

Expand Down
2 changes: 1 addition & 1 deletion packages/issuer-rest/lib/__tests__/ClientIssuerIT.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
JWTPayload,
OpenId4VCIVersion,
PRE_AUTH_CODE_LITERAL,
PRE_AUTH_GRANT_LITERAL
PRE_AUTH_GRANT_LITERAL,
} from '@sphereon/oid4vci-common'
import { AuthorizationServerMetadataBuilder } from '@sphereon/oid4vci-issuer'
import { VcIssuer } from '@sphereon/oid4vci-issuer/dist/VcIssuer'
Expand Down
2 changes: 1 addition & 1 deletion packages/issuer-rest/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ export * from './OID4VCIServer'
export * from './oid4vci-api-functions'
export * from './expressUtils'

// We re-export oidc-client types, as they were previously exported here
// We re-export oidc-client types, as they were previously exported here (the dist is on purpose!)
export * from '@sphereon/oid4vci-common/dist/types/OpenIDClient'
26 changes: 13 additions & 13 deletions packages/issuer-rest/lib/oid4vci-api-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ import {
WellKnownEndpoints,
} from '@sphereon/oid4vci-common'
import { ITokenEndpointOpts, LOG, VcIssuer } from '@sphereon/oid4vci-issuer'
import { env, ISingleEndpointOpts,
sendErrorResponse
} from '@sphereon/ssi-express-support'
import { env, ISingleEndpointOpts, sendErrorResponse } from '@sphereon/ssi-express-support'
import { InitiatorType, SubSystem, System } from '@sphereon/ssi-types'
import { NextFunction, Request, Response, Router } from 'express'

Expand Down Expand Up @@ -87,7 +85,7 @@ export function getIssueStatusEndpoint(router: Router, issuer: VcIssuer, opts: I
})
}

export function getIssuePayloadEndpoint<DIDDoc extends object>(router: Router, issuer: VcIssuer<DIDDoc>, opts: IGetIssueStatusEndpointOpts) : string {
export function getIssuePayloadEndpoint(router: Router, issuer: VcIssuer, opts: IGetIssueStatusEndpointOpts): string {
const path = determinePath(opts.baseUrl, opts?.path ?? '/credential-offers/:id', { stripBasePath: true })
LOG.log(`[OID4VCI] getIssuePayloadEndpoint endpoint enabled at ${path}`)
router.get(path, async (request: Request, response: Response) => {
Expand All @@ -96,7 +94,7 @@ export function getIssuePayloadEndpoint<DIDDoc extends object>(router: Router, i
if (!id) {
return sendErrorResponse(response, 404, {
error: 'invalid_request',
error_description: `query parameter 'id' is missing`
error_description: `query parameter 'id' is missing`,
})
}
const session = await issuer.getCredentialOfferSessionById(id as string, 'preAuthorizedCode')
Expand Down Expand Up @@ -422,9 +420,9 @@ export function getCredentialOfferEndpoint(router: Router, issuer: VcIssuer, opt
})
}

export function deleteCredentialOfferEndpoint<DIDDoc extends object>(
export function deleteCredentialOfferEndpoint(
router: Router,
issuer: VcIssuer<DIDDoc>,
issuer: VcIssuer,
opts?: IGetCredentialOfferEndpointOpts,
) {
const path = determinePath(opts?.baseUrl, opts?.path ?? '/webapp/credential-offers/:id', { stripBasePath: true })
Expand Down Expand Up @@ -466,8 +464,12 @@ function buildIssuerPayloadUri(request: Request<CredentialOfferRESTRequest>, iss
return `${protocol}://${host}${forwardedPrefix}${request.baseUrl}${issuerPayloadPathConst}`
}

export function createCredentialOfferEndpoint(router: Router, issuer: VcIssuer, opts?: ICreateCredentialOfferEndpointOpts & { baseUrl?: string },
issuerPayloadPath?: string) {
export function createCredentialOfferEndpoint(
router: Router,
issuer: VcIssuer,
opts?: ICreateCredentialOfferEndpointOpts & { baseUrl?: string },
issuerPayloadPath?: string,
) {
const issuerPayloadPathConst = issuerPayloadPath
const path = determinePath(opts?.baseUrl, opts?.path ?? '/webapp/credential-offers', { stripBasePath: true })

Expand Down Expand Up @@ -495,9 +497,7 @@ export function createCredentialOfferEndpoint(router: Router, issuer: VcIssuer,
})
}
const qrCodeOpts = request.body.qrCodeOpts ?? opts?.qrCodeOpts
const offerMode: CredentialOfferMode = request.body.offerMode
?? opts?.defaultCredentialOfferPayloadMode
?? 'VALUE' // default to existing mode when nothing specified
const offerMode: CredentialOfferMode = request.body.offerMode ?? opts?.defaultCredentialOfferPayloadMode ?? 'VALUE' // default to existing mode when nothing specified

const client_id: string | undefined = request.body.client_id ?? request.body.original_credential_offer?.client_id
const result = await issuer.createCredentialOfferURI({
Expand All @@ -506,7 +506,7 @@ export function createCredentialOfferEndpoint(router: Router, issuer: VcIssuer,
client_id,
...(offerMode === 'REFERENCE' && { issuerPayloadUri: buildIssuerPayloadUri(request, issuerPayloadPathConst) }),
qrCodeOpts,
grants
grants,
})
const resultResponse: ICreateCredentialOfferURIResponse = result
if ('session' in resultResponse) {
Expand Down
Loading

0 comments on commit cf38c18

Please sign in to comment.