Skip to content

Commit

Permalink
feat: add clone ojbect logic in unpackObj (#181)
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas.J.Han <lukas.j.han@gmail.com>
  • Loading branch information
lukasjhan committed Mar 18, 2024
1 parent 9356aee commit 2e92cb3
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 23 deletions.
40 changes: 17 additions & 23 deletions packages/decode/src/decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export const getClaimsSync = <T>(
return unpackedObj as T;
};

export const unpackArray = (
const unpackArray = (
arr: Array<unknown>,
map: Record<string, Disclosure>,
prefix = '',
Expand All @@ -160,21 +160,15 @@ export const unpackArray = (
const presentKey = prefix ? `${prefix}.${idx}` : `${idx}`;
keys[presentKey] = hash;

const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObj(
disclosed.value,
map,
presentKey,
);
const { unpackedObj, disclosureKeymap: disclosureKeys } =
unpackObjInternal(disclosed.value, map, presentKey);
unpackedArray.push(unpackedObj);
Object.assign(keys, disclosureKeys);
}
} else {
const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObj(
item,
map,
newKey,
);
const { unpackedObj, disclosureKeymap: disclosureKeys } =
unpackObjInternal(item, map, newKey);
unpackedArray.push(unpackedObj);
Object.assign(keys, disclosureKeys);
}
Expand All @@ -185,7 +179,12 @@ export const unpackArray = (
return { unpackedObj: unpackedArray, disclosureKeymap: keys };
};

export const unpackObj = (
export const unpackObj = (obj: unknown, map: Record<string, Disclosure>) => {
const copiedObj = JSON.parse(JSON.stringify(obj));
return unpackObjInternal(copiedObj, map);
};

const unpackObjInternal = (
obj: unknown,
map: Record<string, Disclosure>,
prefix = '',
Expand All @@ -203,11 +202,8 @@ export const unpackObj = (
typeof (obj as Record<string, unknown>)[key] === 'object'
) {
const newKey = prefix ? `${prefix}.${key}` : key;
const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObj(
(obj as Record<string, unknown>)[key],
map,
newKey,
);
const { unpackedObj, disclosureKeymap: disclosureKeys } =
unpackObjInternal((obj as Record<string, unknown>)[key], map, newKey);
(obj as Record<string, unknown>)[key] = unpackedObj;
Object.assign(keys, disclosureKeys);
}
Expand All @@ -226,11 +222,8 @@ export const unpackObj = (
: disclosed.key;
keys[presentKey] = hash;

const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObj(
disclosed.value,
map,
presentKey,
);
const { unpackedObj, disclosureKeymap: disclosureKeys } =
unpackObjInternal(disclosed.value, map, presentKey);
claims[disclosed.key] = unpackedObj;
Object.assign(keys, disclosureKeys);
}
Expand Down Expand Up @@ -281,7 +274,8 @@ export const getSDAlgAndPayload = (SdJwtPayload: Record<string, unknown>) => {
};

// Match the digests of the disclosures with the claims and extract the claims
// unpack function use unpackObj and unpackArray to recursively unpack the claims
// unpack function use unpackObjInternal and unpackArray to recursively unpack the claims
// Since getSDAlgAndPayload create new object So we don't need to clone it again
export const unpack = async (
SdJwtPayload: Record<string, unknown>,
disclosures: Array<Disclosure>,
Expand Down
38 changes: 38 additions & 0 deletions packages/decode/src/test/decode.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { describe, expect, test } from 'vitest';
import {
createHashMapping,
decodeJwt,
decodeSdJwt,
decodeSdJwtSync,
getClaims,
getClaimsSync,
getSDAlgAndPayload,
splitSdJwt,
unpackObj,
} from '../index';
import { digest } from '@sd-jwt/crypto-nodejs';

Expand Down Expand Up @@ -93,6 +95,26 @@ describe('decode tests', () => {
expect(decodedSdJwt.jwt).toBeDefined();
});

test('decode sdjwt sync (with KB)', () => {
const sdjwt =
'eyJ0eXAiOiJzZCtqd3QiLCJhbGciOiJFUzI1NiJ9.eyJpZCI6IjEyMzQiLCJfc2QiOlsiYkRUUnZtNS1Zbi1IRzdjcXBWUjVPVlJJWHNTYUJrNTdKZ2lPcV9qMVZJNCIsImV0M1VmUnlsd1ZyZlhkUEt6Zzc5aGNqRDFJdHpvUTlvQm9YUkd0TW9zRmsiLCJ6V2ZaTlMxOUF0YlJTVGJvN3NKUm4wQlpRdldSZGNob0M3VVphYkZyalk4Il0sIl9zZF9hbGciOiJzaGEtMjU2In0.n27NCtnuwytlBYtUNjgkesDP_7gN7bhaLhWNL4SWT6MaHsOjZ2ZMp987GgQRL6ZkLbJ7Cd3hlePHS84GBXPuvg~WyI1ZWI4Yzg2MjM0MDJjZjJlIiwiZmlyc3RuYW1lIiwiSm9obiJd~WyJjNWMzMWY2ZWYzNTg4MWJjIiwibGFzdG5hbWUiLCJEb2UiXQ~WyJmYTlkYTUzZWJjOTk3OThlIiwic3NuIiwiMTIzLTQ1LTY3ODkiXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE3MTAwNjk3MjIsImF1ZCI6ImRpZDpleGFtcGxlOjEyMyIsIm5vbmNlIjoiazh2ZGYwbmQ2Iiwic2RfaGFzaCI6Il8tTmJWSzNmczl3VzNHaDNOUktSNEt1NmZDMUwzN0R2MFFfalBXd0ppRkUifQ.pqw2OB5IA5ya9Mxf60hE3nr2gsJEIoIlnuCa4qIisijHbwg3WzTDFmW2SuNvK_ORN0WU6RoGbJx5uYZh8k4EbA';
const decodedSdJwt = decodeSdJwtSync(sdjwt, digest);
expect(decodedSdJwt).toBeDefined();
expect(decodedSdJwt.kbJwt).toBeDefined();
expect(decodedSdJwt.disclosures.length).toEqual(3);
expect(decodedSdJwt.jwt).toBeDefined();
});

test('decode sdjwt (with KB)', async () => {
const sdjwt =
'eyJ0eXAiOiJzZCtqd3QiLCJhbGciOiJFUzI1NiJ9.eyJpZCI6IjEyMzQiLCJfc2QiOlsiYkRUUnZtNS1Zbi1IRzdjcXBWUjVPVlJJWHNTYUJrNTdKZ2lPcV9qMVZJNCIsImV0M1VmUnlsd1ZyZlhkUEt6Zzc5aGNqRDFJdHpvUTlvQm9YUkd0TW9zRmsiLCJ6V2ZaTlMxOUF0YlJTVGJvN3NKUm4wQlpRdldSZGNob0M3VVphYkZyalk4Il0sIl9zZF9hbGciOiJzaGEtMjU2In0.n27NCtnuwytlBYtUNjgkesDP_7gN7bhaLhWNL4SWT6MaHsOjZ2ZMp987GgQRL6ZkLbJ7Cd3hlePHS84GBXPuvg~WyI1ZWI4Yzg2MjM0MDJjZjJlIiwiZmlyc3RuYW1lIiwiSm9obiJd~WyJjNWMzMWY2ZWYzNTg4MWJjIiwibGFzdG5hbWUiLCJEb2UiXQ~WyJmYTlkYTUzZWJjOTk3OThlIiwic3NuIiwiMTIzLTQ1LTY3ODkiXQ~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE3MTAwNjk3MjIsImF1ZCI6ImRpZDpleGFtcGxlOjEyMyIsIm5vbmNlIjoiazh2ZGYwbmQ2Iiwic2RfaGFzaCI6Il8tTmJWSzNmczl3VzNHaDNOUktSNEt1NmZDMUwzN0R2MFFfalBXd0ppRkUifQ.pqw2OB5IA5ya9Mxf60hE3nr2gsJEIoIlnuCa4qIisijHbwg3WzTDFmW2SuNvK_ORN0WU6RoGbJx5uYZh8k4EbA';
const decodedSdJwt = await decodeSdJwt(sdjwt, digest);
expect(decodedSdJwt).toBeDefined();
expect(decodedSdJwt.kbJwt).toBeDefined();
expect(decodedSdJwt.disclosures.length).toEqual(3);
expect(decodedSdJwt.jwt).toBeDefined();
});

test('get claims', async () => {
const sdjwt =
'eyJ0eXAiOiJzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJfc2QiOlsiaWQ1azZ1ZVplVTY4bExaMlU2YjJJbF9QR3ZKb1RDMlpkMkpwY0RwMzFIWSJdLCJfc2RfYWxnIjoic2hhLTI1NiJ9.GiLF_HhacrstqCJ223VvWOoJJWU8qk4dYQHklSMwxv36pPF_7ER53Wbty1qYRlQ6NeMUdBRRdj9JQLLCzz1gCQ~WyI2NTMxNDA2ZmVhZmU0YjBmIiwiZm9vIiwiYmFyIl0~';
Expand Down Expand Up @@ -161,4 +183,20 @@ describe('decode tests', () => {
const { _sd_alg, payload } = getSDAlgAndPayload({});
expect(_sd_alg).toBe('sha-256');
});

test('unpackObj clone', async () => {
const sdjwt =
'eyJ0eXAiOiJzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJ0ZXN0Ijp7Il9zZCI6WyJqVEszMHNleDZhYV9kUk1KSWZDR056Q0FwbVB5MzRRNjNBa3QzS3hhSktzIl19LCJfc2QiOlsiME9nMi1ReG95eW1UOGNnVzZZUjVSSFpQLUJuR2tHUi1NM2otLV92RWlzSSIsIkcwZ3lHNnExVFMyUlQxMkZ3X2RRRDVVcjlZc1AwZlVWOXVtQWdGMC1jQ1EiXSwiX3NkX2FsZyI6InNoYS0yNTYifQ.ggEyE4SeDO2Hu3tol3VLmi7NQj56yKzKQDaafocgkLrUBdivghohtzrfcbrMN7CRufJ_Cnh0EL54kymXLGTdDQ~WyIwNGU0MjAzOWU4ZWFiOWRjIiwiYSIsIjEiXQ~WyIwOGE1Yjc5MjMyYjAzYzBhIiwiMSJd~WyJiNWE2YjUzZGQwYTFmMGIwIiwienp6IiwieHh4Il0~WyIxYzdmOTE4ZTE0MjA2NzZiIiwiZm9vIiwiYmFyIl0~WyJmZjYxYzQ5ZGU2NjFiYzMxIiwiYXJyIixbeyIuLi4iOiJTSG96VW5KNUpkd0ZtTjVCbXB5dXZCWGZfZWRjckVvcExPYThTVlBFUmg0In0sIjIiLHsiX3NkIjpbIkpuODNhZkp0OGx4NG1FMzZpRkZyS2U2R2VnN0dlVUQ4Z3UwdVo3NnRZcW8iXX1dXQ~';
const decodedSdJwt = await decodeSdJwt(sdjwt, digest);
const jwtPayload = JSON.parse(JSON.stringify(decodedSdJwt.jwt.payload));

const { _sd_alg, payload } = getSDAlgAndPayload(decodedSdJwt.jwt.payload);
const hash = { hasher: digest, alg: _sd_alg };
const map = await createHashMapping(decodedSdJwt.disclosures, hash);

const { unpackedObj } = unpackObj(decodedSdJwt.jwt.payload, map);

expect(unpackedObj).toBeDefined();
expect(jwtPayload).toStrictEqual(decodedSdJwt.jwt.payload);
});
});

0 comments on commit 2e92cb3

Please sign in to comment.