@raytio/core 11.5.0 → 11.7.0
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/README.md +1708 -217
- package/dist/accessApplication/api/legacy/convertRelationships.d.ts +3 -5
- package/dist/accessApplication/api/legacy/convertRelationships.js +3 -3
- package/dist/crypto/cognitoAttributes.d.ts +3 -0
- package/dist/crypto/cognitoAttributes.js +15 -4
- package/dist/crypto/getAADecryptor.d.ts +1 -1
- package/dist/crypto/getAADecryptor.js +1 -3
- package/dist/crypto/index.d.ts +3 -0
- package/dist/crypto/index.js +6 -0
- package/dist/crypto/kdf/argon2.d.ts +67 -0
- package/dist/crypto/kdf/argon2.js +99 -0
- package/dist/crypto/kdf/index.d.ts +43 -0
- package/dist/crypto/kdf/index.js +106 -0
- package/dist/crypto/kdf/pbkdf2.d.ts +16 -0
- package/dist/crypto/kdf/pbkdf2.js +45 -0
- package/dist/crypto/kdf/twoSecretKdf.d.ts +37 -0
- package/dist/crypto/kdf/twoSecretKdf.js +66 -0
- package/dist/crypto/kdf/types.d.ts +65 -0
- package/dist/crypto/kdf/types.js +50 -0
- package/dist/crypto/kdf/utils.d.ts +59 -0
- package/dist/crypto/kdf/utils.js +110 -0
- package/dist/crypto/localSecret/format.d.ts +48 -0
- package/dist/crypto/localSecret/format.js +157 -0
- package/dist/crypto/localSecret/generator.d.ts +23 -0
- package/dist/crypto/localSecret/generator.js +53 -0
- package/dist/crypto/localSecret/index.d.ts +12 -0
- package/dist/crypto/localSecret/index.js +46 -0
- package/dist/crypto/localSecret/storage.d.ts +53 -0
- package/dist/crypto/localSecret/storage.js +207 -0
- package/dist/crypto/localSecret/types.d.ts +68 -0
- package/dist/crypto/localSecret/types.js +31 -0
- package/dist/crypto/pgpKey/encryption.d.ts +49 -0
- package/dist/crypto/pgpKey/encryption.js +104 -0
- package/dist/crypto/pgpKey/export.d.ts +59 -0
- package/dist/crypto/pgpKey/export.js +322 -0
- package/dist/crypto/pgpKey/format.d.ts +61 -0
- package/dist/crypto/pgpKey/format.js +143 -0
- package/dist/crypto/pgpKey/generator.d.ts +20 -0
- package/dist/crypto/pgpKey/generator.js +76 -0
- package/dist/crypto/pgpKey/import.d.ts +69 -0
- package/dist/crypto/pgpKey/import.js +239 -0
- package/dist/crypto/pgpKey/index.d.ts +19 -0
- package/dist/crypto/pgpKey/index.js +67 -0
- package/dist/crypto/pgpKey/signing.d.ts +44 -0
- package/dist/crypto/pgpKey/signing.js +71 -0
- package/dist/crypto/pgpKey/storage.d.ts +43 -0
- package/dist/crypto/pgpKey/storage.js +141 -0
- package/dist/crypto/pgpKey/types.d.ts +86 -0
- package/dist/crypto/pgpKey/types.js +25 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/rules/calculateScore.d.ts +1 -1
- package/dist/rules/convertInstanceToRuleInput.js +99 -97
- package/dist/rules/evaluateBadge.d.ts +36 -0
- package/dist/rules/evaluateBadge.js +36 -0
- package/dist/rules/index.d.ts +1 -0
- package/dist/rules/index.js +1 -0
- package/dist/rules/types/config.d.ts +1 -1
- package/dist/rules/types/dataValueTypes.d.ts +4 -4
- package/dist/schema/expandSchema/constants.js +1 -1
- package/dist/schema/expandSchema/expandSchema.d.ts +3 -3
- package/dist/schema/expandSchema/expandSchema.js +4 -4
- package/dist/schema/expandSchema/i18n.d.ts +6 -1
- package/dist/schema/expandSchema/i18n.js +32 -4
- package/dist/schema/expandSchema/maybeUseI18n.d.ts +2 -2
- package/dist/schema/expandSchema/maybeUseI18n.js +68 -11
- package/dist/schema/expandSchema/processSchema.js +14 -5
- package/dist/schema/expandSchema/removePrivateFields.d.ts +75 -22
- package/dist/schema/expandSchema/sortSchemaProperties.d.ts +4 -1
- package/dist/schema/expandSchema/sortSchemaProperties.js +24 -1
- package/dist/schema/labels.js +1 -2
- package/dist/util/canonicalJsonify.d.ts +7 -1
- package/dist/util/canonicalJsonify.js +3 -2
- package/dist/verifications/safeHarbour.js +5 -0
- package/dist/verifications/verifyCheck/getOwnRealVerifications.js +2 -0
- package/package.json +6 -4
- package/dist/__tests__/docs.test.d.ts +0 -1
- package/dist/__tests__/docs.test.js +0 -24
- package/dist/accessApplication/api/__tests__/fetchKeysForSubmission.test.d.ts +0 -1
- package/dist/accessApplication/api/__tests__/fetchKeysForSubmission.test.js +0 -28
- package/dist/accessApplication/api/__tests__/fetchPOsOrAOsForSubmission.test.d.ts +0 -1
- package/dist/accessApplication/api/__tests__/fetchPOsOrAOsForSubmission.test.js +0 -23
- package/dist/accessApplication/api/__tests__/fetchRelationshipsForSubmission.test.d.ts +0 -1
- package/dist/accessApplication/api/__tests__/fetchRelationshipsForSubmission.test.js +0 -27
- package/dist/accessApplication/api/__tests__/getMissingDataForInstance.test.d.ts +0 -1
- package/dist/accessApplication/api/__tests__/getMissingDataForInstance.test.js +0 -30
- package/dist/accessApplication/api/legacy/__tests__/convertRelationships.test.d.ts +0 -1
- package/dist/accessApplication/api/legacy/__tests__/convertRelationships.test.js +0 -37
- package/dist/rules/helpers/__tests__/addInfiniteThresholdBoundaries.test.d.ts +0 -1
- package/dist/rules/helpers/__tests__/addInfiniteThresholdBoundaries.test.js +0 -27
- package/dist/rules/helpers/__tests__/checkTypeofValue.test.d.ts +0 -1
- package/dist/rules/helpers/__tests__/checkTypeofValue.test.js +0 -49
- package/dist/rules/helpers/__tests__/getValuesFromPath.test.d.ts +0 -1
- package/dist/rules/helpers/__tests__/getValuesFromPath.test.js +0 -67
- package/dist/rules/helpers/__tests__/thresholds.test.d.ts +0 -1
- package/dist/rules/helpers/__tests__/thresholds.test.js +0 -32
- package/dist/rules/operators/__tests__/bool.test.d.ts +0 -1
- package/dist/rules/operators/__tests__/bool.test.js +0 -21
- package/dist/rules/operators/__tests__/date.test.d.ts +0 -1
- package/dist/rules/operators/__tests__/date.test.js +0 -81
- package/dist/rules/operators/__tests__/hfield.test.d.ts +0 -1
- package/dist/rules/operators/__tests__/hfield.test.js +0 -38
- package/dist/rules/operators/__tests__/hschema.test.d.ts +0 -1
- package/dist/rules/operators/__tests__/hschema.test.js +0 -24
- package/dist/rules/operators/__tests__/number.test.d.ts +0 -1
- package/dist/rules/operators/__tests__/number.test.js +0 -53
- package/dist/rules/operators/__tests__/string.test.d.ts +0 -1
- package/dist/rules/operators/__tests__/string.test.js +0 -74
- package/dist/schema/expandSchema/__tests__/addLoadingTimes.test.d.ts +0 -1
- package/dist/schema/expandSchema/__tests__/addLoadingTimes.test.js +0 -24
- package/dist/schema/expandSchema/__tests__/expandSchema.test.d.ts +0 -1
- package/dist/schema/expandSchema/__tests__/expandSchema.test.js +0 -96
- package/dist/schema/expandSchema/__tests__/i18n.test.d.ts +0 -1
- package/dist/schema/expandSchema/__tests__/i18n.test.js +0 -32
- package/dist/schema/expandSchema/__tests__/maybeUseI18n.test.d.ts +0 -1
- package/dist/schema/expandSchema/__tests__/maybeUseI18n.test.js +0 -98
- package/dist/schema/expandSchema/__tests__/processSchema.test.d.ts +0 -1
- package/dist/schema/expandSchema/__tests__/processSchema.test.js +0 -326
- package/dist/schema/expandSchema/__tests__/sortSchemaProperties.test.d.ts +0 -1
- package/dist/schema/expandSchema/__tests__/sortSchemaProperties.test.js +0 -182
- package/dist/schema/expandSchema/__tests__/util.test.d.ts +0 -1
- package/dist/schema/expandSchema/__tests__/util.test.js +0 -19
- package/dist/verifications/cleanInstance.d.ts +0 -9
- package/dist/verifications/cleanInstance.js +0 -15
- package/dist/verifications/verifyCheck/__tests__/getOwnRealVerifications.test.d.ts +0 -1
- package/dist/verifications/verifyCheck/__tests__/getOwnRealVerifications.test.js +0 -221
- package/dist/verifications/verifyCheck/__tests__/getSomeoneElsesRealVerifications.test.d.ts +0 -1
- package/dist/verifications/verifyCheck/__tests__/getSomeoneElsesRealVerifications.test.js +0 -206
- package/dist/verifications/verifyCheck/operations/__tests__/checkOwnVerification.test.d.ts +0 -1
- package/dist/verifications/verifyCheck/operations/__tests__/checkOwnVerification.test.js +0 -138
- package/dist/verifications/verifyCheck/operations/__tests__/checkSomeoneElsesVerifications.test.d.ts +0 -1
- package/dist/verifications/verifyCheck/operations/__tests__/checkSomeoneElsesVerifications.test.js +0 -49
- package/dist/verifications/verifyCheck/operations/__tests__/sampleBundle.json +0 -44
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable max-classes-per-file -- Error classes grouped in types module */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.DEFAULT_ARGON2ID_PARAMS = exports.UnknownKdfAlgorithmError = exports.LocalSecretRequiredError = void 0;
|
|
5
|
+
exports.isPbkdf2Config = isPbkdf2Config;
|
|
6
|
+
exports.isArgon2idConfig = isArgon2idConfig;
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when LocalSecret is required but not provided
|
|
9
|
+
*/
|
|
10
|
+
// eslint-disable-next-line fp/no-class -- Custom error class for specific error handling
|
|
11
|
+
class LocalSecretRequiredError extends Error {
|
|
12
|
+
constructor(message = "This account requires a Local Secret for decryption") {
|
|
13
|
+
super(message);
|
|
14
|
+
// eslint-disable-next-line fp/no-this, fp/no-mutation -- Required for Error subclassing
|
|
15
|
+
this.name = "LocalSecretRequiredError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.LocalSecretRequiredError = LocalSecretRequiredError;
|
|
19
|
+
/**
|
|
20
|
+
* Error thrown when KDF algorithm is unknown
|
|
21
|
+
*/
|
|
22
|
+
// eslint-disable-next-line fp/no-class -- Custom error class for specific error handling
|
|
23
|
+
class UnknownKdfAlgorithmError extends Error {
|
|
24
|
+
constructor(algorithm) {
|
|
25
|
+
super(`Unknown KDF algorithm: ${algorithm}`);
|
|
26
|
+
// eslint-disable-next-line fp/no-this, fp/no-mutation -- Required for Error subclassing
|
|
27
|
+
this.name = "UnknownKdfAlgorithmError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.UnknownKdfAlgorithmError = UnknownKdfAlgorithmError;
|
|
31
|
+
/**
|
|
32
|
+
* Default Argon2id parameters (matching Bitwarden recommendations)
|
|
33
|
+
*/
|
|
34
|
+
exports.DEFAULT_ARGON2ID_PARAMS = {
|
|
35
|
+
memory: 65536, // 64 MiB
|
|
36
|
+
iterations: 3,
|
|
37
|
+
parallelism: 4,
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Type guard for PBKDF2 config
|
|
41
|
+
*/
|
|
42
|
+
function isPbkdf2Config(config) {
|
|
43
|
+
return config.algorithm_name === "PBKDF2";
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Type guard for Argon2id config
|
|
47
|
+
*/
|
|
48
|
+
function isArgon2idConfig(config) {
|
|
49
|
+
return config.algorithm_name === "Argon2id";
|
|
50
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KDF Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* Encoding, decoding, and cryptographic utilities for KDF operations.
|
|
5
|
+
* Issue #1649
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Convert a base64 string to Uint8Array
|
|
9
|
+
*/
|
|
10
|
+
export declare function base64ToUint8Array(base64: string): Uint8Array;
|
|
11
|
+
/**
|
|
12
|
+
* Convert Uint8Array to base64 string
|
|
13
|
+
*/
|
|
14
|
+
export declare function uint8ArrayToBase64(bytes: Uint8Array): string;
|
|
15
|
+
/**
|
|
16
|
+
* XOR two byte arrays of equal length
|
|
17
|
+
*
|
|
18
|
+
* Used for combining password-derived key with LocalSecret in 2SKD.
|
|
19
|
+
* This follows the 1Password approach of XOR combination.
|
|
20
|
+
*
|
|
21
|
+
* @param a - First byte array
|
|
22
|
+
* @param b - Second byte array
|
|
23
|
+
* @returns XOR result
|
|
24
|
+
* @throws Error if arrays are not the same length
|
|
25
|
+
*/
|
|
26
|
+
export declare function xorBytes(a: Uint8Array, b: Uint8Array): Uint8Array;
|
|
27
|
+
/**
|
|
28
|
+
* Normalize password for key derivation
|
|
29
|
+
*
|
|
30
|
+
* Applies NFKD normalization and trims whitespace.
|
|
31
|
+
* This ensures consistent key derivation across platforms.
|
|
32
|
+
*
|
|
33
|
+
* @param password - Raw password input
|
|
34
|
+
* @returns Normalized password string
|
|
35
|
+
*/
|
|
36
|
+
export declare function normalizePassword(password: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Generate cryptographically secure random bytes
|
|
39
|
+
*
|
|
40
|
+
* @param length - Number of bytes to generate
|
|
41
|
+
* @returns Random bytes
|
|
42
|
+
*/
|
|
43
|
+
export declare function generateRandomBytes(length: number): Uint8Array;
|
|
44
|
+
/**
|
|
45
|
+
* Generate a random salt for key derivation
|
|
46
|
+
*
|
|
47
|
+
* @returns 16-byte random salt as base64 string
|
|
48
|
+
*/
|
|
49
|
+
export declare function generateSalt(): string;
|
|
50
|
+
/**
|
|
51
|
+
* Constant-time comparison of two byte arrays
|
|
52
|
+
*
|
|
53
|
+
* Prevents timing attacks when comparing secrets.
|
|
54
|
+
*
|
|
55
|
+
* @param a - First byte array
|
|
56
|
+
* @param b - Second byte array
|
|
57
|
+
* @returns true if arrays are equal
|
|
58
|
+
*/
|
|
59
|
+
export declare function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable fp/no-mutation, no-plusplus, no-bitwise, @typescript-eslint/prefer-for-of -- Low-level byte manipulation utilities */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.base64ToUint8Array = base64ToUint8Array;
|
|
5
|
+
exports.uint8ArrayToBase64 = uint8ArrayToBase64;
|
|
6
|
+
exports.xorBytes = xorBytes;
|
|
7
|
+
exports.normalizePassword = normalizePassword;
|
|
8
|
+
exports.generateRandomBytes = generateRandomBytes;
|
|
9
|
+
exports.generateSalt = generateSalt;
|
|
10
|
+
exports.constantTimeEqual = constantTimeEqual;
|
|
11
|
+
/**
|
|
12
|
+
* KDF Utility Functions
|
|
13
|
+
*
|
|
14
|
+
* Encoding, decoding, and cryptographic utilities for KDF operations.
|
|
15
|
+
* Issue #1649
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Convert a base64 string to Uint8Array
|
|
19
|
+
*/
|
|
20
|
+
function base64ToUint8Array(base64) {
|
|
21
|
+
const binaryString = atob(base64);
|
|
22
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
23
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
24
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
25
|
+
}
|
|
26
|
+
return bytes;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Convert Uint8Array to base64 string
|
|
30
|
+
*/
|
|
31
|
+
function uint8ArrayToBase64(bytes) {
|
|
32
|
+
let binaryString = "";
|
|
33
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
34
|
+
binaryString += String.fromCharCode(bytes[i]);
|
|
35
|
+
}
|
|
36
|
+
return btoa(binaryString);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* XOR two byte arrays of equal length
|
|
40
|
+
*
|
|
41
|
+
* Used for combining password-derived key with LocalSecret in 2SKD.
|
|
42
|
+
* This follows the 1Password approach of XOR combination.
|
|
43
|
+
*
|
|
44
|
+
* @param a - First byte array
|
|
45
|
+
* @param b - Second byte array
|
|
46
|
+
* @returns XOR result
|
|
47
|
+
* @throws Error if arrays are not the same length
|
|
48
|
+
*/
|
|
49
|
+
function xorBytes(a, b) {
|
|
50
|
+
if (a.length !== b.length) {
|
|
51
|
+
throw new Error(`XOR inputs must be same length (got ${a.length} and ${b.length})`);
|
|
52
|
+
}
|
|
53
|
+
const result = new Uint8Array(a.length);
|
|
54
|
+
for (let i = 0; i < a.length; i++) {
|
|
55
|
+
result[i] = a[i] ^ b[i];
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Normalize password for key derivation
|
|
61
|
+
*
|
|
62
|
+
* Applies NFKD normalization and trims whitespace.
|
|
63
|
+
* This ensures consistent key derivation across platforms.
|
|
64
|
+
*
|
|
65
|
+
* @param password - Raw password input
|
|
66
|
+
* @returns Normalized password string
|
|
67
|
+
*/
|
|
68
|
+
function normalizePassword(password) {
|
|
69
|
+
// Trim leading/trailing whitespace
|
|
70
|
+
const trimmed = password.trim();
|
|
71
|
+
// Apply NFKD normalization for Unicode consistency
|
|
72
|
+
return trimmed.normalize("NFKD");
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Generate cryptographically secure random bytes
|
|
76
|
+
*
|
|
77
|
+
* @param length - Number of bytes to generate
|
|
78
|
+
* @returns Random bytes
|
|
79
|
+
*/
|
|
80
|
+
function generateRandomBytes(length) {
|
|
81
|
+
return crypto.getRandomValues(new Uint8Array(length));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate a random salt for key derivation
|
|
85
|
+
*
|
|
86
|
+
* @returns 16-byte random salt as base64 string
|
|
87
|
+
*/
|
|
88
|
+
function generateSalt() {
|
|
89
|
+
const salt = generateRandomBytes(16);
|
|
90
|
+
return uint8ArrayToBase64(salt);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Constant-time comparison of two byte arrays
|
|
94
|
+
*
|
|
95
|
+
* Prevents timing attacks when comparing secrets.
|
|
96
|
+
*
|
|
97
|
+
* @param a - First byte array
|
|
98
|
+
* @param b - Second byte array
|
|
99
|
+
* @returns true if arrays are equal
|
|
100
|
+
*/
|
|
101
|
+
function constantTimeEqual(a, b) {
|
|
102
|
+
if (a.length !== b.length) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
let result = 0;
|
|
106
|
+
for (let i = 0; i < a.length; i++) {
|
|
107
|
+
result |= a[i] ^ b[i];
|
|
108
|
+
}
|
|
109
|
+
return result === 0;
|
|
110
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalSecret Formatter
|
|
3
|
+
*
|
|
4
|
+
* Formats LocalSecrets for human-readable display and parses them back.
|
|
5
|
+
* Uses an unambiguous character set (no 0, 1, I, O) for easy transcription.
|
|
6
|
+
*
|
|
7
|
+
* Format: A7K2M9-X4P8N3-B5J1L6-Q9W2R8-T3Y7U0-V6Z4C1-...
|
|
8
|
+
*
|
|
9
|
+
* Issue #1649
|
|
10
|
+
*/
|
|
11
|
+
import type { FormattedLocalSecret } from "./types";
|
|
12
|
+
/**
|
|
13
|
+
* Format a LocalSecret for human-readable display
|
|
14
|
+
*
|
|
15
|
+
* @param secret - The 32-byte LocalSecret
|
|
16
|
+
* @returns Formatted LocalSecret with grouped characters
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatLocalSecret(secret: Uint8Array): FormattedLocalSecret;
|
|
19
|
+
/**
|
|
20
|
+
* Parse a formatted LocalSecret back to bytes
|
|
21
|
+
*
|
|
22
|
+
* Handles various input formats:
|
|
23
|
+
* - With dashes: A7K2M9-X4P8N3-...
|
|
24
|
+
* - Without dashes: A7K2M9X4P8N3...
|
|
25
|
+
* - With spaces: A7K2M9 X4P8N3 ...
|
|
26
|
+
* - Lowercase: a7k2m9-x4p8n3-...
|
|
27
|
+
*
|
|
28
|
+
* @param formatted - The formatted LocalSecret string
|
|
29
|
+
* @returns The 32-byte LocalSecret
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseLocalSecret(formatted: string): Uint8Array;
|
|
32
|
+
/**
|
|
33
|
+
* Validate a formatted LocalSecret string
|
|
34
|
+
*
|
|
35
|
+
* @param formatted - The formatted LocalSecret string
|
|
36
|
+
* @returns true if valid, false otherwise
|
|
37
|
+
*/
|
|
38
|
+
export declare function isValidFormattedLocalSecret(formatted: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Mask a LocalSecret for partial display
|
|
41
|
+
*
|
|
42
|
+
* Shows only the first and last groups, masking the middle.
|
|
43
|
+
* Example: A7K2M9-******-******-******-******-V6Z4C1
|
|
44
|
+
*
|
|
45
|
+
* @param formatted - The formatted LocalSecret
|
|
46
|
+
* @returns Masked version for display
|
|
47
|
+
*/
|
|
48
|
+
export declare function maskLocalSecret(formatted: string): string;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LocalSecret Formatter
|
|
4
|
+
*
|
|
5
|
+
* Formats LocalSecrets for human-readable display and parses them back.
|
|
6
|
+
* Uses an unambiguous character set (no 0, 1, I, O) for easy transcription.
|
|
7
|
+
*
|
|
8
|
+
* Format: A7K2M9-X4P8N3-B5J1L6-Q9W2R8-T3Y7U0-V6Z4C1-...
|
|
9
|
+
*
|
|
10
|
+
* Issue #1649
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.formatLocalSecret = formatLocalSecret;
|
|
14
|
+
exports.parseLocalSecret = parseLocalSecret;
|
|
15
|
+
exports.isValidFormattedLocalSecret = isValidFormattedLocalSecret;
|
|
16
|
+
exports.maskLocalSecret = maskLocalSecret;
|
|
17
|
+
const types_1 = require("./types");
|
|
18
|
+
/**
|
|
19
|
+
* Encode bytes to the LocalSecret character set
|
|
20
|
+
*
|
|
21
|
+
* Uses base32-like encoding with our custom character set.
|
|
22
|
+
* Note: This function uses mutation for performance in BigInt arithmetic.
|
|
23
|
+
*/
|
|
24
|
+
function encodeToCharset(bytes) {
|
|
25
|
+
const charset = types_1.LOCAL_SECRET_CHARSET;
|
|
26
|
+
const base = BigInt(charset.length); // 32
|
|
27
|
+
// Convert bytes to a big integer using reduce (functional approach)
|
|
28
|
+
const value = bytes.reduce(
|
|
29
|
+
// eslint-disable-next-line no-bitwise -- Required for byte-to-BigInt conversion
|
|
30
|
+
(acc, byte) => (acc << BigInt(8)) | BigInt(byte), BigInt(0));
|
|
31
|
+
// Convert to base-32 string using recursive approach
|
|
32
|
+
const toChars = (v, acc) => {
|
|
33
|
+
if (v <= BigInt(0))
|
|
34
|
+
return acc;
|
|
35
|
+
const remainder = Number(v % base);
|
|
36
|
+
return toChars(v / base, [charset[remainder], ...acc]);
|
|
37
|
+
};
|
|
38
|
+
const chars = toChars(value, []);
|
|
39
|
+
// Pad to consistent length (ceil(256 bits / 5 bits per char) = 52 chars)
|
|
40
|
+
const expectedLength = Math.ceil((types_1.LOCAL_SECRET_SIZE * 8) / 5);
|
|
41
|
+
const padding = Array.from({
|
|
42
|
+
length: Math.max(0, expectedLength - chars.length),
|
|
43
|
+
}).fill(charset[0]);
|
|
44
|
+
return [...padding, ...chars].join("");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Decode a string from the LocalSecret character set to bytes
|
|
48
|
+
* Note: This function uses mutation for performance in BigInt arithmetic.
|
|
49
|
+
*/
|
|
50
|
+
function decodeFromCharset(encoded) {
|
|
51
|
+
const charset = types_1.LOCAL_SECRET_CHARSET;
|
|
52
|
+
const base = BigInt(charset.length); // 32
|
|
53
|
+
// Convert string to big integer using reduce (functional approach)
|
|
54
|
+
const value = [...encoded.toUpperCase()].reduce((acc, char) => {
|
|
55
|
+
const index = charset.indexOf(char);
|
|
56
|
+
if (index === -1) {
|
|
57
|
+
throw new Error(`Invalid character in LocalSecret: ${char}`);
|
|
58
|
+
}
|
|
59
|
+
return acc * base + BigInt(index);
|
|
60
|
+
}, BigInt(0));
|
|
61
|
+
// Convert big integer to bytes using recursive approach
|
|
62
|
+
const toBytes = (v, count, acc) => {
|
|
63
|
+
if (count <= 0)
|
|
64
|
+
return acc;
|
|
65
|
+
/* eslint-disable no-bitwise -- Required for BigInt-to-byte conversion */
|
|
66
|
+
return toBytes(v >> BigInt(8), count - 1, [
|
|
67
|
+
Number(v & BigInt(0xff)),
|
|
68
|
+
...acc,
|
|
69
|
+
]);
|
|
70
|
+
/* eslint-enable no-bitwise */
|
|
71
|
+
};
|
|
72
|
+
return new Uint8Array(toBytes(value, types_1.LOCAL_SECRET_SIZE, []));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Format a LocalSecret for human-readable display
|
|
76
|
+
*
|
|
77
|
+
* @param secret - The 32-byte LocalSecret
|
|
78
|
+
* @returns Formatted LocalSecret with grouped characters
|
|
79
|
+
*/
|
|
80
|
+
function formatLocalSecret(secret) {
|
|
81
|
+
if (secret.length !== types_1.LOCAL_SECRET_SIZE) {
|
|
82
|
+
throw new Error(`LocalSecret must be ${types_1.LOCAL_SECRET_SIZE} bytes (got ${secret.length})`);
|
|
83
|
+
}
|
|
84
|
+
const encoded = encodeToCharset(secret);
|
|
85
|
+
// Split into groups using functional approach
|
|
86
|
+
const numGroups = Math.ceil(encoded.length / types_1.LOCAL_SECRET_GROUP_SIZE);
|
|
87
|
+
const groups = Array.from({ length: numGroups }, (_, i) => encoded.slice(i * types_1.LOCAL_SECRET_GROUP_SIZE, (i + 1) * types_1.LOCAL_SECRET_GROUP_SIZE));
|
|
88
|
+
return {
|
|
89
|
+
formatted: groups.join("-"),
|
|
90
|
+
groups,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Parse a formatted LocalSecret back to bytes
|
|
95
|
+
*
|
|
96
|
+
* Handles various input formats:
|
|
97
|
+
* - With dashes: A7K2M9-X4P8N3-...
|
|
98
|
+
* - Without dashes: A7K2M9X4P8N3...
|
|
99
|
+
* - With spaces: A7K2M9 X4P8N3 ...
|
|
100
|
+
* - Lowercase: a7k2m9-x4p8n3-...
|
|
101
|
+
*
|
|
102
|
+
* @param formatted - The formatted LocalSecret string
|
|
103
|
+
* @returns The 32-byte LocalSecret
|
|
104
|
+
*/
|
|
105
|
+
function parseLocalSecret(formatted) {
|
|
106
|
+
// Remove dashes, spaces, and convert to uppercase
|
|
107
|
+
const cleaned = formatted.replace(/[-\s]/g, "").toUpperCase();
|
|
108
|
+
// Validate characters
|
|
109
|
+
for (const char of cleaned) {
|
|
110
|
+
if (!types_1.LOCAL_SECRET_CHARSET.includes(char)) {
|
|
111
|
+
throw new Error(`Invalid character in LocalSecret: ${char}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Expected length after encoding
|
|
115
|
+
const expectedLength = Math.ceil((types_1.LOCAL_SECRET_SIZE * 8) / 5);
|
|
116
|
+
if (cleaned.length !== expectedLength) {
|
|
117
|
+
throw new Error(`Invalid LocalSecret length: expected ${expectedLength} characters, got ${cleaned.length}`);
|
|
118
|
+
}
|
|
119
|
+
return decodeFromCharset(cleaned);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Validate a formatted LocalSecret string
|
|
123
|
+
*
|
|
124
|
+
* @param formatted - The formatted LocalSecret string
|
|
125
|
+
* @returns true if valid, false otherwise
|
|
126
|
+
*/
|
|
127
|
+
function isValidFormattedLocalSecret(formatted) {
|
|
128
|
+
try {
|
|
129
|
+
parseLocalSecret(formatted);
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
catch (_a) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Mask a LocalSecret for partial display
|
|
138
|
+
*
|
|
139
|
+
* Shows only the first and last groups, masking the middle.
|
|
140
|
+
* Example: A7K2M9-******-******-******-******-V6Z4C1
|
|
141
|
+
*
|
|
142
|
+
* @param formatted - The formatted LocalSecret
|
|
143
|
+
* @returns Masked version for display
|
|
144
|
+
*/
|
|
145
|
+
function maskLocalSecret(formatted) {
|
|
146
|
+
const groups = formatted.split("-");
|
|
147
|
+
if (groups.length <= 2) {
|
|
148
|
+
return formatted;
|
|
149
|
+
}
|
|
150
|
+
const masked = groups.map((group, index) => {
|
|
151
|
+
if (index === 0 || index === groups.length - 1) {
|
|
152
|
+
return group;
|
|
153
|
+
}
|
|
154
|
+
return "*".repeat(group.length);
|
|
155
|
+
});
|
|
156
|
+
return masked.join("-");
|
|
157
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalSecret Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates cryptographically secure LocalSecrets.
|
|
5
|
+
* Issue #1649
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Generate a new LocalSecret
|
|
9
|
+
*
|
|
10
|
+
* Uses the Web Crypto API's getRandomValues for cryptographically
|
|
11
|
+
* secure random number generation.
|
|
12
|
+
*
|
|
13
|
+
* @returns 32-byte (256-bit) random LocalSecret
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateLocalSecret(): Uint8Array;
|
|
16
|
+
/**
|
|
17
|
+
* Generate a unique device ID
|
|
18
|
+
*
|
|
19
|
+
* Used to identify devices for LocalSecret management.
|
|
20
|
+
*
|
|
21
|
+
* @returns UUID v4 string
|
|
22
|
+
*/
|
|
23
|
+
export declare function generateDeviceId(): string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LocalSecret Generator
|
|
4
|
+
*
|
|
5
|
+
* Generates cryptographically secure LocalSecrets.
|
|
6
|
+
* Issue #1649
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.generateLocalSecret = generateLocalSecret;
|
|
10
|
+
exports.generateDeviceId = generateDeviceId;
|
|
11
|
+
const types_1 = require("./types");
|
|
12
|
+
/**
|
|
13
|
+
* Generate a new LocalSecret
|
|
14
|
+
*
|
|
15
|
+
* Uses the Web Crypto API's getRandomValues for cryptographically
|
|
16
|
+
* secure random number generation.
|
|
17
|
+
*
|
|
18
|
+
* @returns 32-byte (256-bit) random LocalSecret
|
|
19
|
+
*/
|
|
20
|
+
function generateLocalSecret() {
|
|
21
|
+
return crypto.getRandomValues(new Uint8Array(types_1.LOCAL_SECRET_SIZE));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate a unique device ID
|
|
25
|
+
*
|
|
26
|
+
* Used to identify devices for LocalSecret management.
|
|
27
|
+
*
|
|
28
|
+
* @returns UUID v4 string
|
|
29
|
+
*/
|
|
30
|
+
function generateDeviceId() {
|
|
31
|
+
// Use crypto.randomUUID if available (modern browsers)
|
|
32
|
+
if (typeof crypto.randomUUID === "function") {
|
|
33
|
+
return crypto.randomUUID();
|
|
34
|
+
}
|
|
35
|
+
// Fallback for older browsers
|
|
36
|
+
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
37
|
+
// Set version (4) and variant (8, 9, A, or B)
|
|
38
|
+
// eslint-disable-next-line no-bitwise, fp/no-mutation -- UUID v4 specification requires bitwise operations
|
|
39
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
40
|
+
// eslint-disable-next-line no-bitwise, fp/no-mutation -- UUID v4 specification requires bitwise operations
|
|
41
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
42
|
+
// Convert to hex string with dashes
|
|
43
|
+
const hex = Array.from(bytes)
|
|
44
|
+
.map(b => b.toString(16).padStart(2, "0"))
|
|
45
|
+
.join("");
|
|
46
|
+
return [
|
|
47
|
+
hex.slice(0, 8),
|
|
48
|
+
hex.slice(8, 12),
|
|
49
|
+
hex.slice(12, 16),
|
|
50
|
+
hex.slice(16, 20),
|
|
51
|
+
hex.slice(20, 32),
|
|
52
|
+
].join("-");
|
|
53
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalSecret Module
|
|
3
|
+
*
|
|
4
|
+
* Provides generation, formatting, storage, and management of
|
|
5
|
+
* device-bound LocalSecrets for Two-Secret Key Derivation (2SKD).
|
|
6
|
+
*
|
|
7
|
+
* Issue #1649
|
|
8
|
+
*/
|
|
9
|
+
export * from "./types";
|
|
10
|
+
export { generateLocalSecret, generateDeviceId } from "./generator";
|
|
11
|
+
export { formatLocalSecret, parseLocalSecret, isValidFormattedLocalSecret, maskLocalSecret, } from "./format";
|
|
12
|
+
export { storeLocalSecret, getLocalSecret, deleteLocalSecret, hasLocalSecret, getLocalSecretRecord, getOrCreateDeviceId, createIndexedDBStorage, } from "./storage";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LocalSecret Module
|
|
4
|
+
*
|
|
5
|
+
* Provides generation, formatting, storage, and management of
|
|
6
|
+
* device-bound LocalSecrets for Two-Secret Key Derivation (2SKD).
|
|
7
|
+
*
|
|
8
|
+
* Issue #1649
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
22
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.createIndexedDBStorage = exports.getOrCreateDeviceId = exports.getLocalSecretRecord = exports.hasLocalSecret = exports.deleteLocalSecret = exports.getLocalSecret = exports.storeLocalSecret = exports.maskLocalSecret = exports.isValidFormattedLocalSecret = exports.parseLocalSecret = exports.formatLocalSecret = exports.generateDeviceId = exports.generateLocalSecret = void 0;
|
|
26
|
+
// Re-export types
|
|
27
|
+
__exportStar(require("./types"), exports);
|
|
28
|
+
// Re-export generator
|
|
29
|
+
var generator_1 = require("./generator");
|
|
30
|
+
Object.defineProperty(exports, "generateLocalSecret", { enumerable: true, get: function () { return generator_1.generateLocalSecret; } });
|
|
31
|
+
Object.defineProperty(exports, "generateDeviceId", { enumerable: true, get: function () { return generator_1.generateDeviceId; } });
|
|
32
|
+
// Re-export formatter
|
|
33
|
+
var format_1 = require("./format");
|
|
34
|
+
Object.defineProperty(exports, "formatLocalSecret", { enumerable: true, get: function () { return format_1.formatLocalSecret; } });
|
|
35
|
+
Object.defineProperty(exports, "parseLocalSecret", { enumerable: true, get: function () { return format_1.parseLocalSecret; } });
|
|
36
|
+
Object.defineProperty(exports, "isValidFormattedLocalSecret", { enumerable: true, get: function () { return format_1.isValidFormattedLocalSecret; } });
|
|
37
|
+
Object.defineProperty(exports, "maskLocalSecret", { enumerable: true, get: function () { return format_1.maskLocalSecret; } });
|
|
38
|
+
// Re-export storage
|
|
39
|
+
var storage_1 = require("./storage");
|
|
40
|
+
Object.defineProperty(exports, "storeLocalSecret", { enumerable: true, get: function () { return storage_1.storeLocalSecret; } });
|
|
41
|
+
Object.defineProperty(exports, "getLocalSecret", { enumerable: true, get: function () { return storage_1.getLocalSecret; } });
|
|
42
|
+
Object.defineProperty(exports, "deleteLocalSecret", { enumerable: true, get: function () { return storage_1.deleteLocalSecret; } });
|
|
43
|
+
Object.defineProperty(exports, "hasLocalSecret", { enumerable: true, get: function () { return storage_1.hasLocalSecret; } });
|
|
44
|
+
Object.defineProperty(exports, "getLocalSecretRecord", { enumerable: true, get: function () { return storage_1.getLocalSecretRecord; } });
|
|
45
|
+
Object.defineProperty(exports, "getOrCreateDeviceId", { enumerable: true, get: function () { return storage_1.getOrCreateDeviceId; } });
|
|
46
|
+
Object.defineProperty(exports, "createIndexedDBStorage", { enumerable: true, get: function () { return storage_1.createIndexedDBStorage; } });
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalSecret Storage
|
|
3
|
+
*
|
|
4
|
+
* IndexedDB-based storage for LocalSecrets.
|
|
5
|
+
* The LocalSecret is stored locally on the device and never sent to servers.
|
|
6
|
+
*
|
|
7
|
+
* Issue #1649
|
|
8
|
+
*/
|
|
9
|
+
import type { LocalSecretStorage, StoredLocalSecret } from "./types";
|
|
10
|
+
/**
|
|
11
|
+
* Get or create a unique device ID
|
|
12
|
+
*
|
|
13
|
+
* The device ID is stored in localStorage for persistence.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getOrCreateDeviceId(): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Store a LocalSecret in IndexedDB
|
|
18
|
+
*
|
|
19
|
+
* @param userId - User's Cognito sub
|
|
20
|
+
* @param secret - The 32-byte LocalSecret
|
|
21
|
+
*/
|
|
22
|
+
export declare function storeLocalSecret(userId: string, secret: Uint8Array): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Retrieve a LocalSecret from IndexedDB
|
|
25
|
+
*
|
|
26
|
+
* @param userId - User's Cognito sub
|
|
27
|
+
* @returns The LocalSecret or null if not found
|
|
28
|
+
*/
|
|
29
|
+
export declare function getLocalSecret(userId: string): Promise<Uint8Array | null>;
|
|
30
|
+
/**
|
|
31
|
+
* Delete a LocalSecret from IndexedDB
|
|
32
|
+
*
|
|
33
|
+
* @param userId - User's Cognito sub
|
|
34
|
+
*/
|
|
35
|
+
export declare function deleteLocalSecret(userId: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Check if a LocalSecret exists for a user
|
|
38
|
+
*
|
|
39
|
+
* @param userId - User's Cognito sub
|
|
40
|
+
* @returns true if a LocalSecret exists
|
|
41
|
+
*/
|
|
42
|
+
export declare function hasLocalSecret(userId: string): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Get the stored LocalSecret record (including metadata)
|
|
45
|
+
*
|
|
46
|
+
* @param userId - User's Cognito sub
|
|
47
|
+
* @returns The full storage record or null
|
|
48
|
+
*/
|
|
49
|
+
export declare function getLocalSecretRecord(userId: string): Promise<StoredLocalSecret | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Create a LocalSecretStorage implementation using IndexedDB
|
|
52
|
+
*/
|
|
53
|
+
export declare function createIndexedDBStorage(): LocalSecretStorage;
|