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.
- package/LICENSE +21 -0
- package/README.md +255 -0
- package/dist/crypto.cjs +145 -0
- package/dist/crypto.cjs.map +1 -0
- package/dist/crypto.d.cts +45 -0
- package/dist/crypto.d.ts +45 -0
- package/dist/crypto.js +139 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.cjs +379 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +114 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +368 -0
- package/dist/index.js.map +1 -0
- package/dist/storage-xBzobyb-.d.cts +44 -0
- package/dist/storage-xBzobyb-.d.ts +44 -0
- package/dist/testing.cjs +70 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +25 -0
- package/dist/testing.d.ts +25 -0
- package/dist/testing.js +68 -0
- package/dist/testing.js.map +1 -0
- package/dist/totp-algorithm-CUpdtI9d.d.cts +8 -0
- package/dist/totp-algorithm-CUpdtI9d.d.ts +8 -0
- package/package.json +81 -0
package/dist/testing.cjs
ADDED
|
@@ -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 };
|
package/dist/testing.js
ADDED
|
@@ -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"]}
|
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
|
+
}
|