Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/fix/post-merge' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderPostma committed Sep 20, 2024
2 parents 363c631 + 74b00cb commit 5ea7ad2
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 77 deletions.
2 changes: 1 addition & 1 deletion packages/did-auth-siop-adapter/lib/did/DIDResolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,5 @@ export async function resolveDidDocument(did: string, opts?: ResolveOpts): Promi
// todo: This looks like a bug. It seems that sometimes we get back a DID document directly instead of a did resolution results
return result as unknown as DIDDocument
}
return result.didDocument
return result.didDocument as DIDDocument
}
2 changes: 1 addition & 1 deletion packages/did-auth-siop-adapter/lib/did/DidJWT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ export function getSubDidFromPayload(payload: JWTPayload, header?: JWTHeader): s
export function isIssSelfIssued(payload: JWTPayload): boolean {
return (
(payload.iss && payload.iss.includes(ResponseIss.SELF_ISSUED_V1)) ||
payload.iss.includes(ResponseIss.SELF_ISSUED_V2) ||
(payload.iss && payload.iss.includes(ResponseIss.SELF_ISSUED_V2)) ||
payload.iss === payload.sub
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ describe('create JWT from Request JWT should', () => {
},
],
constraints: {
limit_disclosure: 'required',
//limit_disclosure: 'required',
fields: [
{
path: ['$.issuer.id'],
Expand Down Expand Up @@ -486,7 +486,7 @@ describe('create JWT from Request JWT should', () => {
},
],
constraints: {
limit_disclosure: 'required',
// limit_disclosure: 'required',
fields: [
{
path: ['$.issuer.id'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ describe('OID4VCI-Client using Mattr issuer should', () => {

const correlationId = 'test'

const verifiedAuthRequest = await AuthorizationRequest.verify(authorizeRequestUri, {
const authorizationRequest = await AuthorizationRequest.fromUriOrJwt(offer.authorizeRequestUri);
const verifiedAuthRequest = await authorizationRequest.verify({
correlationId,
verifyJwtCallback: getVerifyJwtCallback(getResolver()),
verification: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,10 @@ describe('Language tag util should', () => {
expect(() => LanguageTagUtils.getLanguageTaggedProperties({}, null as any)).toThrowError()
})

it('throw error if list is given but not effective', async () => {
it('return empty if list is given but not effective', async () => {
expect.assertions(1)
await expect(() => LanguageTagUtils.getLanguageTaggedProperties({}, [])).toThrowError()
const result = await LanguageTagUtils.getLanguageTaggedProperties({}, [])
expect(result).toEqual(new Map<string, string>)
})

it('throw error if list is given but no proper field names', async () => {
Expand All @@ -223,9 +224,10 @@ describe('Language tag util should', () => {
expect(LanguageTagUtils.getLanguageTaggedPropertiesMapped({}, null as any)).toEqual(new Map<string, string>())
})

it('throw error if mapping is given but not effective', async () => {
it('return empty map if mapping is given but not effective', async () => {
expect.assertions(1)
await expect(() => LanguageTagUtils.getLanguageTaggedPropertiesMapped({}, new Map<string, string>())).toThrowError()
const result = await LanguageTagUtils.getLanguageTaggedPropertiesMapped({}, new Map<string, string>())
expect(result).toEqual(new Map<string, string>)
})

it('throw error if mapping is given but no proper names', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ import { CreateAuthorizationRequestOpts, VerifyAuthorizationRequestOpts } from '
export class AuthorizationRequest {
private readonly _requestObject?: RequestObject
private readonly _payload: AuthorizationRequestPayload
private readonly _options: CreateAuthorizationRequestOpts | undefined
private _uri: URI | undefined
private readonly _options: CreateAuthorizationRequestOpts
private _uri: URI

private constructor(payload: AuthorizationRequestPayload, requestObject?: RequestObject, opts?: CreateAuthorizationRequestOpts, uri?: URI) {
this._options = opts
Expand Down Expand Up @@ -66,7 +66,7 @@ export class AuthorizationRequest {

const requestObjectArg =
opts.requestObject.passBy !== PassBy.NONE ? (requestObject ? requestObject : await RequestObject.fromOpts(opts)) : undefined
const requestPayload = await createAuthorizationRequestPayload(opts, requestObjectArg)
const requestPayload = opts?.payload ? await createAuthorizationRequestPayload(opts, requestObjectArg) : undefined
return new AuthorizationRequest(requestPayload, requestObjectArg, opts)
}

Expand Down Expand Up @@ -116,13 +116,10 @@ export class AuthorizationRequest {
async verify(opts: VerifyAuthorizationRequestOpts): Promise<VerifiedAuthorizationRequest> {
assertValidVerifyAuthorizationRequestOpts(opts)

let requestObjectPayload: RequestObjectPayload | undefined
let requestObjectPayload: RequestObjectPayload | undefined = undefined

const jwt = await this.requestObjectJwt()
if(jwt === undefined) {
return Promise.reject(Error('jwt could be fetched, request object unavailable'))
}
const parsedJwt = parseJWT(jwt)
const parsedJwt = jwt ? parseJWT(jwt) : undefined

if (parsedJwt) {
requestObjectPayload = parsedJwt.payload as RequestObjectPayload
Expand Down Expand Up @@ -167,10 +164,7 @@ export class AuthorizationRequest {
)
assertValidRPRegistrationMedataPayload(registrationMetadataPayload)
// TODO: We need to do something with the metadata probably
} else {
return Promise.reject(Error(`could not fetch registrationMetadataPayload due to missing payload key ${registrationPropertyKey}`))
}

// When the response_uri parameter is present, the redirect_uri Authorization Request parameter MUST NOT be present. If the redirect_uri Authorization Request parameter is present when the Response Mode is direct_post, the Wallet MUST return an invalid_request Authorization Response error.
let responseURIType: ResponseURIType
let responseURI: string
Expand All @@ -192,7 +186,7 @@ export class AuthorizationRequest {
// TODO: we need to verify somewhere that if response_mode is direct_post, that the response_uri may be present,
// BUT not both redirect_uri and response_uri. What is the best place to do this?

const presentationDefinitions: PresentationDefinitionWithLocation[] = await PresentationExchange.findValidPresentationDefinitions(mergedPayload, await this.getSupportedVersion())
const presentationDefinitions = await PresentationExchange.findValidPresentationDefinitions(mergedPayload, await this.getSupportedVersion())
return {
jwt,
payload: parsedJwt?.payload,
Expand All @@ -211,7 +205,7 @@ export class AuthorizationRequest {
}
}

static async verify(requestOrUri: string, verifyOpts: VerifyAuthorizationRequestOpts): Promise<VerifiedAuthorizationRequest> {
static async verify(requestOrUri: string, verifyOpts: VerifyAuthorizationRequestOpts) {
assertValidVerifyAuthorizationRequestOpts(verifyOpts)
const authorizationRequest = await AuthorizationRequest.fromUriOrJwt(requestOrUri)
return await authorizationRequest.verify(verifyOpts)
Expand All @@ -226,7 +220,7 @@ export class AuthorizationRequest {
throw Error(SIOPErrors.BAD_PARAMS)
}
const requestObject = await RequestObject.fromJwt(jwt)
const payload: AuthorizationRequestPayload = { ...(requestObject && await requestObject.getPayload()) } as AuthorizationRequestPayload
const payload: AuthorizationRequestPayload = { ...(await requestObject.getPayload()) } as AuthorizationRequestPayload
// Although this was a RequestObject we instantiate it as AuthzRequest and then copy in the JWT as the request Object
payload.request = jwt
return new AuthorizationRequest({ ...payload }, requestObject)
Expand All @@ -237,23 +231,22 @@ export class AuthorizationRequest {
throw Error(SIOPErrors.BAD_PARAMS)
}
const uriObject = typeof uri === 'string' ? await URI.fromUri(uri) : uri
const requestObject = uriObject.requestObjectJwt ? await RequestObject.fromJwt(uriObject.requestObjectJwt) : undefined
const requestObject = await RequestObject.fromJwt(uriObject.requestObjectJwt)
return new AuthorizationRequest(uriObject.authorizationRequestPayload, requestObject, undefined, uriObject)
}

public async toStateInfo(): Promise<RequestStateInfo> {

const requestObjectPayload = this.requestObject !== undefined ? await this.requestObject.getPayload() : undefined
const requestObject = await this.requestObject.getPayload()
return {
client_id: this.options?.clientMetadata?.client_id ?? this.payload.client_id,
iat: requestObjectPayload?.iat ?? this.payload.iat,
nonce: requestObjectPayload?.nonce ?? this.payload.nonce,
client_id: this.options.clientMetadata.client_id,
iat: requestObject.iat ?? this.payload.iat,
nonce: requestObject.nonce ?? this.payload.nonce,
state: this.payload.state,
}
}

public async containsResponseType(singleType: ResponseType | string): Promise<boolean> {
const responseType: string | undefined = await this.getMergedProperty('response_type')
const responseType: string = await this.getMergedProperty('response_type')
return responseType?.includes(singleType) === true
}

Expand All @@ -263,14 +256,10 @@ export class AuthorizationRequest {
}

public async mergedPayloads(): Promise<RequestObjectPayload> {
const requestObjectPayload = { ...this.payload, ...(this.requestObject && (await this.requestObject.getPayload())) }
if (typeof requestObjectPayload.scope !== 'string') {
throw new Error('Invalid scope value')
}
return requestObjectPayload as RequestObjectPayload
return { ...this.payload, ...(this.requestObject && (await this.requestObject.getPayload())) }
}

public async getPresentationDefinitions(version?: SupportedVersion): Promise<PresentationDefinitionWithLocation[]> {
public async getPresentationDefinitions(version?: SupportedVersion): Promise<PresentationDefinitionWithLocation[] | undefined> {
return await PresentationExchange.findValidPresentationDefinitions(await this.mergedPayloads(), version)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ export class PresentationExchange {
throw new Error(SIOPErrors.NO_PRESENTATION_SUBMISSION)
}

if (!evaluationResults.areRequiredCredentialsPresent || evaluationResults.errors || !evaluationResults.value) {
if (evaluationResults.areRequiredCredentialsPresent === Status.ERROR || evaluationResults.errors?.length || !evaluationResults.value) {
throw new Error(`message: ${SIOPErrors.COULD_NOT_FIND_VCS_MATCHING_PD}, details: ${JSON.stringify(evaluationResults.errors)}`)
}

Expand Down
16 changes: 6 additions & 10 deletions packages/siop-oid4vp/lib/helpers/LanguageTagUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,12 @@ export class LanguageTagUtils {
}

private static assertValidTargetFieldNames(languageTagEnabledFieldsNamesMapping: Map<string, string>): void {
if (languageTagEnabledFieldsNamesMapping) {
if (!languageTagEnabledFieldsNamesMapping.size) {
throw new Error(SIOPErrors.BAD_PARAMS + ' LanguageTagEnabledFieldsNamesMapping must be non-null or non-empty')
} else {
for (const entry of languageTagEnabledFieldsNamesMapping.entries()) {
const key = entry[0]
const value = entry[1]
if (isStringNullOrEmpty(key) || isStringNullOrEmpty(value)) {
throw new Error(SIOPErrors.BAD_PARAMS + '. languageTagEnabledFieldsName must be non-null or non-empty')
}
if (languageTagEnabledFieldsNamesMapping && languageTagEnabledFieldsNamesMapping.size) {
for (const entry of languageTagEnabledFieldsNamesMapping.entries()) {
const key = entry[0]
const value = entry[1]
if (isStringNullOrEmpty(key) || isStringNullOrEmpty(value)) {
throw new Error(SIOPErrors.BAD_PARAMS + '. languageTagEnabledFieldsName must be non-null or non-empty')
}
}
}
Expand Down
35 changes: 8 additions & 27 deletions packages/siop-oid4vp/lib/helpers/Metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,40 +84,21 @@ function supportedSubjectSyntaxTypes(rpMethods: string[] | string, opMethods: st
return supportedSubjectSyntaxTypes
}

export function collectAlgValues(o: any): string[] {
const algValues: string[] = [];
for (const key of Object.keys(o)) {
// Check if the object has an 'alg' property that's an array of strings
if (key === 'alg' && Array.isArray(o.alg)) {
algValues.push(...o.alg);
}
else if (key === 'sd-jwt_alg_values' && Array.isArray(o['sd-jwt_alg_values'])) {
algValues.push(...o['sd-jwt_alg_values']);
}
}

return algValues;
}

function getFormatIntersection(rpFormat: Format, opFormat: Format): Format {
const intersectionFormat: Record<string, any> = {}
const supportedCredentials = getIntersection(Object.keys(rpFormat), Object.keys(opFormat))
if (!supportedCredentials.length) {
throw new Error(SIOPErrors.CREDENTIAL_FORMATS_NOT_SUPPORTED)
}
supportedCredentials.forEach(function (crFormat: string) {
const rpFormatElement = rpFormat[crFormat as keyof Format];
const opFormatElement = opFormat[crFormat as keyof Format];
const rpAlgs = collectAlgValues(rpFormatElement);
const opAlgs = collectAlgValues(opFormatElement);
let methodKeyRP = undefined;
let methodKeyOP = undefined;
if (rpFormatElement !== undefined) {
Object.keys(rpFormatElement).forEach((k) => (methodKeyRP = k));
}
if (opFormatElement !== undefined) {
Object.keys(opFormatElement).forEach((k) => (methodKeyOP = k));
}
const rpAlgs = []
const opAlgs = []
Object.keys(rpFormat[crFormat]).forEach((k) => rpAlgs.push(...rpFormat[crFormat][k]))
Object.keys(opFormat[crFormat]).forEach((k) => opAlgs.push(...opFormat[crFormat][k]))
let methodKeyRP = undefined
let methodKeyOP = undefined
Object.keys(rpFormat[crFormat]).forEach((k) => (methodKeyRP = k))
Object.keys(opFormat[crFormat]).forEach((k) => (methodKeyOP = k))
if (methodKeyRP !== methodKeyOP) {
throw new Error(SIOPErrors.CREDENTIAL_FORMATS_NOT_SUPPORTED)
}
Expand Down
5 changes: 2 additions & 3 deletions packages/siop-oid4vp/lib/rp/Opts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defaultHasher, uuidv4 } from '@sphereon/oid4vc-common'
import { defaultHasher } from '@sphereon/oid4vc-common'

import { CreateAuthorizationRequestOpts, PropertyTarget, PropertyTargets, RequestPropertyWithTargets } from '../authorization-request'
import { VerifyAuthorizationResponseOpts } from '../authorization-response'
Expand Down Expand Up @@ -48,11 +48,10 @@ export const createRequestOptsFromBuilderOrExistingOpts = (opts: { builder?: RPB
return createRequestOpts
}

export const createVerifyResponseOptsFromBuilderOrExistingOpts = (opts: { builder?: RPBuilder; verifyOpts?: VerifyAuthorizationResponseOpts }):VerifyAuthorizationResponseOpts => {
export const createVerifyResponseOptsFromBuilderOrExistingOpts = (opts: { builder?: RPBuilder; verifyOpts?: VerifyAuthorizationResponseOpts }): Partial<VerifyAuthorizationResponseOpts> => {
return opts.builder
? {
hasher: opts.builder.hasher ?? defaultHasher,
correlationId: uuidv4(),
verifyJwtCallback: opts.builder.verifyJwtCallback,
verification: {
presentationVerificationCallback: opts.builder.presentationVerificationCallback,
Expand Down

0 comments on commit 5ea7ad2

Please sign in to comment.