gdc-common-utils-ts 1.0.4 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AesManager.d.ts +27 -0
- package/dist/AesManager.js +62 -0
- package/dist/CryptographyService.d.ts +76 -0
- package/dist/CryptographyService.js +403 -0
- package/dist/constants/Schemas.d.ts +45 -0
- package/dist/constants/Schemas.js +48 -0
- package/dist/constants/index.js +1 -0
- package/{src/constants/schemaorg.ts → dist/constants/schemaorg.d.ts} +24 -116
- package/dist/constants/schemaorg.js +185 -0
- package/dist/cryptoDecode.d.ts +3 -0
- package/dist/cryptoDecode.js +90 -0
- package/dist/cryptoEncode.d.ts +1 -0
- package/dist/cryptoEncode.js +30 -0
- package/dist/cryptography.abstract.d.ts +13 -0
- package/{src/cryptography.abstract.ts → dist/cryptography.abstract.js} +6 -14
- package/dist/hmac.d.ts +2 -0
- package/{src/hmac.ts → dist/hmac.js} +4 -7
- package/dist/index.js +3 -0
- package/{src/interfaces/Cryptography.types.ts → dist/interfaces/Cryptography.types.d.ts} +71 -71
- package/dist/interfaces/Cryptography.types.js +8 -0
- package/dist/interfaces/ICryptoHelper.d.ts +28 -0
- package/dist/interfaces/ICryptoHelper.js +3 -0
- package/dist/interfaces/ICryptography.d.ts +154 -0
- package/dist/interfaces/ICryptography.js +3 -0
- package/dist/interfaces/IWallet.d.ts +55 -0
- package/dist/interfaces/IWallet.js +3 -0
- package/dist/interfaces/MlDsa.d.ts +9 -0
- package/{src/interfaces/MlDsa.ts → dist/interfaces/MlDsa.js} +1 -5
- package/dist/interfaces/MlKem.d.ts +11 -0
- package/{src/interfaces/MlKem.ts → dist/interfaces/MlKem.js} +0 -5
- package/dist/models/aes.d.ts +85 -0
- package/dist/models/aes.js +10 -0
- package/dist/models/auth.d.ts +35 -0
- package/dist/models/auth.js +3 -0
- package/{src/models/bundle.ts → dist/models/bundle.d.ts} +41 -63
- package/dist/models/bundle.js +26 -0
- package/dist/models/clinical-sections.d.ts +36 -0
- package/dist/models/clinical-sections.en.d.ts +75 -0
- package/dist/models/clinical-sections.en.js +81 -0
- package/dist/models/clinical-sections.js +32 -0
- package/dist/models/comm.d.ts +44 -0
- package/dist/models/comm.js +4 -0
- package/{src/models/confidential-job.ts → dist/models/confidential-job.d.ts} +23 -45
- package/dist/models/confidential-job.js +20 -0
- package/dist/models/confidential-message.d.ts +97 -0
- package/dist/models/confidential-message.js +4 -0
- package/{src/models/confidential-storage.ts → dist/models/confidential-storage.d.ts} +35 -56
- package/dist/models/confidential-storage.js +3 -0
- package/{src/models/consent-rule.ts → dist/models/consent-rule.d.ts} +22 -42
- package/dist/models/consent-rule.js +21 -0
- package/{src/models/crypto.ts → dist/models/crypto.d.ts} +5 -13
- package/dist/models/crypto.js +3 -0
- package/dist/models/device-license.d.ts +133 -0
- package/dist/models/device-license.js +3 -0
- package/{src/models/did.ts → dist/models/did.d.ts} +21 -30
- package/dist/models/did.js +3 -0
- package/dist/models/index.js +31 -0
- package/dist/models/indexing.d.ts +11 -0
- package/dist/models/indexing.js +18 -0
- package/dist/models/issue.d.ts +57 -0
- package/dist/models/issue.js +75 -0
- package/dist/models/jsonapi.d.ts +13 -0
- package/dist/models/jsonapi.js +3 -0
- package/{src/models/jwe.ts → dist/models/jwe.d.ts} +10 -22
- package/dist/models/jwe.js +3 -0
- package/{src/models/jwk.ts → dist/models/jwk.d.ts} +0 -11
- package/dist/models/jwk.js +3 -0
- package/{src/models/jws.ts → dist/models/jws.d.ts} +0 -7
- package/dist/models/jws.js +3 -0
- package/dist/models/jwt.d.ts +9 -0
- package/dist/models/jwt.js +3 -0
- package/dist/models/multibase58.d.ts +13 -0
- package/dist/models/multibase58.js +40 -0
- package/dist/models/oidc4ida.common.model.d.ts +33 -0
- package/dist/models/oidc4ida.common.model.js +3 -0
- package/dist/models/oidc4ida.document.model.d.ts +50 -0
- package/dist/models/oidc4ida.document.model.js +3 -0
- package/{src/models/oidc4ida.electronicRecord.model.ts → dist/models/oidc4ida.electronicRecord.model.d.ts} +18 -37
- package/dist/models/oidc4ida.electronicRecord.model.js +3 -0
- package/{src/models/oidc4ida.evidence.model.ts → dist/models/oidc4ida.evidence.model.d.ts} +17 -35
- package/dist/models/oidc4ida.evidence.model.js +5 -0
- package/dist/models/openid-device.d.ts +119 -0
- package/dist/models/openid-device.js +3 -0
- package/dist/models/operation-outcome.d.ts +26 -0
- package/dist/models/operation-outcome.js +3 -0
- package/{src/models/params.ts → dist/models/params.d.ts} +20 -29
- package/dist/models/params.js +3 -0
- package/dist/models/resource-document.d.ts +14 -0
- package/dist/models/resource-document.js +3 -0
- package/dist/models/response.d.ts +1 -0
- package/dist/models/response.js +3 -0
- package/dist/models/urlPath.d.ts +58 -0
- package/dist/models/urlPath.js +76 -0
- package/dist/models/verifiable-credential.d.ts +45 -0
- package/dist/models/verifiable-credential.js +8 -0
- package/dist/utils/actor.d.ts +18 -0
- package/dist/utils/actor.js +36 -0
- package/dist/utils/base-convert.d.ts +20 -0
- package/{src/utils/base-convert.ts → dist/utils/base-convert.js} +23 -36
- package/dist/utils/baseN.d.ts +35 -0
- package/dist/utils/baseN.js +174 -0
- package/dist/utils/bundle.d.ts +6 -0
- package/dist/utils/bundle.js +32 -0
- package/dist/utils/content.d.ts +55 -0
- package/{src/utils/content.ts → dist/utils/content.js} +4 -10
- package/dist/utils/did.d.ts +67 -0
- package/dist/utils/did.js +123 -0
- package/dist/utils/format-converter.d.ts +21 -0
- package/dist/utils/format-converter.js +109 -0
- package/dist/utils/index.js +13 -0
- package/dist/utils/jwt.d.ts +52 -0
- package/dist/utils/jwt.js +153 -0
- package/dist/utils/manager-error.d.ts +15 -0
- package/dist/utils/manager-error.js +23 -0
- package/dist/utils/multibase58.d.ts +13 -0
- package/dist/utils/multibase58.js +40 -0
- package/dist/utils/multibasehash.d.ts +8 -0
- package/{src/utils/multibasehash.ts → dist/utils/multibasehash.js} +8 -13
- package/dist/utils/normalize.d.ts +16 -0
- package/{src/utils/normalize.ts → dist/utils/normalize.js} +15 -18
- package/dist/utils/object-convert.d.ts +20 -0
- package/{src/utils/object-convert.ts → dist/utils/object-convert.js} +10 -16
- package/dist/utils/string-convert.d.ts +24 -0
- package/{src/utils/string-convert.ts → dist/utils/string-convert.js} +5 -14
- package/dist/utils/string-utils.d.ts +25 -0
- package/{src/utils/string-utils.ts → dist/utils/string-utils.js} +12 -16
- package/dist/utils/url.d.ts +27 -0
- package/{src/utils/url.ts → dist/utils/url.js} +6 -7
- package/package.json +56 -14
- package/PUBLISHING.md +0 -33
- package/__tests__/AesManager.test.ts +0 -53
- package/__tests__/CryptographyService.test.ts +0 -194
- package/__tests__/bundle.test.ts +0 -29
- package/__tests__/content.test.ts +0 -72
- package/__tests__/crypto-encode-decode.test.ts +0 -52
- package/__tests__/crypto-hmac.test.ts +0 -21
- package/__tests__/did-generateServiceId.errors.test.ts +0 -8
- package/__tests__/did-generateServiceId.test.ts +0 -18
- package/__tests__/models-clinical-sections.test.ts +0 -32
- package/__tests__/models-multibase58.test.ts +0 -33
- package/__tests__/multibase58.errors.test.ts +0 -7
- package/__tests__/multibase58.test.ts +0 -28
- package/__tests__/multibasehash.test.ts +0 -25
- package/__tests__/utils-actor.test.ts +0 -46
- package/__tests__/utils-base-convert.test.ts +0 -57
- package/__tests__/utils-baseN.test.ts +0 -40
- package/__tests__/utils-did-extra.test.ts +0 -33
- package/__tests__/utils-format-converter.test.ts +0 -87
- package/__tests__/utils-jwt.test.ts +0 -57
- package/__tests__/utils-manager-error.test.ts +0 -11
- package/__tests__/utils-normalize.test.ts +0 -15
- package/__tests__/utils-object-convert.test.ts +0 -38
- package/__tests__/utils-string-convert.test.ts +0 -20
- package/__tests__/utils-string-utils.test.ts +0 -25
- package/__tests__/utils-url.test.ts +0 -21
- package/babel.config.cjs +0 -5
- package/jest.config.ts +0 -47
- package/src/AesManager.ts +0 -82
- package/src/CryptographyService.ts +0 -461
- package/src/JweManager.ts.txt +0 -365
- package/src/KmsService.txt +0 -493
- package/src/constants/Schemas.ts +0 -61
- package/src/cryptoDecode.ts +0 -104
- package/src/cryptoEncode.ts +0 -36
- package/src/interfaces/ICryptoHelper.ts +0 -33
- package/src/interfaces/ICryptography.ts +0 -177
- package/src/interfaces/IWallet.ts +0 -62
- package/src/models/aes.ts +0 -93
- package/src/models/auth.ts +0 -38
- package/src/models/bundle.txt +0 -93
- package/src/models/clinical-sections.en.ts +0 -82
- package/src/models/clinical-sections.ts +0 -64
- package/src/models/comm.ts +0 -63
- package/src/models/confidential-message.ts +0 -137
- package/src/models/device-license.ts +0 -161
- package/src/models/indexing.ts +0 -20
- package/src/models/issue.ts +0 -85
- package/src/models/jsonapi.ts +0 -19
- package/src/models/jwt.ts +0 -15
- package/src/models/multibase58.ts +0 -46
- package/src/models/oidc4ida.common.model.ts +0 -39
- package/src/models/oidc4ida.document.model.ts +0 -61
- package/src/models/openid-device.ts +0 -146
- package/src/models/operation-outcome.ts +0 -34
- package/src/models/resource-document.ts +0 -21
- package/src/models/response.ts +0 -5
- package/src/models/urlPath.ts +0 -76
- package/src/models/verifiable-credential.ts +0 -52
- package/src/types/noble-hashes.d.ts +0 -4
- package/src/utils/actor.ts +0 -56
- package/src/utils/baseN.ts +0 -203
- package/src/utils/bundle.ts +0 -30
- package/src/utils/did.ts +0 -155
- package/src/utils/format-converter.ts +0 -119
- package/src/utils/jwt.ts +0 -165
- package/src/utils/manager-error.ts +0 -27
- package/src/utils/multibase58.ts +0 -46
- package/tsconfig.json +0 -15
- /package/{src/constants/index.ts → dist/constants/index.d.ts} +0 -0
- /package/{src/index.ts → dist/index.d.ts} +0 -0
- /package/{src/models/index.ts → dist/models/index.d.ts} +0 -0
- /package/{src/utils/index.ts → dist/utils/index.d.ts} +0 -0
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
|
|
3
|
-
import { randomBytes, createHash, randomUUID } from 'crypto';
|
|
4
|
-
import { CryptographyService } from '../src/CryptographyService';
|
|
5
|
-
import type { ICryptoHelper } from '../src/interfaces/ICryptoHelper';
|
|
6
|
-
import { Content } from '../src/utils/content';
|
|
7
|
-
import { MlDsaPrivKeySizeLevel2, MlDsaPubKeySizeLevel2 } from '../src/interfaces/MlDsa';
|
|
8
|
-
import { Kyber512PKBytes } from '../src/interfaces/MlKem';
|
|
9
|
-
|
|
10
|
-
const cryptoHelper: ICryptoHelper = {
|
|
11
|
-
async getRandomBytes(byteCount: number): Promise<Uint8Array> {
|
|
12
|
-
return randomBytes(byteCount);
|
|
13
|
-
},
|
|
14
|
-
async digestString(data: string, algorithm: string): Promise<string> {
|
|
15
|
-
const normalized = String(algorithm).replace('-', '').toLowerCase();
|
|
16
|
-
return createHash(normalized).update(data).digest('hex');
|
|
17
|
-
},
|
|
18
|
-
randomUUID(): string {
|
|
19
|
-
return randomUUID();
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
describe('CryptographyService (PQC)', () => {
|
|
24
|
-
const service = new CryptographyService(cryptoHelper);
|
|
25
|
-
|
|
26
|
-
it('generates ML-KEM key pairs and encapsulates/decapsulates', async () => {
|
|
27
|
-
const { publicJWKey, secretKeyBytes } = await service.generateKeyPairMlKem();
|
|
28
|
-
expect(publicJWKey?.x).toBeDefined();
|
|
29
|
-
expect(publicJWKey?.kid).toBeDefined();
|
|
30
|
-
expect(secretKeyBytes.length).toBeGreaterThan(0);
|
|
31
|
-
|
|
32
|
-
const recipientPublicKeyBytes = Content.base64ToBytes(publicJWKey.x);
|
|
33
|
-
const cekSeedBytes = await cryptoHelper.getRandomBytes(32);
|
|
34
|
-
const { derivedCekBytes, encapsulatedCekBytes } = await service.encapsulate(
|
|
35
|
-
cekSeedBytes,
|
|
36
|
-
secretKeyBytes,
|
|
37
|
-
recipientPublicKeyBytes
|
|
38
|
-
);
|
|
39
|
-
const derivedFromDecap = await service.decapsulate(encapsulatedCekBytes, secretKeyBytes);
|
|
40
|
-
|
|
41
|
-
expect(derivedCekBytes.length).toBeGreaterThan(0);
|
|
42
|
-
expect(derivedFromDecap.length).toBe(derivedCekBytes.length);
|
|
43
|
-
expect(Buffer.from(derivedFromDecap).equals(Buffer.from(derivedCekBytes))).toBe(true);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('generates deterministic ML-KEM key pairs with a seed', async () => {
|
|
47
|
-
const seed = new Uint8Array(64).fill(7);
|
|
48
|
-
const first = await service.generateKeyPairMlKem(seed, 'ML-KEM-512');
|
|
49
|
-
const second = await service.generateKeyPairMlKem(seed, 'ML-KEM-512');
|
|
50
|
-
expect(first.publicJWKey.x).toBe(second.publicJWKey.x);
|
|
51
|
-
expect(first.publicJWKey.kid).toBe(second.publicJWKey.kid);
|
|
52
|
-
expect(first.secretKeyBytes.length).toBeGreaterThan(0);
|
|
53
|
-
expect(Content.base64ToBytes(first.publicJWKey.x).length).toBe(Kyber512PKBytes);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('generates ML-DSA key pairs with expected sizes', async () => {
|
|
57
|
-
const seed = new Uint8Array(32).fill(3);
|
|
58
|
-
const { publicJWKey, secretKeyBytes } = await service.generateKeyPairMlDsa(seed, 'ML-DSA-44');
|
|
59
|
-
expect(publicJWKey.alg).toBe('ML-DSA-44');
|
|
60
|
-
expect(secretKeyBytes.length).toBeGreaterThanOrEqual(MlDsaPrivKeySizeLevel2);
|
|
61
|
-
expect(Content.base64ToBytes(publicJWKey.pub).length).toBe(MlDsaPubKeySizeLevel2);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('signs and verifies with ML-DSA', async () => {
|
|
65
|
-
const { publicJWKey, secretKeyBytes } = await service.generateKeyPairMlDsa(undefined, 'ML-DSA-44');
|
|
66
|
-
const payload = Content.stringToBytesUTF8('test-payload');
|
|
67
|
-
|
|
68
|
-
const signature = await service.signBytes(payload, secretKeyBytes, 'ML-DSA-44');
|
|
69
|
-
const verified = await service.verifyBytes(signature, payload, publicJWKey);
|
|
70
|
-
expect(verified).toBe(true);
|
|
71
|
-
|
|
72
|
-
const tampered = Content.stringToBytesUTF8('test-payload-tampered');
|
|
73
|
-
const verifiedTampered = await service.verifyBytes(signature, tampered, publicJWKey);
|
|
74
|
-
expect(verifiedTampered).toBe(false);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('signs JWS objects and verifies compact + detached forms', async () => {
|
|
78
|
-
const { publicJWKey, secretKeyBytes } = await service.generateKeyPairMlDsa(undefined, 'ML-DSA-44');
|
|
79
|
-
const protectedHeader = { alg: 'ML-DSA-44', typ: 'JWT' };
|
|
80
|
-
const payload = { sub: '123', aud: 'test' };
|
|
81
|
-
|
|
82
|
-
const jws = await service.signDataJws(payload, protectedHeader, secretKeyBytes);
|
|
83
|
-
const compact = `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
84
|
-
const verified = await service.verifyJws(compact, publicJWKey);
|
|
85
|
-
expect(verified).toBe(true);
|
|
86
|
-
|
|
87
|
-
const detached = `${jws.protected}..${jws.signature}`;
|
|
88
|
-
const payloadBytes = Content.stringToBytesUTF8(JSON.stringify(payload));
|
|
89
|
-
expect(await service.verifyDetachedJws(payloadBytes, detached, publicJWKey)).toBe(true);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('throws on invalid detached JWS format', async () => {
|
|
93
|
-
await expect(service.verifyDetachedJws(new Uint8Array([1]), 'not-detached', { kty: 'AKP', alg: 'ML-DSA-44', pub: 'AA' }))
|
|
94
|
-
.rejects.toThrow(/Detached JWS format/);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('throws on missing alg in headers for signing and verification', async () => {
|
|
98
|
-
const { publicJWKey, secretKeyBytes } = await service.generateKeyPairMlDsa(undefined, 'ML-DSA-44');
|
|
99
|
-
await expect(service.signDataJws({ a: 1 }, {}, secretKeyBytes)).rejects.toThrow(/alg/);
|
|
100
|
-
|
|
101
|
-
const missingAlg = { ...publicJWKey };
|
|
102
|
-
delete (missingAlg as any).alg;
|
|
103
|
-
await expect(service.verifyBytes(new Uint8Array([1]), new Uint8Array([2]), missingAlg as any)).rejects.toThrow(/alg/);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('encrypts and decrypts JWE objects (zip + no zip)', async () => {
|
|
107
|
-
const recipient = await service.generateKeyPairMlKem(undefined, 'ML-KEM-768');
|
|
108
|
-
const recipientPrivate = { ...recipient.publicJWKey, dBytes: recipient.secretKeyBytes };
|
|
109
|
-
|
|
110
|
-
const payload = { msg: 'hello' };
|
|
111
|
-
const headerNoZip = { typ: 'JWE', kid: recipient.publicJWKey.kid };
|
|
112
|
-
const jwe = await service.encryptJwe(payload, headerNoZip, recipientPrivate, [recipient.publicJWKey]);
|
|
113
|
-
const decrypted = await service.decryptJwe(jwe, recipientPrivate);
|
|
114
|
-
expect(Content.bytesToStringUTF8(decrypted.decryptedBytes)).toBe(JSON.stringify(payload));
|
|
115
|
-
|
|
116
|
-
const headerZip = { typ: 'JWE', zip: 'DEF', kid: recipient.publicJWKey.kid };
|
|
117
|
-
const jweZip = await service.encryptJwe(payload, headerZip, recipientPrivate, [recipient.publicJWKey]);
|
|
118
|
-
const decryptedZip = await service.decryptJwe(jweZip, recipientPrivate);
|
|
119
|
-
expect(Content.bytesToStringUTF8(decryptedZip.decryptedBytes)).toBe(JSON.stringify(payload));
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('encrypts and decrypts compact JWE', async () => {
|
|
123
|
-
const recipient = await service.generateKeyPairMlKem(undefined, 'ML-KEM-768');
|
|
124
|
-
const recipientPrivate = { ...recipient.publicJWKey, dBytes: recipient.secretKeyBytes };
|
|
125
|
-
|
|
126
|
-
const payload = 'hello-compact';
|
|
127
|
-
const protectedHeader = { typ: 'JWE', zip: 'DEF' };
|
|
128
|
-
const compact = await service.encryptJweToCompact(payload, protectedHeader, recipientPrivate, recipient.publicJWKey);
|
|
129
|
-
const parsed = service.parseCompactJwe(compact);
|
|
130
|
-
const decrypted = await service.decryptJwe(parsed, recipientPrivate);
|
|
131
|
-
expect(Content.bytesToStringUTF8(decrypted.decryptedBytes)).toBe(payload);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('rejects multiple recipients in encryptJwe', async () => {
|
|
135
|
-
const recipient = await service.generateKeyPairMlKem(undefined, 'ML-KEM-768');
|
|
136
|
-
const recipientPrivate = { ...recipient.publicJWKey, dBytes: recipient.secretKeyBytes };
|
|
137
|
-
await expect(
|
|
138
|
-
service.encryptJwe({ a: 1 }, { typ: 'JWE' }, recipientPrivate, [recipient.publicJWKey, recipient.publicJWKey])
|
|
139
|
-
).rejects.toThrow(/single recipient/);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('parses and rejects malformed compact structures', async () => {
|
|
143
|
-
expect(() => service.parseCompactJws('a.b')).toThrow(/Compact JWS/);
|
|
144
|
-
expect(() => service.parseCompactJwe('a.b.c')).toThrow(/Compact JWE/);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('parses compact JWS into structured data', async () => {
|
|
148
|
-
const { publicJWKey, secretKeyBytes } = await service.generateKeyPairMlDsa(undefined, 'ML-DSA-44');
|
|
149
|
-
const jws = await service.signDataJws({ sub: 'abc' }, { alg: 'ML-DSA-44' }, secretKeyBytes);
|
|
150
|
-
const compact = `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
151
|
-
const parsed = service.parseCompactJws(compact);
|
|
152
|
-
expect(parsed.payload).toEqual({ sub: 'abc' });
|
|
153
|
-
expect(parsed.protected).toEqual({ alg: 'ML-DSA-44' });
|
|
154
|
-
expect(await service.verifyJws(compact, publicJWKey)).toBe(true);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('parses JWS JSON serialization', async () => {
|
|
158
|
-
const { secretKeyBytes } = await service.generateKeyPairMlDsa(undefined, 'ML-DSA-44');
|
|
159
|
-
const jws = await service.signDataJws({ sub: 'json' }, { alg: 'ML-DSA-44' }, secretKeyBytes);
|
|
160
|
-
const jwsJson = JSON.stringify({
|
|
161
|
-
payload: jws.payload,
|
|
162
|
-
signatures: [{ protected: jws.protected, signature: jws.signature }],
|
|
163
|
-
});
|
|
164
|
-
const parsed = service.parseCompactJws(jwsJson);
|
|
165
|
-
expect(parsed.payload).toBe(jws.payload);
|
|
166
|
-
expect(parsed.protected).toBe(jws.protected);
|
|
167
|
-
expect(parsed.signature).toBe(jws.signature);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('extracts recipient kids from JWE objects', async () => {
|
|
171
|
-
const recipient = await service.generateKeyPairMlKem(undefined, 'ML-KEM-768');
|
|
172
|
-
const recipientPrivate = { ...recipient.publicJWKey, dBytes: recipient.secretKeyBytes };
|
|
173
|
-
const jwe = await service.encryptJwe({ a: 1 }, { typ: 'JWE', kid: recipient.publicJWKey.kid }, recipientPrivate, [recipient.publicJWKey]);
|
|
174
|
-
expect(service.getRecipientKidsFromJwe(jwe)).toEqual([recipient.publicJWKey.kid]);
|
|
175
|
-
expect(service.getRecipientKidsFromJwe({} as any)).toEqual([]);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('parses JWE JSON serialization', async () => {
|
|
179
|
-
const recipient = await service.generateKeyPairMlKem(undefined, 'ML-KEM-768');
|
|
180
|
-
const recipientPrivate = { ...recipient.publicJWKey, dBytes: recipient.secretKeyBytes };
|
|
181
|
-
const jwe = await service.encryptJwe({ msg: 'json' }, { typ: 'JWE', kid: recipient.publicJWKey.kid }, recipientPrivate, [recipient.publicJWKey]);
|
|
182
|
-
const parsed = service.parseCompactJwe(JSON.stringify(jwe));
|
|
183
|
-
const decrypted = await service.decryptJwe(parsed, recipientPrivate);
|
|
184
|
-
expect(Content.bytesToStringUTF8(decrypted.decryptedBytes)).toBe(JSON.stringify({ msg: 'json' }));
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('computes JWK thumbprints for EC keys', async () => {
|
|
188
|
-
const ecJwk = { kty: 'EC', crv: 'P-256', x: 'AA', y: 'BB' };
|
|
189
|
-
const thumbprint = await (service as any)._computeJwkThumbprint(ecJwk, 'SHA-384');
|
|
190
|
-
const thumbprint2 = await (service as any)._computeJwkThumbprint(ecJwk, 'SHA-384');
|
|
191
|
-
expect(thumbprint).toBe(thumbprint2);
|
|
192
|
-
expect(thumbprint.length).toBeGreaterThan(0);
|
|
193
|
-
});
|
|
194
|
-
});
|
package/__tests__/bundle.test.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
|
|
3
|
-
import { extractResources, getNextLink } from '../src/utils/bundle';
|
|
4
|
-
|
|
5
|
-
describe('bundle utils', () => {
|
|
6
|
-
it('extracts resources from FHIR bundle entry', () => {
|
|
7
|
-
const bundle = {
|
|
8
|
-
entry: [{ resource: { id: 'r1' } }, { resource: { id: 'r2' } }],
|
|
9
|
-
};
|
|
10
|
-
expect(extractResources(bundle)).toEqual([{ id: 'r1' }, { id: 'r2' }]);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('extracts resources from JSON:API data', () => {
|
|
14
|
-
const bundle = {
|
|
15
|
-
data: [{ resource: { id: 'r1' } }, { id: 'r2' }],
|
|
16
|
-
};
|
|
17
|
-
expect(extractResources(bundle)).toEqual([{ id: 'r1' }, { id: 'r2' }]);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('returns resource fallback when bundle is a resource', () => {
|
|
21
|
-
const bundle = { resourceType: 'Patient', id: 'p1' };
|
|
22
|
-
expect(extractResources(bundle)).toEqual([bundle]);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('reads next link', () => {
|
|
26
|
-
const bundle = { link: [{ relation: 'next', url: 'https://next' }] };
|
|
27
|
-
expect(getNextLink(bundle)).toBe('https://next');
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// src/__tests__/unit/utils/convert.test.ts
|
|
2
|
-
|
|
3
|
-
import { Content } from '../src/utils/content.js';
|
|
4
|
-
|
|
5
|
-
describe("Content Class - Conversion Utilities", () => {
|
|
6
|
-
|
|
7
|
-
describe("Base58 Conversions", () => {
|
|
8
|
-
it("should encode and decode a string to/from Base58", () => {
|
|
9
|
-
const testString = "Hello world!";
|
|
10
|
-
const testBytes = Content.stringToBytesUTF8(testString);
|
|
11
|
-
|
|
12
|
-
// Encode
|
|
13
|
-
const encoded = Content.bytesToBase58(testBytes);
|
|
14
|
-
expect(encoded).toBe("2NEpo7TZRhna7vSvL");
|
|
15
|
-
|
|
16
|
-
// Decode
|
|
17
|
-
const decodedBytes = Content.base58ToBytes(encoded);
|
|
18
|
-
const decodedString = Content.bytesToStringUTF8(decodedBytes);
|
|
19
|
-
|
|
20
|
-
expect(decodedString).toBe(testString);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe("Base64URL Conversions", () => {
|
|
25
|
-
it("should encode and decode bytes to/from raw Base64URL", () => {
|
|
26
|
-
const testString = "some important data!?";
|
|
27
|
-
const testBytes = Content.stringToBytesUTF8(testString);
|
|
28
|
-
|
|
29
|
-
// Encode
|
|
30
|
-
const encoded = Content.bytesToRawBase64UrlSafe(testBytes);
|
|
31
|
-
expect(encoded).toBe("c29tZSBpbXBvcnRhbnQgZGF0YSE_");
|
|
32
|
-
|
|
33
|
-
// Decode
|
|
34
|
-
const decodedBytes = Content.base64ToBytes(encoded);
|
|
35
|
-
expect(decodedBytes).toEqual(testBytes);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe("Object Serialization", () => {
|
|
40
|
-
it("should serialize and deserialize an object to/from raw Base64URL", () => {
|
|
41
|
-
const testObject = {
|
|
42
|
-
id: "12345",
|
|
43
|
-
aud: ["did:web:example.com"],
|
|
44
|
-
exp: 1678886400,
|
|
45
|
-
verified: true,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// Serialize
|
|
49
|
-
const encoded = Content.objectToRawBase64UrlSafe(testObject);
|
|
50
|
-
|
|
51
|
-
// Deserialize
|
|
52
|
-
const decodedObject = Content.base64UrlSafeToJSON(encoded);
|
|
53
|
-
|
|
54
|
-
expect(decodedObject).toEqual(testObject);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe("Array Utilities", () => {
|
|
59
|
-
it("should correctly compare two identical arrays of primitives", () => {
|
|
60
|
-
const arr1 = [1, 2, "hello", true, null];
|
|
61
|
-
const arr2 = [1, 2, "hello", true, null];
|
|
62
|
-
expect(Content.arrayCompare(arr1, arr2)).toBe(true);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("should correctly identify two different arrays", () => {
|
|
66
|
-
const arr1 = [1, 2, 5];
|
|
67
|
-
const arr2 = [1, 2, 9];
|
|
68
|
-
expect(Content.arrayCompare(arr1, arr2)).toBe(false);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { encodeJWT as encodeJWTEncode } from '../src/cryptoEncode.js';
|
|
2
|
-
import { encodeJWT as encodeJWTDecode, decodeBase64Url, decodePayloadRequest } from '../src/cryptoDecode.js';
|
|
3
|
-
|
|
4
|
-
function base64UrlEncode(str: string): string {
|
|
5
|
-
return Buffer.from(str)
|
|
6
|
-
.toString('base64')
|
|
7
|
-
.replace(/\+/g, '-')
|
|
8
|
-
.replace(/\//g, '_')
|
|
9
|
-
.replace(/=+$/, '');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
describe('crypto encode/decode', () => {
|
|
13
|
-
it('encodes JWTs with alg none (cryptoEncode)', () => {
|
|
14
|
-
const header = { alg: 'none' };
|
|
15
|
-
const payload = { sub: '123' };
|
|
16
|
-
const token = encodeJWTEncode([], payload, [], header);
|
|
17
|
-
const parts = token.split('.');
|
|
18
|
-
expect(parts.length).toBe(3);
|
|
19
|
-
expect(decodeBase64Url(parts[0])).toBe(JSON.stringify(header));
|
|
20
|
-
expect(decodeBase64Url(parts[1])).toBe(JSON.stringify(payload));
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('encodes JWTs with alg none (cryptoDecode)', () => {
|
|
24
|
-
const header = { alg: 'none' };
|
|
25
|
-
const payload = { sub: '456' };
|
|
26
|
-
const token = encodeJWTDecode([], payload, [], header);
|
|
27
|
-
const parts = token.split('.');
|
|
28
|
-
expect(decodeBase64Url(parts[0])).toBe(JSON.stringify(header));
|
|
29
|
-
expect(decodeBase64Url(parts[1])).toBe(JSON.stringify(payload));
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('decodes payloads from authorization headers', () => {
|
|
33
|
-
const header = { alg: 'none' };
|
|
34
|
-
const payload = { a: 1 };
|
|
35
|
-
const token = `${base64UrlEncode(JSON.stringify(header))}.${base64UrlEncode(JSON.stringify(payload))}.`;
|
|
36
|
-
const decoded = decodePayloadRequest('tenant', undefined, `Bearer ${token}`);
|
|
37
|
-
expect(decoded).toBe(JSON.stringify(payload));
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('returns null when token is missing', () => {
|
|
41
|
-
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
42
|
-
expect(decodePayloadRequest('tenant', undefined, undefined)).toBeNull();
|
|
43
|
-
spy.mockRestore();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('returns empty string for invalid payload JSON', () => {
|
|
47
|
-
const invalid = base64UrlEncode('not-json');
|
|
48
|
-
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
49
|
-
expect(decodeBase64Url(invalid)).toBe('');
|
|
50
|
-
spy.mockRestore();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { computeHmacSha256, computeHmacSha256Base64Url } from '../src/hmac.js';
|
|
2
|
-
|
|
3
|
-
describe('hmac utilities', () => {
|
|
4
|
-
it('computes HMAC-SHA3-256 bytes deterministically', async () => {
|
|
5
|
-
const key = new Uint8Array([1, 2, 3, 4]);
|
|
6
|
-
const message = 'hello';
|
|
7
|
-
const first = await computeHmacSha256(message, key);
|
|
8
|
-
const second = await computeHmacSha256(message, key);
|
|
9
|
-
expect(Array.from(first)).toEqual(Array.from(second));
|
|
10
|
-
expect(first.length).toBe(32);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('computes base64url HMAC output consistently', async () => {
|
|
14
|
-
const key = new Uint8Array([9, 8, 7, 6]);
|
|
15
|
-
const message = 'hello';
|
|
16
|
-
const first = await computeHmacSha256Base64Url(message, key);
|
|
17
|
-
const second = await computeHmacSha256Base64Url(message, key);
|
|
18
|
-
expect(first).toBe(second);
|
|
19
|
-
expect(first.length).toBe(43);
|
|
20
|
-
});
|
|
21
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { generateServiceId } from '../src/utils/did.js';
|
|
2
|
-
|
|
3
|
-
describe('generateServiceId (edge cases)', () => {
|
|
4
|
-
it('keeps action casing', () => {
|
|
5
|
-
const id = generateServiceId({ section: 'identity', format: 'openid', resourceType: 'device', action: '_DCR' });
|
|
6
|
-
expect(id).toBe('#identity:openid:device:_DCR');
|
|
7
|
-
});
|
|
8
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { generateServiceId } from '../src/utils/did.js';
|
|
2
|
-
|
|
3
|
-
describe('generateServiceId', () => {
|
|
4
|
-
it('builds #section:format:resourceType:action', () => {
|
|
5
|
-
const id = generateServiceId({
|
|
6
|
-
section: 'identity',
|
|
7
|
-
format: 'openid',
|
|
8
|
-
resourceType: 'Device',
|
|
9
|
-
action: '_dcr',
|
|
10
|
-
});
|
|
11
|
-
expect(id).toBe('#identity:openid:device:_dcr');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('filters empty parts', () => {
|
|
15
|
-
const id = generateServiceId({ section: 'x', format: 'y', resourceType: '', action: '_batch' });
|
|
16
|
-
expect(id).toBe('#x:y:_batch');
|
|
17
|
-
});
|
|
18
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
clinicalSectionRegistry,
|
|
3
|
-
getClinicalSectionByCode,
|
|
4
|
-
loincI18nKey,
|
|
5
|
-
supportedClinicalSectionCodes,
|
|
6
|
-
clinicalSectionTitleEn,
|
|
7
|
-
} from '../src/models/clinical-sections.js';
|
|
8
|
-
|
|
9
|
-
describe('clinical sections', () => {
|
|
10
|
-
it('builds i18n keys from LOINC codes', () => {
|
|
11
|
-
expect(loincI18nKey('1234-5')).toBe('org.loinc.1234-5');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('exposes supported section codes', () => {
|
|
15
|
-
const codes = Object.keys(clinicalSectionTitleEn);
|
|
16
|
-
expect(supportedClinicalSectionCodes.length).toBe(codes.length);
|
|
17
|
-
expect(supportedClinicalSectionCodes).toContain(codes[0]);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('provides registry entries', () => {
|
|
21
|
-
const code = supportedClinicalSectionCodes[0];
|
|
22
|
-
const entry = clinicalSectionRegistry[code];
|
|
23
|
-
expect(entry.code).toBe(code);
|
|
24
|
-
expect(entry.i18nKey).toBe(loincI18nKey(code));
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('gets clinical section by code', () => {
|
|
28
|
-
const code = supportedClinicalSectionCodes[0];
|
|
29
|
-
expect(getClinicalSectionByCode(code)?.code).toBe(code);
|
|
30
|
-
expect(getClinicalSectionByCode('missing')).toBeUndefined();
|
|
31
|
-
});
|
|
32
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
decodeMultibase58btc,
|
|
3
|
-
decodeMultibase58btcToHex,
|
|
4
|
-
decodeMultibase58btcToUUID,
|
|
5
|
-
encodeHexToMultibase58btc,
|
|
6
|
-
encodeMultibase58btc,
|
|
7
|
-
} from '../src/models/multibase58.js';
|
|
8
|
-
|
|
9
|
-
describe('models multibase58', () => {
|
|
10
|
-
it('round-trips hex to multibase and back', () => {
|
|
11
|
-
const hex = '00112233445566778899aabbccddeeff';
|
|
12
|
-
const encoded = encodeHexToMultibase58btc(hex);
|
|
13
|
-
const decodedHex = decodeMultibase58btcToHex(encoded);
|
|
14
|
-
expect(decodedHex).toBe(hex);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('decodes to UUID with hyphens', () => {
|
|
18
|
-
const hex = '00112233445566778899aabbccddeeff';
|
|
19
|
-
const encoded = encodeHexToMultibase58btc(hex);
|
|
20
|
-
expect(decodeMultibase58btcToUUID(encoded)).toBe('00112233-4455-6677-8899-aabbccddeeff');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('encodes and decodes raw bytes', () => {
|
|
24
|
-
const bytes = new Uint8Array([9, 9, 9]);
|
|
25
|
-
const encoded = encodeMultibase58btc(bytes);
|
|
26
|
-
const decoded = decodeMultibase58btc(encoded);
|
|
27
|
-
expect(Array.from(decoded)).toEqual([9, 9, 9]);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('throws for invalid hex input', () => {
|
|
31
|
-
expect(() => encodeHexToMultibase58btc('not-hex')).toThrow(/Invalid 16-byte hex string/);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
decodeMultibase58btc,
|
|
3
|
-
decodeMultibase58btcToHex,
|
|
4
|
-
decodeMultibase58btcToUUID,
|
|
5
|
-
encodeHexToMultibase58btc,
|
|
6
|
-
encodeMultibase58btc,
|
|
7
|
-
} from '../src/utils/multibase58.js';
|
|
8
|
-
|
|
9
|
-
describe('multibase58', () => {
|
|
10
|
-
it('round-trips bytes', () => {
|
|
11
|
-
const bytes = new Uint8Array([1, 2, 3, 250, 251, 252]);
|
|
12
|
-
const encoded = encodeMultibase58btc(bytes);
|
|
13
|
-
expect(encoded.startsWith('z')).toBe(true);
|
|
14
|
-
const decoded = decodeMultibase58btc(encoded);
|
|
15
|
-
expect(Array.from(decoded)).toEqual(Array.from(bytes));
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('throws if prefix is missing', () => {
|
|
19
|
-
expect(() => decodeMultibase58btc('not-prefixed')).toThrow(/missing 'z' prefix/i);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('round-trips hex to multibase and back', () => {
|
|
23
|
-
const hex = '00112233445566778899aabbccddeeff';
|
|
24
|
-
const encoded = encodeHexToMultibase58btc(hex);
|
|
25
|
-
expect(decodeMultibase58btcToHex(encoded)).toBe(hex);
|
|
26
|
-
expect(decodeMultibase58btcToUUID(encoded)).toBe('00112233-4455-6677-8899-aabbccddeeff');
|
|
27
|
-
});
|
|
28
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
|
|
3
|
-
import baseX from 'base-x';
|
|
4
|
-
import { encodeMultibaseSha384 } from '../src/utils/multibasehash';
|
|
5
|
-
|
|
6
|
-
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
7
|
-
const base58btc = baseX(BASE58_ALPHABET);
|
|
8
|
-
|
|
9
|
-
describe('encodeMultibaseSha384', () => {
|
|
10
|
-
it('returns a multibase base58btc string with SHA-384 prefix', () => {
|
|
11
|
-
const output = encodeMultibaseSha384('hello');
|
|
12
|
-
expect(output.startsWith('z')).toBe(true);
|
|
13
|
-
|
|
14
|
-
const decoded = base58btc.decode(output.slice(1));
|
|
15
|
-
expect(decoded[0]).toBe(0x15);
|
|
16
|
-
expect(decoded[1]).toBe(0x30);
|
|
17
|
-
expect(decoded.length).toBe(2 + 48);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('is deterministic for same input', () => {
|
|
21
|
-
const a = encodeMultibaseSha384('same');
|
|
22
|
-
const b = encodeMultibaseSha384('same');
|
|
23
|
-
expect(a).toBe(b);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { parseActorFromSub } from '../src/utils/actor.js';
|
|
2
|
-
|
|
3
|
-
describe('parseActorFromSub', () => {
|
|
4
|
-
it('returns trimmed subject and minimal info for empty input', () => {
|
|
5
|
-
expect(parseActorFromSub(' ')).toEqual({ sub: '' });
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
it('parses did:web subject with organization, email, and role', () => {
|
|
9
|
-
const sub = 'did:web:api.acme.org:employee:doctor1@acme.org:ISCO-08|2211';
|
|
10
|
-
const parsed = parseActorFromSub(sub);
|
|
11
|
-
expect(parsed.sub).toBe(sub);
|
|
12
|
-
expect(parsed.organization).toBe('did:web:api.acme.org');
|
|
13
|
-
expect(parsed.identifier).toBe('doctor1@acme.org');
|
|
14
|
-
expect(parsed.role).toBe('ISCO-08|2211');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('parses did:web subject with role and device uuid', () => {
|
|
18
|
-
const sub = 'did:web:api.acme.org:employee:doctor1@acme.org:ISCO-08|2211:550e8400-e29b-41d4-a716-446655440000';
|
|
19
|
-
const parsed = parseActorFromSub(sub);
|
|
20
|
-
expect(parsed.organization).toBe('did:web:api.acme.org');
|
|
21
|
-
expect(parsed.identifier).toBe('doctor1@acme.org');
|
|
22
|
-
expect(parsed.role).toBe('ISCO-08|2211');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('parses family subject with role and device uuid', () => {
|
|
26
|
-
const sub = 'did:web:api.acme.org:family:zQmHash123:v3-RoleCode|CHILD:550e8400-e29b-41d4-a716-446655440000';
|
|
27
|
-
const parsed = parseActorFromSub(sub);
|
|
28
|
-
expect(parsed.organization).toBe('did:web:api.acme.org');
|
|
29
|
-
expect(parsed.identifier).toBe('zQmHash123');
|
|
30
|
-
expect(parsed.role).toBe('v3-RoleCode|CHILD');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('parses family subject with ONESELF role and no device uuid', () => {
|
|
34
|
-
const sub = 'did:web:api.acme.org:family:zQmHash123:v3-RoleCode|ONESELF';
|
|
35
|
-
const parsed = parseActorFromSub(sub);
|
|
36
|
-
expect(parsed.organization).toBe('did:web:api.acme.org');
|
|
37
|
-
expect(parsed.identifier).toBe('zQmHash123');
|
|
38
|
-
expect(parsed.role).toBe('v3-RoleCode|ONESELF');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('parses raw email subject', () => {
|
|
42
|
-
const parsed = parseActorFromSub(' User@Example.com ');
|
|
43
|
-
expect(parsed.sub).toBe('User@Example.com');
|
|
44
|
-
expect(parsed.identifier).toBe('user@example.com');
|
|
45
|
-
});
|
|
46
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
base58ToBytes,
|
|
3
|
-
base64OrUrlSafeToBytes,
|
|
4
|
-
base64ToBase64Url,
|
|
5
|
-
base64UrlToBase64,
|
|
6
|
-
bytesToBase58,
|
|
7
|
-
bytesToBase64,
|
|
8
|
-
bytesToHexString,
|
|
9
|
-
bytesToRawBase64UrlSafe,
|
|
10
|
-
stringToBase64Url,
|
|
11
|
-
stringToStdBase64,
|
|
12
|
-
} from '../src/utils/base-convert.js';
|
|
13
|
-
import { stringToBytesUTF8, bytesToStringUTF8 } from '../src/utils/string-convert.js';
|
|
14
|
-
|
|
15
|
-
function toArray(bytes: Uint8Array): number[] {
|
|
16
|
-
return Array.from(bytes);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
describe('base-convert utilities', () => {
|
|
20
|
-
it('converts bytes to hex string', () => {
|
|
21
|
-
const hex = bytesToHexString(new Uint8Array([0, 15, 255]));
|
|
22
|
-
expect(hex).toBe('000fff');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('round-trips base58 encoding', () => {
|
|
26
|
-
const bytes = stringToBytesUTF8('hello');
|
|
27
|
-
const encoded = bytesToBase58(bytes);
|
|
28
|
-
const decoded = base58ToBytes(encoded);
|
|
29
|
-
expect(toArray(decoded)).toEqual(toArray(bytes));
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('handles base64 and base64url conversions', () => {
|
|
33
|
-
const std = stringToStdBase64('hi');
|
|
34
|
-
expect(std).toBe('aGk=');
|
|
35
|
-
const url = stringToBase64Url('hi');
|
|
36
|
-
expect(url).toBe('aGk=');
|
|
37
|
-
expect(base64ToBase64Url('ab+/')).toBe('ab-_');
|
|
38
|
-
expect(base64UrlToBase64('ab-_')).toBe('ab+/');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('decodes base64 or base64url into bytes', () => {
|
|
42
|
-
const withSlash = '//8='; // bytes [255, 255]
|
|
43
|
-
const fromBase64 = base64OrUrlSafeToBytes(withSlash);
|
|
44
|
-
expect(toArray(fromBase64)).toEqual([255, 255]);
|
|
45
|
-
|
|
46
|
-
const urlSafe = 'AQID'; // bytes [1,2,3]
|
|
47
|
-
const fromUrlSafe = base64OrUrlSafeToBytes(urlSafe);
|
|
48
|
-
expect(toArray(fromUrlSafe)).toEqual([1, 2, 3]);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('encodes bytes to base64 and raw base64url', () => {
|
|
52
|
-
const bytes = stringToBytesUTF8('test');
|
|
53
|
-
expect(bytesToBase64(bytes)).toBe('dGVzdA==');
|
|
54
|
-
expect(bytesToRawBase64UrlSafe(bytes)).toBe('dGVzdA');
|
|
55
|
-
expect(bytesToStringUTF8(base64OrUrlSafeToBytes(bytesToRawBase64UrlSafe(bytes)))).toBe('test');
|
|
56
|
-
});
|
|
57
|
-
});
|