@flowerforce/flowerbase 1.2.1-beta.19 → 1.2.1-beta.20

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/custom-function/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAgBzC;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,eAAe,iBA8FlE"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/custom-function/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AASzC;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,eAAe,iBAgGlE"}
@@ -8,14 +8,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
12
  exports.customFunctionController = customFunctionController;
16
13
  const constants_1 = require("../../../constants");
17
- const handleUserRegistration_1 = __importDefault(require("../../../shared/handleUserRegistration"));
18
- const handleUserRegistration_model_1 = require("../../../shared/models/handleUserRegistration.model");
19
14
  const state_1 = require("../../../state");
20
15
  const context_1 = require("../../../utils/context");
21
16
  const crypto_1 = require("../../../utils/crypto");
@@ -31,7 +26,7 @@ function customFunctionController(app) {
31
26
  const functionsList = state_1.StateManager.select('functions');
32
27
  const services = state_1.StateManager.select('services');
33
28
  const db = app.mongo.client.db(constants_1.DB_NAME);
34
- const { refreshTokensCollection } = constants_1.AUTH_CONFIG;
29
+ const { authCollection, refreshTokensCollection } = constants_1.AUTH_CONFIG;
35
30
  const refreshTokenTtlMs = constants_1.DEFAULT_CONFIG.REFRESH_TOKEN_TTL_DAYS * 24 * 60 * 60 * 1000;
36
31
  /**
37
32
  * Endpoint for user login.
@@ -42,7 +37,7 @@ function customFunctionController(app) {
42
37
  */
43
38
  app.post(utils_1.AUTH_ENDPOINTS.LOGIN, {
44
39
  schema: schema_1.LOGIN_SCHEMA
45
- }, function (req) {
40
+ }, function (req, reply) {
46
41
  return __awaiter(this, void 0, void 0, function* () {
47
42
  const { providers } = constants_1.AUTH_CONFIG;
48
43
  const authFunctionName = providers["custom-function"].authFunctionName;
@@ -50,7 +45,7 @@ function customFunctionController(app) {
50
45
  throw new Error("Missing Auth Function");
51
46
  }
52
47
  const { ips, host, hostname, url, method, ip, id } = req;
53
- const res = yield (0, context_1.GenerateContext)({
48
+ const authResult = yield (0, context_1.GenerateContext)({
54
49
  args: [
55
50
  req.body
56
51
  ],
@@ -70,34 +65,36 @@ function customFunctionController(app) {
70
65
  id
71
66
  }
72
67
  });
73
- if (res.id) {
74
- const user = yield (0, handleUserRegistration_1.default)(app, { run_as_system: true, skipUserCheck: true, provider: handleUserRegistration_model_1.PROVIDER.CUSTOM_FUNCTION })({ email: res.id, password: (0, utils_1.generatePassword)() });
75
- if (!(user === null || user === void 0 ? void 0 : user.insertedId)) {
76
- throw new Error('Failed to register custom user');
77
- }
78
- const currentUserData = {
79
- _id: user.insertedId,
80
- user_data: {
81
- _id: user.insertedId
82
- }
83
- };
84
- const refreshToken = this.createRefreshToken(currentUserData);
85
- const refreshTokenHash = (0, crypto_1.hashToken)(refreshToken);
86
- yield db.collection(refreshTokensCollection).insertOne({
87
- userId: user.insertedId,
88
- tokenHash: refreshTokenHash,
89
- createdAt: new Date(),
90
- expiresAt: new Date(Date.now() + refreshTokenTtlMs),
91
- revokedAt: null
92
- });
93
- return {
94
- access_token: this.createAccessToken(currentUserData),
95
- refresh_token: refreshToken,
96
- device_id: '',
97
- user_id: user.insertedId.toString()
98
- };
68
+ if (!authResult.id) {
69
+ reply.code(401).send({ message: 'Unauthorized' });
70
+ return;
71
+ }
72
+ const authUser = yield db.collection(authCollection).findOne({ email: authResult.id });
73
+ if (!authUser) {
74
+ reply.code(401).send({ message: 'Unauthorized' });
75
+ return;
99
76
  }
100
- throw new Error("Authentication Failed");
77
+ const currentUserData = {
78
+ _id: authUser._id,
79
+ user_data: {
80
+ _id: authUser._id
81
+ }
82
+ };
83
+ const refreshToken = this.createRefreshToken(currentUserData);
84
+ const refreshTokenHash = (0, crypto_1.hashToken)(refreshToken);
85
+ yield db.collection(refreshTokensCollection).insertOne({
86
+ userId: authUser._id,
87
+ tokenHash: refreshTokenHash,
88
+ createdAt: new Date(),
89
+ expiresAt: new Date(Date.now() + refreshTokenTtlMs),
90
+ revokedAt: null
91
+ });
92
+ return {
93
+ access_token: this.createAccessToken(currentUserData),
94
+ refresh_token: refreshToken,
95
+ device_id: '',
96
+ user_id: authUser._id.toString()
97
+ };
101
98
  });
102
99
  });
103
100
  });
@@ -8,8 +8,11 @@ export type LoginSuccessDto = {
8
8
  refresh_token: string;
9
9
  user_id: string;
10
10
  };
11
+ export type LoginErrorDto = {
12
+ message: string;
13
+ };
11
14
  export interface LoginDto {
12
15
  Body: LoginUserDto;
13
- Reply: LoginSuccessDto;
16
+ Reply: LoginSuccessDto | LoginErrorDto;
14
17
  }
15
18
  //# sourceMappingURL=dtos.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/custom-function/dtos.ts"],"names":[],"mappings":"AAAA,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,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,CAAA;CACvB"}
1
+ {"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/custom-function/dtos.ts"],"names":[],"mappings":"AAAA,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,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,aAAa,CAAA;CACvC"}
@@ -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;AAqCzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBAgUjE"}
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,iBAsUjE"}
@@ -44,6 +44,7 @@ function localUserPassController(app) {
44
44
  const resetPasswordTtlSeconds = constants_1.DEFAULT_CONFIG.RESET_PASSWORD_TTL_SECONDS;
45
45
  const rateLimitWindowMs = constants_1.DEFAULT_CONFIG.AUTH_RATE_LIMIT_WINDOW_MS;
46
46
  const loginMaxAttempts = constants_1.DEFAULT_CONFIG.AUTH_LOGIN_MAX_ATTEMPTS;
47
+ const registerMaxAttempts = constants_1.DEFAULT_CONFIG.AUTH_REGISTER_MAX_ATTEMPTS;
47
48
  const resetMaxAttempts = constants_1.DEFAULT_CONFIG.AUTH_RESET_MAX_ATTEMPTS;
48
49
  const refreshTokenTtlMs = constants_1.DEFAULT_CONFIG.REFRESH_TOKEN_TTL_DAYS * 24 * 60 * 60 * 1000;
49
50
  try {
@@ -101,6 +102,11 @@ function localUserPassController(app) {
101
102
  app.post(utils_1.AUTH_ENDPOINTS.REGISTRATION, {
102
103
  schema: utils_1.REGISTRATION_SCHEMA
103
104
  }, (req, res) => __awaiter(this, void 0, void 0, function* () {
105
+ const key = `register:${req.ip}`;
106
+ if (isRateLimited(key, registerMaxAttempts, rateLimitWindowMs)) {
107
+ res.status(429).send({ message: 'Too many requests' });
108
+ return;
109
+ }
104
110
  const result = yield (0, handleUserRegistration_1.default)(app, { run_as_system: true, provider: handleUserRegistration_model_1.PROVIDER.LOCAL_USERPASS })({ email: req.body.email.toLowerCase(), password: req.body.password });
105
111
  if (!(result === null || result === void 0 ? void 0 : result.insertedId)) {
106
112
  res === null || res === void 0 ? void 0 : res.status(500);
@@ -10,6 +10,7 @@ export declare const DEFAULT_CONFIG: {
10
10
  RESET_PASSWORD_TTL_SECONDS: number;
11
11
  AUTH_RATE_LIMIT_WINDOW_MS: number;
12
12
  AUTH_LOGIN_MAX_ATTEMPTS: number;
13
+ AUTH_REGISTER_MAX_ATTEMPTS: number;
13
14
  AUTH_RESET_MAX_ATTEMPTS: number;
14
15
  REFRESH_TOKEN_TTL_DAYS: number;
15
16
  ANON_USER_TTL_SECONDS: number;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AAUpC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;iBAkBsB,eAAe,EAAE;;CAEjE,CAAA;AACD,eAAO,MAAM,WAAW,QAA8C,CAAA;AACtE,eAAO,MAAM,YAAY,QAA8B,CAAA;AACvD,eAAO,MAAM,OAAO,QAAgB,CAAA;AAGpC,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;CAavB,CAAA;AAID,eAAO,MAAM,SAAS;;;CAGrB,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AAUpC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;iBAmBsB,eAAe,EAAE;;CAEjE,CAAA;AACD,eAAO,MAAM,WAAW,QAA8C,CAAA;AACtE,eAAO,MAAM,YAAY,QAA8B,CAAA;AACvD,eAAO,MAAM,OAAO,QAAgB,CAAA;AAGpC,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;CAavB,CAAA;AAID,eAAO,MAAM,SAAS;;;CAGrB,CAAA"}
package/dist/constants.js CHANGED
@@ -27,6 +27,7 @@ exports.DEFAULT_CONFIG = {
27
27
  RESET_PASSWORD_TTL_SECONDS: Number(process.env.RESET_PASSWORD_TTL_SECONDS) || 3600,
28
28
  AUTH_RATE_LIMIT_WINDOW_MS: Number(process.env.AUTH_RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000,
29
29
  AUTH_LOGIN_MAX_ATTEMPTS: Number(process.env.AUTH_LOGIN_MAX_ATTEMPTS) || 10,
30
+ AUTH_REGISTER_MAX_ATTEMPTS: Number(process.env.AUTH_REGISTER_MAX_ATTEMPTS) || 5,
30
31
  AUTH_RESET_MAX_ATTEMPTS: Number(process.env.AUTH_RESET_MAX_ATTEMPTS) || 5,
31
32
  REFRESH_TOKEN_TTL_DAYS: Number(process.env.REFRESH_TOKEN_TTL_DAYS) || 60,
32
33
  ANON_USER_TTL_SECONDS: Number(process.env.ANON_USER_TTL_SECONDS) || 3 * 60 * 60,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowerforce/flowerbase",
3
- "version": "1.2.1-beta.19",
3
+ "version": "1.2.1-beta.20",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,17 +1,10 @@
1
1
  import { FastifyInstance } from 'fastify'
2
2
  import { AUTH_CONFIG, DB_NAME, DEFAULT_CONFIG } from '../../../constants'
3
- import handleUserRegistration from '../../../shared/handleUserRegistration'
4
- import { PROVIDER } from '../../../shared/models/handleUserRegistration.model'
5
3
  import { StateManager } from '../../../state'
6
4
  import { GenerateContext } from '../../../utils/context'
7
5
  import { hashToken } from '../../../utils/crypto'
8
- import {
9
- AUTH_ENDPOINTS,
10
- generatePassword,
11
- } from '../../utils'
12
- import {
13
- LoginDto
14
- } from './dtos'
6
+ import { AUTH_ENDPOINTS } from '../../utils'
7
+ import { LoginDto } from './dtos'
15
8
  import { LOGIN_SCHEMA } from './schema'
16
9
 
17
10
  /**
@@ -24,7 +17,7 @@ export async function customFunctionController(app: FastifyInstance) {
24
17
  const functionsList = StateManager.select('functions')
25
18
  const services = StateManager.select('services')
26
19
  const db = app.mongo.client.db(DB_NAME)
27
- const { refreshTokensCollection } = AUTH_CONFIG
20
+ const { authCollection, refreshTokensCollection } = AUTH_CONFIG
28
21
  const refreshTokenTtlMs = DEFAULT_CONFIG.REFRESH_TOKEN_TTL_DAYS * 24 * 60 * 60 * 1000
29
22
 
30
23
  /**
@@ -39,7 +32,7 @@ export async function customFunctionController(app: FastifyInstance) {
39
32
  {
40
33
  schema: LOGIN_SCHEMA
41
34
  },
42
- async function (req) {
35
+ async function (req, reply) {
43
36
  const { providers } = AUTH_CONFIG
44
37
  const authFunctionName = providers["custom-function"].authFunctionName
45
38
 
@@ -58,7 +51,7 @@ export async function customFunctionController(app: FastifyInstance) {
58
51
  } = req
59
52
 
60
53
  type CustomFunctionAuthResult = { id?: string }
61
- const res = await GenerateContext({
54
+ const authResult = await GenerateContext({
62
55
  args: [
63
56
  req.body
64
57
  ],
@@ -80,36 +73,38 @@ export async function customFunctionController(app: FastifyInstance) {
80
73
  }) as CustomFunctionAuthResult
81
74
 
82
75
 
83
- if (res.id) {
84
- const user = await handleUserRegistration(app, { run_as_system: true, skipUserCheck: true, provider: PROVIDER.CUSTOM_FUNCTION })({ email: res.id, password: generatePassword() })
85
- if (!user?.insertedId) {
86
- throw new Error('Failed to register custom user')
87
- }
76
+ if (!authResult.id) {
77
+ reply.code(401).send({ message: 'Unauthorized' })
78
+ return
79
+ }
88
80
 
89
- const currentUserData = {
90
- _id: user.insertedId,
91
- user_data: {
92
- _id: user.insertedId
93
- }
94
- }
95
- const refreshToken = this.createRefreshToken(currentUserData)
96
- const refreshTokenHash = hashToken(refreshToken)
97
- await db.collection(refreshTokensCollection).insertOne({
98
- userId: user.insertedId,
99
- tokenHash: refreshTokenHash,
100
- createdAt: new Date(),
101
- expiresAt: new Date(Date.now() + refreshTokenTtlMs),
102
- revokedAt: null
103
- })
104
- return {
105
- access_token: this.createAccessToken(currentUserData),
106
- refresh_token: refreshToken,
107
- device_id: '',
108
- user_id: user.insertedId.toString()
109
- }
81
+ const authUser = await db.collection(authCollection!).findOne({ email: authResult.id })
82
+ if (!authUser) {
83
+ reply.code(401).send({ message: 'Unauthorized' })
84
+ return
110
85
  }
111
86
 
112
- throw new Error("Authentication Failed")
87
+ const currentUserData = {
88
+ _id: authUser._id,
89
+ user_data: {
90
+ _id: authUser._id
91
+ }
92
+ }
93
+ const refreshToken = this.createRefreshToken(currentUserData)
94
+ const refreshTokenHash = hashToken(refreshToken)
95
+ await db.collection(refreshTokensCollection).insertOne({
96
+ userId: authUser._id,
97
+ tokenHash: refreshTokenHash,
98
+ createdAt: new Date(),
99
+ expiresAt: new Date(Date.now() + refreshTokenTtlMs),
100
+ revokedAt: null
101
+ })
102
+ return {
103
+ access_token: this.createAccessToken(currentUserData),
104
+ refresh_token: refreshToken,
105
+ device_id: '',
106
+ user_id: authUser._id.toString()
107
+ }
113
108
  }
114
109
  )
115
110
 
@@ -10,7 +10,11 @@ export type LoginSuccessDto = {
10
10
  user_id: string
11
11
  }
12
12
 
13
+ export type LoginErrorDto = {
14
+ message: string
15
+ }
16
+
13
17
  export interface LoginDto {
14
18
  Body: LoginUserDto
15
- Reply: LoginSuccessDto
19
+ Reply: LoginSuccessDto | LoginErrorDto
16
20
  }
@@ -48,6 +48,7 @@ export async function localUserPassController(app: FastifyInstance) {
48
48
  const resetPasswordTtlSeconds = DEFAULT_CONFIG.RESET_PASSWORD_TTL_SECONDS
49
49
  const rateLimitWindowMs = DEFAULT_CONFIG.AUTH_RATE_LIMIT_WINDOW_MS
50
50
  const loginMaxAttempts = DEFAULT_CONFIG.AUTH_LOGIN_MAX_ATTEMPTS
51
+ const registerMaxAttempts = DEFAULT_CONFIG.AUTH_REGISTER_MAX_ATTEMPTS
51
52
  const resetMaxAttempts = DEFAULT_CONFIG.AUTH_RESET_MAX_ATTEMPTS
52
53
  const refreshTokenTtlMs = DEFAULT_CONFIG.REFRESH_TOKEN_TTL_DAYS * 24 * 60 * 60 * 1000
53
54
 
@@ -131,6 +132,11 @@ export async function localUserPassController(app: FastifyInstance) {
131
132
  schema: REGISTRATION_SCHEMA
132
133
  },
133
134
  async (req, res) => {
135
+ const key = `register:${req.ip}`
136
+ if (isRateLimited(key, registerMaxAttempts, rateLimitWindowMs)) {
137
+ res.status(429).send({ message: 'Too many requests' })
138
+ return
139
+ }
134
140
 
135
141
  const result = await handleUserRegistration(app, { run_as_system: true, provider: PROVIDER.LOCAL_USERPASS })({ email: req.body.email.toLowerCase(), password: req.body.password })
136
142
 
package/src/constants.ts CHANGED
@@ -20,6 +20,7 @@ export const DEFAULT_CONFIG = {
20
20
  RESET_PASSWORD_TTL_SECONDS: Number(process.env.RESET_PASSWORD_TTL_SECONDS) || 3600,
21
21
  AUTH_RATE_LIMIT_WINDOW_MS: Number(process.env.AUTH_RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000,
22
22
  AUTH_LOGIN_MAX_ATTEMPTS: Number(process.env.AUTH_LOGIN_MAX_ATTEMPTS) || 10,
23
+ AUTH_REGISTER_MAX_ATTEMPTS: Number(process.env.AUTH_REGISTER_MAX_ATTEMPTS) || 5,
23
24
  AUTH_RESET_MAX_ATTEMPTS: Number(process.env.AUTH_RESET_MAX_ATTEMPTS) || 5,
24
25
  REFRESH_TOKEN_TTL_DAYS: Number(process.env.REFRESH_TOKEN_TTL_DAYS) || 60,
25
26
  ANON_USER_TTL_SECONDS: Number(process.env.ANON_USER_TTL_SECONDS) || 3 * 60 * 60,