Skip to content

Commit

Permalink
chore: fixing a flood of typescript errors
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderPostma committed Sep 19, 2024
1 parent 3335c3f commit 125e73d
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 55 deletions.
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
private _uri: URI
private readonly _options: CreateAuthorizationRequestOpts | undefined
private _uri: URI | undefined

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 = opts?.payload ? await createAuthorizationRequestPayload(opts, requestObjectArg) : undefined
const requestPayload = await createAuthorizationRequestPayload(opts, requestObjectArg)
return new AuthorizationRequest(requestPayload, requestObjectArg, opts)
}

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

let requestObjectPayload: RequestObjectPayload
let requestObjectPayload: RequestObjectPayload | undefined

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

if (parsedJwt) {
requestObjectPayload = parsedJwt.payload as RequestObjectPayload
Expand Down Expand Up @@ -148,7 +151,7 @@ export class AuthorizationRequest {
// AuthorizationRequest.assertValidRequestObject(origAuthenticationRequest);

// We use the orig request for default values, but the JWT payload contains signed request object properties
const mergedPayload = { ...this.payload, ...requestObjectPayload }
const mergedPayload = { ...this.payload, ...(requestObjectPayload ? requestObjectPayload : {}) }
if (opts.state && mergedPayload.state !== opts.state) {
throw new Error(`${SIOPErrors.BAD_STATE} payload: ${mergedPayload.state}, supplied: ${opts.state}`)
} else if (opts.nonce && mergedPayload.nonce !== opts.nonce) {
Expand All @@ -164,7 +167,10 @@ 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 Down Expand Up @@ -220,7 +226,7 @@ export class AuthorizationRequest {
throw Error(SIOPErrors.BAD_PARAMS)
}
const requestObject = await RequestObject.fromJwt(jwt)
const payload: AuthorizationRequestPayload = { ...(await requestObject.getPayload()) } as AuthorizationRequestPayload
const payload: AuthorizationRequestPayload = { ...(requestObject && 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 @@ -231,22 +237,23 @@ export class AuthorizationRequest {
throw Error(SIOPErrors.BAD_PARAMS)
}
const uriObject = typeof uri === 'string' ? await URI.fromUri(uri) : uri
const requestObject = await RequestObject.fromJwt(uriObject.requestObjectJwt)
const requestObject = uriObject.requestObjectJwt ? await RequestObject.fromJwt(uriObject.requestObjectJwt) : undefined
return new AuthorizationRequest(uriObject.authorizationRequestPayload, requestObject, undefined, uriObject)
}

public async toStateInfo(): Promise<RequestStateInfo> {
const requestObject = await this.requestObject.getPayload()

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import {
PresentationSubmissionLocation,
SelectResults,
Status,
Validated,
VerifiablePresentationFromOpts,
VerifiablePresentationResult,
VerifiablePresentationResult
} from '@sphereon/pex'
import { PresentationEvaluationResults } from '@sphereon/pex/dist/main/lib/evaluation'
import { Format, PresentationDefinitionV1, PresentationDefinitionV2, PresentationSubmission } from '@sphereon/pex-models'
Expand Down Expand Up @@ -63,14 +64,14 @@ export class PresentationExchange {
...options,
presentationSubmissionLocation: PresentationSubmissionLocation.EXTERNAL,
proofOptions: {
...options.proofOptions,
...options?.proofOptions,
proofPurpose: options?.proofOptions?.proofPurpose ?? IProofPurpose.authentication,
type: options?.proofOptions?.type ?? IProofType.EcdsaSecp256k1Signature2019,
/* challenge: options?.proofOptions?.challenge,
domain: options?.proofOptions?.domain,*/
},
signatureOptions: {
...options.signatureOptions,
...options?.signatureOptions,
// verificationMethod: options?.signatureOptions?.verificationMethod,
keyEncoding: options?.signatureOptions?.keyEncoding ?? KeyEncoding.Hex,
},
Expand Down Expand Up @@ -116,9 +117,10 @@ export class PresentationExchange {
}

public static assertValidPresentationSubmission(presentationSubmission: PresentationSubmission) {
const validationResult = PEX.validateSubmission(presentationSubmission)
if (validationResult[0].message != 'ok') {
throw new Error(`${SIOPErrors.RESPONSE_OPTS_PRESENTATIONS_SUBMISSION_IS_NOT_VALID}, details ${JSON.stringify(validationResult[0])}`)
const validationResult:Validated = PEX.validateSubmission(presentationSubmission)
if (Array.isArray(validationResult) && validationResult[0].message != 'ok'
|| !Array.isArray(validationResult) && validationResult.message != 'ok') {
throw new Error(`${SIOPErrors.RESPONSE_OPTS_PRESENTATIONS_SUBMISSION_IS_NOT_VALID}, details ${JSON.stringify(validationResult)}`)
}
}

Expand Down Expand Up @@ -242,7 +244,8 @@ export class PresentationExchange {

private static assertValidPresentationDefinition(presentationDefinition: IPresentationDefinition) {
const validationResult = PEX.validateDefinition(presentationDefinition)
if (validationResult[0].message != 'ok') {
if (Array.isArray(validationResult) && validationResult[0].message != 'ok'
|| !Array.isArray(validationResult) && validationResult.message != 'ok') {
throw new Error(`${SIOPErrors.REQUEST_CLAIMS_PRESENTATION_DEFINITION_NOT_VALID}`)
}
}
Expand Down Expand Up @@ -317,7 +320,7 @@ export class PresentationExchange {
throw new Error(SIOPErrors.NO_PRESENTATION_SUBMISSION)
}

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

Expand All @@ -330,12 +333,12 @@ export class PresentationExchange {
const presentationsToVerify = Array.isArray(evaluationResults.presentation) ? evaluationResults.presentation : [evaluationResults.presentation]
// The verifyPresentationCallback function is mandatory for RP only,
// So the behavior here is to bypass it if not present
if (verifyPresentationCallback) {
if (verifyPresentationCallback && evaluationResults.value !== undefined) {
// Verify the signature of all VPs
await Promise.all(
presentationsToVerify.map(async (presentation) => {
try {
const verificationResult = await verifyPresentationCallback(presentation as W3CVerifiablePresentation, evaluationResults.value)
const verificationResult = await verifyPresentationCallback(presentation as W3CVerifiablePresentation, evaluationResults.value!)
if (!verificationResult.verified) {
throw new Error(
SIOPErrors.VERIFIABLE_PRESENTATION_SIGNATURE_NOT_VALID + verificationResult.reason ? `. ${verificationResult.reason}` : '',
Expand Down
9 changes: 5 additions & 4 deletions packages/siop-oid4vp/lib/helpers/Encodings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ export function decodeUriAsJson(uri: string) {
}
const parts = parse(queryString, { plainObjects: true, depth: 10, parameterLimit: 5000, ignoreQueryPrefix: true })

const descriptors = parts?.claims?.['vp_token']?.presentation_definition?.['input_descriptors']
const vpToken = (parts?.claims as { [key: string]: any })?.['vp_token'];
const descriptors = vpToken?.presentation_definition?.['input_descriptors']; // FIXME?
if (descriptors && Array.isArray(descriptors)) {
// Whenever we have a [{'uri': 'str1'}, 'uri': 'str2'] qs changes this to {uri: ['str1','str2']} which means schema validation fails. So we have to fix that
parts.claims['vp_token'].presentation_definition['input_descriptors'] = descriptors.map((descriptor: InputDescriptorV1) => {
vpToken.presentation_definition['input_descriptors'] = descriptors.map((descriptor: InputDescriptorV1) => {
if (Array.isArray(descriptor.schema)) {
descriptor.schema = descriptor.schema.flatMap((val) => {
if (typeof val === 'string') {
Expand All @@ -32,7 +33,7 @@ export function decodeUriAsJson(uri: string) {
})
}

const json = {}
const json:Record<string, any> = {}
for (const key in parts) {
const value = parts[key]
if (!value) {
Expand All @@ -56,7 +57,7 @@ export function decodeUriAsJson(uri: string) {
return JSON.parse(JSON.stringify(json))
}

export function encodeJsonAsURI(json: unknown, _opts?: { arraysWithIndex?: string[] }): string {
export function encodeJsonAsURI(json: Record<string, unknown>, _opts?: { arraysWithIndex?: string[] }): string {
if (typeof json === 'string') {
return encodeJsonAsURI(JSON.parse(json))
}
Expand Down
6 changes: 3 additions & 3 deletions packages/siop-oid4vp/lib/helpers/HttpUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const siopFetch = async <T>(
if (!url || url.toLowerCase().startsWith('did:')) {
throw Error(`Invalid URL supplied. Expected a http(s) URL. Recieved: ${url}`)
}
const headers = opts?.customHeaders ? opts.customHeaders : {}
const headers:Record<string, any> = opts?.customHeaders ? opts.customHeaders : {}
if (opts?.bearerToken) {
headers['Authorization'] = `Bearer ${opts.bearerToken}`
}
Expand All @@ -87,7 +87,7 @@ const siopFetch = async <T>(
const textResponseBody = await clonedResponse.text()

const isJSONResponse =
(accept === 'application/json' || origResponse.headers['Content-Type'] === 'application/json') && textResponseBody.trim().startsWith('{')
(accept === 'application/json' || origResponse.headers.get('Content-Type') === 'application/json') && textResponseBody.trim().startsWith('{')
const responseBody = isJSONResponse ? JSON.parse(textResponseBody) : textResponseBody

if (success || opts?.exceptionOnHttpErrorStatus) {
Expand Down Expand Up @@ -131,7 +131,7 @@ export const fetchByReferenceOrUseByValue = async <T>(referenceURI: string, valu
response = await getWithUrl(referenceURI, textResponse)
} catch (e) {
console.log(e)
throw new Error(`${SIOPErrors.REG_PASS_BY_REFERENCE_INCORRECTLY}: ${e.message}, URL: ${referenceURI}`)
throw new Error(`${SIOPErrors.REG_PASS_BY_REFERENCE_INCORRECTLY}: ${(e as Error).message}, URL: ${referenceURI}`)
}
}
return response
Expand Down
8 changes: 4 additions & 4 deletions packages/siop-oid4vp/lib/helpers/LanguageTagUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export class LanguageTagUtils {
*
* @param source is the object from which the language enabled fields and their values will be extracted.
*/
static getAllLanguageTaggedProperties(source: unknown): Map<string, string> {
return this.getLanguageTaggedPropertiesMapped(source, undefined)
static getAllLanguageTaggedProperties(source: object): Map<string, string> {
return this.getLanguageTaggedPropertiesMapped(source, new Map() )
}

/**
Expand All @@ -23,7 +23,7 @@ export class LanguageTagUtils {
* @param source is the object from which the language enabled fields and their values will be extracted.
* @param requiredFieldNames the fields which are supposed to be language enabled. These are the only fields which should be returned.
*/
static getLanguageTaggedProperties(source: unknown, requiredFieldNames: Array<string>): Map<string, string> {
static getLanguageTaggedProperties(source: object, requiredFieldNames: Array<string>): Map<string, string> {
const languageTagEnabledFieldsNamesMapping: Map<string, string> = new Map<string, string>()
requiredFieldNames.forEach((value) => languageTagEnabledFieldsNamesMapping.set(value, value))
return this.getLanguageTaggedPropertiesMapped(source, languageTagEnabledFieldsNamesMapping)
Expand All @@ -36,7 +36,7 @@ export class LanguageTagUtils {
* @param requiredFieldNamesMapping the fields which are supposed to be language enabled. These are the only fields which should be returned. And
* the fields names will be transformed as per the mapping provided.
*/
static getLanguageTaggedPropertiesMapped(source: unknown, requiredFieldNamesMapping: Map<string, string>): Map<string, string> {
static getLanguageTaggedPropertiesMapped(source: object, requiredFieldNamesMapping: Map<string, string>): Map<string, string> {
this.assertSourceIsWorthChecking(source)
this.assertValidTargetFieldNames(requiredFieldNamesMapping)

Expand Down
49 changes: 37 additions & 12 deletions packages/siop-oid4vp/lib/helpers/Metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export function assertValidMetadata(opMetadata: DiscoveryMetadataPayload, rpMeta
const credentials = supportedCredentialsFormats(rpMetadata.vp_formats, opMetadata.vp_formats)
const isValidSubjectSyntax = verifySubjectSyntaxes(rpMetadata.subject_syntax_types_supported)
if (isValidSubjectSyntax && rpMetadata.subject_syntax_types_supported) {
subjectSyntaxTypesSupported = supportedSubjectSyntaxTypes(rpMetadata.subject_syntax_types_supported, opMetadata.subject_syntax_types_supported)
subjectSyntaxTypesSupported = supportedSubjectSyntaxTypes(rpMetadata.subject_syntax_types_supported, opMetadata.subject_syntax_types_supported as string[])
} else if (isValidSubjectSyntax && (!rpMetadata.subject_syntax_types_supported || !rpMetadata.subject_syntax_types_supported.length)) {
if (opMetadata.subject_syntax_types_supported || opMetadata.subject_syntax_types_supported.length) {
if (opMetadata.subject_syntax_types_supported) {
subjectSyntaxTypesSupported = [...opMetadata.subject_syntax_types_supported]
}
}
Expand Down Expand Up @@ -84,21 +84,44 @@ function supportedSubjectSyntaxTypes(rpMethods: string[] | string, opMethods: st
return supportedSubjectSyntaxTypes
}

export function collectAlgValues(o: any): string[] {
const algValues: string[] = [];
for (const value of Object.values(o)) {
if (value) {
// Check if the object has an 'alg' property that's an array of strings
if (Array.isArray((value as any).alg)) {
algValues.push(...(value as any).alg);
}

// Check for the special case 'sd-jwt_alg_values'
if (Array.isArray((value as any)['sd-jwt_alg_values'])) {
algValues.push(...(value as any)['sd-jwt_alg_values']);
}
}
}

return algValues;
}

function getFormatIntersection(rpFormat: Format, opFormat: Format): Format {
const intersectionFormat: 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 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))
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));
}
if (methodKeyRP !== methodKeyOP) {
throw new Error(SIOPErrors.CREDENTIAL_FORMATS_NOT_SUPPORTED)
}
Expand All @@ -107,7 +130,9 @@ function getFormatIntersection(rpFormat: Format, opFormat: Format): Format {
throw new Error(SIOPErrors.CREDENTIAL_FORMATS_NOT_SUPPORTED)
}
intersectionFormat[crFormat] = {}
intersectionFormat[crFormat][methodKeyOP] = algs
if(methodKeyOP !== undefined) {
intersectionFormat[crFormat][methodKeyOP] = algs
}
})
return intersectionFormat
}
Expand Down
4 changes: 2 additions & 2 deletions packages/siop-oid4vp/lib/helpers/ObjectUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function isStringNullOrEmpty(key: string) {
return !key || !key.length
}

export function removeNullUndefined(data: unknown) {
export function removeNullUndefined<T>(data: T) : T {
if (!data) {
return data
}
Expand All @@ -22,5 +22,5 @@ export function removeNullUndefined(data: unknown) {
return [key, value]
})
//transform the key-value pairs back to an object.
return Object.fromEntries(clean)
return Object.fromEntries(clean) as T
}
4 changes: 2 additions & 2 deletions packages/siop-oid4vp/lib/types/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ export class AuthorizationEvent<T> {
this._error = args.error
}

get subject(): T {
get subject(): T | undefined {
return this._subject
}

get timestamp(): number {
return this._timestamp
}

get error(): Error {
get error(): Error | undefined {
return this._error
}

Expand Down
6 changes: 3 additions & 3 deletions packages/siop-oid4vp/lib/types/SIOP.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,9 @@ export interface RequestStateInfo {
client_id: string // RP ID

// sub: string
nonce: string
state: string
iat: number
nonce?: string
state?: string
iat?: number
}

interface DiscoveryMetadataCommonOpts {
Expand Down
Loading

0 comments on commit 125e73d

Please sign in to comment.