gdc-common-utils-ts 1.0.1
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/PUBLISHING.md +33 -0
- package/__tests__/AesManager.test.ts +53 -0
- package/__tests__/CryptographyService.test.ts +194 -0
- package/__tests__/bundle.test.ts +29 -0
- package/__tests__/content.test.ts +72 -0
- package/__tests__/crypto-encode-decode.test.ts +52 -0
- package/__tests__/crypto-hmac.test.ts +21 -0
- package/__tests__/did-generateServiceId.errors.test.ts +8 -0
- package/__tests__/did-generateServiceId.test.ts +18 -0
- package/__tests__/models-clinical-sections.test.ts +32 -0
- package/__tests__/models-multibase58.test.ts +33 -0
- package/__tests__/multibase58.errors.test.ts +7 -0
- package/__tests__/multibase58.test.ts +28 -0
- package/__tests__/multibasehash.test.ts +25 -0
- package/__tests__/utils-actor.test.ts +22 -0
- package/__tests__/utils-base-convert.test.ts +57 -0
- package/__tests__/utils-baseN.test.ts +40 -0
- package/__tests__/utils-did-extra.test.ts +33 -0
- package/__tests__/utils-format-converter.test.ts +87 -0
- package/__tests__/utils-jwt.test.ts +57 -0
- package/__tests__/utils-manager-error.test.ts +11 -0
- package/__tests__/utils-normalize.test.ts +15 -0
- package/__tests__/utils-object-convert.test.ts +38 -0
- package/__tests__/utils-string-convert.test.ts +20 -0
- package/__tests__/utils-string-utils.test.ts +25 -0
- package/__tests__/utils-url.test.ts +21 -0
- package/babel.config.cjs +5 -0
- package/jest.config.ts +46 -0
- package/package.json +36 -0
- package/src/AesManager.ts +82 -0
- package/src/CryptographyService.ts +461 -0
- package/src/JweManager.ts.txt +365 -0
- package/src/KmsService.txt +493 -0
- package/src/constants/Schemas.ts +61 -0
- package/src/constants/index.ts +1 -0
- package/src/constants/schemaorg.ts +193 -0
- package/src/cryptoDecode.ts +104 -0
- package/src/cryptoEncode.ts +36 -0
- package/src/cryptography.abstract.ts +29 -0
- package/src/hmac.ts +15 -0
- package/src/index.ts +3 -0
- package/src/interfaces/Cryptography.types.ts +131 -0
- package/src/interfaces/ICryptoHelper.ts +33 -0
- package/src/interfaces/ICryptography.ts +177 -0
- package/src/interfaces/IWallet.ts +62 -0
- package/src/interfaces/MlDsa.ts +25 -0
- package/src/interfaces/MlKem.ts +18 -0
- package/src/models/aes.ts +93 -0
- package/src/models/auth.ts +38 -0
- package/src/models/bundle.ts +152 -0
- package/src/models/bundle.txt +93 -0
- package/src/models/clinical-sections.en.ts +82 -0
- package/src/models/clinical-sections.ts +64 -0
- package/src/models/comm.ts +63 -0
- package/src/models/confidential-job.ts +100 -0
- package/src/models/confidential-message.ts +137 -0
- package/src/models/confidential-storage.ts +170 -0
- package/src/models/consent-rule.ts +141 -0
- package/src/models/crypto.ts +43 -0
- package/src/models/device-license.ts +161 -0
- package/src/models/did.ts +81 -0
- package/src/models/index.ts +31 -0
- package/src/models/indexing.ts +20 -0
- package/src/models/issue.ts +85 -0
- package/src/models/jsonapi.ts +19 -0
- package/src/models/jwe.ts +132 -0
- package/src/models/jwk.ts +50 -0
- package/src/models/jws.ts +42 -0
- package/src/models/jwt.ts +15 -0
- package/src/models/multibase58.ts +46 -0
- package/src/models/oidc4ida.common.model.ts +39 -0
- package/src/models/oidc4ida.document.model.ts +61 -0
- package/src/models/oidc4ida.electronicRecord.model.ts +86 -0
- package/src/models/oidc4ida.evidence.model.ts +69 -0
- package/src/models/openid-device.ts +146 -0
- package/src/models/operation-outcome.ts +34 -0
- package/src/models/params.ts +142 -0
- package/src/models/resource-document.ts +21 -0
- package/src/models/response.ts +5 -0
- package/src/models/urlPath.ts +76 -0
- package/src/models/verifiable-credential.ts +52 -0
- package/src/types/noble-hashes.d.ts +4 -0
- package/src/utils/actor.ts +52 -0
- package/src/utils/base-convert.ts +77 -0
- package/src/utils/baseN.ts +203 -0
- package/src/utils/bundle.ts +30 -0
- package/src/utils/content.ts +66 -0
- package/src/utils/did.ts +155 -0
- package/src/utils/format-converter.ts +119 -0
- package/src/utils/index.ts +13 -0
- package/src/utils/jwt.ts +165 -0
- package/src/utils/manager-error.ts +27 -0
- package/src/utils/multibase58.ts +46 -0
- package/src/utils/multibasehash.ts +28 -0
- package/src/utils/normalize.ts +43 -0
- package/src/utils/object-convert.ts +57 -0
- package/src/utils/string-convert.ts +71 -0
- package/src/utils/string-utils.ts +70 -0
- package/src/utils/url.ts +46 -0
- package/tsconfig.json +13 -0
package/src/utils/jwt.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// crypto-ts/utils/jwt.ts
|
|
2
|
+
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
3
|
+
|
|
4
|
+
// Use `import * as pako` to ensure compatibility with CommonJS/ESM module resolution.
|
|
5
|
+
// This resolves a stubborn TypeScript error (`esModuleInterop`) during testing.
|
|
6
|
+
import * as pako from 'pako';
|
|
7
|
+
import { Content } from './content';
|
|
8
|
+
import { DataCompactJWT, JwtCompactParts } from '../models/jwt';
|
|
9
|
+
|
|
10
|
+
// --- JWT Parsing and Decoding ---
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Splits a compact JWT string into its three parts.
|
|
14
|
+
* @param compactToken The compact JWT string.
|
|
15
|
+
* @returns A PartsJWT object or undefined if the format is invalid.
|
|
16
|
+
*/
|
|
17
|
+
export function getPartsJWT(compactToken: string | undefined): JwtCompactParts | undefined {
|
|
18
|
+
if (!compactToken) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const parts = compactToken.split('.');
|
|
22
|
+
if (parts.length !== 3) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
protected: parts[0],
|
|
27
|
+
payload: parts[1],
|
|
28
|
+
signature: parts[2],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Decodes the Base64Url header of a JWT into a JSON object.
|
|
34
|
+
* @param headerB64Url The Base64Url-encoded header string.
|
|
35
|
+
* @returns A JSON object representing the header claims.
|
|
36
|
+
*/
|
|
37
|
+
export function decodeHeader(headerB64Url: string): any {
|
|
38
|
+
try {
|
|
39
|
+
const headerBytes = Content.base64ToBytes(headerB64Url);
|
|
40
|
+
const headerString = Content.bytesToStringASCII(headerBytes);
|
|
41
|
+
return JSON.parse(headerString);
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.error(`Cannot decode JWT header: ${e}`);
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Decodes the payload of a JWT, decompressing it if necessary.
|
|
50
|
+
* @param payloadB64Url The Base64Url-encoded payload string.
|
|
51
|
+
* @param isDeflated True if the payload is compressed with DEFLATE.
|
|
52
|
+
* @returns The decoded payload as a JSON object.
|
|
53
|
+
*/
|
|
54
|
+
export async function decodePayload(payloadB64Url: string, isDeflated?: boolean): Promise<object> {
|
|
55
|
+
try {
|
|
56
|
+
let payloadBytes = Content.base64ToBytes(payloadB64Url);
|
|
57
|
+
if (isDeflated) {
|
|
58
|
+
payloadBytes = pako.inflate(payloadBytes);
|
|
59
|
+
}
|
|
60
|
+
// CRITICAL: The output of a decompression library like pako is a raw binary
|
|
61
|
+
// stream. It is NOT guaranteed to be valid UTF-8. Using the strict
|
|
62
|
+
// `bytesToStringUTF8` can fail. `bytesToStringASCII` is a more permissive
|
|
63
|
+
// decoder that is robust enough to handle this binary data and convert it
|
|
64
|
+
// to a string that can be safely parsed by `JSON.parse()`.
|
|
65
|
+
const payloadString = Content.bytesToStringASCII(payloadBytes);
|
|
66
|
+
return JSON.parse(payloadString);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error(`Cannot decode JWT payload: ${e}`);
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Fully decodes a compact JWT into a `DataCompactJWT` object with JSON headers and payload.
|
|
75
|
+
* @returns A (compact) JWT object or undefined if parsing fails.
|
|
76
|
+
*/
|
|
77
|
+
export async function getDataJWT(compactJWT: string | undefined): Promise<DataCompactJWT | undefined> {
|
|
78
|
+
const parts = getPartsJWT(compactJWT);
|
|
79
|
+
if (!parts) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const header = decodeHeader(parts.protected);
|
|
84
|
+
const isDeflated = header.zip === 'DEF';
|
|
85
|
+
const payload = await decodePayload(parts.payload, isDeflated);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
protected: header,
|
|
89
|
+
payload,
|
|
90
|
+
signature: parts.signature ? Content.base64ToBytes(parts.signature) : undefined,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
// --- JWT Creation and Encoding ---
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Encodes a JSON object into a Base64Url string.
|
|
99
|
+
* @param header The header object.
|
|
100
|
+
* @returns The encoded string.
|
|
101
|
+
*/
|
|
102
|
+
export function encodeHeader(header: object): string {
|
|
103
|
+
try {
|
|
104
|
+
return Content.objectToRawBase64UrlSafe(header);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
console.warn('Cannot encode JWT header', e);
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Encodes a JSON object into a Base64Url payload, compressing it if required.
|
|
113
|
+
* @param payload The payload object.
|
|
114
|
+
* @param deflate True to compress the payload with DEFLATE.
|
|
115
|
+
* @returns The encoded string.
|
|
116
|
+
*/
|
|
117
|
+
export async function encodePayload(payload: object, deflate?: boolean): Promise<string> {
|
|
118
|
+
try {
|
|
119
|
+
// CRITICAL: When creating a payload, we start with a JSON string, which IS
|
|
120
|
+
// valid UTF-8. We must use the strict `stringToBytesUTF8` encoder to ensure
|
|
121
|
+
// standards compliance.
|
|
122
|
+
let payloadBytes = Content.stringToBytesUTF8(JSON.stringify(payload));
|
|
123
|
+
if (deflate) {
|
|
124
|
+
payloadBytes = pako.deflate(payloadBytes);
|
|
125
|
+
}
|
|
126
|
+
return Content.bytesToRawBase64UrlSafe(payloadBytes);
|
|
127
|
+
} catch (e) {
|
|
128
|
+
console.warn('Cannot encode JWT payload', e);
|
|
129
|
+
return '';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Encodes a signature byte array into a Base64Url string.
|
|
135
|
+
* @param signatureBytes The signature bytes.
|
|
136
|
+
* @returns The encoded string, or an empty string if no signature is provided.
|
|
137
|
+
*/
|
|
138
|
+
export function encodeSignature(signatureBytes?: Uint8Array): string {
|
|
139
|
+
if (!signatureBytes || signatureBytes.length < 1) {
|
|
140
|
+
return '';
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
return Content.bytesToRawBase64UrlSafe(signatureBytes);
|
|
144
|
+
} catch (e) {
|
|
145
|
+
console.warn('Cannot encode JWT signature', e);
|
|
146
|
+
return '';
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Assembles a header, payload, and signature into a compact JWT string.
|
|
152
|
+
* @param header The header object.
|
|
153
|
+
* @param payload The payload object.
|
|
154
|
+
* @param signatureBytes The optional signature.
|
|
155
|
+
* @returns A compact JWT string.
|
|
156
|
+
*/
|
|
157
|
+
export async function compactJWT(header: object, payload: object, signatureBytes?: Uint8Array): Promise<string> {
|
|
158
|
+
const encodedHeader = encodeHeader(header);
|
|
159
|
+
const isDeflated = (header as any).zip === 'DEF';
|
|
160
|
+
const encodedPayload = await encodePayload(payload, isDeflated);
|
|
161
|
+
const encodedSignature = encodeSignature(signatureBytes);
|
|
162
|
+
|
|
163
|
+
return `${encodedHeader}.${encodedPayload}.${encodedSignature}`;
|
|
164
|
+
}
|
|
165
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/utils/manager-error.ts
|
|
2
|
+
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
3
|
+
|
|
4
|
+
import { IssueTypeCode, IssueTypeToHttpStatus } from "../models/issue";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A custom error class used to propagate specific operational failures from deep
|
|
8
|
+
* within the manager's logic to the central error handler.
|
|
9
|
+
* It carries the necessary information to build a well-formed ErrorEntry.
|
|
10
|
+
*/
|
|
11
|
+
export class ManagerError extends Error {
|
|
12
|
+
public readonly code: IssueTypeCode;
|
|
13
|
+
public readonly status: string; // This is a string
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param message The diagnostic message for the error.
|
|
17
|
+
* @param code The classification of the error, from which the HTTP status will be derived.
|
|
18
|
+
*/
|
|
19
|
+
constructor(message: string, code: IssueTypeCode) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = 'ManagerError';
|
|
22
|
+
this.code = code;
|
|
23
|
+
// Automatically derive the HTTP status string from the issue code.
|
|
24
|
+
this.status = IssueTypeToHttpStatus[code] || '500';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// crypto-ts/crypto-ts/utils/multibase58.ts
|
|
2
|
+
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
3
|
+
|
|
4
|
+
import baseX from "base-x";
|
|
5
|
+
|
|
6
|
+
const BASE58_BTC_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
7
|
+
const base58btc = baseX(BASE58_BTC_ALPHABET);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Encode bytes into multibase base58btc string (prefixed with 'z').
|
|
11
|
+
* Equivalent to multiformats base58btc.encode.
|
|
12
|
+
*/
|
|
13
|
+
export function encodeMultibase58btc(data: Uint8Array): string {
|
|
14
|
+
return "z" + base58btc.encode(Buffer.from(data));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Decode a multibase base58btc string (must start with 'z').
|
|
19
|
+
* Equivalent to multiformats base58btc.decode.
|
|
20
|
+
*/
|
|
21
|
+
export function decodeMultibase58btc(multibaseStr: string): Uint8Array {
|
|
22
|
+
if (!multibaseStr.startsWith("z")) {
|
|
23
|
+
throw new Error("Invalid multibase58btc string: missing 'z' prefix");
|
|
24
|
+
}
|
|
25
|
+
return new Uint8Array(base58btc.decode(multibaseStr.slice(1)));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// HEX ➜ multibase base58btc (quita guiones si los hay)
|
|
29
|
+
export function encodeHexToMultibase58btc(hexStr: string): string {
|
|
30
|
+
const hexClean = hexStr.replace(/-/g, "").toLowerCase();
|
|
31
|
+
if (!/^[0-9a-f]{32}$/i.test(hexClean)) throw new Error("Invalid 16-byte hex string");
|
|
32
|
+
const bytes = new Uint8Array(hexClean.match(/.{1,2}/g)!.map(b => parseInt(b, 16)));
|
|
33
|
+
return encodeMultibase58btc(bytes);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// multibase base58btc ➜ hex (no hyppens)
|
|
37
|
+
export function decodeMultibase58btcToHex(b58str: string): string {
|
|
38
|
+
const bytes = decodeMultibase58btc(b58str);
|
|
39
|
+
return Array.from(bytes).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// multibase base58btc ➜ UUID (with hyppens)
|
|
43
|
+
export function decodeMultibase58btcToUUID(b58str: string): string {
|
|
44
|
+
const hex = decodeMultibase58btcToHex(b58str);
|
|
45
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
46
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
|
|
3
|
+
// Use explicit .js subpaths to satisfy package exports in Metro/Node ESM.
|
|
4
|
+
import { sha384 } from '@noble/hashes/sha2.js';
|
|
5
|
+
import { utf8ToBytes } from '@noble/hashes/utils.js';
|
|
6
|
+
import baseX from 'base-x';
|
|
7
|
+
|
|
8
|
+
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
9
|
+
const base58btc = baseX(BASE58_ALPHABET);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Encodes input into multibase(base58btc(multihash(sha384))).
|
|
13
|
+
* - Multihash prefix: 0x15 0x30
|
|
14
|
+
* - 0x15: code for SHA-384
|
|
15
|
+
* - 0x30: length of SHA-384 = 48 bytes
|
|
16
|
+
* - Multibase prefix: 'z'
|
|
17
|
+
*/
|
|
18
|
+
export function encodeMultibaseSha384(input: string | Uint8Array): string {
|
|
19
|
+
const bytes = typeof input === 'string' ? utf8ToBytes(input) : input;
|
|
20
|
+
const hashBytes = sha384(bytes);
|
|
21
|
+
|
|
22
|
+
const multihashBytes = new Uint8Array(2 + hashBytes.length);
|
|
23
|
+
multihashBytes[0] = 0x15; // SHA-384 code
|
|
24
|
+
multihashBytes[1] = 0x30; // length = 48
|
|
25
|
+
multihashBytes.set(hashBytes, 2);
|
|
26
|
+
|
|
27
|
+
return 'z' + base58btc.encode(multihashBytes);
|
|
28
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
// File: crypto-ts/utils/normalize.ts
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a stable, serialized JSON string from an object by sorting its keys alphabetically.
|
|
6
|
+
* This is the core function for achieving canonical serialization.
|
|
7
|
+
* @param obj The object to serialize.
|
|
8
|
+
* @returns A stable JSON string.
|
|
9
|
+
*/
|
|
10
|
+
function stableStringify(obj: object): string {
|
|
11
|
+
const sortedKeys = Object.keys(obj).sort();
|
|
12
|
+
const sortedObject: { [key: string]: any } = {};
|
|
13
|
+
for (const key of sortedKeys) {
|
|
14
|
+
sortedObject[key] = (obj as any)[key];
|
|
15
|
+
}
|
|
16
|
+
return JSON.stringify(sortedObject);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Normalizes an object for hashing by excluding a standard set of volatile properties.
|
|
21
|
+
* This function is based on the original `normalizeAndSerializeObject` from the backend utils.
|
|
22
|
+
*
|
|
23
|
+
* @param obj The object to normalize.
|
|
24
|
+
* @returns A stable, canonical JSON string of the object's core properties.
|
|
25
|
+
*/
|
|
26
|
+
export function normalizeObject(obj: object): string {
|
|
27
|
+
// Exclude properties that are often volatile or client-specific
|
|
28
|
+
// and should not be part of the core content hash.
|
|
29
|
+
const { id, meta, text, contained, ...coreContent } = obj as any;
|
|
30
|
+
return stableStringify(coreContent);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Normalizes a DIDComm payload specifically for generating the `payload.id` (version hash).
|
|
35
|
+
* According to the defined architecture, this specifically excludes `id` and `meta`.
|
|
36
|
+
*
|
|
37
|
+
* @param payload The DIDComm payload object.
|
|
38
|
+
* @returns A stable JSON string representation of the payload's core content.
|
|
39
|
+
*/
|
|
40
|
+
export function normalizeDidcommPayloadForId(payload: object): string {
|
|
41
|
+
const { id, meta, ...coreContent } = payload as any;
|
|
42
|
+
return stableStringify(coreContent);
|
|
43
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// crypto-ts/utils/object-convert.ts
|
|
2
|
+
|
|
3
|
+
import { decodeURLSafe } from "@stablelib/base64";
|
|
4
|
+
import { bytesToStringUTF8, stringToBytesUTF8 } from './string-convert';
|
|
5
|
+
import { bytesToRawBase64UrlSafe } from './base-convert';
|
|
6
|
+
|
|
7
|
+
/** Compares two arrays and returns true if they are the same, false otherwise. */
|
|
8
|
+
export function arrayCompare(a: any[], b: any[]): boolean {
|
|
9
|
+
if (a.length !== b.length) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
for (let i = 0; i < a.length; i++) {
|
|
13
|
+
if (a[i] !== b[i]) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Merges two Uint8Arrays into a single Uint8Array. */
|
|
21
|
+
export function arrayMerge(a: Uint8Array, b: Uint8Array): Uint8Array {
|
|
22
|
+
const mergedArray = new Uint8Array(a.length + b.length);
|
|
23
|
+
mergedArray.set(a);
|
|
24
|
+
mergedArray.set(b, a.length);
|
|
25
|
+
return mergedArray;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Serializes a JavaScript object to a Uint8Array of UTF-8 bytes.
|
|
30
|
+
* NOTE: This does not perform canonicalization (sorting keys).
|
|
31
|
+
*/
|
|
32
|
+
export function objectToBytes(data: object): Uint8Array {
|
|
33
|
+
return stringToBytesUTF8(JSON.stringify(data));
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Serializes a JavaScript object to a raw Base64URL string.
|
|
38
|
+
* NOTE: This does not perform canonicalization (sorting keys).
|
|
39
|
+
*/
|
|
40
|
+
export function objectToRawBase64UrlSafe(data: object): string {
|
|
41
|
+
const dataBytes = objectToBytes(data);
|
|
42
|
+
return bytesToRawBase64UrlSafe(dataBytes);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Deserializes a Base64URL string back into a JavaScript object.
|
|
47
|
+
* @param base64UrlSafe The Base64URL encoded JSON string.
|
|
48
|
+
* @returns A JavaScript object.
|
|
49
|
+
*/
|
|
50
|
+
export function base64UrlSafeToJSON(base64UrlSafe: string | undefined): object {
|
|
51
|
+
if (!base64UrlSafe) {
|
|
52
|
+
throw new Error("Input string is undefined.");
|
|
53
|
+
}
|
|
54
|
+
const dataBytes: Uint8Array = decodeURLSafe(base64UrlSafe);
|
|
55
|
+
return JSON.parse(bytesToStringUTF8(dataBytes));
|
|
56
|
+
}
|
|
57
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// crypto-ts/utils/string-convert.ts
|
|
2
|
+
|
|
3
|
+
import { encode as encodeUTF8, decode as decodeUTF8 } from "@stablelib/utf8";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Encodes a standard JavaScript string into a Uint8Array of strictly-validated UTF-8 bytes.
|
|
7
|
+
* This is the standard and safest method for serializing text data.
|
|
8
|
+
* @param str The string to convert.
|
|
9
|
+
* @returns A Uint8Array.
|
|
10
|
+
*/
|
|
11
|
+
export function stringToBytesUTF8(str: string): Uint8Array {
|
|
12
|
+
return encodeUTF8(str);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Decodes a Uint8Array of strictly-validated UTF-8 bytes back into a string.
|
|
17
|
+
* This will fail if the byte array does not represent valid UTF-8.
|
|
18
|
+
* Use this for standard text and JSON.
|
|
19
|
+
* @param array The UTF-8 byte array to convert.
|
|
20
|
+
* @returns A string.
|
|
21
|
+
*/
|
|
22
|
+
export function bytesToStringUTF8(array: Uint8Array): string {
|
|
23
|
+
return decodeUTF8(array);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Decodes a Uint8Array containing binary data into a string by processing
|
|
28
|
+
* each byte individually. This is more permissive than `bytesToStringUTF8` and is
|
|
29
|
+
* specifically required for handling payloads from libraries (e.g., pako) that
|
|
30
|
+
* may not be strictly UTF-8. Use this for decoding JWT payloads.
|
|
31
|
+
* @param array The binary/ASCII byte array to convert.
|
|
32
|
+
* @returns A string.
|
|
33
|
+
*/
|
|
34
|
+
export function bytesToStringASCII(array: Uint8Array): string {
|
|
35
|
+
var out, i, len, c;
|
|
36
|
+
var char2, char3;
|
|
37
|
+
|
|
38
|
+
out = "";
|
|
39
|
+
len = array.length;
|
|
40
|
+
i = 0;
|
|
41
|
+
while (i < len) {
|
|
42
|
+
c = array[i++];
|
|
43
|
+
switch (
|
|
44
|
+
c >> 4
|
|
45
|
+
) {
|
|
46
|
+
case 0:
|
|
47
|
+
case 1:
|
|
48
|
+
case 2:
|
|
49
|
+
case 3:
|
|
50
|
+
case 4:
|
|
51
|
+
case 5:
|
|
52
|
+
case 6:
|
|
53
|
+
case 7:
|
|
54
|
+
out += String.fromCharCode(c);
|
|
55
|
+
break;
|
|
56
|
+
case 12:
|
|
57
|
+
case 13:
|
|
58
|
+
char2 = array[i++];
|
|
59
|
+
out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f));
|
|
60
|
+
break;
|
|
61
|
+
case 14:
|
|
62
|
+
char2 = array[i++];
|
|
63
|
+
char3 = array[i++];
|
|
64
|
+
out += String.fromCharCode(
|
|
65
|
+
((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0)
|
|
66
|
+
);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// crypto-ts/utils/string-utils.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Capitalizes the first letter of a string.
|
|
5
|
+
* @param s The input string.
|
|
6
|
+
* @returns The capitalized string.
|
|
7
|
+
*/
|
|
8
|
+
export function capitalize(s: string): string {
|
|
9
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A simple string sanitizer that removes characters that are not alphanumeric or common punctuation.
|
|
14
|
+
* @param str The string to sanitize.
|
|
15
|
+
* @returns The sanitized string.
|
|
16
|
+
*/
|
|
17
|
+
export function sanitizeString(str: string): string {
|
|
18
|
+
str = str.replace(/[^a-z0-9áéíóúñü \.,_-]/gim, "");
|
|
19
|
+
return str.trim();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Converts a string to a string of its ASCII character codes.
|
|
24
|
+
* @param text The input string.
|
|
25
|
+
* @returns A string of character codes.
|
|
26
|
+
*/
|
|
27
|
+
/* tslint:disable:forin */
|
|
28
|
+
export function stringToASCII(text: any): string {
|
|
29
|
+
let ascii = "";
|
|
30
|
+
for (const f in text) {
|
|
31
|
+
ascii = ascii + text.charCodeAt(f);
|
|
32
|
+
}
|
|
33
|
+
return ascii;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Converts a string to an array of numbers representing its byte values.
|
|
38
|
+
* From google closure library: https://github.com/google/closure-library/blob/8598d87242af59aac233270742c8984e2b2bdbe0/closure/goog/crypt/crypt.js#L117-L143
|
|
39
|
+
* @param str The input string.
|
|
40
|
+
* @returns An array of numbers.
|
|
41
|
+
*/
|
|
42
|
+
export function stringToBytesArrayOfNumbers(str: string): number[] {
|
|
43
|
+
let out = [],
|
|
44
|
+
p = 0;
|
|
45
|
+
for (var i = 0; i < str.length; i++) {
|
|
46
|
+
var c = str.charCodeAt(i);
|
|
47
|
+
if (c < 128) {
|
|
48
|
+
out[p++] = c;
|
|
49
|
+
} else if (c < 2048) {
|
|
50
|
+
out[p++] = (c >> 6) | 192;
|
|
51
|
+
out[p++] = (c & 63) | 128;
|
|
52
|
+
} else if (
|
|
53
|
+
(c & 0xfc00) == 0xd800 &&
|
|
54
|
+
i + 1 < str.length &&
|
|
55
|
+
(str.charCodeAt(i + 1) & 0xfc00) == 0xdc00
|
|
56
|
+
) {
|
|
57
|
+
// Surrogate Pair
|
|
58
|
+
c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff);
|
|
59
|
+
out[p++] = (c >> 18) | 240;
|
|
60
|
+
out[p++] = ((c >> 12) & 63) | 128;
|
|
61
|
+
out[p++] = ((c >> 6) & 63) | 128;
|
|
62
|
+
out[p++] = (c & 63) | 128;
|
|
63
|
+
} else {
|
|
64
|
+
out[p++] = (c >> 12) | 224;
|
|
65
|
+
out[p++] = ((c >> 6) & 63) | 128;
|
|
66
|
+
out[p++] = (c & 63) | 128;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
package/src/utils/url.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// crypto-ts/utils/url.ts
|
|
2
|
+
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Join the base_url and path without adding extra slashes.
|
|
6
|
+
*
|
|
7
|
+
* @param base_url - The base URL.
|
|
8
|
+
* @param path - The path to be appended to the base URL.
|
|
9
|
+
* @returns The safely joined URL.
|
|
10
|
+
*/
|
|
11
|
+
export function safelyJoinUrl(base_url: string, path: string): string {
|
|
12
|
+
// Remove trailing slash from base_url if it exists
|
|
13
|
+
if (base_url.endsWith('/')) {
|
|
14
|
+
base_url = base_url.substring(0, base_url.length - 1);
|
|
15
|
+
}
|
|
16
|
+
// Remove leading slash from path if it exists
|
|
17
|
+
if (path.startsWith('/')) {
|
|
18
|
+
path = path.substring(1);
|
|
19
|
+
}
|
|
20
|
+
return `${base_url}/${path}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Splits a given URL into its domain and path components.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} urlString - The full URL string to be split.
|
|
27
|
+
* @returns {{ domain: string; path: string }} An object containing the `domain` and `path` of the URL.
|
|
28
|
+
* If the URL is not valid it returns empty domain and path.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* Returns { domain: 'www.example.com', path: '/some/path' }
|
|
32
|
+
* const result = splitUrl('https://www.example.com/some/path?query=string');
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* Returns null for invalid URLs
|
|
36
|
+
* const result = splitUrl('invalid-url');
|
|
37
|
+
*/
|
|
38
|
+
export function splitUrl(urlString: string): { domain: string; path: string } | null {
|
|
39
|
+
try {
|
|
40
|
+
const url = new URL(urlString);
|
|
41
|
+
return { domain: url.hostname, path: url.pathname };
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error("Invalid URL provided:", (error as any).message);
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true
|
|
10
|
+
},
|
|
11
|
+
"include": ["src/**/*.ts"],
|
|
12
|
+
"exclude": ["node_modules", "__tests__/**", "src/**/*.txt"]
|
|
13
|
+
}
|