@flusys/nestjs-auth 1.0.0-beta → 1.0.0-rc

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 (95) hide show
  1. package/README.md +274 -291
  2. package/cjs/config/auth.constants.js +12 -0
  3. package/cjs/controllers/authentication.controller.js +219 -10
  4. package/cjs/controllers/branch.controller.js +44 -1
  5. package/cjs/controllers/company-selection.controller.js +27 -20
  6. package/cjs/controllers/company.controller.js +44 -1
  7. package/cjs/controllers/user-permission.controller.js +40 -25
  8. package/cjs/controllers/user.controller.js +211 -7
  9. package/cjs/dtos/authentication.dto.js +119 -13
  10. package/cjs/dtos/user-permission.dto.js +28 -0
  11. package/cjs/dtos/user.dto.js +19 -4
  12. package/cjs/entities/index.js +5 -1
  13. package/cjs/entities/pending-registration.entity.js +125 -0
  14. package/cjs/entities/user-company-permission.entity.js +0 -6
  15. package/cjs/entities/user-token.entity.js +129 -0
  16. package/cjs/guards/auth-throttler.guard.js +53 -0
  17. package/cjs/interceptors/clear-token.interceptor.js +3 -6
  18. package/cjs/interceptors/set-token.interceptor.js +38 -31
  19. package/cjs/interfaces/auth-email-provider.interface.js +45 -0
  20. package/cjs/interfaces/index.js +2 -0
  21. package/cjs/interfaces/user-enricher.interface.js +4 -0
  22. package/cjs/modules/auth.module.js +8 -20
  23. package/cjs/services/auth-config.service.js +23 -2
  24. package/cjs/services/auth-datasource.provider.js +5 -3
  25. package/cjs/services/auth-email.service.js +471 -0
  26. package/cjs/services/authentication.service.js +169 -77
  27. package/cjs/services/branch.service.js +6 -5
  28. package/cjs/services/company-selection-session.service.js +1 -1
  29. package/cjs/services/index.js +1 -0
  30. package/cjs/services/user-permission.service.js +0 -2
  31. package/cjs/services/user.service.js +213 -34
  32. package/cjs/validators/password.validator.js +45 -0
  33. package/config/auth.constants.d.ts +3 -0
  34. package/controllers/authentication.controller.d.ts +13 -9
  35. package/controllers/company-selection.controller.d.ts +6 -2
  36. package/controllers/user.controller.d.ts +33 -0
  37. package/dtos/authentication.dto.d.ts +21 -3
  38. package/dtos/company-branch.dto.d.ts +0 -1
  39. package/dtos/company.dto.d.ts +0 -1
  40. package/dtos/user-permission.dto.d.ts +4 -0
  41. package/dtos/user.dto.d.ts +1 -2
  42. package/entities/index.d.ts +7 -3
  43. package/entities/pending-registration.entity.d.ts +17 -0
  44. package/entities/user-company-permission.entity.d.ts +0 -2
  45. package/entities/user-token.entity.d.ts +15 -0
  46. package/fesm/config/auth.constants.js +6 -2
  47. package/fesm/controllers/authentication.controller.js +221 -12
  48. package/fesm/controllers/branch.controller.js +45 -2
  49. package/fesm/controllers/company-selection.controller.js +28 -21
  50. package/fesm/controllers/company.controller.js +45 -2
  51. package/fesm/controllers/user-permission.controller.js +41 -26
  52. package/fesm/controllers/user.controller.js +214 -10
  53. package/fesm/dtos/authentication.dto.js +106 -14
  54. package/fesm/dtos/user-permission.dto.js +28 -0
  55. package/fesm/dtos/user.dto.js +20 -5
  56. package/fesm/entities/index.js +7 -1
  57. package/fesm/entities/pending-registration.entity.js +115 -0
  58. package/fesm/entities/user-company-permission.entity.js +0 -6
  59. package/fesm/entities/user-token.entity.js +113 -0
  60. package/fesm/guards/auth-throttler.guard.js +43 -0
  61. package/fesm/interceptors/clear-token.interceptor.js +2 -5
  62. package/fesm/interceptors/set-token.interceptor.js +37 -30
  63. package/fesm/interfaces/auth-email-provider.interface.js +38 -0
  64. package/fesm/interfaces/authentication.interface.js +1 -1
  65. package/fesm/interfaces/index.js +2 -0
  66. package/fesm/interfaces/user-enricher.interface.js +26 -0
  67. package/fesm/modules/auth.module.js +10 -22
  68. package/fesm/services/auth-config.service.js +24 -3
  69. package/fesm/services/auth-datasource.provider.js +6 -4
  70. package/fesm/services/auth-email.service.js +420 -0
  71. package/fesm/services/authentication.service.js +169 -77
  72. package/fesm/services/branch.service.js +6 -5
  73. package/fesm/services/company-selection-session.service.js +1 -1
  74. package/fesm/services/index.js +1 -0
  75. package/fesm/services/user-permission.service.js +1 -3
  76. package/fesm/services/user.service.js +215 -36
  77. package/fesm/validators/password.validator.js +48 -0
  78. package/guards/auth-throttler.guard.d.ts +7 -0
  79. package/interceptors/set-token.interceptor.d.ts +1 -0
  80. package/interfaces/auth-email-provider.interface.d.ts +6 -0
  81. package/interfaces/auth-module-options.interface.d.ts +4 -1
  82. package/interfaces/authentication.interface.d.ts +14 -0
  83. package/interfaces/index.d.ts +2 -0
  84. package/interfaces/user-enricher.interface.d.ts +64 -0
  85. package/interfaces/user.interface.d.ts +1 -0
  86. package/modules/auth.module.d.ts +0 -1
  87. package/package.json +4 -4
  88. package/services/auth-config.service.d.ts +5 -1
  89. package/services/auth-email.service.d.ts +51 -0
  90. package/services/authentication.service.d.ts +16 -11
  91. package/services/company-selection-session.service.d.ts +1 -1
  92. package/services/index.d.ts +1 -0
  93. package/services/user-permission.service.d.ts +0 -1
  94. package/services/user.service.d.ts +19 -3
  95. package/validators/password.validator.d.ts +10 -0
