import { Buffer } from 'buffer'; import { deflateSync, inflateSync } from 'node:zlib'; import { RevocationStatusList } from './revocationStatusList.js'; import MultiBitArray from './multiBitArray.js'; import { STATUS_LIST } from '../config.js'; import InvalidCredentialIndexException from './exceptions/invalidCredentialIndexException.js'; import { base64url } from 'jose'; export class TokenStatusList implements RevocationStatusList { private readonly bitArray: MultiBitArray; constructor(bitArray: MultiBitArray) { this.bitArray = bitArray; } static fromEncoded( encodedLst: string, bitsPerEntry: number, ): TokenStatusList { const decoded = Buffer.from(base64url.decode(encodedLst)); const uncompressed = inflateSync(decoded); const bitArray = MultiBitArray.fromBuffer(uncompressed, bitsPerEntry); return new TokenStatusList(bitArray); } encoded(): string { const buffer = this.bitArray.toArray(); const compressed = deflateSync(buffer); return base64url.encode(compressed); } revokeCredential(credentialId: number): void { this.checkCredentialId(credentialId); this.bitArray.set(this.mirrorBitInByte(credentialId), 1); } isRevoked(credentialId: number): boolean { this.checkCredentialId(credentialId); return this.bitArray.get(this.mirrorBitInByte(credentialId)) !== 0; } checkCredentialId(credentialId: number): void { if (credentialId < 0 || credentialId > STATUS_LIST.MAX_CREDENTIAL_ID) { throw new InvalidCredentialIndexException(credentialId.toString()); } } private mirrorBitInByte(index: number): number { const byte = Math.floor(index / 8); const bit = index % 8; return byte * 8 + (7 - bit); } }