Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/jwt-status-list/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './status-list';
export * from './status-list-exception';
export * from './status-list-jwt';
export * from './types';
19 changes: 19 additions & 0 deletions packages/jwt-status-list/src/status-list-exception.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* SLException is a custom error class for Status List related exceptions.
*/
export class SLException extends Error {
public details?: unknown;

constructor(message: string, details?: unknown) {
super(message);
Object.setPrototypeOf(this, SLException.prototype);
this.name = 'SLException';
this.details = details;
}

getFullMessage(): string {
return `${this.name}: ${this.message} ${
this.details ? `- ${JSON.stringify(this.details)}` : ''
}`;
}
}
7 changes: 4 additions & 3 deletions packages/jwt-status-list/src/status-list-jwt.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { JwtPayload } from '@sd-jwt/types';
import { base64urlDecode } from '@sd-jwt/utils';
import { StatusList } from './status-list';
import { SLException } from './status-list-exception';
import type {
JWTwithStatusListPayload,
StatusListEntry,
Expand Down Expand Up @@ -33,13 +34,13 @@ export function createHeaderAndPayload(
// validate if the required fieds are present based on https://www.ietf.org/archive/id/draft-ietf-oauth-status-list-02.html#section-5.1

if (!payload.iss) {
throw new Error('iss field is required');
throw new SLException('iss field is required');
}
if (!payload.sub) {
throw new Error('sub field is required');
throw new SLException('sub field is required');
}
if (!payload.iat) {
throw new Error('iat field is required');
throw new SLException('iat field is required');
}
//exp and tll are optional. We will not validate the business logic of the values like exp > iat etc.

Expand Down
5 changes: 3 additions & 2 deletions packages/jwt-status-list/src/status-list.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { base64UrlToUint8Array, uint8ArrayToBase64Url } from '@sd-jwt/utils';
import { deflate, inflate } from 'pako';
import { SLException } from './status-list-exception';
import type { BitsPerStatus } from './types';
/**
* StatusListManager is a class that manages a list of statuses with variable bit size.
Expand All @@ -16,12 +17,12 @@ export class StatusList {
*/
constructor(statusList: number[], bitsPerStatus: BitsPerStatus) {
if (![1, 2, 4, 8].includes(bitsPerStatus)) {
throw new Error('bitsPerStatus must be 1, 2, 4, or 8');
throw new SLException('bitsPerStatus must be 1, 2, 4, or 8');
}
//check that the entries in the statusList are within the range of the bitsPerStatus
for (let i = 0; i < statusList.length; i++) {
if (statusList[i] > 2 ** bitsPerStatus) {
throw Error(
throw new SLException(
`Status value out of range at index ${i} with value ${statusList[i]}`,
);
}
Expand Down
25 changes: 13 additions & 12 deletions packages/sd-jwt-vc/src/sd-jwt-vc-instance.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Jwt, SDJwt, SDJwtInstance, type VerifierOptions } from '@sd-jwt/core';
import {
getListFromStatusListJWT,
SLException,
type StatusListJWTHeaderParameters,
type StatusListJWTPayload,
} from '@sd-jwt/jwt-status-list';
Expand Down Expand Up @@ -306,18 +307,18 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
StatusListJWTPayload
>(statusListJWT);
// check if the status list has a valid signature. The presence of the verifier is checked in the parent class.
await slJWT.verify(
this.userConfig.statusVerifier ??
(this.userConfig.verifier as Verifier),
options,
);

const currentDate =
options?.currentDate ?? Math.floor(Date.now() / 1000);
//check if the status list is expired
if (slJWT.payload?.exp && (slJWT.payload.exp as number) < currentDate) {
throw new SDJWTException('Status list is expired');
}
await slJWT
.verify(
this.userConfig.statusVerifier ??
(this.userConfig.verifier as Verifier),
options,
)
.catch((err: SLException) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think casting this as an SLException is unsafe, since the method could throw other errors as well (since a custom statusVerifier can be passed).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should rather be implemented as if (err instance SLException) {} else {}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a suggestion with a fix here

@TimoGlastra can you please verify it if this was your intention? I agree that we should give the flexibility of throwing own exceptions.

throw new SLException(
`Status List JWT verification failed: ${err.message}`,
err.details,
);
});

// get the status list from the status list JWT
const statusList = getListFromStatusListJWT(statusListJWT);
Expand Down