totp-auth-service 0.1.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.
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ // src/testing/MemoryAdapter.ts
4
+ function cloneEnrollment(enrollment) {
5
+ return {
6
+ ...enrollment,
7
+ createdAt: new Date(enrollment.createdAt),
8
+ confirmedAt: enrollment.confirmedAt ? new Date(enrollment.confirmedAt) : null,
9
+ revokedAt: enrollment.revokedAt ? new Date(enrollment.revokedAt) : null
10
+ };
11
+ }
12
+ function cloneRecoveryCode(code) {
13
+ return {
14
+ ...code,
15
+ usedAt: code.usedAt ? new Date(code.usedAt) : null
16
+ };
17
+ }
18
+ var MemoryAdapter = class {
19
+ enrollments = /* @__PURE__ */ new Map();
20
+ recoveryCodes = /* @__PURE__ */ new Map();
21
+ async saveEnrollment(enrollment) {
22
+ this.enrollments.set(enrollment.userId, cloneEnrollment(enrollment));
23
+ }
24
+ async getEnrollment(userId) {
25
+ const enrollment = this.enrollments.get(userId);
26
+ return enrollment ? cloneEnrollment(enrollment) : null;
27
+ }
28
+ async updateEnrollment(userId, patch) {
29
+ const existing = this.enrollments.get(userId);
30
+ if (!existing) return;
31
+ this.enrollments.set(userId, cloneEnrollment({ ...existing, ...patch }));
32
+ }
33
+ async deleteEnrollment(userId) {
34
+ this.enrollments.delete(userId);
35
+ }
36
+ async saveRecoveryCodes(codes) {
37
+ if (codes.length === 0) return;
38
+ const userId = codes[0].userId;
39
+ this.recoveryCodes.set(
40
+ userId,
41
+ codes.map((c) => cloneRecoveryCode(c))
42
+ );
43
+ }
44
+ async getRecoveryCodes(userId) {
45
+ const codes = this.recoveryCodes.get(userId) ?? [];
46
+ return codes.map(cloneRecoveryCode);
47
+ }
48
+ async markRecoveryCodeUsed(userId, codeHash) {
49
+ const codes = this.recoveryCodes.get(userId);
50
+ if (!codes) return;
51
+ this.recoveryCodes.set(
52
+ userId,
53
+ codes.map(
54
+ (c) => c.codeHash === codeHash ? { ...c, usedAt: /* @__PURE__ */ new Date() } : cloneRecoveryCode(c)
55
+ )
56
+ );
57
+ }
58
+ async deleteRecoveryCodes(userId) {
59
+ this.recoveryCodes.delete(userId);
60
+ }
61
+ /** Clear all stored data — for test isolation between cases. */
62
+ reset() {
63
+ this.enrollments.clear();
64
+ this.recoveryCodes.clear();
65
+ }
66
+ };
67
+
68
+ exports.MemoryAdapter = MemoryAdapter;
69
+ //# sourceMappingURL=testing.cjs.map
70
+ //# sourceMappingURL=testing.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing/MemoryAdapter.ts"],"names":[],"mappings":"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","file":"testing.cjs","sourcesContent":["/**\n * In-memory StorageAdapter for tests and consumer test suites.\n * Not for production — no persistence, no cross-process sharing.\n *\n * Clones Date instances on read/write so callers cannot mutate internal state.\n */\nimport type {\n RecoveryCode,\n StorageAdapter,\n TOTPEnrollment,\n} from '../adapters/storage.js'\n\nfunction cloneEnrollment(enrollment: TOTPEnrollment): TOTPEnrollment {\n return {\n ...enrollment,\n createdAt: new Date(enrollment.createdAt),\n confirmedAt: enrollment.confirmedAt\n ? new Date(enrollment.confirmedAt)\n : null,\n revokedAt: enrollment.revokedAt ? new Date(enrollment.revokedAt) : null,\n }\n}\n\nfunction cloneRecoveryCode(code: RecoveryCode): RecoveryCode {\n return {\n ...code,\n usedAt: code.usedAt ? new Date(code.usedAt) : null,\n }\n}\n\nexport class MemoryAdapter implements StorageAdapter {\n private readonly enrollments = new Map<string, TOTPEnrollment>()\n private readonly recoveryCodes = new Map<string, RecoveryCode[]>()\n\n async saveEnrollment(enrollment: TOTPEnrollment): Promise<void> {\n this.enrollments.set(enrollment.userId, cloneEnrollment(enrollment))\n }\n\n async getEnrollment(userId: string): Promise<TOTPEnrollment | null> {\n const enrollment = this.enrollments.get(userId)\n return enrollment ? cloneEnrollment(enrollment) : null\n }\n\n async updateEnrollment(\n userId: string,\n patch: Partial<TOTPEnrollment>,\n ): Promise<void> {\n const existing = this.enrollments.get(userId)\n if (!existing) return\n this.enrollments.set(userId, cloneEnrollment({ ...existing, ...patch }))\n }\n\n async deleteEnrollment(userId: string): Promise<void> {\n this.enrollments.delete(userId)\n }\n\n async saveRecoveryCodes(codes: RecoveryCode[]): Promise<void> {\n if (codes.length === 0) return\n const userId = codes[0]!.userId\n this.recoveryCodes.set(\n userId,\n codes.map((c) => cloneRecoveryCode(c)),\n )\n }\n\n async getRecoveryCodes(userId: string): Promise<RecoveryCode[]> {\n const codes = this.recoveryCodes.get(userId) ?? []\n return codes.map(cloneRecoveryCode)\n }\n\n async markRecoveryCodeUsed(\n userId: string,\n codeHash: string,\n ): Promise<void> {\n const codes = this.recoveryCodes.get(userId)\n if (!codes) return\n\n this.recoveryCodes.set(\n userId,\n codes.map((c) =>\n c.codeHash === codeHash\n ? { ...c, usedAt: new Date() }\n : cloneRecoveryCode(c),\n ),\n )\n }\n\n async deleteRecoveryCodes(userId: string): Promise<void> {\n this.recoveryCodes.delete(userId)\n }\n\n /** Clear all stored data — for test isolation between cases. */\n reset(): void {\n this.enrollments.clear()\n this.recoveryCodes.clear()\n }\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { S as StorageAdapter, T as TOTPEnrollment, R as RecoveryCode } from './storage-xBzobyb-.cjs';
2
+
3
+ /**
4
+ * In-memory StorageAdapter for tests and consumer test suites.
5
+ * Not for production — no persistence, no cross-process sharing.
6
+ *
7
+ * Clones Date instances on read/write so callers cannot mutate internal state.
8
+ */
9
+
10
+ declare class MemoryAdapter implements StorageAdapter {
11
+ private readonly enrollments;
12
+ private readonly recoveryCodes;
13
+ saveEnrollment(enrollment: TOTPEnrollment): Promise<void>;
14
+ getEnrollment(userId: string): Promise<TOTPEnrollment | null>;
15
+ updateEnrollment(userId: string, patch: Partial<TOTPEnrollment>): Promise<void>;
16
+ deleteEnrollment(userId: string): Promise<void>;
17
+ saveRecoveryCodes(codes: RecoveryCode[]): Promise<void>;
18
+ getRecoveryCodes(userId: string): Promise<RecoveryCode[]>;
19
+ markRecoveryCodeUsed(userId: string, codeHash: string): Promise<void>;
20
+ deleteRecoveryCodes(userId: string): Promise<void>;
21
+ /** Clear all stored data — for test isolation between cases. */
22
+ reset(): void;
23
+ }
24
+
25
+ export { MemoryAdapter };
@@ -0,0 +1,25 @@
1
+ import { S as StorageAdapter, T as TOTPEnrollment, R as RecoveryCode } from './storage-xBzobyb-.js';
2
+
3
+ /**
4
+ * In-memory StorageAdapter for tests and consumer test suites.
5
+ * Not for production — no persistence, no cross-process sharing.
6
+ *
7
+ * Clones Date instances on read/write so callers cannot mutate internal state.
8
+ */
9
+
10
+ declare class MemoryAdapter implements StorageAdapter {
11
+ private readonly enrollments;
12
+ private readonly recoveryCodes;
13
+ saveEnrollment(enrollment: TOTPEnrollment): Promise<void>;
14
+ getEnrollment(userId: string): Promise<TOTPEnrollment | null>;
15
+ updateEnrollment(userId: string, patch: Partial<TOTPEnrollment>): Promise<void>;
16
+ deleteEnrollment(userId: string): Promise<void>;
17
+ saveRecoveryCodes(codes: RecoveryCode[]): Promise<void>;
18
+ getRecoveryCodes(userId: string): Promise<RecoveryCode[]>;
19
+ markRecoveryCodeUsed(userId: string, codeHash: string): Promise<void>;
20
+ deleteRecoveryCodes(userId: string): Promise<void>;
21
+ /** Clear all stored data — for test isolation between cases. */
22
+ reset(): void;
23
+ }
24
+
25
+ export { MemoryAdapter };
@@ -0,0 +1,68 @@
1
+ // src/testing/MemoryAdapter.ts
2
+ function cloneEnrollment(enrollment) {
3
+ return {
4
+ ...enrollment,
5
+ createdAt: new Date(enrollment.createdAt),
6
+ confirmedAt: enrollment.confirmedAt ? new Date(enrollment.confirmedAt) : null,
7
+ revokedAt: enrollment.revokedAt ? new Date(enrollment.revokedAt) : null
8
+ };
9
+ }
10
+ function cloneRecoveryCode(code) {
11
+ return {
12
+ ...code,
13
+ usedAt: code.usedAt ? new Date(code.usedAt) : null
14
+ };
15
+ }
16
+ var MemoryAdapter = class {
17
+ enrollments = /* @__PURE__ */ new Map();
18
+ recoveryCodes = /* @__PURE__ */ new Map();
19
+ async saveEnrollment(enrollment) {
20
+ this.enrollments.set(enrollment.userId, cloneEnrollment(enrollment));
21
+ }
22
+ async getEnrollment(userId) {
23
+ const enrollment = this.enrollments.get(userId);
24
+ return enrollment ? cloneEnrollment(enrollment) : null;
25
+ }
26
+ async updateEnrollment(userId, patch) {
27
+ const existing = this.enrollments.get(userId);
28
+ if (!existing) return;
29
+ this.enrollments.set(userId, cloneEnrollment({ ...existing, ...patch }));
30
+ }
31
+ async deleteEnrollment(userId) {
32
+ this.enrollments.delete(userId);
33
+ }
34
+ async saveRecoveryCodes(codes) {
35
+ if (codes.length === 0) return;
36
+ const userId = codes[0].userId;
37
+ this.recoveryCodes.set(
38
+ userId,
39
+ codes.map((c) => cloneRecoveryCode(c))
40
+ );
41
+ }
42
+ async getRecoveryCodes(userId) {
43
+ const codes = this.recoveryCodes.get(userId) ?? [];
44
+ return codes.map(cloneRecoveryCode);
45
+ }
46
+ async markRecoveryCodeUsed(userId, codeHash) {
47
+ const codes = this.recoveryCodes.get(userId);
48
+ if (!codes) return;
49
+ this.recoveryCodes.set(
50
+ userId,
51
+ codes.map(
52
+ (c) => c.codeHash === codeHash ? { ...c, usedAt: /* @__PURE__ */ new Date() } : cloneRecoveryCode(c)
53
+ )
54
+ );
55
+ }
56
+ async deleteRecoveryCodes(userId) {
57
+ this.recoveryCodes.delete(userId);
58
+ }
59
+ /** Clear all stored data — for test isolation between cases. */
60
+ reset() {
61
+ this.enrollments.clear();
62
+ this.recoveryCodes.clear();
63
+ }
64
+ };
65
+
66
+ export { MemoryAdapter };
67
+ //# sourceMappingURL=testing.js.map
68
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/testing/MemoryAdapter.ts"],"names":[],"mappings":"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","file":"testing.js","sourcesContent":["/**\n * In-memory StorageAdapter for tests and consumer test suites.\n * Not for production — no persistence, no cross-process sharing.\n *\n * Clones Date instances on read/write so callers cannot mutate internal state.\n */\nimport type {\n RecoveryCode,\n StorageAdapter,\n TOTPEnrollment,\n} from '../adapters/storage.js'\n\nfunction cloneEnrollment(enrollment: TOTPEnrollment): TOTPEnrollment {\n return {\n ...enrollment,\n createdAt: new Date(enrollment.createdAt),\n confirmedAt: enrollment.confirmedAt\n ? new Date(enrollment.confirmedAt)\n : null,\n revokedAt: enrollment.revokedAt ? new Date(enrollment.revokedAt) : null,\n }\n}\n\nfunction cloneRecoveryCode(code: RecoveryCode): RecoveryCode {\n return {\n ...code,\n usedAt: code.usedAt ? new Date(code.usedAt) : null,\n }\n}\n\nexport class MemoryAdapter implements StorageAdapter {\n private readonly enrollments = new Map<string, TOTPEnrollment>()\n private readonly recoveryCodes = new Map<string, RecoveryCode[]>()\n\n async saveEnrollment(enrollment: TOTPEnrollment): Promise<void> {\n this.enrollments.set(enrollment.userId, cloneEnrollment(enrollment))\n }\n\n async getEnrollment(userId: string): Promise<TOTPEnrollment | null> {\n const enrollment = this.enrollments.get(userId)\n return enrollment ? cloneEnrollment(enrollment) : null\n }\n\n async updateEnrollment(\n userId: string,\n patch: Partial<TOTPEnrollment>,\n ): Promise<void> {\n const existing = this.enrollments.get(userId)\n if (!existing) return\n this.enrollments.set(userId, cloneEnrollment({ ...existing, ...patch }))\n }\n\n async deleteEnrollment(userId: string): Promise<void> {\n this.enrollments.delete(userId)\n }\n\n async saveRecoveryCodes(codes: RecoveryCode[]): Promise<void> {\n if (codes.length === 0) return\n const userId = codes[0]!.userId\n this.recoveryCodes.set(\n userId,\n codes.map((c) => cloneRecoveryCode(c)),\n )\n }\n\n async getRecoveryCodes(userId: string): Promise<RecoveryCode[]> {\n const codes = this.recoveryCodes.get(userId) ?? []\n return codes.map(cloneRecoveryCode)\n }\n\n async markRecoveryCodeUsed(\n userId: string,\n codeHash: string,\n ): Promise<void> {\n const codes = this.recoveryCodes.get(userId)\n if (!codes) return\n\n this.recoveryCodes.set(\n userId,\n codes.map((c) =>\n c.codeHash === codeHash\n ? { ...c, usedAt: new Date() }\n : cloneRecoveryCode(c),\n ),\n )\n }\n\n async deleteRecoveryCodes(userId: string): Promise<void> {\n this.recoveryCodes.delete(userId)\n }\n\n /** Clear all stored data — for test isolation between cases. */\n reset(): void {\n this.enrollments.clear()\n this.recoveryCodes.clear()\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /** HMAC algorithm for TOTP (otpauth `algorithm` param and HMAC digest). */
2
+ declare enum TotpAlgorithm {
3
+ SHA1 = "SHA1",
4
+ SHA256 = "SHA256",
5
+ SHA512 = "SHA512"
6
+ }
7
+
8
+ export { TotpAlgorithm as T };
@@ -0,0 +1,8 @@
1
+ /** HMAC algorithm for TOTP (otpauth `algorithm` param and HMAC digest). */
2
+ declare enum TotpAlgorithm {
3
+ SHA1 = "SHA1",
4
+ SHA256 = "SHA256",
5
+ SHA512 = "SHA512"
6
+ }
7
+
8
+ export { TotpAlgorithm as T };
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "totp-auth-service",
3
+ "version": "0.1.0",
4
+ "description": "Self-hostable TOTP MFA library for Node.js — enrollment, verification, and recovery codes",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/ameyaaklekar/totp-auth-service.git"
9
+ },
10
+ "homepage": "https://github.com/ameyaaklekar/totp-auth-service#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/ameyaaklekar/totp-auth-service/issues"
13
+ },
14
+ "type": "module",
15
+ "sideEffects": false,
16
+ "main": "./dist/index.cjs",
17
+ "module": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "import": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "require": {
26
+ "types": "./dist/index.d.cts",
27
+ "default": "./dist/index.cjs"
28
+ }
29
+ },
30
+ "./crypto": {
31
+ "import": {
32
+ "types": "./dist/crypto.d.ts",
33
+ "default": "./dist/crypto.js"
34
+ },
35
+ "require": {
36
+ "types": "./dist/crypto.d.cts",
37
+ "default": "./dist/crypto.cjs"
38
+ }
39
+ },
40
+ "./testing": {
41
+ "import": {
42
+ "types": "./dist/testing.d.ts",
43
+ "default": "./dist/testing.js"
44
+ },
45
+ "require": {
46
+ "types": "./dist/testing.d.cts",
47
+ "default": "./dist/testing.cjs"
48
+ }
49
+ }
50
+ },
51
+ "files": [
52
+ "dist"
53
+ ],
54
+ "scripts": {
55
+ "build": "tsup",
56
+ "demo": "tsx example/try-flow.ts",
57
+ "prepublishOnly": "npm run build && npm test",
58
+ "test": "vitest run",
59
+ "test:watch": "vitest",
60
+ "typecheck": "tsc --noEmit"
61
+ },
62
+ "engines": {
63
+ "node": ">=18"
64
+ },
65
+ "keywords": [
66
+ "totp",
67
+ "mfa",
68
+ "2fa",
69
+ "authenticator",
70
+ "otp"
71
+ ],
72
+ "devDependencies": {
73
+ "@types/node": "^22.15.21",
74
+ "@types/qrcode": "^1.5.5",
75
+ "qrcode": "^1.5.4",
76
+ "tsup": "^8.5.0",
77
+ "tsx": "^4.19.4",
78
+ "typescript": "^5.8.3",
79
+ "vitest": "^3.1.4"
80
+ }
81
+ }