Skip to content

Commit

Permalink
added tests for creating decoys
Browse files Browse the repository at this point in the history
Signed-off-by: Berend Sliedrecht <[email protected]>
  • Loading branch information
berendsliedrecht committed Oct 5, 2023
1 parent 9db759a commit 09935b4
Show file tree
Hide file tree
Showing 11 changed files with 578 additions and 550 deletions.
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"printWidth": 80,
"tabWidth": 4,
"semi": false,
"trailingComma": "none",
"singleQuote": true
}
820 changes: 410 additions & 410 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/base64url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class Base64url {
}

public static decodeToJson<
T extends Record<string, unknown> = Record<string, unknown>,
T extends Record<string, unknown> = Record<string, unknown>
>(input: string): T {
return JSON.parse(Buffer.from(input, 'base64url').toString()) as T
}
Expand Down
2 changes: 1 addition & 1 deletion src/createDecoys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type SaltGenerator = () => OrPromise<string>
export const createDecoys = async (
count: number,
saltGenerator: SaltGenerator,
hasher: Hasher,
hasher: Hasher
) => {
const decoys: Array<string> = []
for (let i = 0; i < count; i++) {
Expand Down
6 changes: 3 additions & 3 deletions src/createDisclosure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { Base64url } from './base64url'
export const createObjectDisclosure = (
salt: string,
key: string,
value: unknown,
value: unknown
) => {
if (typeof value === 'number' && isNaN(value)) {
throw new SdJwtError('NaN is not allowed to be used in a disclosure.')
}

if (typeof value === 'number' && !isFinite(value)) {
throw new SdJwtError(
'Infinite is not allowed to be used in a disclosure.',
'Infinite is not allowed to be used in a disclosure.'
)
}

Expand All @@ -28,7 +28,7 @@ export const createArrayDisclosure = (salt: string, value: unknown) => {

if (typeof value === 'number' && !isFinite(value)) {
throw new SdJwtError(
'Infinite is not allowed to be used in a disclosure.',
'Infinite is not allowed to be used in a disclosure.'
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/hasherAlgorithm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,5 @@ export enum HasherAlgorithm {
/**
* K12-512: 512 bits. [draft-irtf-cfrg-kangarootwelve-06] (current)
*/
K12_512 = 'k12-512',
K12_512 = 'k12-512'
}
54 changes: 27 additions & 27 deletions src/sdJwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export type VerifyOptions<Header extends Record<string, unknown>> = {
header: Header
}
export type Verifier<Header extends Record<string, unknown>> = (
options: VerifyOptions<Header>,
options: VerifyOptions<Header>
) => OrPromise<boolean>

/**
Expand All @@ -53,18 +53,18 @@ export type HasherAndAlgorithm = {
}

export type Signer<
Header extends Record<string, unknown> = Record<string, unknown>,
Header extends Record<string, unknown> = Record<string, unknown>
> = (input: string, header: Header) => OrPromise<Uint8Array>

export type SdJwtToCompactOptions<
DisclosablePayload extends Record<string, unknown>,
DisclosablePayload extends Record<string, unknown>
> = {
disclosureFrame?: DisclosureFrame<DisclosablePayload>
}

export type SdJwtOptions<
Header extends Record<string, unknown>,
Payload extends Record<string, unknown>,
Payload extends Record<string, unknown>
> = {
header?: Header
payload?: Payload
Expand All @@ -90,7 +90,7 @@ type CommonSdJwtHeaderProperties = {

export class SdJwt<
Header extends Record<string, unknown> = Record<string, unknown>,
Payload extends Record<string, unknown> = Record<string, unknown>,
Payload extends Record<string, unknown> = Record<string, unknown>
> {
public header?: Header & CommonSdJwtHeaderProperties
public payload?: Payload & CommonSdJwtPayloadProperties
Expand All @@ -103,7 +103,7 @@ export class SdJwt<

public constructor(
options?: SdJwtOptions<Header, Payload>,
additionalOptions?: SdJwtAdditionalOptions<Payload>,
additionalOptions?: SdJwtAdditionalOptions<Payload>
) {
this.header = options?.header
this.payload = options?.payload
Expand All @@ -124,7 +124,7 @@ export class SdJwt<

public static fromCompact<
Header extends Record<string, unknown> = Record<string, unknown>,
Payload extends Record<string, unknown> = Record<string, unknown>,
Payload extends Record<string, unknown> = Record<string, unknown>
>(compact: string) {
const [sHeader, sPayload, sSignatureAndDisclosures] = compact.split('.')

Expand All @@ -137,7 +137,7 @@ export class SdJwt<
const sdJwt = new SdJwt<Header, Payload>({
header,
payload,
signature,
signature
})

return sdJwt as ReturnSdJwtWithHeaderAndPayload<typeof sdJwt>
Expand All @@ -154,7 +154,7 @@ export class SdJwt<
}

public withHasher(
hasherAndAlgorithm: HasherAndAlgorithm,
hasherAndAlgorithm: HasherAndAlgorithm
): ReturnSdJwtWithPayload<this> {
this.hasherAndAlgorithm = hasherAndAlgorithm

Expand All @@ -170,7 +170,7 @@ export class SdJwt<

public addHeaderClaim(
item: keyof Header,
value: Header[typeof item] | unknown,
value: Header[typeof item] | unknown
): ReturnSdJwtWithHeader<this> {
this.header ??= {} as Header
this.header = { [item]: value, ...this.header }
Expand All @@ -189,23 +189,23 @@ export class SdJwt<

public addPayloadClaim(
item: keyof Payload,
value: Payload[typeof item] | unknown,
value: Payload[typeof item] | unknown
): ReturnSdJwtWithPayload<this> {
this.payload ??= {} as Payload
this.payload = { [item]: value, ...this.payload }
return this as ReturnSdJwtWithPayload<this>
}

public withSignature(
signature: Uint8Array,
signature: Uint8Array
): ReturnSdJwtWithSignature<this> {
this.signature = signature
return this as ReturnSdJwtWithSignature<this>
}

private async createDisclosure(
key: string,
value: unknown,
value: unknown
): Promise<string> {
this.assertSaltGenerator()

Expand All @@ -228,7 +228,7 @@ export class SdJwt<
const decoys = await createDecoys(
count,
this.saltGenerator!,
this.hasherAndAlgorithm!.hasher,
this.hasherAndAlgorithm!.hasher
)

return decoys
Expand All @@ -239,7 +239,7 @@ export class SdJwt<
frame: DisclosureFrame<Payload>,
disclosures: Array<string> = [],
keys: Array<string> = [],
cleanup: Array<Array<string>> = [],
cleanup: Array<Array<string>> = []
): Promise<{
disclosures: Array<string>
payload: Record<string, unknown>
Expand All @@ -248,7 +248,7 @@ export class SdJwt<
const newKeys = [...keys, key]
if (key === '__decoyCount' && typeof value === 'number') {
const sd: Array<string> = Array.from(
(object._sd as string[]) ?? [],
(object._sd as string[]) ?? []
)
const decoy = await this.createDecoys(value)
decoy.forEach((digest) => sd.push(digest))
Expand All @@ -257,12 +257,12 @@ export class SdJwt<
} else if (typeof value === 'boolean') {
if (value === true) {
const sd: Array<string> = Array.from(
(object._sd as string[]) ?? [],
(object._sd as string[]) ?? []
)

const disclosure = await this.createDisclosure(
key,
object[key],
object[key]
)

disclosures.push(disclosure)
Expand All @@ -281,11 +281,11 @@ export class SdJwt<
value as DisclosureFrame<Payload>,
disclosures,
newKeys,
cleanup,
cleanup
)
} else {
throw new SdJwtError(
`Invalid type in frame with key '${key}' and type '${typeof value}'. Only Record<string, unknown> and boolean are allowed.`,
`Invalid type in frame with key '${key}' and type '${typeof value}'. Only Record<string, unknown> and boolean are allowed.`
)
}
}
Expand Down Expand Up @@ -319,23 +319,23 @@ export class SdJwt<
private assertSaltGenerator() {
if (!this.saltGenerator) {
throw new SdJwtError(
'Cannot create a disclosure without a salt generator. You can set it with this.withSaltGenerator()',
'Cannot create a disclosure without a salt generator. You can set it with this.withSaltGenerator()'
)
}
}

private assertHashAndAlgorithm() {
if (!this.hasherAndAlgorithm) {
throw new SdJwtError(
'A hasher and algorithm must be set in order to create a digest of a disclosure. You can set it with this.withHasherAndAlgorithm()',
'A hasher and algorithm must be set in order to create a digest of a disclosure. You can set it with this.withHasherAndAlgorithm()'
)
}
}

private assertSigner() {
if (!this.signer) {
throw new SdJwtError(
'A signer must be provided to create a signature. You can set it with this.withSigner()',
'A signer must be provided to create a signature. You can set it with this.withSigner()'
)
}
}
Expand Down Expand Up @@ -369,12 +369,12 @@ export class SdJwt<
return await cb({
message,
header: this.header as Header,
signature: this.signature!,
signature: this.signature!
})
}

public async toCompact(
options?: SdJwtToCompactOptions<Payload>,
options?: SdJwtToCompactOptions<Payload>
): Promise<string> {
this.assertHeader()
this.assertPayload()
Expand All @@ -384,7 +384,7 @@ export class SdJwt<
const { disclosures, payload } = frame
? await this.applyDisclosureFrame(
{ ...this.payload } as Payload,
frame as DisclosureFrame<Payload>,
frame as DisclosureFrame<Payload>
)
: { disclosures: [], payload: this.payload }

Expand All @@ -393,7 +393,7 @@ export class SdJwt<

if (disclosures.length > 0 && this.signature) {
throw new SdJwtError(
'Signature is already set by the user when selectively disclosable items still have to be removed. This will invalidate the signature. Try to provide a signer on SdJwt.withSigner and SdJwt.toCompact will call it at the correct time.',
'Signature is already set by the user when selectively disclosable items still have to be removed. This will invalidate the signature. Try to provide a signer on SdJwt.withSigner and SdJwt.toCompact will call it at the correct time.'
)
}

Expand Down
Loading

0 comments on commit 09935b4

Please sign in to comment.