@puzzle-ui/auth 0.0.0-stage → 0.5.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 +301 -2
- package/dist/LICENSE +21 -0
- package/dist/auth.lifecycle.manager.cjs +835 -0
- package/dist/auth.lifecycle.manager.cjs.map +1 -0
- package/dist/auth.lifecycle.manager.d.cts +115 -0
- package/dist/auth.lifecycle.manager.d.ts +115 -0
- package/dist/auth.lifecycle.manager.js +835 -0
- package/dist/auth.lifecycle.manager.js.map +1 -0
- package/dist/auth.manager.cjs +454 -0
- package/dist/auth.manager.cjs.map +1 -0
- package/dist/auth.manager.d.cts +54 -0
- package/dist/auth.manager.d.ts +54 -0
- package/dist/auth.manager.js +454 -0
- package/dist/auth.manager.js.map +1 -0
- package/dist/auth.mfa.manager.cjs +1488 -0
- package/dist/auth.mfa.manager.cjs.map +1 -0
- package/dist/auth.mfa.manager.d.cts +100 -0
- package/dist/auth.mfa.manager.d.ts +100 -0
- package/dist/auth.mfa.manager.js +1488 -0
- package/dist/auth.mfa.manager.js.map +1 -0
- package/dist/auth.rate-limit.cjs +78 -0
- package/dist/auth.rate-limit.cjs.map +1 -0
- package/dist/auth.rate-limit.d.cts +24 -0
- package/dist/auth.rate-limit.d.ts +24 -0
- package/dist/auth.rate-limit.js +78 -0
- package/dist/auth.rate-limit.js.map +1 -0
- package/dist/auth.step-up.manager.cjs +269 -0
- package/dist/auth.step-up.manager.cjs.map +1 -0
- package/dist/auth.step-up.manager.d.cts +74 -0
- package/dist/auth.step-up.manager.d.ts +74 -0
- package/dist/auth.step-up.manager.js +268 -0
- package/dist/auth.step-up.manager.js.map +1 -0
- package/dist/auth.storage.cjs +164 -0
- package/dist/auth.storage.cjs.map +1 -0
- package/dist/auth.storage.d.cts +29 -0
- package/dist/auth.storage.d.ts +29 -0
- package/dist/auth.storage.js +148 -0
- package/dist/auth.storage.js.map +1 -0
- package/dist/errors/auth.errors.cjs +101 -0
- package/dist/errors/auth.errors.cjs.map +1 -0
- package/dist/errors/auth.errors.d.cts +62 -0
- package/dist/errors/auth.errors.d.ts +62 -0
- package/dist/errors/auth.errors.js +90 -0
- package/dist/errors/auth.errors.js.map +1 -0
- package/dist/index.cjs +54 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +13 -0
- package/dist/providers/mfa-provider.types.d.cts +66 -0
- package/dist/providers/mfa-provider.types.d.ts +66 -0
- package/dist/providers/provider.types.d.cts +34 -0
- package/dist/providers/provider.types.d.ts +34 -0
- package/dist/providers/simplewebauthn-provider.cjs +185 -0
- package/dist/providers/simplewebauthn-provider.cjs.map +1 -0
- package/dist/providers/simplewebauthn-provider.d.cts +35 -0
- package/dist/providers/simplewebauthn-provider.d.ts +35 -0
- package/dist/providers/simplewebauthn-provider.js +185 -0
- package/dist/providers/simplewebauthn-provider.js.map +1 -0
- package/dist/providers/webcrypto-secret-protector.cjs +118 -0
- package/dist/providers/webcrypto-secret-protector.cjs.map +1 -0
- package/dist/providers/webcrypto-secret-protector.d.cts +14 -0
- package/dist/providers/webcrypto-secret-protector.d.ts +14 -0
- package/dist/providers/webcrypto-secret-protector.js +118 -0
- package/dist/providers/webcrypto-secret-protector.js.map +1 -0
- package/dist/types/auth-lifecycle.types.d.cts +53 -0
- package/dist/types/auth-lifecycle.types.d.ts +53 -0
- package/dist/types/auth-manager.types.d.cts +106 -0
- package/dist/types/auth-manager.types.d.ts +106 -0
- package/dist/types/credential.types.d.cts +9 -0
- package/dist/types/credential.types.d.ts +9 -0
- package/dist/types/mfa.types.d.cts +244 -0
- package/dist/types/mfa.types.d.ts +244 -0
- package/dist/types/state.types.d.cts +33 -0
- package/dist/types/state.types.d.ts +33 -0
- package/dist/types/user.types.d.cts +9 -0
- package/dist/types/user.types.d.ts +9 -0
- package/dist/utils/auth-crypto.utils.cjs +38 -0
- package/dist/utils/auth-crypto.utils.cjs.map +1 -0
- package/dist/utils/auth-crypto.utils.d.cts +4 -0
- package/dist/utils/auth-crypto.utils.d.ts +4 -0
- package/dist/utils/auth-crypto.utils.js +35 -0
- package/dist/utils/auth-crypto.utils.js.map +1 -0
- package/dist/utils/email.utils.cjs +20 -0
- package/dist/utils/email.utils.cjs.map +1 -0
- package/dist/utils/email.utils.d.cts +2 -0
- package/dist/utils/email.utils.d.ts +2 -0
- package/dist/utils/email.utils.js +19 -0
- package/dist/utils/email.utils.js.map +1 -0
- package/dist/utils/totp.utils.cjs +145 -0
- package/dist/utils/totp.utils.cjs.map +1 -0
- package/dist/utils/totp.utils.d.cts +26 -0
- package/dist/utils/totp.utils.d.ts +26 -0
- package/dist/utils/totp.utils.js +140 -0
- package/dist/utils/totp.utils.js.map +1 -0
- package/package.json +45 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"totp.utils.cjs","names":["AuthConfigurationError","AuthValidationError"],"sources":["../../src/utils/totp.utils.ts"],"sourcesContent":["import {\n AuthConfigurationError,\n AuthValidationError,\n} from \"../errors/auth.errors\";\n\nconst BASE32_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\";\n\ntype TotpOptions = {\n readonly digits: number;\n readonly periodSeconds: number;\n};\n\ntype TotpVerificationOptions = TotpOptions & {\n readonly window: number;\n};\n\nconst getCrypto = (): Crypto => {\n const cryptoApi = globalThis.crypto;\n\n if (!cryptoApi?.getRandomValues || !cryptoApi.subtle) {\n throw new AuthConfigurationError(\n \"This runtime does not provide the required Web Crypto APIs.\",\n );\n }\n\n return cryptoApi;\n};\n\nconst validateTotpOptions = (options: TotpOptions): void => {\n if (\n !Number.isInteger(options.digits) ||\n options.digits < 6 ||\n options.digits > 8\n ) {\n throw new AuthValidationError(\"TOTP digits must be between 6 and 8.\");\n }\n\n if (\n !Number.isInteger(options.periodSeconds) ||\n options.periodSeconds < 15 ||\n options.periodSeconds > 120\n ) {\n throw new AuthValidationError(\n \"The TOTP period must be between 15 and 120 seconds.\",\n );\n }\n};\n\nconst getTimeStep = (timestamp: number, periodSeconds: number): number => {\n if (!Number.isFinite(timestamp) || timestamp < 0) {\n throw new AuthValidationError(\"A valid TOTP timestamp is required.\");\n }\n\n const step = Math.floor(timestamp / 1000 / periodSeconds);\n\n if (!Number.isSafeInteger(step)) {\n throw new AuthValidationError(\"The TOTP timestamp is out of range.\");\n }\n\n return step;\n};\n\n/**\n * Copies bytes into an ArrayBuffer.\n *\n * Web Crypto APIs accept BufferSource values backed by ArrayBuffer.\n * This avoids ArrayBufferLike incompatibilities with newer TypeScript\n * typed-array definitions.\n */\nconst toArrayBuffer = (bytes: Uint8Array): ArrayBuffer => {\n const buffer = new ArrayBuffer(bytes.byteLength);\n const target = new Uint8Array(buffer);\n\n for (let index = 0; index < bytes.length; index++) {\n target[index] = bytes[index]!;\n }\n\n return buffer;\n};\n\nconst constantTimeEqual = (left: string, right: string): boolean => {\n if (left.length !== right.length) {\n return false;\n }\n\n let difference = 0;\n\n for (let index = 0; index < left.length; index++) {\n difference |= left.charCodeAt(index) ^ right.charCodeAt(index);\n }\n\n return difference === 0;\n};\n\nexport const encodeBase32 = (input: Uint8Array): string => {\n let output = \"\";\n let buffer = 0;\n let bits = 0;\n\n for (const byte of input) {\n buffer = (buffer << 8) | byte;\n bits += 8;\n\n while (bits >= 5) {\n bits -= 5;\n output += BASE32_ALPHABET.charAt((buffer >>> bits) & 31);\n }\n }\n\n if (bits > 0) {\n output += BASE32_ALPHABET.charAt((buffer << (5 - bits)) & 31);\n }\n\n return output;\n};\n\nexport const decodeBase32 = (input: string): Uint8Array => {\n if (typeof input !== \"string\" || input.length === 0) {\n throw new AuthValidationError(\"A valid TOTP secret is required.\");\n }\n\n const normalized = input.toUpperCase().replace(/[\\s=-]/g, \"\");\n\n if (normalized.length === 0) {\n throw new AuthValidationError(\"The TOTP secret is invalid.\");\n }\n\n const output: number[] = [];\n let buffer = 0;\n let bits = 0;\n\n for (const character of normalized) {\n const value = BASE32_ALPHABET.indexOf(character);\n\n if (value < 0) {\n throw new AuthValidationError(\"The TOTP secret is invalid.\");\n }\n\n buffer = (buffer << 5) | value;\n bits += 5;\n\n if (bits >= 8) {\n bits -= 8;\n output.push((buffer >>> bits) & 255);\n }\n }\n\n // Remaining bits are padding bits and must be zero.\n if (bits > 0 && (buffer & ((1 << bits) - 1)) !== 0) {\n throw new AuthValidationError(\"The TOTP secret is invalid.\");\n }\n\n if (output.length === 0) {\n throw new AuthValidationError(\"The TOTP secret is invalid.\");\n }\n\n return new Uint8Array(output);\n};\n\nexport const generateTotpSecret = (): string => {\n const bytes = new Uint8Array(20);\n\n getCrypto().getRandomValues(bytes);\n\n return encodeBase32(bytes);\n};\n\nexport const generateTotpCode = async (\n secret: string,\n timestamp: number,\n options: TotpOptions,\n): Promise<string> => {\n validateTotpOptions(options);\n\n const counter = BigInt(getTimeStep(timestamp, options.periodSeconds));\n\n const counterBuffer = new ArrayBuffer(8);\n const counterView = new DataView(counterBuffer);\n\n let remaining = counter;\n\n for (let index = 7; index >= 0; index--) {\n counterView.setUint8(index, Number(remaining & 255n));\n remaining >>= 8n;\n }\n\n const cryptoApi = getCrypto();\n const secretBytes = decodeBase32(secret);\n\n const key = await cryptoApi.subtle.importKey(\n \"raw\",\n toArrayBuffer(secretBytes),\n {\n name: \"HMAC\",\n hash: \"SHA-1\",\n },\n false,\n [\"sign\"],\n );\n\n const signature = await cryptoApi.subtle.sign(\"HMAC\", key, counterBuffer);\n\n const hash = new Uint8Array(signature);\n\n if (hash.length < 20) {\n throw new AuthConfigurationError(\n \"The runtime returned an invalid HMAC signature.\",\n );\n }\n\n const offset = hash[hash.length - 1]! & 0x0f;\n\n const binary =\n ((hash[offset]! & 0x7f) << 24) |\n (hash[offset + 1]! << 16) |\n (hash[offset + 2]! << 8) |\n hash[offset + 3]!;\n\n const modulus = 10 ** options.digits;\n const value = (binary >>> 0) % modulus;\n\n return String(value).padStart(options.digits, \"0\");\n};\n\n/**\n * Returns the matching time step, or null.\n *\n * The caller must persist the accepted step and reject a step that\n * has already been consumed.\n */\nexport const verifyTotpCode = async (\n secret: string,\n code: string,\n timestamp: number,\n options: TotpVerificationOptions,\n): Promise<number | null> => {\n validateTotpOptions(options);\n\n if (\n !Number.isInteger(options.window) ||\n options.window < 0 ||\n options.window > 2\n ) {\n throw new AuthValidationError(\n \"The TOTP validation window must be between 0 and 2.\",\n );\n }\n\n if (\n typeof code !== \"string\" ||\n !new RegExp(`^\\\\d{${options.digits}}$`).test(code)\n ) {\n return null;\n }\n\n const currentStep = getTimeStep(timestamp, options.periodSeconds);\n\n let matchedStep: number | null = null;\n\n for (\n let step = currentStep - options.window;\n step <= currentStep + options.window;\n step++\n ) {\n if (step < 0) {\n continue;\n }\n\n const expected = await generateTotpCode(\n secret,\n step * options.periodSeconds * 1000,\n options,\n );\n\n if (constantTimeEqual(expected, code)) {\n matchedStep = step;\n }\n }\n\n return matchedStep;\n};\n\nexport const createTotpUri = (input: {\n readonly issuer: string;\n readonly account: string;\n readonly secret: string;\n readonly digits: number;\n readonly periodSeconds: number;\n}): string => {\n validateTotpOptions({\n digits: input.digits,\n periodSeconds: input.periodSeconds,\n });\n\n if (\n typeof input.issuer !== \"string\" ||\n input.issuer.trim().length === 0 ||\n typeof input.account !== \"string\" ||\n input.account.trim().length === 0\n ) {\n throw new AuthValidationError(\n \"A TOTP issuer and account name are required.\",\n );\n }\n\n // Validate the secret before exposing it in a provisioning URI.\n decodeBase32(input.secret);\n\n const label = encodeURIComponent(\n `${input.issuer.trim()}:${input.account.trim()}`,\n );\n\n const parameters = new URLSearchParams({\n secret: input.secret,\n issuer: input.issuer.trim(),\n algorithm: \"SHA1\",\n digits: String(input.digits),\n period: String(input.periodSeconds),\n });\n\n return `otpauth://totp/${label}?${parameters.toString()}`;\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type TotpOptions = {
|
|
2
|
+
readonly digits: number;
|
|
3
|
+
readonly periodSeconds: number;
|
|
4
|
+
};
|
|
5
|
+
type TotpVerificationOptions = TotpOptions & {
|
|
6
|
+
readonly window: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const encodeBase32: (input: Uint8Array) => string;
|
|
9
|
+
export declare const decodeBase32: (input: string) => Uint8Array;
|
|
10
|
+
export declare const generateTotpSecret: () => string;
|
|
11
|
+
export declare const generateTotpCode: (secret: string, timestamp: number, options: TotpOptions) => Promise<string>;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the matching time step, or null.
|
|
14
|
+
*
|
|
15
|
+
* The caller must persist the accepted step and reject a step that
|
|
16
|
+
* has already been consumed.
|
|
17
|
+
*/
|
|
18
|
+
export declare const verifyTotpCode: (secret: string, code: string, timestamp: number, options: TotpVerificationOptions) => Promise<number | null>;
|
|
19
|
+
export declare const createTotpUri: (input: {
|
|
20
|
+
readonly issuer: string;
|
|
21
|
+
readonly account: string;
|
|
22
|
+
readonly secret: string;
|
|
23
|
+
readonly digits: number;
|
|
24
|
+
readonly periodSeconds: number;
|
|
25
|
+
}) => string;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type TotpOptions = {
|
|
2
|
+
readonly digits: number;
|
|
3
|
+
readonly periodSeconds: number;
|
|
4
|
+
};
|
|
5
|
+
type TotpVerificationOptions = TotpOptions & {
|
|
6
|
+
readonly window: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const encodeBase32: (input: Uint8Array) => string;
|
|
9
|
+
export declare const decodeBase32: (input: string) => Uint8Array;
|
|
10
|
+
export declare const generateTotpSecret: () => string;
|
|
11
|
+
export declare const generateTotpCode: (secret: string, timestamp: number, options: TotpOptions) => Promise<string>;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the matching time step, or null.
|
|
14
|
+
*
|
|
15
|
+
* The caller must persist the accepted step and reject a step that
|
|
16
|
+
* has already been consumed.
|
|
17
|
+
*/
|
|
18
|
+
export declare const verifyTotpCode: (secret: string, code: string, timestamp: number, options: TotpVerificationOptions) => Promise<number | null>;
|
|
19
|
+
export declare const createTotpUri: (input: {
|
|
20
|
+
readonly issuer: string;
|
|
21
|
+
readonly account: string;
|
|
22
|
+
readonly secret: string;
|
|
23
|
+
readonly digits: number;
|
|
24
|
+
readonly periodSeconds: number;
|
|
25
|
+
}) => string;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { AuthConfigurationError, AuthValidationError } from "../errors/auth.errors.js";
|
|
2
|
+
// src/utils/totp.utils.ts
|
|
3
|
+
const BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
4
|
+
const getCrypto = () => {
|
|
5
|
+
const cryptoApi = globalThis.crypto;
|
|
6
|
+
if (!cryptoApi?.getRandomValues || !cryptoApi.subtle) throw new AuthConfigurationError("This runtime does not provide the required Web Crypto APIs.");
|
|
7
|
+
return cryptoApi;
|
|
8
|
+
};
|
|
9
|
+
const validateTotpOptions = (options) => {
|
|
10
|
+
if (!Number.isInteger(options.digits) || options.digits < 6 || options.digits > 8) throw new AuthValidationError("TOTP digits must be between 6 and 8.");
|
|
11
|
+
if (!Number.isInteger(options.periodSeconds) || options.periodSeconds < 15 || options.periodSeconds > 120) throw new AuthValidationError("The TOTP period must be between 15 and 120 seconds.");
|
|
12
|
+
};
|
|
13
|
+
const getTimeStep = (timestamp, periodSeconds) => {
|
|
14
|
+
if (!Number.isFinite(timestamp) || timestamp < 0) throw new AuthValidationError("A valid TOTP timestamp is required.");
|
|
15
|
+
const step = Math.floor(timestamp / 1e3 / periodSeconds);
|
|
16
|
+
if (!Number.isSafeInteger(step)) throw new AuthValidationError("The TOTP timestamp is out of range.");
|
|
17
|
+
return step;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Copies bytes into an ArrayBuffer.
|
|
21
|
+
*
|
|
22
|
+
* Web Crypto APIs accept BufferSource values backed by ArrayBuffer.
|
|
23
|
+
* This avoids ArrayBufferLike incompatibilities with newer TypeScript
|
|
24
|
+
* typed-array definitions.
|
|
25
|
+
*/
|
|
26
|
+
const toArrayBuffer = (bytes) => {
|
|
27
|
+
const buffer = new ArrayBuffer(bytes.byteLength);
|
|
28
|
+
const target = new Uint8Array(buffer);
|
|
29
|
+
for (let index = 0; index < bytes.length; index++) target[index] = bytes[index];
|
|
30
|
+
return buffer;
|
|
31
|
+
};
|
|
32
|
+
const constantTimeEqual = (left, right) => {
|
|
33
|
+
if (left.length !== right.length) return false;
|
|
34
|
+
let difference = 0;
|
|
35
|
+
for (let index = 0; index < left.length; index++) difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
36
|
+
return difference === 0;
|
|
37
|
+
};
|
|
38
|
+
const encodeBase32 = (input) => {
|
|
39
|
+
let output = "";
|
|
40
|
+
let buffer = 0;
|
|
41
|
+
let bits = 0;
|
|
42
|
+
for (const byte of input) {
|
|
43
|
+
buffer = buffer << 8 | byte;
|
|
44
|
+
bits += 8;
|
|
45
|
+
while (bits >= 5) {
|
|
46
|
+
bits -= 5;
|
|
47
|
+
output += BASE32_ALPHABET.charAt(buffer >>> bits & 31);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (bits > 0) output += BASE32_ALPHABET.charAt(buffer << 5 - bits & 31);
|
|
51
|
+
return output;
|
|
52
|
+
};
|
|
53
|
+
const decodeBase32 = (input) => {
|
|
54
|
+
if (typeof input !== "string" || input.length === 0) throw new AuthValidationError("A valid TOTP secret is required.");
|
|
55
|
+
const normalized = input.toUpperCase().replace(/[\s=-]/g, "");
|
|
56
|
+
if (normalized.length === 0) throw new AuthValidationError("The TOTP secret is invalid.");
|
|
57
|
+
const output = [];
|
|
58
|
+
let buffer = 0;
|
|
59
|
+
let bits = 0;
|
|
60
|
+
for (const character of normalized) {
|
|
61
|
+
const value = BASE32_ALPHABET.indexOf(character);
|
|
62
|
+
if (value < 0) throw new AuthValidationError("The TOTP secret is invalid.");
|
|
63
|
+
buffer = buffer << 5 | value;
|
|
64
|
+
bits += 5;
|
|
65
|
+
if (bits >= 8) {
|
|
66
|
+
bits -= 8;
|
|
67
|
+
output.push(buffer >>> bits & 255);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (bits > 0 && (buffer & (1 << bits) - 1) !== 0) throw new AuthValidationError("The TOTP secret is invalid.");
|
|
71
|
+
if (output.length === 0) throw new AuthValidationError("The TOTP secret is invalid.");
|
|
72
|
+
return new Uint8Array(output);
|
|
73
|
+
};
|
|
74
|
+
const generateTotpSecret = () => {
|
|
75
|
+
const bytes = /* @__PURE__ */ new Uint8Array(20);
|
|
76
|
+
getCrypto().getRandomValues(bytes);
|
|
77
|
+
return encodeBase32(bytes);
|
|
78
|
+
};
|
|
79
|
+
const generateTotpCode = async (secret, timestamp, options) => {
|
|
80
|
+
validateTotpOptions(options);
|
|
81
|
+
const counter = BigInt(getTimeStep(timestamp, options.periodSeconds));
|
|
82
|
+
const counterBuffer = /* @__PURE__ */ new ArrayBuffer(8);
|
|
83
|
+
const counterView = new DataView(counterBuffer);
|
|
84
|
+
let remaining = counter;
|
|
85
|
+
for (let index = 7; index >= 0; index--) {
|
|
86
|
+
counterView.setUint8(index, Number(remaining & 255n));
|
|
87
|
+
remaining >>= 8n;
|
|
88
|
+
}
|
|
89
|
+
const cryptoApi = getCrypto();
|
|
90
|
+
const secretBytes = decodeBase32(secret);
|
|
91
|
+
const key = await cryptoApi.subtle.importKey("raw", toArrayBuffer(secretBytes), {
|
|
92
|
+
name: "HMAC",
|
|
93
|
+
hash: "SHA-1"
|
|
94
|
+
}, false, ["sign"]);
|
|
95
|
+
const signature = await cryptoApi.subtle.sign("HMAC", key, counterBuffer);
|
|
96
|
+
const hash = new Uint8Array(signature);
|
|
97
|
+
if (hash.length < 20) throw new AuthConfigurationError("The runtime returned an invalid HMAC signature.");
|
|
98
|
+
const offset = hash[hash.length - 1] & 15;
|
|
99
|
+
const binary = (hash[offset] & 127) << 24 | hash[offset + 1] << 16 | hash[offset + 2] << 8 | hash[offset + 3];
|
|
100
|
+
const modulus = 10 ** options.digits;
|
|
101
|
+
const value = (binary >>> 0) % modulus;
|
|
102
|
+
return String(value).padStart(options.digits, "0");
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Returns the matching time step, or null.
|
|
106
|
+
*
|
|
107
|
+
* The caller must persist the accepted step and reject a step that
|
|
108
|
+
* has already been consumed.
|
|
109
|
+
*/
|
|
110
|
+
const verifyTotpCode = async (secret, code, timestamp, options) => {
|
|
111
|
+
validateTotpOptions(options);
|
|
112
|
+
if (!Number.isInteger(options.window) || options.window < 0 || options.window > 2) throw new AuthValidationError("The TOTP validation window must be between 0 and 2.");
|
|
113
|
+
if (typeof code !== "string" || !new RegExp(`^\\d{${options.digits}}$`).test(code)) return null;
|
|
114
|
+
const currentStep = getTimeStep(timestamp, options.periodSeconds);
|
|
115
|
+
let matchedStep = null;
|
|
116
|
+
for (let step = currentStep - options.window; step <= currentStep + options.window; step++) {
|
|
117
|
+
if (step < 0) continue;
|
|
118
|
+
const expected = await generateTotpCode(secret, step * options.periodSeconds * 1e3, options);
|
|
119
|
+
if (constantTimeEqual(expected, code)) matchedStep = step;
|
|
120
|
+
}
|
|
121
|
+
return matchedStep;
|
|
122
|
+
};
|
|
123
|
+
const createTotpUri = (input) => {
|
|
124
|
+
validateTotpOptions({
|
|
125
|
+
digits: input.digits,
|
|
126
|
+
periodSeconds: input.periodSeconds
|
|
127
|
+
});
|
|
128
|
+
if (typeof input.issuer !== "string" || input.issuer.trim().length === 0 || typeof input.account !== "string" || input.account.trim().length === 0) throw new AuthValidationError("A TOTP issuer and account name are required.");
|
|
129
|
+
decodeBase32(input.secret);
|
|
130
|
+
return `otpauth://totp/${encodeURIComponent(`${input.issuer.trim()}:${input.account.trim()}`)}?${new URLSearchParams({
|
|
131
|
+
secret: input.secret,
|
|
132
|
+
issuer: input.issuer.trim(),
|
|
133
|
+
algorithm: "SHA1",
|
|
134
|
+
digits: String(input.digits),
|
|
135
|
+
period: String(input.periodSeconds)
|
|
136
|
+
}).toString()}`;
|
|
137
|
+
};
|
|
138
|
+
export { createTotpUri, decodeBase32, encodeBase32, generateTotpCode, generateTotpSecret, verifyTotpCode };
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=totp.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"totp.utils.js","names":[],"sources":["../../src/utils/totp.utils.ts"],"sourcesContent":["import {\n AuthConfigurationError,\n AuthValidationError,\n} from \"../errors/auth.errors\";\n\nconst BASE32_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\";\n\ntype TotpOptions = {\n readonly digits: number;\n readonly periodSeconds: number;\n};\n\ntype TotpVerificationOptions = TotpOptions & {\n readonly window: number;\n};\n\nconst getCrypto = (): Crypto => {\n const cryptoApi = globalThis.crypto;\n\n if (!cryptoApi?.getRandomValues || !cryptoApi.subtle) {\n throw new AuthConfigurationError(\n \"This runtime does not provide the required Web Crypto APIs.\",\n );\n }\n\n return cryptoApi;\n};\n\nconst validateTotpOptions = (options: TotpOptions): void => {\n if (\n !Number.isInteger(options.digits) ||\n options.digits < 6 ||\n options.digits > 8\n ) {\n throw new AuthValidationError(\"TOTP digits must be between 6 and 8.\");\n }\n\n if (\n !Number.isInteger(options.periodSeconds) ||\n options.periodSeconds < 15 ||\n options.periodSeconds > 120\n ) {\n throw new AuthValidationError(\n \"The TOTP period must be between 15 and 120 seconds.\",\n );\n }\n};\n\nconst getTimeStep = (timestamp: number, periodSeconds: number): number => {\n if (!Number.isFinite(timestamp) || timestamp < 0) {\n throw new AuthValidationError(\"A valid TOTP timestamp is required.\");\n }\n\n const step = Math.floor(timestamp / 1000 / periodSeconds);\n\n if (!Number.isSafeInteger(step)) {\n throw new AuthValidationError(\"The TOTP timestamp is out of range.\");\n }\n\n return step;\n};\n\n/**\n * Copies bytes into an ArrayBuffer.\n *\n * Web Crypto APIs accept BufferSource values backed by ArrayBuffer.\n * This avoids ArrayBufferLike incompatibilities with newer TypeScript\n * typed-array definitions.\n */\nconst toArrayBuffer = (bytes: Uint8Array): ArrayBuffer => {\n const buffer = new ArrayBuffer(bytes.byteLength);\n const target = new Uint8Array(buffer);\n\n for (let index = 0; index < bytes.length; index++) {\n target[index] = bytes[index]!;\n }\n\n return buffer;\n};\n\nconst constantTimeEqual = (left: string, right: string): boolean => {\n if (left.length !== right.length) {\n return false;\n }\n\n let difference = 0;\n\n for (let index = 0; index < left.length; index++) {\n difference |= left.charCodeAt(index) ^ right.charCodeAt(index);\n }\n\n return difference === 0;\n};\n\nexport const encodeBase32 = (input: Uint8Array): string => {\n let output = \"\";\n let buffer = 0;\n let bits = 0;\n\n for (const byte of input) {\n buffer = (buffer << 8) | byte;\n bits += 8;\n\n while (bits >= 5) {\n bits -= 5;\n output += BASE32_ALPHABET.charAt((buffer >>> bits) & 31);\n }\n }\n\n if (bits > 0) {\n output += BASE32_ALPHABET.charAt((buffer << (5 - bits)) & 31);\n }\n\n return output;\n};\n\nexport const decodeBase32 = (input: string): Uint8Array => {\n if (typeof input !== \"string\" || input.length === 0) {\n throw new AuthValidationError(\"A valid TOTP secret is required.\");\n }\n\n const normalized = input.toUpperCase().replace(/[\\s=-]/g, \"\");\n\n if (normalized.length === 0) {\n throw new AuthValidationError(\"The TOTP secret is invalid.\");\n }\n\n const output: number[] = [];\n let buffer = 0;\n let bits = 0;\n\n for (const character of normalized) {\n const value = BASE32_ALPHABET.indexOf(character);\n\n if (value < 0) {\n throw new AuthValidationError(\"The TOTP secret is invalid.\");\n }\n\n buffer = (buffer << 5) | value;\n bits += 5;\n\n if (bits >= 8) {\n bits -= 8;\n output.push((buffer >>> bits) & 255);\n }\n }\n\n // Remaining bits are padding bits and must be zero.\n if (bits > 0 && (buffer & ((1 << bits) - 1)) !== 0) {\n throw new AuthValidationError(\"The TOTP secret is invalid.\");\n }\n\n if (output.length === 0) {\n throw new AuthValidationError(\"The TOTP secret is invalid.\");\n }\n\n return new Uint8Array(output);\n};\n\nexport const generateTotpSecret = (): string => {\n const bytes = new Uint8Array(20);\n\n getCrypto().getRandomValues(bytes);\n\n return encodeBase32(bytes);\n};\n\nexport const generateTotpCode = async (\n secret: string,\n timestamp: number,\n options: TotpOptions,\n): Promise<string> => {\n validateTotpOptions(options);\n\n const counter = BigInt(getTimeStep(timestamp, options.periodSeconds));\n\n const counterBuffer = new ArrayBuffer(8);\n const counterView = new DataView(counterBuffer);\n\n let remaining = counter;\n\n for (let index = 7; index >= 0; index--) {\n counterView.setUint8(index, Number(remaining & 255n));\n remaining >>= 8n;\n }\n\n const cryptoApi = getCrypto();\n const secretBytes = decodeBase32(secret);\n\n const key = await cryptoApi.subtle.importKey(\n \"raw\",\n toArrayBuffer(secretBytes),\n {\n name: \"HMAC\",\n hash: \"SHA-1\",\n },\n false,\n [\"sign\"],\n );\n\n const signature = await cryptoApi.subtle.sign(\"HMAC\", key, counterBuffer);\n\n const hash = new Uint8Array(signature);\n\n if (hash.length < 20) {\n throw new AuthConfigurationError(\n \"The runtime returned an invalid HMAC signature.\",\n );\n }\n\n const offset = hash[hash.length - 1]! & 0x0f;\n\n const binary =\n ((hash[offset]! & 0x7f) << 24) |\n (hash[offset + 1]! << 16) |\n (hash[offset + 2]! << 8) |\n hash[offset + 3]!;\n\n const modulus = 10 ** options.digits;\n const value = (binary >>> 0) % modulus;\n\n return String(value).padStart(options.digits, \"0\");\n};\n\n/**\n * Returns the matching time step, or null.\n *\n * The caller must persist the accepted step and reject a step that\n * has already been consumed.\n */\nexport const verifyTotpCode = async (\n secret: string,\n code: string,\n timestamp: number,\n options: TotpVerificationOptions,\n): Promise<number | null> => {\n validateTotpOptions(options);\n\n if (\n !Number.isInteger(options.window) ||\n options.window < 0 ||\n options.window > 2\n ) {\n throw new AuthValidationError(\n \"The TOTP validation window must be between 0 and 2.\",\n );\n }\n\n if (\n typeof code !== \"string\" ||\n !new RegExp(`^\\\\d{${options.digits}}$`).test(code)\n ) {\n return null;\n }\n\n const currentStep = getTimeStep(timestamp, options.periodSeconds);\n\n let matchedStep: number | null = null;\n\n for (\n let step = currentStep - options.window;\n step <= currentStep + options.window;\n step++\n ) {\n if (step < 0) {\n continue;\n }\n\n const expected = await generateTotpCode(\n secret,\n step * options.periodSeconds * 1000,\n options,\n );\n\n if (constantTimeEqual(expected, code)) {\n matchedStep = step;\n }\n }\n\n return matchedStep;\n};\n\nexport const createTotpUri = (input: {\n readonly issuer: string;\n readonly account: string;\n readonly secret: string;\n readonly digits: number;\n readonly periodSeconds: number;\n}): string => {\n validateTotpOptions({\n digits: input.digits,\n periodSeconds: input.periodSeconds,\n });\n\n if (\n typeof input.issuer !== \"string\" ||\n input.issuer.trim().length === 0 ||\n typeof input.account !== \"string\" ||\n input.account.trim().length === 0\n ) {\n throw new AuthValidationError(\n \"A TOTP issuer and account name are required.\",\n );\n }\n\n // Validate the secret before exposing it in a provisioning URI.\n decodeBase32(input.secret);\n\n const label = encodeURIComponent(\n `${input.issuer.trim()}:${input.account.trim()}`,\n );\n\n const parameters = new URLSearchParams({\n secret: input.secret,\n issuer: input.issuer.trim(),\n algorithm: \"SHA1\",\n digits: String(input.digits),\n period: String(input.periodSeconds),\n });\n\n return `otpauth://totp/${label}?${parameters.toString()}`;\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puzzle-ui/auth",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Framework-independent authentication core for Puzzle.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public",
|
|
8
|
+
"registry": "https://registry.npmjs.org/"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"main": "./dist/index.cjs",
|
|
12
|
+
"module": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"require": {
|
|
21
|
+
"types": "./dist/index.d.cts",
|
|
22
|
+
"default": "./dist/index.cjs"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsdown",
|
|
32
|
+
"typecheck": "tsc --noEmit -p .",
|
|
33
|
+
"test": "node --test",
|
|
34
|
+
"vitest": "node --test",
|
|
35
|
+
"clean": "rm -rf dist",
|
|
36
|
+
"prepack": "tsdown"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"tsdown": "^0.23.1",
|
|
40
|
+
"typescript": "^7.0.2"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@puzzle-ui/storage": "^0.5.0",
|
|
44
|
+
"@puzzle-ui/session": "^0.5.0",
|
|
45
|
+
"@simplewebauthn/server": "^14.1.0"
|
|
46
|
+
}
|
|
47
|
+
}
|