@flowerforce/flowerbase 1.8.4-beta.8 → 1.8.4-beta.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AA4CzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBAmajE"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AA+CzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBA0bjE"}
@@ -20,6 +20,7 @@ const state_1 = require("../../../state");
20
20
  const context_1 = require("../../../utils/context");
21
21
  const crypto_1 = require("../../../utils/crypto");
22
22
  const utils_1 = require("../../utils");
23
+ const handleUserRegistration_2 = require("../../../shared/handleUserRegistration");
23
24
  const rateLimitStore = new Map();
24
25
  const isRateLimited = (key, maxAttempts, windowMs) => {
25
26
  var _a;
@@ -210,6 +211,22 @@ function localUserPassController(app) {
210
211
  res.status(200);
211
212
  return { status: 'confirmed' };
212
213
  }));
214
+ app.post(utils_1.AUTH_ENDPOINTS.CONFIRM_SEND, {
215
+ schema: utils_1.CONFIRM_SEND_SCHEMA
216
+ }, (req, res) => __awaiter(this, void 0, void 0, function* () {
217
+ const localUserpassProvider = resolveLocalUserpassProvider();
218
+ if (!localUserpassProvider || localUserpassProvider.disabled) {
219
+ throw new Error('Local userpass authentication disabled');
220
+ }
221
+ const key = `confirm-send:${req.ip}`;
222
+ if (isRateLimited(key, resetMaxAttempts, rateLimitWindowMs)) {
223
+ res.status(429).send({ message: 'Too many requests' });
224
+ return;
225
+ }
226
+ yield (0, handleUserRegistration_2.sendConfirmationRequest)(app, req.body.email);
227
+ res.status(202);
228
+ return { status: 'ok' };
229
+ }));
213
230
  /**
214
231
  * Endpoint for user login.
215
232
  *
@@ -51,4 +51,9 @@ export interface ConfirmUserDto {
51
51
  tokenId: string;
52
52
  };
53
53
  }
54
+ export interface ConfirmUserSendDto {
55
+ Body: {
56
+ email: string;
57
+ };
58
+ }
54
59
  //# sourceMappingURL=dtos.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/dtos.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,EAAE,cAAc,CAAA;IACrB,UAAU,EAAE,iBAAiB,CAAA;CAC9B,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,gBAAgB,GAAG,0BAA0B,CAAA;CACvE;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAA;KACtB,CAAA;CACF;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF"}
1
+ {"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/dtos.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,EAAE,cAAc,CAAA;IACrB,UAAU,EAAE,iBAAiB,CAAA;CAC9B,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,gBAAgB,GAAG,0BAA0B,CAAA;CACvE;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAA;KACtB,CAAA;CACF;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF"}
@@ -95,6 +95,21 @@ export declare const CONFIRM_USER_SCHEMA: {
95
95
  required: string[];
96
96
  };
97
97
  };
98
+ export declare const CONFIRM_SEND_SCHEMA: {
99
+ tags: string[];
100
+ body: {
101
+ type: string;
102
+ properties: {
103
+ email: {
104
+ type: string;
105
+ pattern: string;
106
+ minLength: number;
107
+ maxLength: number;
108
+ };
109
+ };
110
+ required: string[];
111
+ };
112
+ };
98
113
  export declare const RESET_SCHEMA: {
99
114
  tags: string[];
100
115
  body: {
@@ -134,6 +149,7 @@ export declare enum AUTH_ENDPOINTS {
134
149
  LOGIN = "/login",
135
150
  REGISTRATION = "/register",
136
151
  CONFIRM = "/confirm",
152
+ CONFIRM_SEND = "/confirm/send",
137
153
  PROFILE = "/profile",
138
154
  SESSION = "/session",
139
155
  RESET = "/reset/send",
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/auth/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc;;;CAA4C,CAAC;AACxE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;CAexB,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;CAc7B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;CAgB7B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;CAWhC,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAU/B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAAoB,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;CAe/B,CAAA;AAED,oBAAY,cAAc;IACxB,KAAK,WAAW;IAChB,YAAY,cAAc;IAC1B,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,KAAK,gBAAgB;IACrB,UAAU,gBAAgB;IAC1B,aAAa,WAAW;IACxB,UAAU,sBAAsB;CACjC;AAED,oBAAY,WAAW;IACrB,mBAAmB,wBAAwB;IAC3C,aAAa,mCAAmC;IAChD,oBAAoB,sCAAsC;IAC1D,sBAAsB,2BAA2B;IACjD,+BAA+B,oCAAoC;IACnE,kBAAkB,uBAAuB;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;IAC/B,iBAAiB,EAAE,cAAc,CAAA;IACjC,WAAW,CAAC,EAAE,QAAQ,CAAA;CACvB;AAED,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AACD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACN,kBAAkB,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,iBAAiB,EAAE,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,uBAAuB,EAAE,OAAO,CAAA;IAChC,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,8BAA8B,EAAE,MAAM,CAAA;CACvC;AAMD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,UAuCjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAarC,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,eAAW,WAG3C,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/auth/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc;;;CAA4C,CAAC;AACxE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;CAexB,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;CAc7B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;CAgB7B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;CAWhC,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAU/B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAAoB,CAAA;AAEpD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAAoB,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;CAe/B,CAAA;AAED,oBAAY,cAAc;IACxB,KAAK,WAAW;IAChB,YAAY,cAAc;IAC1B,OAAO,aAAa;IACpB,YAAY,kBAAkB;IAC9B,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,KAAK,gBAAgB;IACrB,UAAU,gBAAgB;IAC1B,aAAa,WAAW;IACxB,UAAU,sBAAsB;CACjC;AAED,oBAAY,WAAW;IACrB,mBAAmB,wBAAwB;IAC3C,aAAa,mCAAmC;IAChD,oBAAoB,sCAAsC;IAC1D,sBAAsB,2BAA2B;IACjD,+BAA+B,oCAAoC;IACnE,kBAAkB,uBAAuB;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;IAC/B,iBAAiB,EAAE,cAAc,CAAA;IACjC,WAAW,CAAC,EAAE,QAAQ,CAAA;CACvB;AAED,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AACD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACN,kBAAkB,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,iBAAiB,EAAE,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,uBAAuB,EAAE,OAAO,CAAA;IAChC,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,8BAA8B,EAAE,MAAM,CAAA;CACvC;AAMD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,UAuCjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAarC,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,eAAW,WAG3C,CAAA"}
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generatePassword = exports.loadCustomUserData = exports.loadAuthConfig = exports.AUTH_ERRORS = exports.AUTH_ENDPOINTS = exports.REGISTRATION_SCHEMA = exports.RESET_SCHEMA = exports.CONFIRM_USER_SCHEMA = exports.CONFIRM_RESET_SCHEMA = exports.RESET_CALL_SCHEMA = exports.RESET_SEND_SCHEMA = exports.LOGIN_SCHEMA = exports.PASSWORD_RULES = void 0;
6
+ exports.generatePassword = exports.loadCustomUserData = exports.loadAuthConfig = exports.AUTH_ERRORS = exports.AUTH_ENDPOINTS = exports.REGISTRATION_SCHEMA = exports.RESET_SCHEMA = exports.CONFIRM_SEND_SCHEMA = exports.CONFIRM_USER_SCHEMA = exports.CONFIRM_RESET_SCHEMA = exports.RESET_CALL_SCHEMA = exports.RESET_SEND_SCHEMA = exports.LOGIN_SCHEMA = exports.PASSWORD_RULES = void 0;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
@@ -80,6 +80,7 @@ exports.CONFIRM_USER_SCHEMA = {
80
80
  required: ['token', 'tokenId']
81
81
  }
82
82
  };
83
+ exports.CONFIRM_SEND_SCHEMA = exports.RESET_SEND_SCHEMA;
83
84
  exports.RESET_SCHEMA = exports.RESET_SEND_SCHEMA;
84
85
  exports.REGISTRATION_SCHEMA = {
85
86
  tags: ['Auth'],
@@ -102,6 +103,7 @@ var AUTH_ENDPOINTS;
102
103
  AUTH_ENDPOINTS["LOGIN"] = "/login";
103
104
  AUTH_ENDPOINTS["REGISTRATION"] = "/register";
104
105
  AUTH_ENDPOINTS["CONFIRM"] = "/confirm";
106
+ AUTH_ENDPOINTS["CONFIRM_SEND"] = "/confirm/send";
105
107
  AUTH_ENDPOINTS["PROFILE"] = "/profile";
106
108
  AUTH_ENDPOINTS["SESSION"] = "/session";
107
109
  AUTH_ENDPOINTS["RESET"] = "/reset/send";
@@ -1,4 +1,12 @@
1
+ import type { FastifyInstance } from "fastify/types/instance";
1
2
  import { HandleUserRegistration } from "./models/handleUserRegistration.model";
3
+ export declare const sendConfirmationRequest: (app: FastifyInstance, email: string) => Promise<{
4
+ status: "success";
5
+ } | {
6
+ status: "pending";
7
+ } | {
8
+ status: "fail";
9
+ } | null>;
2
10
  /**
3
11
  * Register user
4
12
  *
@@ -1 +1 @@
1
- {"version":3,"file":"handleUserRegistration.d.ts","sourceRoot":"","sources":["../../src/shared/handleUserRegistration.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAE9E;;;;;;GAMG;AACH,QAAA,MAAM,sBAAsB,EAAE,sBAwJ7B,CAAA;AAED,eAAe,sBAAsB,CAAA"}
1
+ {"version":3,"file":"handleUserRegistration.d.ts","sourceRoot":"","sources":["../../src/shared/handleUserRegistration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAM7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAI9E,eAAO,MAAM,uBAAuB,GAChC,KAAK,eAAe,EACpB,OAAO,MAAM;;;;;;SAgGhB,CAAA;AAED;;;;;;GAMG;AACH,QAAA,MAAM,sBAAsB,EAAE,sBA+E7B,CAAA;AAED,eAAe,sBAAsB,CAAA"}
@@ -9,11 +9,89 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.sendConfirmationRequest = void 0;
12
13
  const constants_1 = require("../constants");
13
14
  const monitoring_1 = require("../services/monitoring");
14
15
  const state_1 = require("../state");
15
16
  const context_1 = require("../utils/context");
16
17
  const crypto_1 = require("../utils/crypto");
18
+ const sendConfirmationRequest = (app, email) => __awaiter(void 0, void 0, void 0, function* () {
19
+ var _a;
20
+ const { authCollection } = constants_1.AUTH_CONFIG;
21
+ const localUserpassConfig = constants_1.AUTH_CONFIG.localUserpassConfig;
22
+ const autoConfirm = (localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.autoConfirm) === true;
23
+ const runConfirmationFunction = (localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.runConfirmationFunction) === true;
24
+ const confirmationFunctionName = localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.confirmationFunctionName;
25
+ const normalizedEmail = email.toLowerCase();
26
+ const mongo = app === null || app === void 0 ? void 0 : app.mongo;
27
+ const db = mongo.client.db(constants_1.AUTH_DB_NAME);
28
+ const authUser = yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).findOne({ email: normalizedEmail }));
29
+ if (!authUser) {
30
+ return null;
31
+ }
32
+ if (authUser.status === 'confirmed' || autoConfirm) {
33
+ return { status: 'success' };
34
+ }
35
+ if (!runConfirmationFunction) {
36
+ throw new Error('Missing confirmation function');
37
+ }
38
+ if (!confirmationFunctionName) {
39
+ throw new Error('Missing confirmation function name');
40
+ }
41
+ const functionsList = state_1.StateManager.select('functions');
42
+ const services = state_1.StateManager.select('services');
43
+ const confirmationFunction = functionsList[confirmationFunctionName];
44
+ if (!confirmationFunction) {
45
+ throw new Error(`Confirmation function not found: ${confirmationFunctionName}`);
46
+ }
47
+ const token = (0, crypto_1.generateToken)();
48
+ const tokenId = (0, crypto_1.generateToken)();
49
+ yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ email: normalizedEmail }, {
50
+ $set: {
51
+ status: 'pending',
52
+ confirmationToken: token,
53
+ confirmationTokenId: tokenId
54
+ }
55
+ }));
56
+ let confirmationStatus = 'fail';
57
+ try {
58
+ const response = yield (0, context_1.GenerateContext)({
59
+ args: [{
60
+ token,
61
+ tokenId,
62
+ username: normalizedEmail
63
+ }],
64
+ app,
65
+ rules: {},
66
+ user: {},
67
+ currentFunction: confirmationFunction,
68
+ functionName: confirmationFunctionName,
69
+ functionsList,
70
+ services,
71
+ runAsSystem: true
72
+ });
73
+ confirmationStatus = (_a = response === null || response === void 0 ? void 0 : response.status) !== null && _a !== void 0 ? _a : 'fail';
74
+ }
75
+ catch (_b) {
76
+ confirmationStatus = 'fail';
77
+ }
78
+ if (confirmationStatus === 'success') {
79
+ yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ email: normalizedEmail }, {
80
+ $set: { status: 'confirmed' },
81
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
82
+ }));
83
+ return { status: 'success' };
84
+ }
85
+ if (confirmationStatus === 'pending') {
86
+ return { status: 'pending' };
87
+ }
88
+ yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ email: normalizedEmail }, {
89
+ $set: { status: 'failed' },
90
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
91
+ }));
92
+ return { status: 'fail' };
93
+ });
94
+ exports.sendConfirmationRequest = sendConfirmationRequest;
17
95
  /**
18
96
  * Register user
19
97
  *
@@ -22,7 +100,7 @@ const crypto_1 = require("../utils/crypto");
22
100
  * @returns {Promise<InsertOneResult<Document>>} A promise resolving to the result of the insert operation.
23
101
  */
