@mrxsys/mrx-core 2.6.0 → 2.8.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/CHANGELOG.md +84 -19
- package/dist/chunk-4mt568fz.js +26 -0
- package/dist/chunk-7g8k2epn.js +104 -0
- package/dist/chunk-kv9hms2z.js +28 -0
- package/dist/{chunk-7m70tmz2.js → chunk-m18th1g5.js} +1 -1
- package/dist/chunk-ncc0m208.js +8 -0
- package/dist/chunk-r1kcf1q6.js +62 -0
- package/dist/chunk-sepwfqdh.js +6 -0
- package/dist/chunk-snqdnkk7.js +10 -0
- package/dist/{chunk-9wk2pajt.js → chunk-syhskygx.js} +9 -8
- package/dist/{chunk-64d6w5kt.js → chunk-y78xrx17.js} +2 -2
- package/dist/chunk-yd82hdxv.js +6 -0
- package/dist/chunk-z1skzn1j.js +8 -0
- package/dist/modules/data/data.d.ts +1 -1
- package/dist/modules/database/index.js +2 -2
- package/dist/modules/elysia/cache/cache.d.ts +306 -0
- package/dist/modules/elysia/cache/index.d.ts +1 -0
- package/dist/modules/elysia/cache/index.js +68 -0
- package/dist/modules/elysia/cache/types/cacheItem.d.ts +7 -0
- package/dist/modules/elysia/cache/types/cacheOptions.d.ts +21 -0
- package/dist/modules/elysia/cache/types/index.d.ts +1 -0
- package/dist/modules/elysia/cache/utils/generateCacheKey.d.ts +5 -0
- package/dist/modules/elysia/cache/utils/index.d.ts +1 -0
- package/dist/modules/elysia/cache/utils/index.js +7 -0
- package/dist/modules/elysia/crud/crud.d.ts +1 -1
- package/dist/modules/elysia/crud/index.js +13 -10
- package/dist/modules/elysia/crud/types/crudOptions.d.ts +2 -0
- package/dist/modules/elysia/dbResolver/dbResolver.d.ts +1 -1
- package/dist/modules/elysia/dbResolver/index.js +3 -3
- package/dist/modules/elysia/error/index.js +11 -2
- package/dist/modules/elysia/rateLimit/enums/index.d.ts +1 -0
- package/dist/modules/elysia/rateLimit/enums/index.js +7 -0
- package/dist/modules/elysia/rateLimit/enums/rateLimitErrorKeys.d.ts +3 -0
- package/dist/modules/elysia/rateLimit/index.d.ts +1 -0
- package/dist/modules/elysia/rateLimit/index.js +59 -0
- package/dist/modules/elysia/{ratelimit/ratelimit.d.ts → rateLimit/rateLimit.d.ts} +32 -15
- package/dist/modules/elysia/{ratelimit → rateLimit}/types/rateLimitOptions.d.ts +7 -16
- package/dist/modules/jwt/enums/index.d.ts +2 -0
- package/dist/modules/jwt/enums/index.js +11 -0
- package/dist/modules/jwt/enums/jwtErrorKeys.d.ts +5 -0
- package/dist/modules/jwt/enums/parseHumanTimeToSecondsErrorKeys.d.ts +3 -0
- package/dist/modules/jwt/index.d.ts +1 -0
- package/dist/modules/jwt/index.js +58 -0
- package/dist/modules/jwt/jwt.d.ts +3 -0
- package/dist/modules/jwt/utils/index.d.ts +1 -0
- package/dist/modules/jwt/utils/index.js +9 -0
- package/dist/modules/jwt/utils/parseHumanTimeToSeconds.d.ts +17 -0
- package/dist/modules/kvStore/enums/index.d.ts +1 -0
- package/dist/modules/kvStore/enums/index.js +7 -0
- package/dist/modules/kvStore/enums/kvStoreErrorKeys.d.ts +5 -0
- package/dist/modules/kvStore/ioredis/index.d.ts +1 -0
- package/dist/modules/kvStore/ioredis/index.js +102 -0
- package/dist/modules/kvStore/ioredis/ioredisStore.d.ts +107 -0
- package/dist/modules/kvStore/memory/index.d.ts +1 -0
- package/dist/modules/kvStore/memory/index.js +9 -0
- package/dist/modules/kvStore/memory/memoryStore.d.ts +119 -0
- package/dist/modules/kvStore/memory/types/memoryStoreEntry.d.ts +11 -0
- package/dist/modules/kvStore/types/index.d.ts +1 -0
- package/dist/modules/kvStore/types/index.js +1 -0
- package/dist/modules/kvStore/types/kvStore.d.ts +81 -0
- package/dist/modules/repository/index.js +1 -1
- package/dist/modules/repository/types/queryOptions.d.ts +5 -1
- package/dist/modules/totp/enums/index.d.ts +1 -0
- package/dist/modules/totp/enums/index.js +7 -0
- package/dist/modules/totp/enums/totpErrorKeys.d.ts +7 -0
- package/dist/modules/totp/hotp.d.ts +11 -0
- package/dist/modules/totp/index.d.ts +3 -0
- package/dist/modules/totp/index.js +110 -0
- package/dist/modules/totp/otpAuthUri.d.ts +21 -0
- package/dist/modules/totp/totp.d.ts +23 -0
- package/dist/modules/totp/types/index.d.ts +3 -0
- package/dist/modules/totp/types/index.js +1 -0
- package/dist/modules/totp/types/otpAuthUri.d.ts +35 -0
- package/dist/modules/totp/types/totpOptions.d.ts +23 -0
- package/dist/modules/totp/types/verifyOptions.d.ts +18 -0
- package/dist/modules/totp/utils/base32.d.ts +19 -0
- package/dist/modules/totp/utils/createCounterBuffer.d.ts +8 -0
- package/dist/modules/totp/utils/dynamicTruncation.d.ts +9 -0
- package/dist/modules/totp/utils/generateHmac.d.ts +9 -0
- package/dist/modules/totp/utils/generateSecretBytes.d.ts +10 -0
- package/dist/modules/totp/utils/index.d.ts +6 -0
- package/dist/modules/totp/utils/index.js +81 -0
- package/dist/modules/totp/utils/timeRemaining.d.ts +9 -0
- package/dist/utils/types/index.d.ts +1 -0
- package/dist/utils/types/renameKey.d.ts +10 -0
- package/package.json +86 -75
- package/dist/chunk-cqw9xq4y.js +0 -7
- package/dist/chunk-twaga0fp.js +0 -6
- package/dist/modules/elysia/jwt/enums/index.d.ts +0 -1
- package/dist/modules/elysia/jwt/enums/index.js +0 -7
- package/dist/modules/elysia/jwt/enums/jwtErrorKeys.d.ts +0 -4
- package/dist/modules/elysia/jwt/index.d.ts +0 -1
- package/dist/modules/elysia/jwt/index.js +0 -77
- package/dist/modules/elysia/jwt/jwt.d.ts +0 -119
- package/dist/modules/elysia/jwt/types/index.d.ts +0 -1
- package/dist/modules/elysia/jwt/types/jwtOptions.d.ts +0 -98
- package/dist/modules/elysia/ratelimit/enums/index.d.ts +0 -1
- package/dist/modules/elysia/ratelimit/enums/index.js +0 -7
- package/dist/modules/elysia/ratelimit/enums/ratelimitErrorKeys.d.ts +0 -3
- package/dist/modules/elysia/ratelimit/index.d.ts +0 -1
- package/dist/modules/elysia/ratelimit/index.js +0 -52
- /package/dist/modules/elysia/{jwt → cache}/types/index.js +0 -0
- /package/dist/modules/elysia/{ratelimit → rateLimit}/types/index.d.ts +0 -0
- /package/dist/modules/elysia/{ratelimit → rateLimit}/types/index.js +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export interface KvStore {
|
|
2
|
+
/**
|
|
3
|
+
* Connect to the store.
|
|
4
|
+
*/
|
|
5
|
+
connect?(): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Close the connection to the store.
|
|
8
|
+
*/
|
|
9
|
+
close?(): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Get the value associated with a key.
|
|
12
|
+
*
|
|
13
|
+
* @template T - The type of the value to retrieve.
|
|
14
|
+
*
|
|
15
|
+
* @param key - The key to retrieve the value for.
|
|
16
|
+
*
|
|
17
|
+
* @returns The value associated with the key, or `null` if the key does not exist.
|
|
18
|
+
*/
|
|
19
|
+
get<T = unknown>(key: string): T | null | Promise<T | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Set the value associated with a key.
|
|
22
|
+
*
|
|
23
|
+
* @template T - The type of the value to set.
|
|
24
|
+
*
|
|
25
|
+
* @param key - The key to set the value for.
|
|
26
|
+
* @param value - The value to set.
|
|
27
|
+
* @param ttlSec - The time-to-live for the key, in seconds.
|
|
28
|
+
*/
|
|
29
|
+
set<T = unknown>(key: string, value: T, ttlSec?: number): void | Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Increment the value associated with a key.
|
|
32
|
+
* Value needs to be a number.
|
|
33
|
+
*
|
|
34
|
+
* @param key - The key to increment the value for.
|
|
35
|
+
* @param amount - The amount to increment by.
|
|
36
|
+
*
|
|
37
|
+
* @returns The new value after incrementing.
|
|
38
|
+
*/
|
|
39
|
+
increment(key: string, amount?: number): number | Promise<number>;
|
|
40
|
+
/**
|
|
41
|
+
* Decrement the value associated with a key.
|
|
42
|
+
* Value needs to be a number.
|
|
43
|
+
*
|
|
44
|
+
* @param key - The key to decrement the value for.
|
|
45
|
+
* @param amount - The amount to decrement by.
|
|
46
|
+
*
|
|
47
|
+
* @returns The new value after decrementing.
|
|
48
|
+
*/
|
|
49
|
+
decrement(key: string, amount?: number): number | Promise<number>;
|
|
50
|
+
/**
|
|
51
|
+
* Delete a key from the store.
|
|
52
|
+
*
|
|
53
|
+
* @param key - The key to delete.
|
|
54
|
+
*
|
|
55
|
+
* @returns `true` if the key was deleted, `false` otherwise.
|
|
56
|
+
*/
|
|
57
|
+
del(key: string): boolean | Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Set the expiration time for a key.
|
|
60
|
+
*
|
|
61
|
+
* @param key - The key to set the expiration for.
|
|
62
|
+
* @param ttlSec - The time-to-live for the key, in seconds.
|
|
63
|
+
*
|
|
64
|
+
* @returns `true` if the expiration was set, `false` otherwise.
|
|
65
|
+
*/
|
|
66
|
+
expire(key: string, ttlSec: number): boolean | Promise<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* Get the remaining time-to-live for a key.
|
|
69
|
+
*
|
|
70
|
+
* @param key - The key to retrieve the TTL for.
|
|
71
|
+
*
|
|
72
|
+
* @returns The remaining time-to-live for the key, in seconds.
|
|
73
|
+
*/
|
|
74
|
+
ttl(key: string): number | Promise<number>;
|
|
75
|
+
/**
|
|
76
|
+
* Clean all keys from the store.
|
|
77
|
+
*
|
|
78
|
+
* @returns The number of keys that were removed.
|
|
79
|
+
*/
|
|
80
|
+
clean(): number | Promise<number>;
|
|
81
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { HTTP_ERROR_STATUS_CODES } from '../../../errors/enums/httpErrorStatusCodes';
|
|
1
2
|
import type { Filter } from './filter';
|
|
2
3
|
import type { OrderByItem } from './orderByItem';
|
|
3
4
|
import type { SelectedFields } from './selectedFields';
|
|
@@ -28,7 +29,10 @@ export interface QueryOptions<TModel> {
|
|
|
28
29
|
* Whether to throw an error if the query does not return any result.
|
|
29
30
|
* @defaultValue false
|
|
30
31
|
*/
|
|
31
|
-
readonly throwIfNoResult?: boolean |
|
|
32
|
+
readonly throwIfNoResult?: boolean | {
|
|
33
|
+
message?: string;
|
|
34
|
+
code?: keyof typeof HTTP_ERROR_STATUS_CODES | typeof HTTP_ERROR_STATUS_CODES[keyof typeof HTTP_ERROR_STATUS_CODES];
|
|
35
|
+
};
|
|
32
36
|
/**
|
|
33
37
|
* The transaction context for the query. ({@link Transaction})
|
|
34
38
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TOTP_ERROR_KEYS } from './totpErrorKeys';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const TOTP_ERROR_KEYS: {
|
|
2
|
+
readonly INVALID_BASE32_CHARACTER: "totp.error.invalid_base32_character";
|
|
3
|
+
readonly INVALID_SECRET_LENGTH: "totp.error.invalid_secret_length";
|
|
4
|
+
readonly INVALID_ALGORITHM: "totp.error.invalid_algorithm";
|
|
5
|
+
readonly INVALID_OTP_AUTH_URI: "totp.error.invalid_otp_auth_uri";
|
|
6
|
+
readonly MISSING_SECRET: "totp.error.missing_secret";
|
|
7
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TotpOptions } from './types/totpOptions';
|
|
2
|
+
/**
|
|
3
|
+
* HMAC-based One-Time Password (HOTP) implementation
|
|
4
|
+
*
|
|
5
|
+
* @param secret - Secret key as bytes
|
|
6
|
+
* @param counter - Counter value
|
|
7
|
+
* @param opts - HOTP options
|
|
8
|
+
*
|
|
9
|
+
* @returns Promise resolving to the HOTP code
|
|
10
|
+
*/
|
|
11
|
+
export declare const hotp: (secret: Uint8Array, counter: number | bigint, { algorithm, digits }?: TotpOptions) => Promise<string>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
createCounterBuffer,
|
|
4
|
+
dynamicTruncation,
|
|
5
|
+
generateHmac
|
|
6
|
+
} from "../../chunk-4mt568fz.js";
|
|
7
|
+
import {
|
|
8
|
+
TOTP_ERROR_KEYS
|
|
9
|
+
} from "../../chunk-snqdnkk7.js";
|
|
10
|
+
import {
|
|
11
|
+
BaseError
|
|
12
|
+
} from "../../chunk-vknq69e0.js";
|
|
13
|
+
|
|
14
|
+
// source/modules/totp/hotp.ts
|
|
15
|
+
import { webcrypto } from "crypto";
|
|
16
|
+
var hotp = async (secret, counter, {
|
|
17
|
+
algorithm = "SHA-1",
|
|
18
|
+
digits = 6
|
|
19
|
+
} = {}) => {
|
|
20
|
+
const counterBuffer = createCounterBuffer(counter);
|
|
21
|
+
const key = await webcrypto.subtle.importKey("raw", secret, { name: "HMAC", hash: algorithm }, false, ["sign"]);
|
|
22
|
+
const hmacArray = await generateHmac(key, counterBuffer);
|
|
23
|
+
return dynamicTruncation(hmacArray, digits);
|
|
24
|
+
};
|
|
25
|
+
// source/modules/totp/otpAuthUri.ts
|
|
26
|
+
var buildOtpAuthUri = ({
|
|
27
|
+
secretBase32,
|
|
28
|
+
label,
|
|
29
|
+
issuer,
|
|
30
|
+
algorithm = "SHA-1",
|
|
31
|
+
digits = 6,
|
|
32
|
+
period = 30
|
|
33
|
+
}) => {
|
|
34
|
+
const encodedLabel = encodeURIComponent(label);
|
|
35
|
+
const encodedIssuer = issuer ? encodeURIComponent(issuer) : undefined;
|
|
36
|
+
let uri = `otpauth://totp/${encodedLabel}?secret=${secretBase32}`;
|
|
37
|
+
if (encodedIssuer)
|
|
38
|
+
uri += `&issuer=${encodedIssuer}`;
|
|
39
|
+
if (algorithm !== "SHA-1")
|
|
40
|
+
uri += `&algorithm=${algorithm}`;
|
|
41
|
+
if (digits !== 6)
|
|
42
|
+
uri += `&digits=${digits}`;
|
|
43
|
+
if (period !== 30)
|
|
44
|
+
uri += `&period=${period}`;
|
|
45
|
+
return uri;
|
|
46
|
+
};
|
|
47
|
+
var parseOtpAuthUri = (uri) => {
|
|
48
|
+
const url = new URL(uri);
|
|
49
|
+
if (url.protocol !== "otpauth:")
|
|
50
|
+
throw new BaseError({
|
|
51
|
+
message: TOTP_ERROR_KEYS.INVALID_OTP_AUTH_URI
|
|
52
|
+
});
|
|
53
|
+
if (url.hostname !== "totp")
|
|
54
|
+
throw new BaseError({
|
|
55
|
+
message: TOTP_ERROR_KEYS.INVALID_OTP_AUTH_URI
|
|
56
|
+
});
|
|
57
|
+
const label = decodeURIComponent(url.pathname.slice(1));
|
|
58
|
+
const secretBase32 = url.searchParams.get("secret");
|
|
59
|
+
if (!secretBase32)
|
|
60
|
+
throw new BaseError({
|
|
61
|
+
message: TOTP_ERROR_KEYS.MISSING_SECRET
|
|
62
|
+
});
|
|
63
|
+
const issuerParam = url.searchParams.get("issuer");
|
|
64
|
+
const issuer = issuerParam ? decodeURIComponent(issuerParam) : undefined;
|
|
65
|
+
const algorithm = url.searchParams.get("algorithm") || "SHA-1";
|
|
66
|
+
const digits = parseInt(url.searchParams.get("digits") || "6", 10);
|
|
67
|
+
const period = parseInt(url.searchParams.get("period") || "30", 10);
|
|
68
|
+
const result = {
|
|
69
|
+
secretBase32,
|
|
70
|
+
label,
|
|
71
|
+
algorithm,
|
|
72
|
+
digits,
|
|
73
|
+
period,
|
|
74
|
+
...issuer && { issuer }
|
|
75
|
+
};
|
|
76
|
+
return result;
|
|
77
|
+
};
|
|
78
|
+
// source/modules/totp/totp.ts
|
|
79
|
+
var totp = async (secret, {
|
|
80
|
+
algorithm = "SHA-1",
|
|
81
|
+
digits = 6,
|
|
82
|
+
period = 30,
|
|
83
|
+
now = Date.now()
|
|
84
|
+
} = {}) => {
|
|
85
|
+
const timeStep = Math.floor(now / 1000 / period);
|
|
86
|
+
return hotp(secret, timeStep, { algorithm, digits });
|
|
87
|
+
};
|
|
88
|
+
var verifyTotp = async (secret, code, {
|
|
89
|
+
algorithm = "SHA-1",
|
|
90
|
+
digits = 6,
|
|
91
|
+
period = 30,
|
|
92
|
+
window = 0,
|
|
93
|
+
now = Date.now()
|
|
94
|
+
} = {}) => {
|
|
95
|
+
const currentTimeStep = Math.floor(now / 1000 / period);
|
|
96
|
+
for (let i = -window;i <= window; ++i) {
|
|
97
|
+
const timeStep = currentTimeStep + i;
|
|
98
|
+
const expectedCode = await hotp(secret, timeStep, { algorithm, digits });
|
|
99
|
+
if (expectedCode === code)
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
};
|
|
104
|
+
export {
|
|
105
|
+
verifyTotp,
|
|
106
|
+
totp,
|
|
107
|
+
parseOtpAuthUri,
|
|
108
|
+
hotp,
|
|
109
|
+
buildOtpAuthUri
|
|
110
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { OtpAuthUri } from './types/otpAuthUri';
|
|
2
|
+
/**
|
|
3
|
+
* Build an OTPAuth URI for QR code generation
|
|
4
|
+
*
|
|
5
|
+
* @param params - URI parameters
|
|
6
|
+
*
|
|
7
|
+
* @returns OTPAuth URI string
|
|
8
|
+
*/
|
|
9
|
+
export declare const buildOtpAuthUri: ({ secretBase32, label, issuer, algorithm, digits, period }: OtpAuthUri) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Parse an OTPAuth URI
|
|
12
|
+
*
|
|
13
|
+
* @param uri - OTPAuth URI to parse
|
|
14
|
+
*
|
|
15
|
+
* @throws ({@link BaseError}) - if the URI is invalid or missing required parameters
|
|
16
|
+
*
|
|
17
|
+
* @returns Parsed URI parameters
|
|
18
|
+
*/
|
|
19
|
+
export declare const parseOtpAuthUri: (uri: string) => Required<Omit<OtpAuthUri, "issuer">> & {
|
|
20
|
+
issuer?: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TotpOptions } from './types/totpOptions';
|
|
2
|
+
import type { VerifyOptions } from './types/verifyOptions';
|
|
3
|
+
/**
|
|
4
|
+
* Time-based One-Time Password (TOTP) implementation
|
|
5
|
+
*
|
|
6
|
+
* @param secret - Secret key as bytes
|
|
7
|
+
* @param opts - TOTP options including current time
|
|
8
|
+
*
|
|
9
|
+
* @returns Promise resolving to the TOTP code
|
|
10
|
+
*/
|
|
11
|
+
export declare const totp: (secret: Uint8Array, { algorithm, digits, period, now }?: TotpOptions & {
|
|
12
|
+
now?: number;
|
|
13
|
+
}) => Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Verify a TOTP code against a secret
|
|
16
|
+
*
|
|
17
|
+
* @param secret - Secret key as bytes
|
|
18
|
+
* @param code - Code to verify
|
|
19
|
+
* @param opts - Verification options
|
|
20
|
+
*
|
|
21
|
+
* @returns Promise resolving to true if code is valid
|
|
22
|
+
*/
|
|
23
|
+
export declare const verifyTotp: (secret: Uint8Array, code: string, { algorithm, digits, period, window, now }?: VerifyOptions) => Promise<boolean>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complete OTPAuth URI data structure
|
|
3
|
+
*/
|
|
4
|
+
export interface OtpAuthUri {
|
|
5
|
+
/**
|
|
6
|
+
* Base32 encoded secret
|
|
7
|
+
*/
|
|
8
|
+
secretBase32: string;
|
|
9
|
+
/**
|
|
10
|
+
* Label for the account (usually email or username)
|
|
11
|
+
*/
|
|
12
|
+
label: string;
|
|
13
|
+
/**
|
|
14
|
+
* Issuer name (app/service name)
|
|
15
|
+
*/
|
|
16
|
+
issuer: string;
|
|
17
|
+
/**
|
|
18
|
+
* Hash algorithm
|
|
19
|
+
*
|
|
20
|
+
* @defaultValue 'SHA-1'
|
|
21
|
+
*/
|
|
22
|
+
algorithm?: 'SHA-1' | 'SHA-256' | 'SHA-512';
|
|
23
|
+
/**
|
|
24
|
+
* Number of digits
|
|
25
|
+
*
|
|
26
|
+
* @defaultValue 6
|
|
27
|
+
*/
|
|
28
|
+
digits?: 6 | 8;
|
|
29
|
+
/**
|
|
30
|
+
* Time period in seconds
|
|
31
|
+
*
|
|
32
|
+
* @defaultValue 30
|
|
33
|
+
*/
|
|
34
|
+
period?: number;
|
|
35
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for TOTP/HOTP generation
|
|
3
|
+
*/
|
|
4
|
+
export interface TotpOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Hash algorithm to use
|
|
7
|
+
*
|
|
8
|
+
* @defaultValue SHA-1
|
|
9
|
+
*/
|
|
10
|
+
algorithm?: 'SHA-1' | 'SHA-256' | 'SHA-512';
|
|
11
|
+
/**
|
|
12
|
+
* Number of digits in the code
|
|
13
|
+
*
|
|
14
|
+
* @defaultValue 6
|
|
15
|
+
*/
|
|
16
|
+
digits?: 6 | 8;
|
|
17
|
+
/**
|
|
18
|
+
* Time step in seconds for TOTP
|
|
19
|
+
*
|
|
20
|
+
* @defaultValue 30
|
|
21
|
+
*/
|
|
22
|
+
period?: number;
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TotpOptions } from './totpOptions';
|
|
2
|
+
/**
|
|
3
|
+
* Options for TOTP verification
|
|
4
|
+
*/
|
|
5
|
+
export interface VerifyOptions extends TotpOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Time window for verification (±window periods)
|
|
8
|
+
*
|
|
9
|
+
* @defaultValue 1
|
|
10
|
+
*/
|
|
11
|
+
window?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Current timestamp in milliseconds
|
|
14
|
+
*
|
|
15
|
+
* @defaultValue Date.now()
|
|
16
|
+
*/
|
|
17
|
+
now?: number;
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encode bytes to Base32 string
|
|
3
|
+
*
|
|
4
|
+
* @param input - Bytes or string to encode
|
|
5
|
+
* @param withPadding - Whether to include padding (default: true)
|
|
6
|
+
*
|
|
7
|
+
* @returns Base32 encoded string
|
|
8
|
+
*/
|
|
9
|
+
export declare const base32Encode: (input: string | Uint8Array, withPadding?: boolean) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Decode Base32 string to bytes
|
|
12
|
+
*
|
|
13
|
+
* @param base32 - Base32 string to decode
|
|
14
|
+
*
|
|
15
|
+
* @throws ({@link BaseError}) - if invalid Base32 character is found
|
|
16
|
+
*
|
|
17
|
+
* @returns Decoded bytes
|
|
18
|
+
*/
|
|
19
|
+
export declare const base32Decode: (base32: string) => Uint8Array;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a counter value to an 8-byte big-endian buffer
|
|
3
|
+
*
|
|
4
|
+
* @param counter - Counter value as number or bigint
|
|
5
|
+
*
|
|
6
|
+
* @returns ArrayBuffer containing the counter in big-endian format
|
|
7
|
+
*/
|
|
8
|
+
export declare const createCounterBuffer: (counter: number | bigint) => ArrayBuffer;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Perform dynamic truncation on HMAC result according to RFC 4226
|
|
3
|
+
*
|
|
4
|
+
* @param hmacArray - HMAC result as byte array
|
|
5
|
+
* @param digits - Number of digits in the final code
|
|
6
|
+
*
|
|
7
|
+
* @returns Truncated code as string with leading zeros
|
|
8
|
+
*/
|
|
9
|
+
export declare const dynamicTruncation: (hmacArray: Uint8Array, digits: number) => string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate HMAC for given data using a crypto key
|
|
3
|
+
*
|
|
4
|
+
* @param key - Crypto key for HMAC
|
|
5
|
+
* @param data - Data to sign
|
|
6
|
+
*
|
|
7
|
+
* @returns Promise resolving to HMAC as Uint8Array
|
|
8
|
+
*/
|
|
9
|
+
export declare const generateHmac: (key: CryptoKey, data: ArrayBuffer) => Promise<Uint8Array>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate cryptographically secure random bytes for TOTP secret
|
|
3
|
+
*
|
|
4
|
+
* @param length - Number of bytes to generate (default: 20)
|
|
5
|
+
*
|
|
6
|
+
* @throws ({@link BaseError}) if length is not positive
|
|
7
|
+
*
|
|
8
|
+
* @returns Uint8Array containing the random bytes
|
|
9
|
+
*/
|
|
10
|
+
export declare const generateSecretBytes: (length?: number) => Uint8Array;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { base32Decode, base32Encode } from './base32';
|
|
2
|
+
export { createCounterBuffer } from './createCounterBuffer';
|
|
3
|
+
export { dynamicTruncation } from './dynamicTruncation';
|
|
4
|
+
export { generateHmac } from './generateHmac';
|
|
5
|
+
export { generateSecretBytes } from './generateSecretBytes';
|
|
6
|
+
export { timeRemaining } from './timeRemaining';
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
createCounterBuffer,
|
|
4
|
+
dynamicTruncation,
|
|
5
|
+
generateHmac
|
|
6
|
+
} from "../../../chunk-4mt568fz.js";
|
|
7
|
+
import {
|
|
8
|
+
TOTP_ERROR_KEYS
|
|
9
|
+
} from "../../../chunk-snqdnkk7.js";
|
|
10
|
+
import {
|
|
11
|
+
BaseError
|
|
12
|
+
} from "../../../chunk-vknq69e0.js";
|
|
13
|
+
|
|
14
|
+
// source/modules/totp/utils/base32.ts
|
|
15
|
+
var BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
16
|
+
var base32Encode = (input, withPadding = true) => {
|
|
17
|
+
let result = "";
|
|
18
|
+
let bits = 0;
|
|
19
|
+
let value = 0;
|
|
20
|
+
const bytes = input instanceof Uint8Array ? input : new TextEncoder().encode(input);
|
|
21
|
+
for (const byte of bytes) {
|
|
22
|
+
value = value << 8 | byte;
|
|
23
|
+
bits += 8;
|
|
24
|
+
while (bits >= 5) {
|
|
25
|
+
result += BASE32_ALPHABET[value >>> bits - 5 & 31];
|
|
26
|
+
bits -= 5;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (bits > 0)
|
|
30
|
+
result += BASE32_ALPHABET[value << 5 - bits & 31];
|
|
31
|
+
if (withPadding)
|
|
32
|
+
while (result.length % 8 !== 0)
|
|
33
|
+
result += "=";
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
var base32Decode = (base32) => {
|
|
37
|
+
const cleanBase32 = base32.replace(/=+$/, "");
|
|
38
|
+
if (cleanBase32.length === 0)
|
|
39
|
+
return new Uint8Array(0);
|
|
40
|
+
const result = [];
|
|
41
|
+
let bits = 0;
|
|
42
|
+
let value = 0;
|
|
43
|
+
for (const char of cleanBase32) {
|
|
44
|
+
const charValue = BASE32_ALPHABET.indexOf(char);
|
|
45
|
+
if (charValue === -1)
|
|
46
|
+
throw new BaseError({
|
|
47
|
+
message: TOTP_ERROR_KEYS.INVALID_BASE32_CHARACTER,
|
|
48
|
+
cause: `Invalid Base32 character: ${char}`
|
|
49
|
+
});
|
|
50
|
+
value = value << 5 | charValue;
|
|
51
|
+
bits += 5;
|
|
52
|
+
if (bits >= 8) {
|
|
53
|
+
result.push(value >>> bits - 8 & 255);
|
|
54
|
+
bits -= 8;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return new Uint8Array(result);
|
|
58
|
+
};
|
|
59
|
+
// source/modules/totp/utils/generateSecretBytes.ts
|
|
60
|
+
import { getRandomValues } from "crypto";
|
|
61
|
+
var generateSecretBytes = (length = 20) => {
|
|
62
|
+
if (length <= 0)
|
|
63
|
+
throw new BaseError({
|
|
64
|
+
message: TOTP_ERROR_KEYS.INVALID_SECRET_LENGTH
|
|
65
|
+
});
|
|
66
|
+
return getRandomValues(new Uint8Array(length));
|
|
67
|
+
};
|
|
68
|
+
// source/modules/totp/utils/timeRemaining.ts
|
|
69
|
+
var timeRemaining = (period = 30, now = Date.now()) => {
|
|
70
|
+
const elapsed = Math.floor(now / 1000) % period;
|
|
71
|
+
return period - elapsed;
|
|
72
|
+
};
|
|
73
|
+
export {
|
|
74
|
+
timeRemaining,
|
|
75
|
+
generateSecretBytes,
|
|
76
|
+
generateHmac,
|
|
77
|
+
dynamicTruncation,
|
|
78
|
+
createCounterBuffer,
|
|
79
|
+
base32Encode,
|
|
80
|
+
base32Decode
|
|
81
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate remaining time until next TOTP code
|
|
3
|
+
*
|
|
4
|
+
* @param period - Time period in seconds (default: 30)
|
|
5
|
+
* @param now - Current timestamp in milliseconds (default: Date.now())
|
|
6
|
+
*
|
|
7
|
+
* @returns Seconds remaining until next code
|
|
8
|
+
*/
|
|
9
|
+
export declare const timeRemaining: (period?: number, now?: number) => number;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renames a key in an object type while preserving all other properties.
|
|
3
|
+
*
|
|
4
|
+
* @template T - The original object type
|
|
5
|
+
* @template From - The key to rename (must exist in T)
|
|
6
|
+
* @template To - The new key name
|
|
7
|
+
*/
|
|
8
|
+
export type RenameKey<T, From extends keyof T, To extends PropertyKey> = {
|
|
9
|
+
[K in keyof T as K extends From ? To : K]: T[K];
|
|
10
|
+
};
|