@flowerforce/flowerbase 1.2.1-beta.11 → 1.2.1-beta.13

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;AAmCzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBA+RjE"}
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;AAqCzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBAgUjE"}
@@ -109,6 +109,38 @@ function localUserPassController(app) {
109
109
  res === null || res === void 0 ? void 0 : res.status(201);
110
110
  return { userId: result.insertedId.toString() };
111
111
  }));
112
+ /**
113
+ * Endpoint for confirming a user registration.
114
+ *
115
+ * @route {POST} /confirm
116
+ * @param {ConfirmUserDto} req - The request object with confirmation data.
117
+ * @returns {Promise<Object>} A promise resolving with confirmation status.
118
+ */
119
+ app.post(utils_1.AUTH_ENDPOINTS.CONFIRM, {
120
+ schema: utils_1.CONFIRM_USER_SCHEMA
121
+ }, (req, res) => __awaiter(this, void 0, void 0, function* () {
122
+ const key = `confirm:${req.ip}`;
123
+ if (isRateLimited(key, resetMaxAttempts, rateLimitWindowMs)) {
124
+ res.status(429).send({ message: 'Too many requests' });
125
+ return;
126
+ }
127
+ const existing = yield db.collection(authCollection).findOne({
128
+ confirmationToken: req.body.token,
129
+ confirmationTokenId: req.body.tokenId
130
+ });
131
+ if (!existing) {
132
+ res.status(500);
133
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_TOKEN);
134
+ }
135
+ if (existing.status !== 'confirmed') {
136
+ yield db.collection(authCollection).updateOne({ _id: existing._id }, {
137
+ $set: { status: 'confirmed' },
138
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
139
+ });
140
+ }
141
+ res.status(200);
142
+ return { status: 'confirmed' };
143
+ }));
112
144
  /**
113
145
  * Endpoint for user login.
114
146
  *
@@ -142,17 +174,8 @@ function localUserPassController(app) {
142
174
  : {};
143
175
  authUser === null || authUser === void 0 ? true : delete authUser.password;
144
176
  const userWithCustomData = Object.assign(Object.assign({}, authUser), { user_data: Object.assign(Object.assign({}, (user || {})), { _id: authUser._id }), data: { email: authUser.email }, id: authUser._id.toString() });
145
- if (authUser && authUser.status === 'pending') {
146
- try {
147
- yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ _id: authUser._id }, {
148
- $set: {
149
- status: 'confirmed'
150
- }
151
- }));
152
- }
153
- catch (error) {
154
- console.log('>>> 🚀 ~ localUserPassController ~ error:', error);
155
- }
177
+ if (authUser && authUser.status !== 'confirmed') {
178
+ throw new Error(utils_1.AUTH_ERRORS.USER_NOT_CONFIRMED);
156
179
  }
157
180
  const refreshToken = this.createRefreshToken(userWithCustomData);
158
181
  const refreshTokenHash = (0, crypto_1.hashToken)(refreshToken);
@@ -41,4 +41,10 @@ export interface ConfirmResetPasswordDto {
41
41
  password: string;
42
42
  };
43
43
  }
44
+ export interface ConfirmUserDto {
45
+ Body: {
46
+ token: string;
47
+ tokenId: string;
48
+ };
49
+ }
44
50
  //# 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,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAAA;CAC1C;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"}
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,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAAA;CAC1C;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"}
@@ -72,6 +72,20 @@ export declare const CONFIRM_RESET_SCHEMA: {
72
72
  required: string[];
73
73
  };
74
74
  };
75
+ export declare const CONFIRM_USER_SCHEMA: {
76
+ body: {
77
+ type: string;
78
+ properties: {
79
+ token: {
80
+ type: string;
81
+ };
82
+ tokenId: {
83
+ type: string;
84
+ };
85
+ };
86
+ required: string[];
87
+ };
88
+ };
75
89
  export declare const RESET_SCHEMA: {
76
90
  body: {
77
91
  type: string;
@@ -108,6 +122,7 @@ export declare const REGISTRATION_SCHEMA: {
108
122
  export declare enum AUTH_ENDPOINTS {
109
123
  LOGIN = "/login",
110
124
  REGISTRATION = "/register",
125
+ CONFIRM = "/confirm",
111
126
  PROFILE = "/profile",
112
127
  SESSION = "/session",
113
128
  RESET = "/reset/send",
@@ -119,7 +134,8 @@ export declare enum AUTH_ERRORS {
119
134
  INVALID_CREDENTIALS = "Invalid credentials",
120
135
  INVALID_TOKEN = "Invalid refresh token provided",
121
136
  INVALID_RESET_PARAMS = "Invalid token or tokenId provided",
122
- MISSING_RESET_FUNCTION = "Missing reset function"
137
+ MISSING_RESET_FUNCTION = "Missing reset function",
138
+ USER_NOT_CONFIRMED = "User not confirmed"
123
139
  }
124
140
  export interface AuthConfig {
125
141
  auth_collection?: string;
@@ -148,6 +164,7 @@ interface CustomFunction {
148
164
  }
149
165
  export interface Config {
150
166
  autoConfirm: boolean;
167
+ confirmationFunctionName?: string;
151
168
  resetFunctionName: string;
152
169
  resetPasswordUrl: string;
153
170
  runConfirmationFunction: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/auth/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;CAcxB,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;CAa7B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;CAe7B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;CAUhC,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;CAAoB,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;CAc/B,CAAA;AAED,oBAAY,cAAc;IACxB,KAAK,WAAW;IAChB,YAAY,cAAc;IAC1B,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;CAClD;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;IAC/B,iBAAiB,EAAE,cAAc,CAAA;CAClC;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,MAAM;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,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,UAGjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAGrC,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,YAAY;;;;;;;;;;;;;;;;;;CAcxB,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;CAa7B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;CAe7B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;CAUhC,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;CAS/B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;CAAoB,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;CAc/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,kBAAkB,uBAAuB;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;IAC/B,iBAAiB,EAAE,cAAc,CAAA;CAClC;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,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,UAGjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAGrC,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_RESET_SCHEMA = exports.RESET_CALL_SCHEMA = exports.RESET_SEND_SCHEMA = exports.LOGIN_SCHEMA = void 0;
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 = 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"));
@@ -64,6 +64,16 @@ exports.CONFIRM_RESET_SCHEMA = {
64
64
  required: ['password', 'token', 'tokenId']
65
65
  }
66
66
  };
67
+ exports.CONFIRM_USER_SCHEMA = {
68
+ body: {
69
+ type: 'object',
70
+ properties: {
71
+ token: { type: 'string' },
72
+ tokenId: { type: 'string' }
73
+ },
74
+ required: ['token', 'tokenId']
75
+ }
76
+ };
67
77
  exports.RESET_SCHEMA = exports.RESET_SEND_SCHEMA;
68
78
  exports.REGISTRATION_SCHEMA = {
69
79
  body: {
@@ -84,6 +94,7 @@ var AUTH_ENDPOINTS;
84
94
  (function (AUTH_ENDPOINTS) {
85
95
  AUTH_ENDPOINTS["LOGIN"] = "/login";
86
96
  AUTH_ENDPOINTS["REGISTRATION"] = "/register";
97
+ AUTH_ENDPOINTS["CONFIRM"] = "/confirm";
87
98
  AUTH_ENDPOINTS["PROFILE"] = "/profile";
88
99
  AUTH_ENDPOINTS["SESSION"] = "/session";
89
100
  AUTH_ENDPOINTS["RESET"] = "/reset/send";
@@ -97,6 +108,7 @@ var AUTH_ERRORS;
97
108
  AUTH_ERRORS["INVALID_TOKEN"] = "Invalid refresh token provided";
98
109
  AUTH_ERRORS["INVALID_RESET_PARAMS"] = "Invalid token or tokenId provided";
99
110
  AUTH_ERRORS["MISSING_RESET_FUNCTION"] = "Missing reset function";
111
+ AUTH_ERRORS["USER_NOT_CONFIRMED"] = "User not confirmed";
100
112
  })(AUTH_ERRORS || (exports.AUTH_ERRORS = AUTH_ERRORS = {}));
101
113
  const resolveAppPath = () => { var _a, _b, _c; return (_c = (_a = process.env.FLOWERBASE_APP_PATH) !== null && _a !== void 0 ? _a : (_b = require.main) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : process.cwd(); };
102
114
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAA;AAG/C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAU,0CAIpC,sBAAsB,kBA+DxB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAA;AAG/C;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAU,0CAIpC,sBAAsB,kBAgExB,CAAA"}
@@ -48,6 +48,7 @@ const activateTriggers = (_a) => __awaiter(void 0, [_a], void 0, function* ({ fa
48
48
  type: 'AUTHENTICATION',
49
49
  disabled: false,
50
50
  config: {
51
+ isAutoTrigger: true,
51
52
  collection: (_e = constants_1.AUTH_CONFIG.authCollection) !== null && _e !== void 0 ? _e : 'auth_users',
52
53
  database: constants_1.DB_NAME,
53
54
  full_document: true,
@@ -19,6 +19,7 @@ type Config = {
19
19
  database: string;
20
20
  full_document: boolean;
21
21
  full_document_before_change: boolean;
22
+ isAutoTrigger?: boolean;
22
23
  match: Record<string, unknown>;
23
24
  operation_types: string[];
24
25
  project: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAE5D,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE;QAChB,QAAQ,EAAE;YACR,MAAM,EAAE;gBACN,aAAa,EAAE,MAAM,CAAA;aACtB,CAAA;SACF,CAAA;KACF,CAAA;CACF;AAED,KAAK,MAAM,GAAG;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,OAAO,CAAA;IACtB,2BAA2B,EAAE,OAAO,CAAA;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,EAAE,OAAO,CAAA;IAC5B,sBAAsB,EAAE,OAAO,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,gBAAgB,CAAA;AACrE,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,EAAE,CAAA;AAE/D,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,QAAQ,CAAA;IACxB,GAAG,EAAE,eAAe,CAAA;IACpB,QAAQ,EAAE,QAAQ,CAAA;IAClB,aAAa,EAAE,SAAS,CAAA;CACzB,CAAA"}
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAE5D,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE;QAChB,QAAQ,EAAE;YACR,MAAM,EAAE;gBACN,aAAa,EAAE,MAAM,CAAA;aACtB,CAAA;SACF,CAAA;KACF,CAAA;CACF;AAED,KAAK,MAAM,GAAG;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,OAAO,CAAA;IACtB,2BAA2B,EAAE,OAAO,CAAA;IACpC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,EAAE,OAAO,CAAA;IAC5B,sBAAsB,EAAE,OAAO,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,gBAAgB,CAAA;AACrE,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,EAAE,CAAA;AAE/D,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,QAAQ,CAAA;IACxB,GAAG,EAAE,eAAe,CAAA;IACpB,QAAQ,EAAE,QAAQ,CAAA;IAClB,aAAa,EAAE,SAAS,CAAA;CACzB,CAAA"}
@@ -119,7 +119,7 @@ const handleCronTrigger = (_a) => __awaiter(void 0, [_a], void 0, function* ({ c
119
119
  });
120
120
  const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, function* ({ config, triggerHandler, functionsList, services, app }) {
121
121
  var _b;
122
- const { database } = config;
122
+ const { database, isAutoTrigger } = config;
123
123
  const authCollection = (_b = constants_1.AUTH_CONFIG.authCollection) !== null && _b !== void 0 ? _b : 'auth_users';
124
124
  const collection = app.mongo.client.db(database || constants_1.DB_NAME).collection(authCollection);
125
125
  const pipeline = [
@@ -186,13 +186,12 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
186
186
  delete document.password;
187
187
  const currentUser = Object.assign({}, document);
188
188
  delete currentUser.password;
189
+ const userData = Object.assign(Object.assign({}, currentUser), { id: currentUser._id.toString(), data: {
190
+ _id: currentUser._id.toString(),
191
+ email: currentUser.email
192
+ } });
189
193
  yield (0, context_1.GenerateContext)({
190
- args: [{
191
- user: Object.assign(Object.assign({}, currentUser), { id: currentUser._id.toString(), data: {
192
- _id: currentUser._id.toString(),
193
- email: currentUser.email
194
- } })
195
- }],
194
+ args: isAutoTrigger ? [userData] : [Object.assign({ user: userData }, change)],
196
195
  app,
197
196
  rules: state_1.StateManager.select("rules"),
198
197
  user: {}, // TODO from currentUser ??
@@ -1 +1 @@
1
- {"version":3,"file":"handleUserRegistration.d.ts","sourceRoot":"","sources":["../../src/shared/handleUserRegistration.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAE9E;;;;;;GAMG;AACH,QAAA,MAAM,sBAAsB,EAAE,sBAoD7B,CAAA;AAED,eAAe,sBAAsB,CAAA"}
1
+ {"version":3,"file":"handleUserRegistration.d.ts","sourceRoot":"","sources":["../../src/shared/handleUserRegistration.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAE9E;;;;;;GAMG;AACH,QAAA,MAAM,sBAAsB,EAAE,sBAkI7B,CAAA;AAED,eAAe,sBAAsB,CAAA"}
@@ -10,6 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const constants_1 = require("../constants");
13
+ const state_1 = require("../state");
14
+ const context_1 = require("../utils/context");
13
15
  const crypto_1 = require("../utils/crypto");
14
16
  /**
15
17
  * Register user
@@ -25,7 +27,10 @@ const handleUserRegistration = (app, opt) => (_a) => __awaiter(void 0, [_a], voi
25
27
  throw new Error('only run_as_system');
26
28
  }
27
29
  const { authCollection } = constants_1.AUTH_CONFIG;
28
- const autoConfirm = ((_b = constants_1.AUTH_CONFIG.localUserpassConfig) === null || _b === void 0 ? void 0 : _b.autoConfirm) === true;
30
+ const localUserpassConfig = constants_1.AUTH_CONFIG.localUserpassConfig;
31
+ const autoConfirm = (localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.autoConfirm) === true;
32
+ const runConfirmationFunction = (localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.runConfirmationFunction) === true;
33
+ const confirmationFunctionName = localUserpassConfig === null || localUserpassConfig === void 0 ? void 0 : localUserpassConfig.confirmationFunctionName;
29
34
  const mongo = app === null || app === void 0 ? void 0 : app.mongo;
30
35
  const db = mongo.client.db(constants_1.DB_NAME);
31
36
  const hashedPassword = yield (0, crypto_1.hashPassword)(password);
@@ -60,6 +65,64 @@ const handleUserRegistration = (app, opt) => (_a) => __awaiter(void 0, [_a], voi
60
65
  ]
61
66
  }
62
67
  }));
68
+ if (!(result === null || result === void 0 ? void 0 : result.insertedId) || skipUserCheck || autoConfirm) {
69
+ return result;
70
+ }
71
+ if (!runConfirmationFunction) {
72
+ throw new Error('Missing confirmation function');
73
+ }
74
+ if (!confirmationFunctionName) {
75
+ throw new Error('Missing confirmation function name');
76
+ }
77
+ const functionsList = state_1.StateManager.select('functions');
78
+ const services = state_1.StateManager.select('services');
79
+ const confirmationFunction = functionsList[confirmationFunctionName];
80
+ if (!confirmationFunction) {
81
+ throw new Error(`Confirmation function not found: ${confirmationFunctionName}`);
82
+ }
83
+ const token = (0, crypto_1.generateToken)();
84
+ const tokenId = (0, crypto_1.generateToken)();
85
+ yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ _id: result.insertedId }, {
86
+ $set: {
87
+ confirmationToken: token,
88
+ confirmationTokenId: tokenId
89
+ }
90
+ }));
91
+ let confirmationStatus = 'fail';
92
+ try {
93
+ const response = yield (0, context_1.GenerateContext)({
94
+ args: [{
95
+ token,
96
+ tokenId,
97
+ username: email
98
+ }],
99
+ app,
100
+ rules: {},
101
+ user: {},
102
+ currentFunction: confirmationFunction,
103
+ functionsList,
104
+ services,
105
+ runAsSystem: true
106
+ });
107
+ confirmationStatus = (_b = response === null || response === void 0 ? void 0 : response.status) !== null && _b !== void 0 ? _b : 'fail';
108
+ }
109
+ catch (_c) {
110
+ confirmationStatus = 'fail';
111
+ }
112
+ if (confirmationStatus === 'success') {
113
+ yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ _id: result.insertedId }, {
114
+ $set: { status: 'confirmed' },
115
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
116
+ }));
117
+ return result;
118
+ }
119
+ if (confirmationStatus === 'pending') {
120
+ return result;
121
+ }
122
+ yield (db === null || db === void 0 ? void 0 : db.collection(authCollection).updateOne({ _id: result.insertedId }, {
123
+ $set: { status: 'failed' },
124
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
125
+ }));
63
126
  return result;
64
127
  });
65
128
  exports.default = handleUserRegistration;
@@ -23,10 +23,10 @@ export declare const generateContextData: ({ user, services, app, rules, current
23
23
  method?: string | undefined;
24
24
  url?: string | undefined;
25
25
  host?: string | undefined;
26
- id?: string | undefined;
27
26
  ips?: string[];
28
27
  hostname?: string | undefined;
29
28
  ip?: string | undefined;
29
+ id?: string | undefined;
30
30
  };
31
31
  user: unknown;
32
32
  environment: {
@@ -69,16 +69,16 @@ export declare const generateContextData: ({ user, services, app, rules, current
69
69
  message: string;
70
70
  };
71
71
  } | import("undici").Dispatcher.ResponseData<T>>;
72
- } | {
73
- emailPasswordAuth: {
74
- registerUser: ReturnType<import("../../shared/models/handleUserRegistration.model").HandleUserRegistration>;
75
- };
76
72
  } | {
77
73
  lambda: (region: string) => import("aws-sdk").Lambda & {
78
74
  Invoke: (...args: Parameters<import("aws-sdk").Lambda["invoke"]>) => Promise<import("aws-sdk/lib/request").PromiseResult<import("aws-sdk/clients/lambda").InvocationResponse, import("aws-sdk").AWSError>>;
79
75
  InvokeAsync: import("aws-sdk").Lambda["invokeAsync"];
80
76
  };
81
77
  s3: (region: string) => import("aws-sdk").S3;
78
+ } | {
79
+ emailPasswordAuth: {
80
+ registerUser: ReturnType<import("../../shared/models/handleUserRegistration.model").HandleUserRegistration>;
81
+ };
82
82
  } | undefined;
83
83
  };
84
84
  functions: {
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/context/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAEvD;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAAI,0FASjC,yBAAyB;;;uBAGT,SAAS;yBAGP,SAAS;;;;;;;;;;;;;;;;;;uBAcb,MAAM;;;+BAGE,MAAM,OAAO,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAlCG,GAE3C;;;;;;;4BAiDgB,MAAM,OAAO,aAAa,WAAW,SAAS;;;CAclE,CAAA"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/context/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAEvD;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAAI,0FASjC,yBAAyB;;;uBAGT,SAAS;yBAGP,SAAS;;;;;;;;;;;;;;;;;;uBAcb,MAAM;;;+BAGE,MAAM,OAAO,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAlCG,GAE3C;;;;;;;;;;;4BAiDgB,MAAM,OAAO,aAAa,WAAW,SAAS;;;CAclE,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowerforce/flowerbase",
3
- "version": "1.2.1-beta.11",
3
+ "version": "1.2.1-beta.13",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  import { FastifyInstance } from 'fastify'
2
+ import { ObjectId } from 'mongodb'
2
3
  import { AUTH_CONFIG, DB_NAME, DEFAULT_CONFIG } from '../../../constants'
3
- import { services } from '../../../services'
4
4
  import handleUserRegistration from '../../../shared/handleUserRegistration'
5
5
  import { PROVIDER } from '../../../shared/models/handleUserRegistration.model'
6
6
  import { StateManager } from '../../../state'
@@ -10,6 +10,7 @@ import {
10
10
  AUTH_ENDPOINTS,
11
11
  AUTH_ERRORS,
12
12
  CONFIRM_RESET_SCHEMA,
13
+ CONFIRM_USER_SCHEMA,
13
14
  LOGIN_SCHEMA,
14
15
  REGISTRATION_SCHEMA,
15
16
  RESET_CALL_SCHEMA,
@@ -17,6 +18,7 @@ import {
17
18
  } from '../../utils'
18
19
  import {
19
20
  ConfirmResetPasswordDto,
21
+ ConfirmUserDto,
20
22
  LoginDto,
21
23
  RegistrationDto,
22
24
  ResetPasswordCallDto,
@@ -142,6 +144,50 @@ export async function localUserPassController(app: FastifyInstance) {
142
144
  }
143
145
  )
144
146
 
147
+ /**
148
+ * Endpoint for confirming a user registration.
149
+ *
150
+ * @route {POST} /confirm
151
+ * @param {ConfirmUserDto} req - The request object with confirmation data.
152
+ * @returns {Promise<Object>} A promise resolving with confirmation status.
153
+ */
154
+ app.post<ConfirmUserDto>(
155
+ AUTH_ENDPOINTS.CONFIRM,
156
+ {
157
+ schema: CONFIRM_USER_SCHEMA
158
+ },
159
+ async (req, res) => {
160
+ const key = `confirm:${req.ip}`
161
+ if (isRateLimited(key, resetMaxAttempts, rateLimitWindowMs)) {
162
+ res.status(429).send({ message: 'Too many requests' })
163
+ return
164
+ }
165
+
166
+ const existing = await db.collection(authCollection!).findOne({
167
+ confirmationToken: req.body.token,
168
+ confirmationTokenId: req.body.tokenId
169
+ }) as { _id: ObjectId; status?: string } | null
170
+
171
+ if (!existing) {
172
+ res.status(500)
173
+ throw new Error(AUTH_ERRORS.INVALID_TOKEN)
174
+ }
175
+
176
+ if (existing.status !== 'confirmed') {
177
+ await db.collection(authCollection!).updateOne(
178
+ { _id: existing._id },
179
+ {
180
+ $set: { status: 'confirmed' },
181
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
182
+ }
183
+ )
184
+ }
185
+
186
+ res.status(200)
187
+ return { status: 'confirmed' }
188
+ }
189
+ )
190
+
145
191
  /**
146
192
  * Endpoint for user login.
147
193
  *
@@ -192,19 +238,8 @@ export async function localUserPassController(app: FastifyInstance) {
192
238
  id: authUser._id.toString()
193
239
  }
194
240
 
195
- if (authUser && authUser.status === 'pending') {
196
- try {
197
- await db?.collection(authCollection!).updateOne(
198
- { _id: authUser._id },
199
- {
200
- $set: {
201
- status: 'confirmed'
202
- }
203
- }
204
- )
205
- } catch (error) {
206
- console.log('>>> 🚀 ~ localUserPassController ~ error:', error)
207
- }
241
+ if (authUser && authUser.status !== 'confirmed') {
242
+ throw new Error(AUTH_ERRORS.USER_NOT_CONFIRMED)
208
243
  }
209
244
 
210
245
  const refreshToken = this.createRefreshToken(userWithCustomData)
@@ -49,3 +49,10 @@ export interface ConfirmResetPasswordDto {
49
49
  password: string
50
50
  }
51
51
  }
52
+
53
+ export interface ConfirmUserDto {
54
+ Body: {
55
+ token: string
56
+ tokenId: string
57
+ }
58
+ }
package/src/auth/utils.ts CHANGED
@@ -64,6 +64,17 @@ export const CONFIRM_RESET_SCHEMA = {
64
64
  }
65
65
  }
66
66
 
67
+ export const CONFIRM_USER_SCHEMA = {
68
+ body: {
69
+ type: 'object',
70
+ properties: {
71
+ token: { type: 'string' },
72
+ tokenId: { type: 'string' }
73
+ },
74
+ required: ['token', 'tokenId']
75
+ }
76
+ }
77
+
67
78
  export const RESET_SCHEMA = RESET_SEND_SCHEMA
68
79
 
69
80
  export const REGISTRATION_SCHEMA = {
@@ -85,6 +96,7 @@ export const REGISTRATION_SCHEMA = {
85
96
  export enum AUTH_ENDPOINTS {
86
97
  LOGIN = '/login',
87
98
  REGISTRATION = '/register',
99
+ CONFIRM = '/confirm',
88
100
  PROFILE = '/profile',
89
101
  SESSION = '/session',
90
102
  RESET = '/reset/send',
@@ -97,7 +109,8 @@ export enum AUTH_ERRORS {
97
109
  INVALID_CREDENTIALS = 'Invalid credentials',
98
110
  INVALID_TOKEN = 'Invalid refresh token provided',
99
111
  INVALID_RESET_PARAMS = 'Invalid token or tokenId provided',
100
- MISSING_RESET_FUNCTION = 'Missing reset function'
112
+ MISSING_RESET_FUNCTION = 'Missing reset function',
113
+ USER_NOT_CONFIRMED = 'User not confirmed'
101
114
  }
102
115
 
103
116
  export interface AuthConfig {
@@ -130,6 +143,7 @@ interface CustomFunction {
130
143
 
131
144
  export interface Config {
132
145
  autoConfirm: boolean
146
+ confirmationFunctionName?: string
133
147
  resetFunctionName: string
134
148
  resetPasswordUrl: string
135
149
  runConfirmationFunction: boolean
@@ -24,7 +24,7 @@ export const activateTriggers = async ({
24
24
  (trigger) =>
25
25
  trigger.content.type === 'AUTHENTICATION' &&
26
26
  trigger.content.event_processors?.FUNCTION?.config?.function_name ===
27
- AUTH_CONFIG.on_user_creation_function_name
27
+ AUTH_CONFIG.on_user_creation_function_name
28
28
  )
29
29
  if (!alreadyDeclared) {
30
30
  triggersToActivate.push({
@@ -34,6 +34,7 @@ export const activateTriggers = async ({
34
34
  type: 'AUTHENTICATION',
35
35
  disabled: false,
36
36
  config: {
37
+ isAutoTrigger: true,
37
38
  collection: AUTH_CONFIG.authCollection ?? 'auth_users',
38
39
  database: DB_NAME,
39
40
  full_document: true,
@@ -21,6 +21,7 @@ type Config = {
21
21
  database: string
22
22
  full_document: boolean
23
23
  full_document_before_change: boolean
24
+ isAutoTrigger?: boolean
24
25
  match: Record<string, unknown>
25
26
  operation_types: string[]
26
27
  project: Record<string, unknown>
@@ -110,7 +110,7 @@ const handleAuthenticationTrigger = async ({
110
110
  services,
111
111
  app
112
112
  }: HandlerParams) => {
113
- const { database } = config
113
+ const { database, isAutoTrigger } = config
114
114
  const authCollection = AUTH_CONFIG.authCollection ?? 'auth_users'
115
115
  const collection = app.mongo.client.db(database || DB_NAME).collection(authCollection)
116
116
  const pipeline = [
@@ -191,17 +191,17 @@ const handleAuthenticationTrigger = async ({
191
191
 
192
192
  const currentUser = { ...document }
193
193
  delete (currentUser as { password?: unknown }).password
194
+
195
+ const userData = {
196
+ ...currentUser,
197
+ id: (currentUser as { _id: { toString: () => string } })._id.toString(),
198
+ data: {
199
+ _id: (currentUser as { _id: { toString: () => string } })._id.toString(),
200
+ email: (currentUser as { email?: string }).email
201
+ }
202
+ }
194
203
  await GenerateContext({
195
- args: [{
196
- user: {
197
- ...currentUser,
198
- id: (currentUser as { _id: { toString: () => string } })._id.toString(),
199
- data: {
200
- _id: (currentUser as { _id: { toString: () => string } })._id.toString(),
201
- email: (currentUser as { email?: string }).email
202
- }
203
- }
204
- }],
204
+ args: isAutoTrigger ? [userData] : [{ user: userData, ...change }],
205
205
  app,
206
206
  rules: StateManager.select("rules"),
207
207
  user: {}, // TODO from currentUser ??
@@ -1,5 +1,7 @@
1
1
  import { AUTH_CONFIG, DB_NAME } from "../constants"
2
- import { hashPassword } from "../utils/crypto"
2
+ import { StateManager } from "../state"
3
+ import { GenerateContext } from "../utils/context"
4
+ import { generateToken, hashPassword } from "../utils/crypto"
3
5
  import { HandleUserRegistration } from "./models/handleUserRegistration.model"
4
6
 
5
7
  /**
@@ -17,7 +19,10 @@ const handleUserRegistration: HandleUserRegistration = (app, opt) => async ({ em
17
19
  }
18
20
 
19
21
  const { authCollection } = AUTH_CONFIG
20
- const autoConfirm = AUTH_CONFIG.localUserpassConfig?.autoConfirm === true
22
+ const localUserpassConfig = AUTH_CONFIG.localUserpassConfig
23
+ const autoConfirm = localUserpassConfig?.autoConfirm === true
24
+ const runConfirmationFunction = localUserpassConfig?.runConfirmationFunction === true
25
+ const confirmationFunctionName = localUserpassConfig?.confirmationFunctionName
21
26
  const mongo = app?.mongo
22
27
  const db = mongo.client.db(DB_NAME)
23
28
  const hashedPassword = await hashPassword(password)
@@ -59,6 +64,81 @@ const handleUserRegistration: HandleUserRegistration = (app, opt) => async ({ em
59
64
  }
60
65
  )
61
66
 
67
+ if (!result?.insertedId || skipUserCheck || autoConfirm) {
68
+ return result
69
+ }
70
+
71
+ if (!runConfirmationFunction) {
72
+ throw new Error('Missing confirmation function')
73
+ }
74
+
75
+ if (!confirmationFunctionName) {
76
+ throw new Error('Missing confirmation function name')
77
+ }
78
+
79
+ const functionsList = StateManager.select('functions')
80
+ const services = StateManager.select('services')
81
+ const confirmationFunction = functionsList[confirmationFunctionName]
82
+ if (!confirmationFunction) {
83
+ throw new Error(`Confirmation function not found: ${confirmationFunctionName}`)
84
+ }
85
+
86
+ const token = generateToken()
87
+ const tokenId = generateToken()
88
+ await db?.collection(authCollection!).updateOne(
89
+ { _id: result.insertedId },
90
+ {
91
+ $set: {
92
+ confirmationToken: token,
93
+ confirmationTokenId: tokenId
94
+ }
95
+ }
96
+ )
97
+
98
+ type ConfirmationResult = { status?: 'success' | 'pending' | 'fail' }
99
+ let confirmationStatus: ConfirmationResult['status'] = 'fail'
100
+ try {
101
+ const response = await GenerateContext({
102
+ args: [{
103
+ token,
104
+ tokenId,
105
+ username: email
106
+ }],
107
+ app,
108
+ rules: {},
109
+ user: {},
110
+ currentFunction: confirmationFunction,
111
+ functionsList,
112
+ services,
113
+ runAsSystem: true
114
+ }) as ConfirmationResult
115
+ confirmationStatus = response?.status ?? 'fail'
116
+ } catch {
117
+ confirmationStatus = 'fail'
118
+ }
119
+
120
+ if (confirmationStatus === 'success') {
121
+ await db?.collection(authCollection!).updateOne(
122
+ { _id: result.insertedId },
123
+ {
124
+ $set: { status: 'confirmed' },
125
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
126
+ }
127
+ )
128
+ return result
129
+ }
130
+
131
+ if (confirmationStatus === 'pending') {
132
+ return result
133
+ }
134
+
135
+ await db?.collection(authCollection!).updateOne(
136
+ { _id: result.insertedId },
137
+ {
138
+ $set: { status: 'failed' },
139
+ $unset: { confirmationToken: '', confirmationTokenId: '' }
140
+ }
141
+ )
62
142
  return result
63
143
 
64
144
  }