24
102
  const handleUserRegistration = (app, opt) => (_a) => __awaiter(void 0, [_a], void 0, function* ({ email, password }) {
25
- var _b, _c;
103
+ var _b;
26
104
  const { run_as_system, skipUserCheck, provider } = opt !== null && opt !== void 0 ? opt : {};
27
105
  const origin = (_b = opt === null || opt === void 0 ? void 0 : opt.monitoring) === null || _b === void 0 ? void 0 : _b.invokedFrom;
28
106
  const meta = { action: 'registerUser', email, provider };
@@ -40,8 +118,6 @@ const handleUserRegistration = (app, opt) => (_a) => __awaiter(void 0, [_a], voi
40
118
  const { authCollection } = constants_1.AUTH_CONFIG;
41
119
  const localUserpassConfig = constants_1.AUTH_CONFIG.localUserpassConfig;
42
120
  const autoConfirm = (localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.autoConfirm) === true;
43
- const runConfirmationFunction = (localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.runConfirmationFunction) === true;
44
- const confirmationFunctionName = localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.confirmationFunctionName;
45
121
  const mongo = app === null || app === void 0 ? void 0 : app.mongo;
46
122
  const db = mongo.client.db(constants_1.AUTH_DB_NAME);
47
123
  const hashedPassword = yield (0, crypto_1.hashPassword)(password);
@@ -79,62 +155,7 @@ const handleUserRegistration = (app, opt) => (_a) => __awaiter(void 0, [_a], voi
79
155
  if (!(result === null || result === void 0 ? void 0 : result.insertedId) || skipUserCheck || autoConfirm) {
80
156
  return result;
81
157
  }
82
- if (!runConfirmationFunction) {
83
- throw new Error('Missing confirmation function');
84
- }
85
- if (!confirmationFunctionName) {
86
- throw new Error('Missing confirmation function name');
87
- }
88
- const functionsList = state_1.StateManager.select('functions');
89
- const services = state_1.StateManager.select('services');
90
- const confirmationFunction = functionsList[confirmationFunctionName];
91
- if (!confirmationFunction) {
92
- throw new Error(`Confirmation function not found: ${confirmationFunctionName}`);
93
- }
94
- const token = (0, crypto_1.generateToken)();
95
- const tokenId = (0, crypto_1.generateToken)();
96
- yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ _id: result.insertedId }, {
97
- $set: {
98
- confirmationToken: token,
99
- confirmationTokenId: tokenId
100
- }
101
- }));
102
- let confirmationStatus = 'fail';
103
- try {
104
- const response = yield (0, context_1.GenerateContext)({
105
- args: [{
106
- token,
107
- tokenId,
108
- username: email
109
- }],
110
- app,
111
- rules: {},
112
- user: {},
113
- currentFunction: confirmationFunction,
114
- functionName: confirmationFunctionName,
115
- functionsList,
116
- services,
117
- runAsSystem: true
118
- });
119
- confirmationStatus = (_c = response === null || response === void 0 ? void 0 : response.status) !== null && _c !== void 0 ? _c : 'fail';
120
- }
121
- catch (_d) {
122
- confirmationStatus = 'fail';
123
- }
124
- if (confirmationStatus === 'success') {
125
- yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ _id: result.insertedId }, {
126
- $set: { status: 'confirmed' },
127
- $unset: { confirmationToken: '', confirmationTokenId: '' }
128
- }));
129
- return result;
130
- }
131
- if (confirmationStatus === 'pending') {
132
- return result;
133
- }
134
- yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ _id: result.insertedId }, {
135
- $set: { status: 'failed' },
136
- $unset: { confirmationToken: '', confirmationTokenId: '' }
137
- }));
158
+ yield (0, exports.sendConfirmationRequest)(app, email);
138
159
  return result;
