Skip to content

Commit

Permalink
fix: (WIP) fixed all the build errors
Browse files Browse the repository at this point in the history
  • Loading branch information
sksadjad committed May 8, 2024
1 parent 10c4ca2 commit e522a3d
Show file tree
Hide file tree
Showing 21 changed files with 9,173 additions and 6,306 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
ProofOfPossession,
} from '@sphereon/oid4vci-common'
import { CredentialOfferSession } from '@sphereon/oid4vci-common/dist'
import { CredentialSupportedBuilderV1_13, VcIssuer, VcIssuerBuilder } from '@sphereon/oid4vci-issuer'
import { CredentialSupportedBuilderV1_13, VcIssuer, VcIssuerBuilderV1_0_11 } from '@sphereon/oid4vci-issuer'
import { MemoryStates } from '@sphereon/oid4vci-issuer'
import { CredentialDataSupplierResult } from '@sphereon/oid4vci-issuer/dist/types'
import { ICredential, IProofPurpose, IProofType, W3CVerifiableCredential } from '@sphereon/ssi-types'
Expand Down Expand Up @@ -140,7 +140,7 @@ describe('issuerCallback', () => {

const nonces = new MemoryStates<CNonceState>()
await nonces.set('test_value', { cNonce: 'test_value', createdAt: +new Date(), issuerState: 'existing-state' })
vcIssuer = new VcIssuerBuilder<DIDDocument>()
vcIssuer = new VcIssuerBuilderV1_0_11<DIDDocument>()
.withAuthorizationServer('https://authorization-server')
.withCredentialEndpoint('https://credential-endpoint')
.withCredentialIssuer(IDENTIPROOF_ISSUER_URL)
Expand Down
6 changes: 3 additions & 3 deletions packages/client/lib/AuthorizationCodeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
AuthorizationRequestOpts,
CodeChallengeMethod,
convertJsonToURI,
CredentialOfferRequestWithBaseUrl,
CredentialConfigurationSupported,
CredentialOfferRequestWithBaseUrl,
EndpointMetadataResult,
formPost,
JsonURIMode,
Expand All @@ -28,7 +28,7 @@ export const createAuthorizationRequestUrl = async ({
endpointMetadata: EndpointMetadataResult;
authorizationRequest: AuthorizationRequestOpts;
credentialOffer?: CredentialOfferRequestWithBaseUrl;
credentialsSupported?: CredentialConfigurationSupported[];
credentialsSupported?: Record<string, CredentialConfigurationSupported>;
}): Promise<string> => {
const { redirectUri, clientId } = authorizationRequest;
let { scope, authorizationDetails } = authorizationRequest;
Expand All @@ -47,7 +47,7 @@ export const createAuthorizationRequestUrl = async ({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
authorizationDetails = creds
.flatMap((cred) => (typeof cred === 'string' ? credentialsSupported : (cred as CredentialConfigurationSupported)))
.flatMap((cred) => (typeof cred === 'string' && credentialsSupported ? Object.values(credentialsSupported) : (cred as CredentialConfigurationSupported)))
.filter((cred) => !!cred)
.map((cred) => {
return {
Expand Down
4 changes: 2 additions & 2 deletions packages/client/lib/OpenID4VCIClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import {
AuthorizationResponse,
AuthzFlowType,
CodeChallengeMethod,
CredentialConfigurationSupported,
CredentialOfferPayloadV1_0_08,
CredentialOfferRequestWithBaseUrl,
CredentialResponse,
CredentialConfigurationSupported,
DefaultURISchemes,
EndpointMetadataResult,
getClientIdFromCredentialOfferPayload,
Expand Down Expand Up @@ -446,7 +446,7 @@ export class OpenID4VCIClient {
getCredentialsSupported(
restrictToInitiationTypes: boolean,
format?: (OID4VCICredentialFormat | string) | (OID4VCICredentialFormat | string)[],
): CredentialConfigurationSupported[] {
): Record<string, CredentialConfigurationSupported> {
return getSupportedCredentials({
issuerMetadata: this.endpointMetadata.credentialIssuerMetadata,
version: this.version(),
Expand Down
6 changes: 3 additions & 3 deletions packages/client/lib/__tests__/SdJwt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AccessTokenRequest, CredentialRequestV1_0_11, CredentialSupportedSdJwtV
import nock from 'nock';

import { OpenID4VCIClient } from '..';
import { createAccessTokenResponse, IssuerMetadataBuilderV1_13, VcIssuerBuilder } from '../../../issuer';
import { createAccessTokenResponse, IssuerMetadataBuilderV1_13, VcIssuerBuilderV1_0_11 } from '../../../issuer';

export const UNIT_TEST_TIMEOUT = 30000;

Expand All @@ -15,14 +15,14 @@ const issuerMetadata = new IssuerMetadataBuilderV1_13()
.withCredentialIssuer('https://example.com')
.withCredentialEndpoint('https://credenital-endpoint.example.com')
.withTokenEndpoint('https://token-endpoint.example.com')
.addSupportedCredential({
.addCredentialConfigurationsSupported({
format: 'vc+sd-jwt',
vct: 'SdJwtCredential',
id: 'SdJwtCredentialId',
})
.build();

const vcIssuer = new VcIssuerBuilder()
const vcIssuer = new VcIssuerBuilderV1_0_11()
.withIssuerMetadata(issuerMetadata)
.withInMemoryCNonceState()
.withInMemoryCredentialOfferState()
Expand Down
19 changes: 18 additions & 1 deletion packages/common/lib/functions/CredentialOfferUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ export const getStateFromCredentialOfferPayload = (credentialOffer: CredentialOf
};

export function determineSpecVersionFromOffer(offer: CredentialOfferPayload | CredentialOffer): OpenId4VCIVersion {
if (isCredentialOfferV1_0_12(offer)) {
if (isCredentialOfferV1_0_13(offer)) {
return OpenId4VCIVersion.VER_1_0_13;
} else if (isCredentialOfferV1_0_12(offer)) {
return OpenId4VCIVersion.VER_1_0_12;
} else if (isCredentialOfferV1_0_11(offer)) {
return OpenId4VCIVersion.VER_1_0_11;
Expand Down Expand Up @@ -200,6 +202,21 @@ function isCredentialOfferV1_0_12(offer: CredentialOfferPayload | CredentialOffe
return 'credential_offer_uri' in offer;
}

function isCredentialOfferV1_0_13(offer: CredentialOfferPayload | CredentialOffer): boolean {
if (!offer) {
return false;
}
if ('credential_issuer' in offer && 'credential_configuration_ids' in offer) {
// payload
return true;
}
if ('credential_offer' in offer && offer['credential_offer']) {
// offer, so check payload
return isCredentialOfferV1_0_13(offer['credential_offer']);
}
return 'credential_offer_uri' in offer;
}

export async function toUniformCredentialOfferRequest(
offer: CredentialOffer,
opts?: {
Expand Down
132 changes: 50 additions & 82 deletions packages/common/lib/functions/IssuerMetadataUtils.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
import {
AuthorizationServerMetadata,
CredentialIssuerMetadata,
CredentialOfferFormat,
CredentialConfigurationSupported,
CredentialIssuerMetadata,
CredentialSupportedTypeV1_0_08,
CredentialSupportedV1_0_08,
IssuerMetadataV1_0_08,
MetadataDisplay,
OID4VCICredentialFormat,
OpenId4VCIVersion,
} from '../types';
import { IssuerMetadataV1_0_13 } from '../types/v1_0_13.types';
OpenId4VCIVersion
} from '../types'
import { CredentialIssuerMetadataOptsV1_0_13, IssuerMetadataV1_0_13 } from '../types/v1_0_13.types'

export function getSupportedCredentials(opts?: {
export function getSupportedCredentials(options?: {
issuerMetadata?: CredentialIssuerMetadata | IssuerMetadataV1_0_08 | IssuerMetadataV1_0_13;
version: OpenId4VCIVersion;
types?: string[][];
format?: (OID4VCICredentialFormat | string) | (OID4VCICredentialFormat | string)[];
}): CredentialConfigurationSupported[] {
if (opts?.types && Array.isArray(opts?.types)) {
return opts.types.flatMap((types) => getSupportedCredential({ ...opts, types }));
format?: OID4VCICredentialFormat | string | (OID4VCICredentialFormat | string)[];
}): Record<string, CredentialConfigurationSupported> {
if (options?.types && Array.isArray(options.types)) {
return options.types.map(typeSet => {
return getSupportedCredential({ ...options, types: typeSet });
}).reduce((acc, result) => {
Object.assign(acc, result);
return acc;
}, {} as Record<string, CredentialConfigurationSupported>);
}
return getSupportedCredential(opts ? { ...opts, types: undefined } : undefined);

return getSupportedCredential(options ? { ...options, types: undefined } : undefined);
}

export function getSupportedCredential(opts?: {
Expand All @@ -30,76 +35,50 @@ export function getSupportedCredential(opts?: {
types?: string | string[];
format?: (OID4VCICredentialFormat | string) | (OID4VCICredentialFormat | string)[];
}): Record<string, CredentialConfigurationSupported> {
const { issuerMetadata } = opts ?? {};
let formats: (OID4VCICredentialFormat | string)[];
if (opts?.format && Array.isArray(opts.format)) {
formats = opts.format;
} else if (opts?.format && !Array.isArray(opts.format)) {
formats = [opts.format];
} else {
formats = [];
}
let credentialConfigsSupported: Record<string, CredentialConfigurationSupported>;
// Safely extract properties from opts with default values
const { issuerMetadata, types, format } = opts ?? {};

// Default to an empty object if no metadata is provided
if (!issuerMetadata) {
return {};
}
const { version, types } = opts ?? { version: OpenId4VCIVersion.VER_1_0_13 };
if (version === OpenId4VCIVersion.VER_1_0_08
|| (!Array.isArray(issuerMetadata.credentials_supported) && !Array.isArray(issuerMetadata.credential_configurations_supported))) {
credentialConfigsSupported = credentialsSupportedV8ToV13((issuerMetadata as IssuerMetadataV1_0_08).credentials_supported ?? {});
} else {
credentialConfigsSupported = (issuerMetadata as CredentialIssuerMetadata).credential_configurations_supported;

// Handle formats array
let formats: (OID4VCICredentialFormat | string)[] = [];
if (Array.isArray(format)) {
formats = format;
} else if (format) {
formats = [format];
}

if (credentialConfigsSupported === undefined || Object.keys(credentialConfigsSupported).length === 0) {
// Define and fill credential configuration based on version and metadata
let credentialConfigsSupported: Record<string, CredentialConfigurationSupported> = {};
if (Object.keys(credentialConfigsSupported).length === 0) {
return {};
} else if (!types || types.length === 0) {
return credentialConfigsSupported;
}
/**
* the following (not array part is a legacy code from version 1_0-08 which JFF plugfest 2 implementors used)
*/
let initiationTypes: string[] | undefined;
if (opts?.types) {
if (typeof opts.types === 'string') {
initiationTypes = [opts.types];
} else {
initiationTypes = opts.types;
}
}
if (version === OpenId4VCIVersion.VER_1_0_08 && (!initiationTypes || initiationTypes?.length === 0)) {
initiationTypes = formats;
} else if ('credential_configurations_supported' in issuerMetadata) {
credentialConfigsSupported = (issuerMetadata as CredentialIssuerMetadataOptsV1_0_13).credential_configurations_supported!;
}
const supportedFormats: (CredentialOfferFormat | string)[] = formats && formats.length > 0 ? formats : ['jwt_vc_json', 'jwt_vc_json-ld', 'ldp_vc'];

const credentialSupportedOverlap: Record<string, CredentialConfigurationSupported> ={};
if ((opts?.types && typeof opts?.types === 'string') || opts?.types?.length === 1) {
const types = Array.isArray(opts.types) ? opts.types[0] : opts.types;
const supported = credentialConfigsSupported.filter(
(sup) => sup.id === types || (initiationTypes && arrayEqualsIgnoreOrder(getTypesFromCredentialSupported(sup), initiationTypes)),
);
if (supported) {
credentialSupportedOverlap.push(...supported);
}

// Exit early if no credentials are supported or no filtering is required
if (!types && Object.keys(credentialConfigsSupported).length > 0) {
return credentialConfigsSupported;
}

if (credentialSupportedOverlap.length === 0) {
// Make sure we include Verifiable Credential both on the offer side as well as in the metadata side, to ensure consistency of the issuer does not.
if (initiationTypes && !initiationTypes.includes('VerifiableCredential')) {
initiationTypes.push('VerifiableCredential');
}
const supported = credentialConfigsSupported.filter((sup) => {
const supTypes = getTypesFromCredentialSupported(sup);
if (!supTypes.includes('VerifiableCredential')) {
supTypes.push('VerifiableCredential');
}
return (!initiationTypes || arrayEqualsIgnoreOrder(supTypes, initiationTypes)) && supportedFormats.includes(sup.format);
});
if (supported) {
credentialSupportedOverlap.push(...supported);
// Normalize types to an array
const normalizedTypes = Array.isArray(types) ? types : types ? [types] : [];

// Filter configurations based on types and formats
const filteredConfigs: Record<string, CredentialConfigurationSupported> = {};
Object.entries(credentialConfigsSupported).forEach(([key, value]) => {
const isTypeMatch = normalizedTypes.length === 0 || normalizedTypes.includes(key);
const isFormatMatch = formats.length === 0 || formats.includes(value.format);

if (isTypeMatch && isFormatMatch) {
filteredConfigs[key] = value;
}
}
return credentialSupportedOverlap;
});

return filteredConfigs;
}

export function getTypesFromCredentialSupported(credentialSupported: CredentialConfigurationSupported, opts?: { filterVerifiableCredential: boolean }) {
Expand All @@ -124,17 +103,6 @@ export function getTypesFromCredentialSupported(credentialSupported: CredentialC
return types;
}

function arrayEqualsIgnoreOrder(a: string[], b: string[]) {
if (a.length !== b.length) return false;
const uniqueValues = new Set([...a, ...b]);
for (const v of uniqueValues) {
const aCount = a.filter((e) => e === v).length;
const bCount = b.filter((e) => e === v).length;
if (aCount !== bCount) return false;
}
return true;
}

export function credentialsSupportedV8ToV13(supportedV8: CredentialSupportedTypeV1_0_08): Record<string, CredentialConfigurationSupported> {
const credentialConfigsSupported:Record<string, CredentialConfigurationSupported> = {};
Object.entries(supportedV8).flatMap((entry) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/common/lib/types/CredentialIssuance.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { OpenId4VCIVersion } from './OpenID4VCIVersions.types';
import { CredentialOfferPayloadV1_0_08 } from './v1_0_08.types';
import { CredentialOfferPayloadV1_0_09, CredentialOfferV1_0_09 } from './v1_0_09.types';
import { CredentialOfferPayloadV1_0_11, CredentialOfferV1_0_11 } from './v1_0_11.types';
import { CredentialOfferPayloadV1_0_13 } from './v1_0_13.types'

export interface CredentialResponse {
credential?: W3CVerifiableCredential; // OPTIONAL. Contains issued Credential. MUST be present when acceptance_token is not returned. MAY be a JSON string or a JSON object, depending on the Credential format. See Appendix E for the Credential format specific encoding requirements
Expand All @@ -27,7 +28,7 @@ export interface CredentialOfferRequestWithBaseUrl extends UniformCredentialOffe

export type CredentialOffer = CredentialOfferV1_0_09 | CredentialOfferV1_0_11;

export type CredentialOfferPayload = (CredentialOfferPayloadV1_0_08 | CredentialOfferPayloadV1_0_09 | CredentialOfferPayloadV1_0_11) & {
export type CredentialOfferPayload = (CredentialOfferPayloadV1_0_08 | CredentialOfferPayloadV1_0_09 | CredentialOfferPayloadV1_0_11 | CredentialOfferPayloadV1_0_13) & {
[x: string]: any;
};

Expand Down
Loading

0 comments on commit e522a3d

Please sign in to comment.