@@ -254,9 +254,23 @@ _ts_decorate([
254
254
  ], UserBranchPermissionDto.prototype, "companyId", void 0);
255
255
  let UserCompaniesResponseDto = class UserCompaniesResponseDto {
256
256
  constructor(){
257
+ _define_property(this, "success", void 0);
258
+ _define_property(this, "message", void 0);
257
259
  _define_property(this, "data", void 0);
258
260
  }
259
261
  };
262
+ _ts_decorate([
263
+ (0, _swagger.ApiProperty)({
264
+ example: true
265
+ }),
266
+ _ts_metadata("design:type", Boolean)
267
+ ], UserCompaniesResponseDto.prototype, "success", void 0);
268
+ _ts_decorate([
269
+ (0, _swagger.ApiProperty)({
270
+ example: 'User companies retrieved successfully'
271
+ }),
272
+ _ts_metadata("design:type", String)
273
+ ], UserCompaniesResponseDto.prototype, "message", void 0);
260
274
  _ts_decorate([
261
275
  (0, _swagger.ApiProperty)({
262
276
  description: 'List of companies the user has access to',
@@ -284,9 +298,23 @@ _ts_decorate([
284
298
  ], UserCompaniesResponseDto.prototype, "data", void 0);
285
299
  let UserBranchesResponseDto = class UserBranchesResponseDto {
286
300
  constructor(){
301
+ _define_property(this, "success", void 0);
302
+ _define_property(this, "message", void 0);
287
303
  _define_property(this, "data", void 0);
288
304
  }
289
305
  };
306
+ _ts_decorate([
307
+ (0, _swagger.ApiProperty)({
308
+ example: true
309
+ }),
310
+ _ts_metadata("design:type", Boolean)
311
+ ], UserBranchesResponseDto.prototype, "success", void 0);
312
+ _ts_decorate([
313
+ (0, _swagger.ApiProperty)({
314
+ example: 'User branches retrieved successfully'
315
+ }),
316
+ _ts_metadata("design:type", String)
317
+ ], UserBranchesResponseDto.prototype, "message", void 0);
290
318
  _ts_decorate([
291
319
  (0, _swagger.ApiProperty)({
292
320
  description: 'List of branches the user has access to',
@@ -21,6 +21,7 @@ _export(exports, {
21
21
  });
22
22
  const _swagger = require("@nestjs/swagger");
23
23
  const _classvalidator = require("class-validator");
24
+ const _passwordvalidator = require("../validators/password.validator");
24
25
  function _define_property(obj, key, value) {
25
26
  if (key in obj) {
26
27
  Object.defineProperty(obj, key, {
@@ -83,10 +84,13 @@ _ts_decorate([
83
84
  ], CreateUserDto.prototype, "email", void 0);
84
85
  _ts_decorate([
85
86
  (0, _swagger.ApiProperty)({
86
- example: 'password123',
87
- description: 'Password'
87
+ example: 'SecureP@ss123',
88
+ description: 'Password (must meet complexity requirements)'
88
89
  }),
89
90
  (0, _classvalidator.IsString)(),
91
+ (0, _classvalidator.IsNotEmpty)(),
92
+ (0, _passwordvalidator.IsStrongPassword)(),
93
+ (0, _classvalidator.MaxLength)(128),
90
94
  _ts_metadata("design:type", String)
91
95
  ], CreateUserDto.prototype, "password", void 0);
92
96
  _ts_decorate([
@@ -139,6 +143,7 @@ let UpdateUserDto = class UpdateUserDto {
139
143
  _define_property(this, "phone", void 0);
140
144
  _define_property(this, "email", void 0);
141
145
  _define_property(this, "password", void 0);
146
+ _define_property(this, "oldPassword", void 0);
142
147
  _define_property(this, "profilePictureId", void 0);
143
148
  _define_property(this, "isActive", void 0);
144
149
  _define_property(this, "emailVerified", void 0);
@@ -150,7 +155,7 @@ _ts_decorate([
150
155
  (0, _swagger.ApiProperty)({
151
156
  description: 'User ID'
152
157
  }),
153
- (0, _classvalidator.IsString)(),
158
+ (0, _classvalidator.IsUUID)(),
154
159
  _ts_metadata("design:type", String)
155
160
  ], UpdateUserDto.prototype, "id", void 0);
156
161
  _ts_decorate([
@@ -182,12 +187,22 @@ _ts_decorate([
182
187
  ], UpdateUserDto.prototype, "email", void 0);
183
188
  _ts_decorate([
184
189
  (0, _swagger.ApiPropertyOptional)({
185
- description: 'New password'
190
+ description: 'New password (must meet complexity requirements)'
186
191
  }),
187
192
  (0, _classvalidator.IsOptional)(),
188
193
  (0, _classvalidator.IsString)(),
194
+ (0, _passwordvalidator.IsStrongPassword)(),
195
+ (0, _classvalidator.MaxLength)(128),
189
196
  _ts_metadata("design:type", String)
190
197
  ], UpdateUserDto.prototype, "password", void 0);
198
+ _ts_decorate([
199
+ (0, _swagger.ApiPropertyOptional)({
200
+ description: 'Current password (required when changing password on own profile)'
201
+ }),
202
+ (0, _classvalidator.IsOptional)(),
203
+ (0, _classvalidator.IsString)(),
204
+ _ts_metadata("design:type", String)
205
+ ], UpdateUserDto.prototype, "oldPassword", void 0);
191
206
  _ts_decorate([
192
207
  (0, _swagger.ApiPropertyOptional)({
193
208
  description: 'Profile picture file ID'
@@ -30,8 +30,10 @@ _export(exports, {
30
30
  });
31
31
  const _companybranchentity = _export_star(require("./company-branch.entity"), exports);
32
32
  const _companyentity = _export_star(require("./company.entity"), exports);
33
+ const _pendingregistrationentity = _export_star(require("./pending-registration.entity"), exports);
33
34
  const _usercompanypermissionentity = require("./user-company-permission.entity");
34
35
  const _userentity = _export_star(require("./user.entity"), exports);
36
+ const _usertokenentity = _export_star(require("./user-token.entity"), exports);
35
37
  function _export_star(from, to) {
36
38
  Object.keys(from).forEach(function(k) {
37
39
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
@@ -46,7 +48,9 @@ function _export_star(from, to) {
46
48
  return from;
47
49
  }
48
50
  const CoreEntities = [
49
- _userentity.User
51
+ _userentity.User,
52
+ _usertokenentity.UserToken,
53
+ _pendingregistrationentity.PendingRegistration
50
54
  ];
51
55
  const CompanyEntities = [
52
56
  _companyentity.Company,
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "PendingRegistration", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return PendingRegistration;
9
+ }
10
+ });
11
+ const _typeorm = require("typeorm");
12
+ function _define_property(obj, key, value) {
13
+ if (key in obj) {
14
+ Object.defineProperty(obj, key, {
15
+ value: value,
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true
19
+ });
20
+ } else {
21
+ obj[key] = value;
22
+ }
23
+ return obj;
24
+ }
25
+ function _ts_decorate(decorators, target, key, desc) {
26
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
27
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
28
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
29
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
30
+ }
31
+ function _ts_metadata(k, v) {
32
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
33
+ }
34
+ let PendingRegistration = class PendingRegistration {
35
+ constructor(){
36
+ _define_property(this, "id", void 0);
37
+ _define_property(this, "email", void 0);
38
+ _define_property(this, "name", void 0);
39
+ _define_property(this, "phone", void 0);
40
+ _define_property(this, "passwordHash", void 0);
41
+ _define_property(this, "token", void 0);
42
+ _define_property(this, "expiresAt", void 0);
43
+ _define_property(this, "companyData", void 0);
44
+ _define_property(this, "createdAt", void 0);
45
+ }
46
+ };
47
+ _ts_decorate([
48
+ (0, _typeorm.PrimaryGeneratedColumn)('uuid'),
49
+ _ts_metadata("design:type", String)
50
+ ], PendingRegistration.prototype, "id", void 0);
51
+ _ts_decorate([
52
+ (0, _typeorm.Column)({
53
+ type: 'varchar',
54
+ length: 255
55
+ }),
56
+ _ts_metadata("design:type", String)
57
+ ], PendingRegistration.prototype, "email", void 0);
58
+ _ts_decorate([
59
+ (0, _typeorm.Column)({
60
+ type: 'varchar',
61
+ length: 255,
62
+ nullable: true
63
+ }),
64
+ _ts_metadata("design:type", Object)
65
+ ], PendingRegistration.prototype, "name", void 0);
66
+ _ts_decorate([
67
+ (0, _typeorm.Column)({
68
+ type: 'varchar',
69
+ length: 255,
70
+ nullable: true
71
+ }),
72
+ _ts_metadata("design:type", Object)
73
+ ], PendingRegistration.prototype, "phone", void 0);
74
+ _ts_decorate([
75
+ (0, _typeorm.Column)({
76
+ type: 'text',
77
+ name: 'passwordHash'
78
+ }),
79
+ _ts_metadata("design:type", String)
80
+ ], PendingRegistration.prototype, "passwordHash", void 0);
81
+ _ts_decorate([
82
+ (0, _typeorm.Column)({
83
+ type: 'varchar',
84
+ length: 64
85
+ }),
86
+ _ts_metadata("design:type", String)
87
+ ], PendingRegistration.prototype, "token", void 0);
88
+ _ts_decorate([
89
+ (0, _typeorm.Column)({
90
+ type: 'timestamp',
91
+ name: 'expires_at'
92
+ }),
93
+ _ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
94
+ ], PendingRegistration.prototype, "expiresAt", void 0);
95
+ _ts_decorate([
96
+ (0, _typeorm.Column)({
97
+ type: 'json',
98
+ nullable: true,
99
+ name: 'company_data'
100
+ }),
101
+ _ts_metadata("design:type", Object)
102
+ ], PendingRegistration.prototype, "companyData", void 0);
103
+ _ts_decorate([
104
+ (0, _typeorm.CreateDateColumn)({
105
+ type: 'timestamp',
106
+ name: 'created_at'
107
+ }),
108
+ _ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
109
+ ], PendingRegistration.prototype, "createdAt", void 0);
110
+ PendingRegistration = _ts_decorate([
111
+ (0, _typeorm.Entity)('pending_registrations'),
112
+ (0, _typeorm.Index)('IDX_pending_reg_email', [
113
+ 'email'
114
+ ], {
115
+ unique: true
116
+ }),
117
+ (0, _typeorm.Index)('IDX_pending_reg_token', [
118
+ 'token'
119
+ ], {
120
+ unique: true
121
+ }),
122
+ (0, _typeorm.Index)('IDX_pending_reg_expires', [
123
+ 'expiresAt'
124
+ ])
125
+ ], PendingRegistration);
@@ -44,12 +44,6 @@ function _ts_metadata(k, v) {
44
44
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
45
45
  }
46
46
  let UserCompanyPermission = class UserCompanyPermission {
47
- /* ---------- Helpers ---------- */ isCompanyPermission() {
48
- return this.permissionType === _enums.PermissionType.COMPANY;
49
- }
50
- isBranchPermission() {
51
- return this.permissionType === _enums.PermissionType.BRANCH;
52
- }
53
47
  constructor(){
54
48
  _define_property(this, "id", void 0);
55
49
  /* ---------- Ownership ---------- */ _define_property(this, "userId", void 0);
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get TokenType () {
13
+ return TokenType;
14
+ },
15
+ get UserToken () {
16
+ return UserToken;
17
+ }
18
+ });
19
+ const _typeorm = require("typeorm");
20
+ function _define_property(obj, key, value) {
21
+ if (key in obj) {
22
+ Object.defineProperty(obj, key, {
23
+ value: value,
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true
27
+ });
28
+ } else {
29
+ obj[key] = value;
30
+ }
31
+ return obj;
32
+ }
33
+ function _ts_decorate(decorators, target, key, desc) {
34
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
35
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
36
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
37
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
38
+ }
39
+ function _ts_metadata(k, v) {
40
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
41
+ }
42
+ var TokenType = /*#__PURE__*/ function(TokenType) {
43
+ TokenType["PASSWORD_RESET"] = "password_reset";
44
+ TokenType["EMAIL_VERIFICATION"] = "email_verification";
45
+ TokenType["EMAIL_CHANGE"] = "email_change";
46
+ return TokenType;
47
+ }({});
48
+ let UserToken = class UserToken {
49
+ constructor(){
50
+ _define_property(this, "id", void 0);
51
+ _define_property(this, "userId", void 0);
52
+ _define_property(this, "type", void 0);
53
+ _define_property(this, "token", void 0);
54
+ _define_property(this, "expiresAt", void 0);
55
+ _define_property(this, "usedAt", void 0);
56
+ _define_property(this, "metadata", void 0);
57
+ _define_property(this, "createdAt", void 0);
58
+ }
59
+ };
60
+ _ts_decorate([
61
+ (0, _typeorm.PrimaryGeneratedColumn)('uuid'),
62
+ _ts_metadata("design:type", String)
63
+ ], UserToken.prototype, "id", void 0);
64
+ _ts_decorate([
65
+ (0, _typeorm.Column)({
66
+ type: 'uuid',
67
+ name: 'user_id'
68
+ }),
69
+ _ts_metadata("design:type", String)
70
+ ], UserToken.prototype, "userId", void 0);
71
+ _ts_decorate([
72
+ (0, _typeorm.Column)({
73
+ type: 'varchar',
74
+ length: 32
75
+ }),
76
+ _ts_metadata("design:type", String)
77
+ ], UserToken.prototype, "type", void 0);
78
+ _ts_decorate([
79
+ (0, _typeorm.Column)({
80
+ type: 'varchar',
81
+ length: 64
82
+ }),
83
+ _ts_metadata("design:type", String)
84
+ ], UserToken.prototype, "token", void 0);
85
+ _ts_decorate([
86
+ (0, _typeorm.Column)({
87
+ type: 'timestamp',
88
+ name: 'expires_at'
89
+ }),
90
+ _ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
91
+ ], UserToken.prototype, "expiresAt", void 0);
92
+ _ts_decorate([
93
+ (0, _typeorm.Column)({
94
+ type: 'timestamp',
95
+ name: 'used_at',
96
+ nullable: true
97
+ }),
98
+ _ts_metadata("design:type", Object)
99
+ ], UserToken.prototype, "usedAt", void 0);
100
+ _ts_decorate([
101
+ (0, _typeorm.Column)({
102
+ type: 'varchar',
103
+ length: 255,
104
+ nullable: true
105
+ }),
106
+ _ts_metadata("design:type", Object)
107
+ ], UserToken.prototype, "metadata", void 0);
108
+ _ts_decorate([
109
+ (0, _typeorm.CreateDateColumn)({
110
+ type: 'timestamp',
111
+ name: 'created_at'
112
+ }),
113
+ _ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
114
+ ], UserToken.prototype, "createdAt", void 0);
115
+ UserToken = _ts_decorate([
116
+ (0, _typeorm.Entity)('user_tokens'),
117
+ (0, _typeorm.Index)('IDX_user_token_token', [
118
+ 'token'
119
+ ], {
120
+ unique: true
121
+ }),
122
+ (0, _typeorm.Index)('IDX_user_token_user_type', [
123
+ 'userId',
124
+ 'type'
125
+ ]),
126
+ (0, _typeorm.Index)('IDX_user_token_expires', [
127
+ 'expiresAt'
128
+ ])
129
+ ], UserToken);
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "AuthThrottlerGuard", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return AuthThrottlerGuard;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ const _throttler = require("@nestjs/throttler");
13
+ function _ts_decorate(decorators, target, key, desc) {
14
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
15
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
16
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
17
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
18
+ }
19
+ let AuthThrottlerGuard = class AuthThrottlerGuard extends _throttler.ThrottlerGuard {
20
+ /**
21
+ * Generate tracker key combining IP and email for login attempts.
22
+ * This prevents attackers from brute-forcing multiple accounts from the same IP.
23
+ */ async getTracker(req) {
24
+ const ip = req.ip || req.headers?.['x-forwarded-for'] || 'unknown';
25
+ const body = req.body;
26
+ const email = body?.email || '';
27
+ return `auth:${ip}:${email}`;
28
+ }
29
+ /**
30
+ * Custom error message for rate limit exceeded.
31
+ */ throwThrottlingException() {
32
+ throw new _throttler.ThrottlerException('Too many authentication attempts. Please try again later.');
33
+ }
34
+ /**
35
+ * Skip rate limiting for authenticated users on certain endpoints.
36
+ */ async shouldSkip(context) {
37
+ const request = context.switchToHttp().getRequest();
38
+ const path = request.path || request.url || '';
39
+ // Remove query string for comparison
40
+ const pathOnly = path.split('?')[0];
41
+ // Skip rate limiting for authenticated endpoints (they have their own protection)
42
+ // Use exact match or prefix match to prevent bypass via path manipulation
43
+ const authenticatedEndpoints = [
44
+ '/auth/me',
45
+ '/auth/logout',
46
+ '/auth/change-password'
47
+ ];
48
+ return authenticatedEndpoints.some((endpoint)=>pathOnly === endpoint || pathOnly.startsWith(`${endpoint}/`));
49
+ }
50
+ };
51
+ AuthThrottlerGuard = _ts_decorate([
52
+ (0, _common.Injectable)()
53
+ ], AuthThrottlerGuard);
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "ClearToken", {
10
10
  });
11
11
  const _common = require("@nestjs/common");
12
12
  const _rxjs = require("rxjs");
13
+ const _config = require("../config");
13
14
  const _authconfigservice = require("../services/auth-config.service");
14
15
  function _define_property(obj, key, value) {
15
16
  if (key in obj) {
@@ -38,23 +39,19 @@ function _ts_param(paramIndex, decorator) {
38
39
  decorator(target, key, paramIndex);
39
40
  };
40
41
  }
41
- const DEFAULT_COOKIE_NAME = 'fsn_refresh_token';
42
42
  let ClearToken = class ClearToken {
43
43
  get cookieName() {
44
- return this.authConfig?.getRefreshTokenCookieName() ?? DEFAULT_COOKIE_NAME;
44
+ return this.authConfig?.getRefreshTokenCookieName() ?? _config.DEFAULT_COOKIE_NAME;
45
45
  }
46
46
  intercept(context, next) {
47
47
  const req = context.switchToHttp().getRequest();
48
48
  const res = context.switchToHttp().getResponse();
49
49
  return next.handle().pipe((0, _rxjs.map)((value)=>{
50
- // Clear the refresh token cookie
51
50
  this.clearRefreshTokenCookie(req, res);
52
51
  return value;
53
52
  }));
54
53
  }
55
- /**
56
- * Clear refresh token cookie
57
- */ clearRefreshTokenCookie(req, res) {
54
+ clearRefreshTokenCookie(req, res) {
58
55
  const origin = req.headers.origin || '';
59
56
  const hostname = req.hostname || '';
60
57
  const isHttps = origin.startsWith('https://') || req.secure;
@@ -11,6 +11,7 @@ Object.defineProperty(exports, "SetToken", {
11
11
  const _common = require("@nestjs/common");
12
12
  const _buffer = require("buffer");
13
13
  const _rxjs = require("rxjs");
14
+ const _config = require("../config");
14
15
  const _authconfigservice = require("../services/auth-config.service");
15
16
  function _define_property(obj, key, value) {
16
17
  if (key in obj) {
@@ -39,80 +40,85 @@ function _ts_param(paramIndex, decorator) {
39
40
  decorator(target, key, paramIndex);
40
41
  };
41
42
  }
42
- const DEFAULT_COOKIE_NAME = 'fsn_refresh_token';
43
- const MAX_COOKIE_BYTES = 3500;
44
43
  let SetToken = class SetToken {
45
44
  get cookieName() {
46
- return this.authConfig?.getRefreshTokenCookieName() ?? DEFAULT_COOKIE_NAME;
45
+ return this.authConfig?.getRefreshTokenCookieName() ?? _config.DEFAULT_COOKIE_NAME;
46
+ }
47
+ /** Convert expiration string (e.g., '7d', '24h') to milliseconds */ getMaxAgeMs() {
48
+ const expiry = this.authConfig?.getRefreshTokenExpiration() ?? '7d';
49
+ const match = expiry.match(/^(\d+)(s|m|h|d|w)$/);
50
+ if (!match) {
51
+ return 7 * 24 * 60 * 60 * 1000; // Default 7 days
52
+ }
53
+ const value = parseInt(match[1], 10);
54
+ const unit = match[2];
55
+ const multipliers = {
56
+ s: 1000,
57
+ m: 60 * 1000,
58
+ h: 60 * 60 * 1000,
59
+ d: 24 * 60 * 60 * 1000,
60
+ w: 7 * 24 * 60 * 60 * 1000
61
+ };
62
+ return value * (multipliers[unit] || multipliers['d']);
47
63
  }
48
64
  intercept(context, next) {
49
65
  const req = context.switchToHttp().getRequest();
50
66
  const res = context.switchToHttp().getResponse();
51
67
  return next.handle().pipe((0, _rxjs.map)((value)=>{
52
- // Skip if no refreshToken in response
53
68
  if (!value || !value.refreshToken) {
54
69
  return value;
55
70
  }
56
71
  const isBrowser = this.isBrowserRequest(req);
57
72
  const tokenValue = value.refreshToken;
58
73
  if (isBrowser) {
59
- // Browser: Set cookie and remove from response body
60
74
  this.setRefreshTokenCookie(req, res, tokenValue);
61
- // Return response without refreshToken for browsers
62
75
  const { refreshToken, ...responseWithoutToken } = value;
63
76
  return responseWithoutToken;
64
77
  }
65
- // API/Mobile: Keep refreshToken in response body
66
78
  return value;
67
79
  }), (0, _rxjs.catchError)((err)=>(0, _rxjs.throwError)(()=>err)));
68
80
  }
69
- /**
70
- * Detect if request is from a browser
71
- * Checks Accept header and custom X-Client-Type header
72
- */ isBrowserRequest(req) {
73
- // Check custom header first (allows explicit client identification)
81
+ isBrowserRequest(req) {
74
82
  const clientType = req.headers['x-client-type'];
75
83
  if (clientType) {
76
84
  return clientType.toLowerCase() === 'browser' || clientType.toLowerCase() === 'web';
77
85
  }
78
- // Check Accept header - browsers typically include text/html
79
86
  const accept = req.headers['accept'] || '';
80
87
  if (accept.includes('text/html')) {
81
88
  return true;
82
89
  }
83
- // Check User-Agent for common browsers
84
90
  const userAgent = req.headers['user-agent'] || '';
85
91
  const browserPatterns = /mozilla|chrome|safari|firefox|edge|opera|msie/i;
86
- if (browserPatterns.test(userAgent) && !userAgent.includes('Postman')) {
87
- return true;
88
- }
89
- return false;
92
+ return browserPatterns.test(userAgent) && !userAgent.includes('Postman');
90
93
  }
91
- /**
92
- * Set refresh token in HTTP-only cookie
93
- */ setRefreshTokenCookie(req, res, tokenValue) {
94
- const origin = req.headers.origin || '';
94
+ setRefreshTokenCookie(req, res, tokenValue) {
95
95
  const hostname = req.hostname || '';
96
- const isHttps = origin.startsWith('https://') || req.secure;
97
- let cookieDomain = hostname;
96
+ // Determine if we're in production - always use secure cookies in production
97
+ // This handles TLS-terminating proxies correctly (they set x-forwarded-proto)
98
+ const isProduction = process.env.NODE_ENV === 'production';
99
+ const forwardedProto = req.headers['x-forwarded-proto'];
100
+ const isHttps = isProduction || forwardedProto === 'https' || req.secure;
101
+ // Set cookie domain - only for subdomains with 3+ parts
102
+ // For security, limit to same domain unless explicitly configured
103
+ let cookieDomain;
98
104
  const domainParts = hostname.split('.');
99
- if (domainParts.length > 2) {
105
+ if (domainParts.length > 2 && !hostname.includes('localhost')) {
100
106
  cookieDomain = '.' + domainParts.slice(-2).join('.');
101
107
  }
102
- // Check cookie size
103
- const rawCookieString = `${this.cookieName}=${tokenValue}; HttpOnly; Domain=${cookieDomain}`;
108
+ const rawCookieString = `${this.cookieName}=${tokenValue}; HttpOnly`;
104
109
  const estimatedBytes = _buffer.Buffer.byteLength(rawCookieString, 'utf8');
105
- if (estimatedBytes > MAX_COOKIE_BYTES) {
110
+ if (estimatedBytes > _config.MAX_COOKIE_BYTES) {
106
111
  throw new _common.PayloadTooLargeException(`Refresh token too large (≈${estimatedBytes} bytes)`);
107
112
  }
108
- // Set HTTP-only secure cookie
109
113
  res.cookie(this.cookieName, tokenValue, {
110
114
  httpOnly: true,
111
115
  secure: isHttps,
112
116
  sameSite: isHttps ? 'strict' : 'lax',
113
- domain: cookieDomain,
117
+ ...cookieDomain && {
118
+ domain: cookieDomain
119
+ },
114
120
  path: '/',
115
- maxAge: 7 * 24 * 60 * 60 * 1000
121
+ maxAge: this.getMaxAgeMs()
116
122
  });
117
123
  }
118
124
  constructor(authConfig){
@@ -123,6 +129,7 @@ let SetToken = class SetToken {
123
129
  SetToken = _ts_decorate([
124
130
  (0, _common.Injectable)(),
125
131
  _ts_param(0, (0, _common.Optional)()),
132
+ _ts_param(0, (0, _common.Inject)(_authconfigservice.AuthConfigService)),
126
133
  _ts_metadata("design:type", Function),
127
134
  _ts_metadata("design:paramtypes", [
128
135
  typeof _authconfigservice.AuthConfigService === "undefined" ? Object : _authconfigservice.AuthConfigService
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Auth Email Provider Interface
3
+ *
4
+ * This interface defines the contract for email sending in the auth module.
5
+ * It allows auth to work independently of the email module.
6
+ *
7
+ * To use email features in auth:
8
+ * 1. Provide AUTH_EMAIL_PROVIDER in your app module
9
+ * 2. Implement IAuthEmailProvider using EmailSendService from nestjs-email
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * // In app.module.ts or a provider file
14
+ * {
15
+ * provide: AUTH_EMAIL_PROVIDER,
16
+ * useFactory: (emailSendService: EmailSendService) => ({
17
+ * sendPasswordResetEmail: async (email, token, resetUrl) => {
18
+ * await emailSendService.sendTemplateEmail({
19
+ * templateSlug: 'password-reset',
20
+ * to: email,
21
+ * variables: { resetUrl, token },
22
+ * });
23
+ * },
24
+ * sendVerificationEmail: async (email, token, verifyUrl) => {
25
+ * await emailSendService.sendTemplateEmail({
26
+ * templateSlug: 'email-verification',
27
+ * to: email,
28
+ * variables: { verifyUrl, token },
29
+ * });
30
+ * },
31
+ * }),
32
+ * inject: [EmailSendService],
33
+ * }
34
+ * ```
35
+ */ "use strict";
36
+ Object.defineProperty(exports, "__esModule", {
37
+ value: true
38
+ });
39
+ Object.defineProperty(exports, "AUTH_EMAIL_PROVIDER", {
40
+ enumerable: true,
41
+ get: function() {
42
+ return AUTH_EMAIL_PROVIDER;
43
+ }
44
+ });
45
+ const AUTH_EMAIL_PROVIDER = 'AUTH_EMAIL_PROVIDER';
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
5
  _export_star(require("./authentication.interface"), exports);
6
+ _export_star(require("./auth-email-provider.interface"), exports);
6
7
  _export_star(require("./company-branch.interface"), exports);
7
8
  _export_star(require("./company.interface"), exports);
8
9
  _export_star(require("./user.interface"), exports);
10
+ _export_star(require("./user-enricher.interface"), exports);
9
11
  _export_star(require("./auth-module-options.interface"), exports);
10
12
  function _export_star(from, to) {
11
13
  Object.keys(from).forEach(function(k) {