@sphereon/did-auth-siop
Version:
Self Issued OpenID V2 (SIOPv2) and OpenID 4 Verifiable Presentations (OID4VP)
89 lines (76 loc) • 3.45 kB
text/typescript
import { Hasher } from '@sphereon/ssi-types'
import { DcqlMdocCredential, DcqlPresentation, DcqlPresentationResult, DcqlQuery, DcqlSdJwtVcCredential } from 'dcql'
import { extractDataFromPath } from '../helpers'
import { AuthorizationRequestPayload, SIOPErrors } from '../types'
import { extractDcqlPresentationFromDcqlVpToken } from './OpenID4VP'
/**
* Finds a valid DcqlQuery inside the given AuthenticationRequestPayload
* throws exception if the DcqlQuery is not valid
* returns the decoded dcql query if a valid instance found
* @param authorizationRequestPayload object that can have a dcql_query inside
* @param version
*/
export class Dcql {
static findValidDcqlQuery = async (authorizationRequestPayload: AuthorizationRequestPayload): Promise<DcqlQuery | undefined> => {
const dcqlQuery: string[] = extractDataFromPath(authorizationRequestPayload, '$.dcql_query').map((d) => d.value)
const definitions = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition')
const definitionsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition[*]')
const definitionRefs = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri')
const definitionRefsFromList = extractDataFromPath(authorizationRequestPayload, '$.presentation_definition_uri[*]')
const hasPD = (definitions && definitions.length > 0) || (definitionsFromList && definitionsFromList.length > 0)
const hasPdRef = (definitionRefs && definitionRefs.length > 0) || (definitionRefsFromList && definitionRefsFromList.length > 0)
const hasDcql = dcqlQuery && dcqlQuery.length > 0
if ([hasPD, hasPdRef, hasDcql].filter(Boolean).length > 1) {
throw new Error(SIOPErrors.REQUEST_CLAIMS_PRESENTATION_NON_EXCLUSIVE)
}
if (dcqlQuery.length === 0) return undefined
if (dcqlQuery.length > 1) {
throw new Error('Found multiple dcql_query in vp_token. Only one is allowed')
}
return DcqlQuery.parse(JSON.parse(dcqlQuery[0]))
}
static getDcqlPresentationResult = (
record: DcqlPresentation | string,
dcqlQuery: DcqlQuery,
opts: {
hasher?: Hasher
},
) => {
const dcqlPresentation = Object.fromEntries(
Object.entries(extractDcqlPresentationFromDcqlVpToken(record, opts)).map(([queryId, p]) => {
if (p.format === 'mso_mdoc') {
return [
queryId,
{
credential_format: 'mso_mdoc',
doctype: p.vcs[0].credential.toJson().docType,
namespaces: p.vcs[0].decoded,
} satisfies DcqlMdocCredential,
]
} else if (p.format === 'vc+sd-jwt') {
return [
queryId,
{
credential_format: 'vc+sd-jwt',
vct: p.vcs[0].decoded.vct,
claims: p.vcs[0].decoded,
} satisfies DcqlSdJwtVcCredential,
]
} else {
throw new Error('DcqlPresentation atm only supports mso_mdoc and vc+sd-jwt')
}
}),
)
return DcqlPresentationResult.fromDcqlPresentation(dcqlPresentation, { dcqlQuery })
}
static assertValidDcqlPresentationResult = async (
record: DcqlPresentation | string,
dcqlQuery: DcqlQuery,
opts: {
hasher?: Hasher
},
) => {
const result = Dcql.getDcqlPresentationResult(record, dcqlQuery, opts)
return DcqlPresentationResult.validate(result)
}
}