@sphereon/ssi-sdk.vc-status-list
Version:
Sphereon SSI-SDK plugin for Status List management, like StatusList2021.
81 lines (70 loc) • 2.69 kB
text/typescript
import { type CompactJWT, JoseSignatureAlgorithm } from '@sphereon/ssi-types'
import { createHeaderAndPayload, StatusList, type StatusListJWTHeaderParameters, type StatusListJWTPayload } from '@sd-jwt/jwt-status-list'
import base64url from 'base64url'
import type { JWTPayload } from 'did-jwt'
import type { IRequiredContext, SignedStatusListData } from '../../types'
import { type DecodedStatusListPayload, resolveIdentifier } from './common'
import type { TKeyType } from '@veramo/core'
import { ensureManagedIdentifierResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
const STATUS_LIST_JWT_TYP = 'statuslist+jwt'
export const createSignedJwt = async (
context: IRequiredContext,
statusList: StatusList,
issuerString: string,
id: string,
expiresAt?: Date,
keyRef?: string,
): Promise<SignedStatusListData> => {
const identifier = await resolveIdentifier(context, issuerString, keyRef)
const resolution = await ensureManagedIdentifierResult(identifier, context)
const payload: JWTPayload = {
iss: issuerString,
sub: id,
iat: Math.floor(Date.now() / 1000),
...(expiresAt && { exp: Math.floor(expiresAt.getTime() / 1000) }),
}
const header: StatusListJWTHeaderParameters = {
alg: getSigningAlgo(resolution.key.type),
typ: STATUS_LIST_JWT_TYP,
}
const values = createHeaderAndPayload(statusList, payload, header)
const signedJwt = await context.agent.jwtCreateJwsCompactSignature({
issuer: { ...identifier, noIssPayloadUpdate: false },
protectedHeader: values.header,
payload: values.payload,
})
return {
statusListCredential: signedJwt.jwt,
encodedList: (values.payload as StatusListJWTPayload).status_list.lst,
}
}
export const decodeStatusListJWT = (jwt: CompactJWT): DecodedStatusListPayload => {
const [, payloadBase64] = jwt.split('.')
const payload = JSON.parse(base64url.decode(payloadBase64))
if (!payload.iss || !payload.sub || !payload.status_list) {
throw new Error('Missing required fields in JWT payload')
}
const statusList = StatusList.decompressStatusList(payload.status_list.lst, payload.status_list.bits)
return {
issuer: payload.iss,
id: payload.sub,
statusList,
exp: payload.exp,
ttl: payload.ttl,
iat: payload.iat,
}
}
export const getSigningAlgo = (type: TKeyType): JoseSignatureAlgorithm => {
switch (type) {
case 'Ed25519':
return JoseSignatureAlgorithm.EdDSA
case 'Secp256k1':
return JoseSignatureAlgorithm.ES256K
case 'Secp256r1':
return JoseSignatureAlgorithm.ES256
case 'RSA':
return JoseSignatureAlgorithm.RS256
default:
throw Error('Key type not yet supported')
}
}