@flink-app/otp-auth-plugin 0.12.1-alpha.40

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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +879 -0
  3. package/dist/OtpAuthPlugin.d.ts +64 -0
  4. package/dist/OtpAuthPlugin.js +231 -0
  5. package/dist/OtpAuthPluginContext.d.ts +10 -0
  6. package/dist/OtpAuthPluginContext.js +2 -0
  7. package/dist/OtpAuthPluginOptions.d.ts +112 -0
  8. package/dist/OtpAuthPluginOptions.js +2 -0
  9. package/dist/OtpInternalContext.d.ts +11 -0
  10. package/dist/OtpInternalContext.js +2 -0
  11. package/dist/functions/initiate.d.ts +18 -0
  12. package/dist/functions/initiate.js +104 -0
  13. package/dist/functions/verify.d.ts +20 -0
  14. package/dist/functions/verify.js +142 -0
  15. package/dist/handlers/PostOtpInitiate.d.ts +7 -0
  16. package/dist/handlers/PostOtpInitiate.js +70 -0
  17. package/dist/handlers/PostOtpVerify.d.ts +7 -0
  18. package/dist/handlers/PostOtpVerify.js +86 -0
  19. package/dist/index.d.ts +11 -0
  20. package/dist/index.js +24 -0
  21. package/dist/repos/OtpSessionRepo.d.ts +13 -0
  22. package/dist/repos/OtpSessionRepo.js +145 -0
  23. package/dist/schemas/InitiateRequest.d.ts +8 -0
  24. package/dist/schemas/InitiateRequest.js +2 -0
  25. package/dist/schemas/InitiateResponse.d.ts +8 -0
  26. package/dist/schemas/InitiateResponse.js +2 -0
  27. package/dist/schemas/OtpSession.d.ts +25 -0
  28. package/dist/schemas/OtpSession.js +2 -0
  29. package/dist/schemas/VerifyRequest.d.ts +6 -0
  30. package/dist/schemas/VerifyRequest.js +2 -0
  31. package/dist/schemas/VerifyResponse.d.ts +12 -0
  32. package/dist/schemas/VerifyResponse.js +2 -0
  33. package/dist/utils/otp-utils.d.ts +43 -0
  34. package/dist/utils/otp-utils.js +95 -0
  35. package/examples/basic-usage.ts +145 -0
  36. package/package.json +37 -0
  37. package/spec/OtpAuthPlugin.spec.ts +159 -0
  38. package/spec/OtpSessionRepo.spec.ts +194 -0
  39. package/spec/otp-utils.spec.ts +172 -0
  40. package/spec/support/jasmine.json +7 -0
  41. package/src/OtpAuthPlugin.ts +163 -0
  42. package/src/OtpAuthPluginContext.ts +11 -0
  43. package/src/OtpAuthPluginOptions.ts +135 -0
  44. package/src/OtpInternalContext.ts +12 -0
  45. package/src/functions/initiate.ts +86 -0
  46. package/src/functions/verify.ts +123 -0
  47. package/src/handlers/PostOtpInitiate.ts +28 -0
  48. package/src/handlers/PostOtpVerify.ts +42 -0
  49. package/src/index.ts +17 -0
  50. package/src/repos/OtpSessionRepo.ts +47 -0
  51. package/src/schemas/InitiateRequest.ts +8 -0
  52. package/src/schemas/InitiateResponse.ts +8 -0
  53. package/src/schemas/OtpSession.ts +25 -0
  54. package/src/schemas/VerifyRequest.ts +6 -0
  55. package/src/schemas/VerifyResponse.ts +12 -0
  56. package/src/utils/otp-utils.ts +89 -0
  57. package/tsconfig.dist.json +4 -0
  58. package/tsconfig.json +24 -0
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.verify = void 0;
40
+ var flink_1 = require("@flink-app/flink");
41
+ function verify(ctx, options) {
42
+ return __awaiter(this, void 0, void 0, function () {
43
+ var sessionId, code, pluginOptions, session, codeMatches, updatedSession, remainingAttempts, user, authResult, error_1;
44
+ return __generator(this, function (_a) {
45
+ switch (_a.label) {
46
+ case 0:
47
+ sessionId = options.sessionId, code = options.code;
48
+ pluginOptions = ctx.plugins.otpAuth.options;
49
+ // Validate input
50
+ if (!sessionId || !code) {
51
+ throw (0, flink_1.badRequest)("Session ID and code are required");
52
+ }
53
+ return [4 /*yield*/, ctx.repos.otpSessionRepo.getSession(sessionId)];
54
+ case 1:
55
+ session = _a.sent();
56
+ if (!session) {
57
+ flink_1.log.warn("OTP session not found: ".concat(sessionId));
58
+ return [2 /*return*/, {
59
+ status: "not_found",
60
+ message: "Session not found or expired",
61
+ }];
62
+ }
63
+ // Check if session is already verified
64
+ if (session.status === "verified") {
65
+ flink_1.log.warn("Attempt to verify already verified session: ".concat(sessionId));
66
+ throw (0, flink_1.badRequest)("Session already verified");
67
+ }
68
+ // Check if session is locked
69
+ if (session.status === "locked") {
70
+ flink_1.log.warn("Attempt to verify locked session: ".concat(sessionId));
71
+ return [2 /*return*/, {
72
+ status: "locked",
73
+ message: "Too many failed attempts. Session is locked.",
74
+ }];
75
+ }
76
+ if (!(session.status === "expired" || new Date() > session.expiresAt)) return [3 /*break*/, 4];
77
+ if (!(session.status !== "expired")) return [3 /*break*/, 3];
78
+ return [4 /*yield*/, ctx.repos.otpSessionRepo.markAsExpired(sessionId)];
79
+ case 2:
80
+ _a.sent();
81
+ _a.label = 3;
82
+ case 3:
83
+ flink_1.log.warn("Attempt to verify expired session: ".concat(sessionId));
84
+ return [2 /*return*/, {
85
+ status: "expired",
86
+ message: "Verification code has expired",
87
+ }];
88
+ case 4:
89
+ codeMatches = session.code === code;
90
+ if (!!codeMatches) return [3 /*break*/, 6];
91
+ return [4 /*yield*/, ctx.repos.otpSessionRepo.incrementAttempts(sessionId)];
92
+ case 5:
93
+ updatedSession = _a.sent();
94
+ remainingAttempts = updatedSession.maxAttempts - updatedSession.attempts;
95
+ flink_1.log.warn("Invalid OTP code for session ".concat(sessionId, ". Remaining attempts: ").concat(remainingAttempts));
96
+ if (updatedSession.status === "locked") {
97
+ return [2 /*return*/, {
98
+ status: "locked",
99
+ message: "Too many failed attempts. Session is locked.",
100
+ remainingAttempts: 0,
101
+ }];
102
+ }
103
+ return [2 /*return*/, {
104
+ status: "invalid_code",
105
+ message: "Invalid verification code",
106
+ remainingAttempts: remainingAttempts,
107
+ }];
108
+ case 6:
109
+ // Code is valid - mark session as verified
110
+ return [4 /*yield*/, ctx.repos.otpSessionRepo.markAsVerified(sessionId)];
111
+ case 7:
112
+ // Code is valid - mark session as verified
113
+ _a.sent();
114
+ return [4 /*yield*/, pluginOptions.onGetUser(session.identifier, session.method, session.payload)];
115
+ case 8:
116
+ user = _a.sent();
117
+ if (!user) {
118
+ flink_1.log.error("User not found for identifier ".concat(session.identifier, " after successful OTP verification"));
119
+ throw (0, flink_1.notFound)("User not found");
120
+ }
121
+ _a.label = 9;
122
+ case 9:
123
+ _a.trys.push([9, 11, , 12]);
124
+ return [4 /*yield*/, pluginOptions.onVerifySuccess(user, session.identifier, session.method, session.payload)];
125
+ case 10:
126
+ authResult = _a.sent();
127
+ flink_1.log.info("OTP verification successful for session ".concat(sessionId, ", identifier: ").concat(session.identifier));
128
+ return [2 /*return*/, {
129
+ status: "success",
130
+ token: authResult.token,
131
+ user: authResult.user,
132
+ }];
133
+ case 11:
134
+ error_1 = _a.sent();
135
+ flink_1.log.error("Error in onVerifySuccess callback: ".concat(error_1));
136
+ throw new Error("Failed to complete authentication");
137
+ case 12: return [2 /*return*/];
138
+ }
139
+ });
140
+ });
141
+ }
142
+ exports.verify = verify;
@@ -0,0 +1,7 @@
1
+ import { Handler, RouteProps } from "@flink-app/flink";
2
+ import InitiateRequest from "../schemas/InitiateRequest";
3
+ import InitiateResponse from "../schemas/InitiateResponse";
4
+ import { OtpInternalContext } from "../OtpInternalContext";
5
+ export declare const Route: RouteProps;
6
+ declare const PostOtpInitiate: Handler<OtpInternalContext, InitiateRequest, InitiateResponse>;
7
+ export default PostOtpInitiate;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Route = void 0;
40
+ var flink_1 = require("@flink-app/flink");
41
+ var initiate_1 = require("../functions/initiate");
42
+ exports.Route = {
43
+ path: "/otp/initiate",
44
+ method: flink_1.HttpMethod.post,
45
+ };
46
+ var PostOtpInitiate = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
47
+ var response, error_1;
48
+ var ctx = _b.ctx, req = _b.req;
49
+ return __generator(this, function (_c) {
50
+ switch (_c.label) {
51
+ case 0:
52
+ _c.trys.push([0, 2, , 3]);
53
+ return [4 /*yield*/, (0, initiate_1.initiate)(ctx, {
54
+ identifier: req.body.identifier,
55
+ method: req.body.method,
56
+ payload: req.body.payload,
57
+ })];
58
+ case 1:
59
+ response = _c.sent();
60
+ return [2 /*return*/, {
61
+ data: response,
62
+ }];
63
+ case 2:
64
+ error_1 = _c.sent();
65
+ return [2 /*return*/, (0, flink_1.internalServerError)(error_1.message || "Failed to initiate OTP authentication")];
66
+ case 3: return [2 /*return*/];
67
+ }
68
+ });
69
+ }); };
70
+ exports.default = PostOtpInitiate;
@@ -0,0 +1,7 @@
1
+ import { Handler, RouteProps } from "@flink-app/flink";
2
+ import { OtpInternalContext } from "../OtpInternalContext";
3
+ import VerifyRequest from "../schemas/VerifyRequest";
4
+ import VerifyResponse from "../schemas/VerifyResponse";
5
+ export declare const Route: RouteProps;
6
+ declare const PostOtpVerify: Handler<OtpInternalContext, VerifyRequest, VerifyResponse>;
7
+ export default PostOtpVerify;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Route = void 0;
40
+ var flink_1 = require("@flink-app/flink");
41
+ var verify_1 = require("../functions/verify");
42
+ exports.Route = {
43
+ path: "/otp/verify",
44
+ method: flink_1.HttpMethod.post,
45
+ };
46
+ var PostOtpVerify = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
47
+ var response;
48
+ var ctx = _b.ctx, req = _b.req;
49
+ return __generator(this, function (_c) {
50
+ switch (_c.label) {
51
+ case 0: return [4 /*yield*/, (0, verify_1.verify)(ctx, {
52
+ sessionId: req.body.sessionId,
53
+ code: req.body.code,
54
+ })];
55
+ case 1:
56
+ response = _c.sent();
57
+ // Return appropriate HTTP status based on verification result
58
+ if (response.status === "success") {
59
+ return [2 /*return*/, {
60
+ data: response,
61
+ }];
62
+ }
63
+ else if (response.status === "not_found") {
64
+ return [2 /*return*/, {
65
+ status: 404,
66
+ data: response,
67
+ }];
68
+ }
69
+ else if (response.status === "locked" || response.status === "expired") {
70
+ return [2 /*return*/, {
71
+ status: 403,
72
+ data: response,
73
+ }];
74
+ }
75
+ else {
76
+ // invalid_code
77
+ return [2 /*return*/, {
78
+ status: 401,
79
+ data: response,
80
+ }];
81
+ }
82
+ return [2 /*return*/];
83
+ }
84
+ });
85
+ }); };
86
+ exports.default = PostOtpVerify;
@@ -0,0 +1,11 @@
1
+ export * from "./OtpAuthPlugin";
2
+ export * from "./OtpAuthPluginContext";
3
+ export * from "./OtpAuthPluginOptions";
4
+ export * from "./functions/initiate";
5
+ export * from "./functions/verify";
6
+ export type { default as OtpSession } from "./schemas/OtpSession";
7
+ export type { default as InitiateRequest } from "./schemas/InitiateRequest";
8
+ export type { default as InitiateResponse } from "./schemas/InitiateResponse";
9
+ export type { default as VerifyRequest } from "./schemas/VerifyRequest";
10
+ export type { default as VerifyResponse } from "./schemas/VerifyResponse";
11
+ export * from "./utils/otp-utils";
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./OtpAuthPlugin"), exports);
18
+ __exportStar(require("./OtpAuthPluginContext"), exports);
19
+ __exportStar(require("./OtpAuthPluginOptions"), exports);
20
+ // Functions
21
+ __exportStar(require("./functions/initiate"), exports);
22
+ __exportStar(require("./functions/verify"), exports);
23
+ // Utils
24
+ __exportStar(require("./utils/otp-utils"), exports);
@@ -0,0 +1,13 @@
1
+ import { FlinkRepo } from "@flink-app/flink";
2
+ import OtpSession from "../schemas/OtpSession";
3
+ declare class OtpSessionRepo extends FlinkRepo<any, OtpSession> {
4
+ getSession(sessionId: string): Promise<OtpSession | null>;
5
+ createSession(session: Omit<OtpSession, "_id">): Promise<Omit<OtpSession, "_id"> & {
6
+ _id: string;
7
+ }>;
8
+ incrementAttempts(sessionId: string): Promise<OtpSession | null>;
9
+ markAsVerified(sessionId: string): Promise<OtpSession | null>;
10
+ markAsExpired(sessionId: string): Promise<OtpSession | null>;
11
+ ensureExpiringIndex(ttlSec: number): Promise<void>;
12
+ }
13
+ export default OtpSessionRepo;
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
+ return new (P || (P = Promise))(function (resolve, reject) {
20
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
24
+ });
25
+ };
26
+ var __generator = (this && this.__generator) || function (thisArg, body) {
27
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
28
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
+ function verb(n) { return function (v) { return step([n, v]); }; }
30
+ function step(op) {
31
+ if (f) throw new TypeError("Generator is already executing.");
32
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
33
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
+ if (y = 0, t) op = [op[0] & 2, t.value];
35
+ switch (op[0]) {
36
+ case 0: case 1: t = op; break;
37
+ case 4: _.label++; return { value: op[1], done: false };
38
+ case 5: _.label++; y = op[1]; op = [0]; continue;
39
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
+ default:
41
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
+ if (t[2]) _.ops.pop();
46
+ _.trys.pop(); continue;
47
+ }
48
+ op = body.call(thisArg, _);
49
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
+ }
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ var flink_1 = require("@flink-app/flink");
55
+ var OtpSessionRepo = /** @class */ (function (_super) {
56
+ __extends(OtpSessionRepo, _super);
57
+ function OtpSessionRepo() {
58
+ return _super !== null && _super.apply(this, arguments) || this;
59
+ }
60
+ OtpSessionRepo.prototype.getSession = function (sessionId) {
61
+ return __awaiter(this, void 0, void 0, function () {
62
+ return __generator(this, function (_a) {
63
+ return [2 /*return*/, this.getOne({ sessionId: sessionId })];
64
+ });
65
+ });
66
+ };
67
+ OtpSessionRepo.prototype.createSession = function (session) {
68
+ return __awaiter(this, void 0, void 0, function () {
69
+ return __generator(this, function (_a) {
70
+ switch (_a.label) {
71
+ case 0: return [4 /*yield*/, this.create(session)];
72
+ case 1: return [2 /*return*/, _a.sent()];
73
+ }
74
+ });
75
+ });
76
+ };
77
+ OtpSessionRepo.prototype.incrementAttempts = function (sessionId) {
78
+ return __awaiter(this, void 0, void 0, function () {
79
+ var session, newAttempts, newStatus;
80
+ return __generator(this, function (_a) {
81
+ switch (_a.label) {
82
+ case 0: return [4 /*yield*/, this.getSession(sessionId)];
83
+ case 1:
84
+ session = _a.sent();
85
+ if (!session) {
86
+ throw new Error("Session not found");
87
+ }
88
+ newAttempts = session.attempts + 1;
89
+ newStatus = newAttempts >= session.maxAttempts ? "locked" : session.status;
90
+ return [4 /*yield*/, this.collection.updateOne({ sessionId: sessionId }, { $set: { attempts: newAttempts, status: newStatus } })];
91
+ case 2:
92
+ _a.sent();
93
+ return [2 /*return*/, this.getSession(sessionId)];
94
+ }
95
+ });
96
+ });
97
+ };
98
+ OtpSessionRepo.prototype.markAsVerified = function (sessionId) {
99
+ return __awaiter(this, void 0, void 0, function () {
100
+ return __generator(this, function (_a) {
101
+ switch (_a.label) {
102
+ case 0: return [4 /*yield*/, this.collection.updateOne({ sessionId: sessionId }, { $set: { status: "verified", verifiedAt: new Date() } })];
103
+ case 1:
104
+ _a.sent();
105
+ return [2 /*return*/, this.getSession(sessionId)];
106
+ }
107
+ });
108
+ });
109
+ };
110
+ OtpSessionRepo.prototype.markAsExpired = function (sessionId) {
111
+ return __awaiter(this, void 0, void 0, function () {
112
+ return __generator(this, function (_a) {
113
+ switch (_a.label) {
114
+ case 0: return [4 /*yield*/, this.collection.updateOne({ sessionId: sessionId }, { $set: { status: "expired" } })];
115
+ case 1:
116
+ _a.sent();
117
+ return [2 /*return*/, this.getSession(sessionId)];
118
+ }
119
+ });
120
+ });
121
+ };
122
+ OtpSessionRepo.prototype.ensureExpiringIndex = function (ttlSec) {
123
+ return __awaiter(this, void 0, void 0, function () {
124
+ var err_1;
125
+ return __generator(this, function (_a) {
126
+ switch (_a.label) {
127
+ case 0:
128
+ _a.trys.push([0, 2, , 3]);
129
+ return [4 /*yield*/, this.collection.createIndex({ createdAt: 1 }, { expireAfterSeconds: ttlSec })];
130
+ case 1:
131
+ _a.sent();
132
+ flink_1.log.info("OTP Auth Plugin: Created TTL index with ".concat(ttlSec, "s expiration"));
133
+ return [3 /*break*/, 3];
134
+ case 2:
135
+ err_1 = _a.sent();
136
+ flink_1.log.error("Error creating expiring index for OTP sessions:", err_1);
137
+ return [3 /*break*/, 3];
138
+ case 3: return [2 /*return*/];
139
+ }
140
+ });
141
+ });
142
+ };
143
+ return OtpSessionRepo;
144
+ }(flink_1.FlinkRepo));
145
+ exports.default = OtpSessionRepo;
@@ -0,0 +1,8 @@
1
+ export default interface InitiateRequest {
2
+ /** User identifier (phone number or email) */
3
+ identifier: string;
4
+ /** Delivery method for the OTP code */
5
+ method: "sms" | "email";
6
+ /** Optional custom payload to attach to the session */
7
+ payload?: Record<string, any>;
8
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ export default interface InitiateResponse {
2
+ /** Unique session ID for this OTP session */
3
+ sessionId: string;
4
+ /** When the code expires */
5
+ expiresAt: Date;
6
+ /** Time-to-live in seconds */
7
+ ttl: number;
8
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,25 @@
1
+ export default interface OtpSession {
2
+ _id?: string;
3
+ /** Unique identifier for the OTP session */
4
+ sessionId: string;
5
+ /** User identifier (phone number, email, or user ID) */
6
+ identifier: string;
7
+ /** The delivery method for this session */
8
+ method: "sms" | "email";
9
+ /** The generated OTP code */
10
+ code: string;
11
+ /** Number of verification attempts made */
12
+ attempts: number;
13
+ /** Maximum allowed attempts before session is locked */
14
+ maxAttempts: number;
15
+ /** Session status */
16
+ status: "pending" | "verified" | "expired" | "locked";
17
+ /** When the session was created */
18
+ createdAt: Date;
19
+ /** When the session expires */
20
+ expiresAt: Date;
21
+ /** When the session was verified (if verified) */
22
+ verifiedAt?: Date;
23
+ /** Optional custom payload passed during initiation */
24
+ payload?: Record<string, any>;
25
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export default interface VerifyRequest {
2
+ /** The session ID from the initiate response */
3
+ sessionId: string;
4
+ /** The OTP code entered by the user */
5
+ code: string;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ export default interface VerifyResponse {
2
+ /** Verification status */
3
+ status: "success" | "invalid_code" | "expired" | "locked" | "not_found";
4
+ /** JWT token if successful */
5
+ token?: string;
6
+ /** User object if successful */
7
+ user?: any;
8
+ /** Remaining attempts if code was invalid */
9
+ remainingAttempts?: number;
10
+ /** Error message */
11
+ message?: string;
12
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Generates a random numeric OTP code.
3
+ *
4
+ * @param length - Number of digits (4-8)
5
+ * @returns A numeric string of the specified length
6
+ */
7
+ export declare function generateOtpCode(length?: number): string;
8
+ /**
9
+ * Generates a unique session ID.
10
+ *
11
+ * @returns A cryptographically secure random hex string
12
+ */
13
+ export declare function generateSessionId(): string;
14
+ /**
15
+ * Validates that an identifier looks like a valid phone number or email.
16
+ *
17
+ * @param identifier - The identifier to validate
18
+ * @param method - The expected delivery method
19
+ * @returns true if valid, false otherwise
20
+ */
21
+ export declare function validateIdentifier(identifier: string, method: "sms" | "email"): boolean;
22
+ /**
23
+ * Normalizes a phone number by removing formatting characters.
24
+ *
25
+ * @param phoneNumber - The phone number to normalize
26
+ * @returns Normalized phone number (digits and + only)
27
+ */
28
+ export declare function normalizePhoneNumber(phoneNumber: string): string;
29
+ /**
30
+ * Normalizes an email by converting to lowercase and trimming.
31
+ *
32
+ * @param email - The email to normalize
33
+ * @returns Normalized email
34
+ */
35
+ export declare function normalizeEmail(email: string): string;
36
+ /**
37
+ * Normalizes an identifier based on the delivery method.
38
+ *
39
+ * @param identifier - The identifier to normalize
40
+ * @param method - The delivery method
41
+ * @returns Normalized identifier
42
+ */
43
+ export declare function normalizeIdentifier(identifier: string, method: "sms" | "email"): string;