All files jwt.ts

96.26% Statements 103/107
88.88% Branches 16/18
100% Functions 8/8
96.26% Lines 103/107

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 1081x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 172x 172x 172x 172x 1x 1x 125x 125x 125x 125x 125x 125x 125x 1x 1x 108x 108x 108x 108x 108x 108x 108x 108x 108x 108x 108x 108x 108x 108x 108x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 47x     47x 47x 47x 47x 47x 47x 47x 47x 1x 1x 105x 1x 1x 104x 104x 104x 104x 104x 104x 104x 105x 1x 1x 44x     44x 44x 44x 44x 44x 44x 44x 1x 1x 43x 44x 1x  
import { Base64urlEncode, SDJWTException } from '@hopae/sd-jwt-util';
import { Base64urlString, Signer, Verifier } from '@hopae/sd-jwt-type';
import { decodeJwt } from '@hopae/sd-jwt-decode';
 
export type JwtData<
  Header extends Record<string, any>,
  Payload extends Record<string, any>,
> = {
  header?: Header;
  payload?: Payload;
  signature?: Base64urlString;
};
 
// This class is used to create and verify JWT
// Contains header, payload, and signature
export class Jwt<
  Header extends Record<string, any> = Record<string, any>,
  Payload extends Record<string, any> = Record<string, any>,
> {
  public header?: Header;
  public payload?: Payload;
  public signature?: Base64urlString;
 
  constructor(data?: JwtData<Header, Payload>) {
    this.header = data?.header;
    this.payload = data?.payload;
    this.signature = data?.signature;
  }
 
  public static decodeJWT<
    Header extends Record<string, any> = Record<string, any>,
    Payload extends Record<string, any> = Record<string, any>,
  >(
    jwt: string,
  ): { header: Header; payload: Payload; signature: Base64urlString } {
    return decodeJwt(jwt);
  }
 
  public static fromEncode<
    Header extends Record<string, any> = Record<string, any>,
    Payload extends Record<string, any> = Record<string, any>,
  >(encodedJwt: string): Jwt<Header, Payload> {
    const { header, payload, signature } = Jwt.decodeJWT<Header, Payload>(
      encodedJwt,
    );
 
    const jwt = new Jwt<Header, Payload>({
      header,
      payload,
      signature,
    });
 
    return jwt;
  }
 
  public setHeader(header: Header): Jwt<Header, Payload> {
    this.header = header;
    return this;
  }
 
  public setPayload(payload: Payload): Jwt<Header, Payload> {
    this.payload = payload;
    return this;
  }
 
  public async sign(signer: Signer) {
    if (!this.header || !this.payload) {
      throw new SDJWTException('Sign Error: Invalid JWT');
    }
 
    const header = Base64urlEncode(JSON.stringify(this.header));
    const payload = Base64urlEncode(JSON.stringify(this.payload));
    const data = `${header}.${payload}`;
    this.signature = await signer(data);
 
    return this.encodeJwt();
  }
 
  public encodeJwt(): string {
    if (!this.header || !this.payload || !this.signature) {
      throw new SDJWTException('Serialize Error: Invalid JWT');
    }
 
    const header = Base64urlEncode(JSON.stringify(this.header));
    const payload = Base64urlEncode(JSON.stringify(this.payload));
    const signature = this.signature;
    const compact = `${header}.${payload}.${signature}`;
 
    return compact;
  }
 
  public async verify(verifier: Verifier) {
    if (!this.header || !this.payload || !this.signature) {
      throw new SDJWTException('Verify Error: Invalid JWT');
    }
 
    const header = Base64urlEncode(JSON.stringify(this.header));
    const payload = Base64urlEncode(JSON.stringify(this.payload));
    const data = `${header}.${payload}`;
 
    const verified = verifier(data, this.signature);
    if (!verified) {
      throw new SDJWTException('Verify Error: Invalid JWT Signature');
    }
    return { payload: this.payload, header: this.header };
  }
}