139
160
  }
140
161
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowerforce/flowerbase",
3
- "version": "1.8.4-beta.8",
3
+ "version": "1.8.4-beta.9",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,6 +13,11 @@ jest.mock('../../../../constants', () => ({
13
13
  resetPasswordConfig: {
14
14
  runResetFunction: true,
15
15
  resetFunctionName: 'customReset'
16
+ },
17
+ localUserpassConfig: {
18
+ autoConfirm: false,
19
+ runConfirmationFunction: true,
20
+ confirmationFunctionName: 'customConfirm'
16
21
  }
17
22
  },
18
23
  AUTH_DB_NAME: 'test-auth-db',
@@ -32,7 +37,8 @@ jest.mock('../../../../state', () => ({
32
37
  select: jest.fn((key: string) => {
33
38
  if (key === 'functions') {
34
39
  return {
35
- customReset: { name: 'customReset', code: 'exports = async () => ({ status: "success" })' }
40
+ customReset: { name: 'customReset', code: 'exports = async () => ({ status: "success" })' },
41
+ customConfirm: { name: 'customConfirm', code: 'exports = async () => ({ status: "pending" })' }
36
42
  }
37
43
  }
38
44
  if (key === 'services') {
@@ -61,15 +67,14 @@ import { hashPassword } from '../../../../utils/crypto'
61
67
 
62
68
  describe('localUserPassController reset call', () => {
63
69
  const buildApp = () => {
64
- let resetCallHandler:
65
- | ((req: { body: { email: string; password: string; arguments?: unknown[] }; ip: string }, res: { status: jest.Mock }) => Promise<unknown>)
66
- | undefined
70
+ const routeHandlers: Record<string, ((req: { body: any; ip: string }, res: { status: jest.Mock; send?: jest.Mock }) => Promise<unknown>) | undefined> = {}
67
71
 
68
72
  const authUsersCollection = {
69
73
  findOne: jest.fn().mockResolvedValue({
70
74
  _id: 'auth-user-1',
71
75
  email: 'john@doe.com',
72
- password: 'old-hash'
76
+ password: 'old-hash',
77
+ status: 'pending'
73
78
  }),
74
79
  updateOne: jest.fn().mockResolvedValue({ acknowledged: true })
75
80
  }
@@ -97,14 +102,17 @@ describe('localUserPassController reset call', () => {
97
102
  }
98
103
  const app = {
99
104
  mongo: { client: { db: jest.fn().mockReturnValue(db) } },
100
- post: jest.fn((path: string, _opts: unknown, handler: typeof resetCallHandler) => {
101
- if (path === '/reset/call') {
102
- resetCallHandler = handler
103
- }
105
+ post: jest.fn((path: string, _opts: unknown, handler: (req: { body: any; ip: string }, res: { status: jest.Mock; send?: jest.Mock }) => Promise<unknown>) => {
106
+ routeHandlers[path] = handler
104
107
  })
105
108
  }
106
109
 
107
- return { app, authUsersCollection, resetCollection, resetCallHandlerRef: () => resetCallHandler }
110
+ return {
111
+ app,
112
+ authUsersCollection,
113
+ resetCollection,
114
+ routeHandlerRef: (path: string) => routeHandlers[path]
115
+ }
108
116
  }
109
117
 
110
118
  beforeEach(() => {
@@ -112,13 +120,13 @@ describe('localUserPassController reset call', () => {
112
120
  })
113
121
 
114
122
  it('hashes and applies the password when the custom reset function returns success', async () => {
115
- ;(GenerateContext as jest.Mock).mockResolvedValue({ status: 'success' })
116
- const { app, authUsersCollection, resetCollection, resetCallHandlerRef } = buildApp()
123
+ ; (GenerateContext as jest.Mock).mockResolvedValue({ status: 'success' })
124
+ const { app, authUsersCollection, resetCollection, routeHandlerRef } = buildApp()
117
125
 
118
126
  await localUserPassController(app as never)
119
127
 
120
128
  const res = { status: jest.fn() }
121
- const result = await resetCallHandlerRef()?.(
129
+ const result = await routeHandlerRef('/reset/call')?.(
122
130
  {
123
131
  body: { email: 'john@doe.com', password: 'new-secret', arguments: ['extra'] },
124
132
  ip: '127.0.0.1'
@@ -150,13 +158,13 @@ describe('localUserPassController reset call', () => {
150
158
  })
151
159
 
152
160
  it('returns pending without changing the password when the custom reset function returns pending', async () => {
153
- ;(GenerateContext as jest.Mock).mockResolvedValue({ status: 'pending' })
154
- const { app, authUsersCollection, resetCollection, resetCallHandlerRef } = buildApp()
161
+ ; (GenerateContext as jest.Mock).mockResolvedValue({ status: 'pending' })
162
+ const { app, authUsersCollection, resetCollection, routeHandlerRef } = buildApp()
155
163
 
156
164
  await localUserPassController(app as never)
157
165
 
158
166
  const res = { status: jest.fn() }
159
- const result = await resetCallHandlerRef()?.(
167
+ const result = await routeHandlerRef('/reset/call')?.(
160
168
  {
161
169
  body: { email: 'john@doe.com', password: 'new-secret' },
162
170
  ip: '127.0.0.1'
@@ -175,15 +183,15 @@ describe('localUserPassController reset call', () => {
175
183
  })
176
184
 
177
185
  it('rejects the request when the custom reset function returns fail', async () => {
178
- ;(GenerateContext as jest.Mock).mockResolvedValue({ status: 'fail' })
179
- const { app, authUsersCollection, resetCollection, resetCallHandlerRef } = buildApp()
186
+ ; (GenerateContext as jest.Mock).mockResolvedValue({ status: 'fail' })
187
+ const { app, authUsersCollection, resetCollection, routeHandlerRef } = buildApp()
180
188
 
181
189
  await localUserPassController(app as never)
182
190
 
183
191
  const res = { status: jest.fn() }
184
192
 
185
193
  await expect(
186
- resetCallHandlerRef()?.(
194
+ routeHandlerRef('/reset/call')?.(
187
195
  {
188
196
  body: { email: 'john@doe.com', password: 'new-secret' },
189
197
  ip: '127.0.0.1'
@@ -197,4 +205,44 @@ describe('localUserPassController reset call', () => {
197
205
  expect(resetCollection.deleteOne).not.toHaveBeenCalled()
198
206
  expect(res.status).not.toHaveBeenCalled()
199
207
  })
208
+
209
+ it('resends the confirmation email for local-userpass users', async () => {
210
+ ; (GenerateContext as jest.Mock).mockResolvedValue({ status: 'pending' })
211
+ const { app, authUsersCollection, routeHandlerRef } = buildApp()
212
+
213
+ await localUserPassController(app as never)
214
+
215
+ const res = { status: jest.fn() }
216
+ const result = await routeHandlerRef('/confirm/send')?.(
217
+ {
218
+ body: { email: 'John@Doe.com' },
219
+ ip: '127.0.0.1'
220
+ },
221
+ res
222
+ )
223
+
224
+ expect(GenerateContext).toHaveBeenCalledWith(expect.objectContaining({
225
+ args: [
226
+ {
227
+ token: 'generated-token',
228
+ tokenId: 'generated-token',
229
+ username: 'john@doe.com'
230
+ }
231
+ ],
232
+ functionName: 'customConfirm',
233
+ runAsSystem: true
234
+ }))
235
+ expect(authUsersCollection.updateOne).toHaveBeenCalledWith(
236
+ { email: 'john@doe.com' },
237
+ {
238
+ $set: {
239
+ status: 'pending',
240
+ confirmationToken: 'generated-token',
241
+ confirmationTokenId: 'generated-token'
242
+ }
243
+ }
244
+ )
245
+ expect(res.status).toHaveBeenCalledWith(202)
246
+ expect(result).toEqual({ status: 'ok' })
247
+ })
200
248
  })
@@ -15,6 +15,7 @@ import {
15
15
  AUTH_ENDPOINTS,
16
16
  AUTH_ERRORS,
17
17
  CONFIRM_RESET_SCHEMA,
18
+ CONFIRM_SEND_SCHEMA,
18
19
  CONFIRM_USER_SCHEMA,
19
20
  LOGIN_SCHEMA,
20
21
  REGISTRATION_SCHEMA,
@@ -23,12 +24,14 @@ import {
23
24
  } from '../../utils'
24
25
  import {
25
26
  ConfirmResetPasswordDto,
27
+ ConfirmUserSendDto,
26
28
  ConfirmUserDto,
27
29
  LoginDto,
28
30
  RegistrationDto,
29
31
  ResetPasswordCallDto,
30
32
  ResetPasswordSendDto
31
33
  } from './dtos'
34
+ import { sendConfirmationRequest } from '../../../shared/handleUserRegistration'
32
35
 
33
36
  const rateLimitStore = new Map<string, number[]>()
34
37
 
@@ -267,6 +270,29 @@ export async function localUserPassController(app: FastifyInstance) {
267
270
  }
268
271
  )
269
272
 
273
+ app.post<ConfirmUserSendDto>(
274
+ AUTH_ENDPOINTS.CONFIRM_SEND,
275
+ {
276
+ schema: CONFIRM_SEND_SCHEMA
277
+ },
278
+ async (req, res) => {
279
+ const localUserpassProvider = resolveLocalUserpassProvider()
280
+ if (!localUserpassProvider || localUserpassProvider.disabled) {
281
+ throw new Error('Local userpass authentication disabled')
282
+ }
283
+ const key = `confirm-send:${req.ip}`
284
+ if (isRateLimited(key, resetMaxAttempts, rateLimitWindowMs)) {
285
+ res.status(429).send({ message: 'Too many requests' })
286
+ return
287
+ }
288
+
289
+ await sendConfirmationRequest(app, req.body.email)
290
+
291
+ res.status(202)
292
+ return { status: 'ok' }
293
+ }
294
+ )
295
+
270
296
  /**
271
297
  * Endpoint for user login.
272
298
  *
@@ -308,8 +334,8 @@ export async function localUserPassController(app: FastifyInstance) {
308
334
  const user =
309
335
  user_id_field && userCollection
310
336
  ? await customUserDb
311
- .collection(userCollection)
312
- .findOne({ [user_id_field]: authUser._id.toString() })
337
+ .collection(userCollection)
338
+ .findOne({ [user_id_field]: authUser._id.toString() })
313
339
  : {}
314
340
  delete authUser?.password
315
341
 
@@ -61,3 +61,9 @@ export interface ConfirmUserDto {
61
61
  tokenId: string
62
62
  }
63
63
  }
64
+
65
+ export interface ConfirmUserSendDto {
66
+ Body: {
67
+ email: string
68
+ }
69
+ }
package/src/auth/utils.ts CHANGED
@@ -81,6 +81,8 @@ export const CONFIRM_USER_SCHEMA = {
81
81
  }
82
82
  }
83
83
 
84
+ export const CONFIRM_SEND_SCHEMA = RESET_SEND_SCHEMA
85
+
84
86
  export const RESET_SCHEMA = RESET_SEND_SCHEMA
85
87
 
86
88
  export const REGISTRATION_SCHEMA = {
@@ -104,6 +106,7 @@ export enum AUTH_ENDPOINTS {
104
106
  LOGIN = '/login',
105
107
  REGISTRATION = '/register',
106
108
  CONFIRM = '/confirm',
109
+ CONFIRM_SEND = '/confirm/send',
107
110
  PROFILE = '/profile',
108
111
  SESSION = '/session',
109
112
  RESET = '/reset/send',
@@ -1,3 +1,4 @@
1
+ import type { FastifyInstance } from "fastify/types/instance"
1
2
  import { AUTH_CONFIG, AUTH_DB_NAME } from "../constants"
2
3
  import { emitServiceEvent } from "../services/monitoring"
3
4
  import { StateManager } from "../state"
@@ -5,6 +6,108 @@ import { GenerateContext } from "../utils/context"
5
6
  import { generateToken, hashPassword } from "../utils/crypto"
6
7
  import { HandleUserRegistration } from "./models/handleUserRegistration.model"
7
8
 
9
+ type ConfirmationResult = { status?: 'success' | 'pending' | 'fail' }
10
+
11
+ export const sendConfirmationRequest = async (
12
+ app: FastifyInstance,
13
+ email: string
14
+ ) => {
15
+ const { authCollection } = AUTH_CONFIG
16
+ const localUserpassConfig = AUTH_CONFIG.localUserpassConfig
17
+ const autoConfirm = localUserpassConfig?.autoConfirm === true
18
+ const runConfirmationFunction = localUserpassConfig?.runConfirmationFunction === true
19
+ const confirmationFunctionName = localUserpassConfig?.confirmationFunctionName
20
+ const normalizedEmail = email.toLowerCase()
21
+ const mongo = app?.mongo
22
+ const db = mongo.client.db(AUTH_DB_NAME)
23
+ const authUser = await db?.collection(authCollection!).findOne({ email: normalizedEmail }) as {
24
+ status?: string
25
+ } | null
26
+
27
+ if (!authUser) {
28
+ return null
29
+ }
30
+
31
+ if (authUser.status === 'confirmed' || autoConfirm) {
32
+ return { status: 'success' as const }
33
+ }
34
+
35
+ if (!runConfirmationFunction) {
36
+ throw new Error('Missing confirmation function')
37
+ }
38
+
39
+ if (!confirmationFunctionName) {
40
+ throw new Error('Missing confirmation function name')
41
+ }
42
+
43
+ const functionsList = StateManager.select('functions')
44
+ const services = StateManager.select('services')
45
+ const confirmationFunction = functionsList[confirmationFunctionName]
46
+ if (!confirmationFunction) {
47
+ throw new Error(`Confirmation function not found: ${confirmationFunctionName}`)
48
+ }
49
+
50
+ const token = generateToken()
51
+ const tokenId = generateToken()
52
+ await db?.collection(authCollection!).updateOne(
53
+ { email: normalizedEmail },
54
+ {
55
+ $set: {
56
+ status: 'pending',
57
+ confirmationToken: token,
58
+ confirmationTokenId: tokenId
59
+ }
60
+ }
61
+ )
62
+
63
+ let confirmationStatus: ConfirmationResult['status'] = 'fail'
64
+ try {
65
+ const response = await GenerateContext({
66
+ args: [{
67
+ token,
68
+ tokenId,
69
+ username: normalizedEmail
70
+ }],
71
+ app,
72
+ rules: {},
73
+ user: {},
74
+ currentFunction: confirmationFunction,
75
+ functionName: confirmationFunctionName,
76
+ functionsList,
77
+ services,
78
+ runAsSystem: true
79
+ }) as ConfirmationResult
80
+ confirmationStatus = response?.status ?? 'fail'
81
+ } catch {
82
+ confirmationStatus = 'fail'
83
+ }
84
+
85
+ if (confirmationStatus === 'success') {
86
+ await db?.collection(authCollection!).updateOne(
87
+ { email: normalizedEmail },
88
+ {
89
+ $set: { status: 'confirmed' },
90
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
91
+ }
92
+ )
93
+ return { status: 'success' as const }
94
+ }
95
+
96
+ if (confirmationStatus === 'pending') {
97
+ return { status: 'pending' as const }
98
+ }
99
+
100
+ await db?.collection(authCollection!).updateOne(
101
+ { email: normalizedEmail },
102
+ {
103
+ $set: { status: 'failed' },
104
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
105
+ }
106
+ )
107
+
108
+ return { status: 'fail' as const }
109
+ }
110
+
8
111
  /**
9
112
  * Register user
10
113
  *
@@ -32,8 +135,6 @@ const handleUserRegistration: HandleUserRegistration = (app, opt) => async ({ em
32
135
  const { authCollection } = AUTH_CONFIG
33
136
  const localUserpassConfig = AUTH_CONFIG.localUserpassConfig
34
137
  const autoConfirm = localUserpassConfig?.autoConfirm === true
35
- const runConfirmationFunction = localUserpassConfig?.runConfirmationFunction === true
36
- const confirmationFunctionName = localUserpassConfig?.confirmationFunctionName
37
138
  const mongo = app?.mongo
38
139
  const db = mongo.client.db(AUTH_DB_NAME)
39
140
  const hashedPassword = await hashPassword(password)
@@ -79,78 +180,7 @@ const handleUserRegistration: HandleUserRegistration = (app, opt) => async ({ em
79
180
  return result
80
181
  }
81
182
 
82
- if (!runConfirmationFunction) {
83
- throw new Error('Missing confirmation function')
84
- }
85
-
86
- if (!confirmationFunctionName) {
87
- throw new Error('Missing confirmation function name')
88
- }
89
-
90
- const functionsList = StateManager.select('functions')
91
- const services = StateManager.select('services')
92
- const confirmationFunction = functionsList[confirmationFunctionName]
93
- if (!confirmationFunction) {
94
- throw new Error(`Confirmation function not found: ${confirmationFunctionName}`)
95
- }
96
-
97
- const token = generateToken()
98
- const tokenId = generateToken()
99
- await db?.collection(authCollection!).updateOne(
100
- { _id: result.insertedId },
101
- {
102
- $set: {
103
- confirmationToken: token,
104
- confirmationTokenId: tokenId
105
- }
106
- }
107
- )
108
-
109
- type ConfirmationResult = { status?: 'success' | 'pending' | 'fail' }
110
- let confirmationStatus: ConfirmationResult['status'] = 'fail'
111
- try {
112
- const response = await GenerateContext({
113
- args: [{
114
- token,
115
- tokenId,
116
- username: email
117
- }],
118
- app,
119
- rules: {},
120
- user: {},
121
- currentFunction: confirmationFunction,
122
- functionName: confirmationFunctionName,
123
- functionsList,
124
- services,
125
- runAsSystem: true
126
- }) as ConfirmationResult
127
- confirmationStatus = response?.status ?? 'fail'
128
- } catch {
129
- confirmationStatus = 'fail'
130
- }
131
-
132
- if (confirmationStatus === 'success') {
133
- await db?.collection(authCollection!).updateOne(
134
- { _id: result.insertedId },
135
- {
136
- $set: { status: 'confirmed' },
137
- $unset: { confirmationToken: '', confirmationTokenId: '' }
138
- }
139
- )
140
- return result
141
- }
142
-
143
- if (confirmationStatus === 'pending') {
144
- return result
145
- }
146
-
147
- await db?.collection(authCollection!).updateOne(
148
- { _id: result.insertedId },
149
- {
150
- $set: { status: 'failed' },
151
- $unset: { confirmationToken: '', confirmationTokenId: '' }
152
- }
153
- )
183
+ await sendConfirmationRequest(app, email)
154
184
  return result
155
185
  } catch (error) {
156
186
  emitServiceEvent({