@warlock.js/auth 4.0.31 → 4.0.41

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 (169) hide show
  1. package/cjs/index.js +725 -1
  2. package/cjs/index.js.map +1 -1
  3. package/esm/index.js +705 -1
  4. package/esm/index.js.map +1 -1
  5. package/package.json +48 -34
  6. package/cjs/commands/auth-cleanup-command.d.ts +0 -10
  7. package/cjs/commands/auth-cleanup-command.d.ts.map +0 -1
  8. package/cjs/commands/auth-cleanup-command.js +0 -29
  9. package/cjs/commands/auth-cleanup-command.js.map +0 -1
  10. package/cjs/commands/jwt-secret-generator-command.d.ts +0 -2
  11. package/cjs/commands/jwt-secret-generator-command.d.ts.map +0 -1
  12. package/cjs/commands/jwt-secret-generator-command.js +0 -7
  13. package/cjs/commands/jwt-secret-generator-command.js.map +0 -1
  14. package/cjs/contracts/auth-contract.d.ts +0 -23
  15. package/cjs/contracts/auth-contract.d.ts.map +0 -1
  16. package/cjs/contracts/index.d.ts +0 -3
  17. package/cjs/contracts/index.d.ts.map +0 -1
  18. package/cjs/contracts/types.d.ts +0 -134
  19. package/cjs/contracts/types.d.ts.map +0 -1
  20. package/cjs/contracts/types.js +0 -20
  21. package/cjs/contracts/types.js.map +0 -1
  22. package/cjs/index.d.ts +0 -8
  23. package/cjs/index.d.ts.map +0 -1
  24. package/cjs/middleware/auth.middleware.d.ts +0 -2
  25. package/cjs/middleware/auth.middleware.d.ts.map +0 -1
  26. package/cjs/middleware/auth.middleware.js +0 -73
  27. package/cjs/middleware/auth.middleware.js.map +0 -1
  28. package/cjs/middleware/index.d.ts +0 -2
  29. package/cjs/middleware/index.d.ts.map +0 -1
  30. package/cjs/models/access-token/access-token.d.ts +0 -12
  31. package/cjs/models/access-token/access-token.d.ts.map +0 -1
  32. package/cjs/models/access-token/access-token.js +0 -16
  33. package/cjs/models/access-token/access-token.js.map +0 -1
  34. package/cjs/models/access-token/index.d.ts +0 -3
  35. package/cjs/models/access-token/index.d.ts.map +0 -1
  36. package/cjs/models/access-token/migration.d.ts +0 -3
  37. package/cjs/models/access-token/migration.d.ts.map +0 -1
  38. package/cjs/models/access-token/migration.js +0 -10
  39. package/cjs/models/access-token/migration.js.map +0 -1
  40. package/cjs/models/auth.d.ts +0 -47
  41. package/cjs/models/auth.d.ts.map +0 -1
  42. package/cjs/models/auth.js +0 -58
  43. package/cjs/models/auth.js.map +0 -1
  44. package/cjs/models/casts/cast-password.d.ts +0 -7
  45. package/cjs/models/casts/cast-password.d.ts.map +0 -1
  46. package/cjs/models/casts/cast-password.js +0 -9
  47. package/cjs/models/casts/cast-password.js.map +0 -1
  48. package/cjs/models/casts/index.d.ts +0 -2
  49. package/cjs/models/casts/index.d.ts.map +0 -1
  50. package/cjs/models/index.d.ts +0 -5
  51. package/cjs/models/index.d.ts.map +0 -1
  52. package/cjs/models/refresh-token/index.d.ts +0 -2
  53. package/cjs/models/refresh-token/index.d.ts.map +0 -1
  54. package/cjs/models/refresh-token/migration.d.ts +0 -3
  55. package/cjs/models/refresh-token/migration.d.ts.map +0 -1
  56. package/cjs/models/refresh-token/refresh-token.d.ts +0 -32
  57. package/cjs/models/refresh-token/refresh-token.d.ts.map +0 -1
  58. package/cjs/models/refresh-token/refresh-token.js +0 -52
  59. package/cjs/models/refresh-token/refresh-token.js.map +0 -1
  60. package/cjs/services/auth-events.d.ts +0 -84
  61. package/cjs/services/auth-events.d.ts.map +0 -1
  62. package/cjs/services/auth-events.js +0 -65
  63. package/cjs/services/auth-events.js.map +0 -1
  64. package/cjs/services/auth.service.d.ts +0 -78
  65. package/cjs/services/auth.service.d.ts.map +0 -1
  66. package/cjs/services/auth.service.js +0 -265
  67. package/cjs/services/auth.service.js.map +0 -1
  68. package/cjs/services/generate-jwt-secret.d.ts +0 -2
  69. package/cjs/services/generate-jwt-secret.d.ts.map +0 -1
  70. package/cjs/services/generate-jwt-secret.js +0 -26
  71. package/cjs/services/generate-jwt-secret.js.map +0 -1
  72. package/cjs/services/index.d.ts +0 -5
  73. package/cjs/services/index.d.ts.map +0 -1
  74. package/cjs/services/jwt.d.ts +0 -23
  75. package/cjs/services/jwt.d.ts.map +0 -1
  76. package/cjs/services/jwt.js +0 -39
  77. package/cjs/services/jwt.js.map +0 -1
  78. package/cjs/utils/auth-error-codes.d.ts +0 -18
  79. package/cjs/utils/auth-error-codes.d.ts.map +0 -1
  80. package/cjs/utils/auth-error-codes.js +0 -18
  81. package/cjs/utils/auth-error-codes.js.map +0 -1
  82. package/cjs/utils/duration.d.ts +0 -45
  83. package/cjs/utils/duration.d.ts.map +0 -1
  84. package/cjs/utils/duration.js +0 -93
  85. package/cjs/utils/duration.js.map +0 -1
  86. package/cjs/utils/index.d.ts +0 -3
  87. package/cjs/utils/index.d.ts.map +0 -1
  88. package/esm/commands/auth-cleanup-command.d.ts +0 -10
  89. package/esm/commands/auth-cleanup-command.d.ts.map +0 -1
  90. package/esm/commands/auth-cleanup-command.js +0 -29
  91. package/esm/commands/auth-cleanup-command.js.map +0 -1
  92. package/esm/commands/jwt-secret-generator-command.d.ts +0 -2
  93. package/esm/commands/jwt-secret-generator-command.d.ts.map +0 -1
  94. package/esm/commands/jwt-secret-generator-command.js +0 -7
  95. package/esm/commands/jwt-secret-generator-command.js.map +0 -1
  96. package/esm/contracts/auth-contract.d.ts +0 -23
  97. package/esm/contracts/auth-contract.d.ts.map +0 -1
  98. package/esm/contracts/index.d.ts +0 -3
  99. package/esm/contracts/index.d.ts.map +0 -1
  100. package/esm/contracts/types.d.ts +0 -134
  101. package/esm/contracts/types.d.ts.map +0 -1
  102. package/esm/contracts/types.js +0 -20
  103. package/esm/contracts/types.js.map +0 -1
  104. package/esm/index.d.ts +0 -8
  105. package/esm/index.d.ts.map +0 -1
  106. package/esm/middleware/auth.middleware.d.ts +0 -2
  107. package/esm/middleware/auth.middleware.d.ts.map +0 -1
  108. package/esm/middleware/auth.middleware.js +0 -73
  109. package/esm/middleware/auth.middleware.js.map +0 -1
  110. package/esm/middleware/index.d.ts +0 -2
  111. package/esm/middleware/index.d.ts.map +0 -1
  112. package/esm/models/access-token/access-token.d.ts +0 -12
  113. package/esm/models/access-token/access-token.d.ts.map +0 -1
  114. package/esm/models/access-token/access-token.js +0 -16
  115. package/esm/models/access-token/access-token.js.map +0 -1
  116. package/esm/models/access-token/index.d.ts +0 -3
  117. package/esm/models/access-token/index.d.ts.map +0 -1
  118. package/esm/models/access-token/migration.d.ts +0 -3
  119. package/esm/models/access-token/migration.d.ts.map +0 -1
  120. package/esm/models/access-token/migration.js +0 -10
  121. package/esm/models/access-token/migration.js.map +0 -1
  122. package/esm/models/auth.d.ts +0 -47
  123. package/esm/models/auth.d.ts.map +0 -1
  124. package/esm/models/auth.js +0 -58
  125. package/esm/models/auth.js.map +0 -1
  126. package/esm/models/casts/cast-password.d.ts +0 -7
  127. package/esm/models/casts/cast-password.d.ts.map +0 -1
  128. package/esm/models/casts/cast-password.js +0 -9
  129. package/esm/models/casts/cast-password.js.map +0 -1
  130. package/esm/models/casts/index.d.ts +0 -2
  131. package/esm/models/casts/index.d.ts.map +0 -1
  132. package/esm/models/index.d.ts +0 -5
  133. package/esm/models/index.d.ts.map +0 -1
  134. package/esm/models/refresh-token/index.d.ts +0 -2
  135. package/esm/models/refresh-token/index.d.ts.map +0 -1
  136. package/esm/models/refresh-token/migration.d.ts +0 -3
  137. package/esm/models/refresh-token/migration.d.ts.map +0 -1
  138. package/esm/models/refresh-token/refresh-token.d.ts +0 -32
  139. package/esm/models/refresh-token/refresh-token.d.ts.map +0 -1
  140. package/esm/models/refresh-token/refresh-token.js +0 -52
  141. package/esm/models/refresh-token/refresh-token.js.map +0 -1
  142. package/esm/services/auth-events.d.ts +0 -84
  143. package/esm/services/auth-events.d.ts.map +0 -1
  144. package/esm/services/auth-events.js +0 -65
  145. package/esm/services/auth-events.js.map +0 -1
  146. package/esm/services/auth.service.d.ts +0 -78
  147. package/esm/services/auth.service.d.ts.map +0 -1
  148. package/esm/services/auth.service.js +0 -265
  149. package/esm/services/auth.service.js.map +0 -1
  150. package/esm/services/generate-jwt-secret.d.ts +0 -2
  151. package/esm/services/generate-jwt-secret.d.ts.map +0 -1
  152. package/esm/services/generate-jwt-secret.js +0 -26
  153. package/esm/services/generate-jwt-secret.js.map +0 -1
  154. package/esm/services/index.d.ts +0 -5
  155. package/esm/services/index.d.ts.map +0 -1
  156. package/esm/services/jwt.d.ts +0 -23
  157. package/esm/services/jwt.d.ts.map +0 -1
  158. package/esm/services/jwt.js +0 -39
  159. package/esm/services/jwt.js.map +0 -1
  160. package/esm/utils/auth-error-codes.d.ts +0 -18
  161. package/esm/utils/auth-error-codes.d.ts.map +0 -1
  162. package/esm/utils/auth-error-codes.js +0 -18
  163. package/esm/utils/auth-error-codes.js.map +0 -1
  164. package/esm/utils/duration.d.ts +0 -45
  165. package/esm/utils/duration.d.ts.map +0 -1
  166. package/esm/utils/duration.js +0 -93
  167. package/esm/utils/duration.js.map +0 -1
  168. package/esm/utils/index.d.ts +0 -3
  169. package/esm/utils/index.d.ts.map +0 -1
package/cjs/index.js CHANGED
@@ -1 +1,725 @@
1
- 'use strict';var authCleanupCommand=require('./commands/auth-cleanup-command.js'),jwtSecretGeneratorCommand=require('./commands/jwt-secret-generator-command.js'),types=require('./contracts/types.js'),auth_middleware=require('./middleware/auth.middleware.js'),accessToken=require('./models/access-token/access-token.js');require('./models/access-token/migration.js');var auth=require('./models/auth.js'),castPassword=require('./models/casts/cast-password.js'),refreshToken=require('./models/refresh-token/refresh-token.js'),authEvents=require('./services/auth-events.js'),auth_service=require('./services/auth.service.js'),generateJwtSecret=require('./services/generate-jwt-secret.js'),jwt=require('./services/jwt.js'),authErrorCodes=require('./utils/auth-error-codes.js'),duration=require('./utils/duration.js');exports.registerAuthCleanupCommand=authCleanupCommand.registerAuthCleanupCommand;exports.registerJWTSecretGeneratorCommand=jwtSecretGeneratorCommand.registerJWTSecretGeneratorCommand;exports.NO_EXPIRATION=types.NO_EXPIRATION;exports.authMiddleware=auth_middleware.authMiddleware;exports.AccessToken=accessToken.AccessToken;exports.Auth=auth.Auth;exports.castPassword=castPassword.castPassword;exports.RefreshToken=refreshToken.RefreshToken;exports.authEvents=authEvents.authEvents;exports.authService=auth_service.authService;exports.generateJWTSecret=generateJwtSecret.generateJWTSecret;exports.jwt=jwt.jwt;Object.defineProperty(exports,'AuthErrorCodes',{enumerable:true,get:function(){return authErrorCodes.AuthErrorCodes}});exports.parseExpirationToMs=duration.parseExpirationToMs;exports.toJwtExpiresIn=duration.toJwtExpiresIn;//# sourceMappingURL=index.js.map
1
+ 'use strict';
2
+
3
+ var copper = require('@mongez/copper');
4
+ var core = require('@warlock.js/core');
5
+ var password = require('@mongez/password');
6
+ var reinforcements = require('@mongez/reinforcements');
7
+ var cascade = require('@warlock.js/cascade');
8
+ var seal = require('@warlock.js/seal');
9
+ var events = require('@mongez/events');
10
+ var fastJwt = require('fast-jwt');
11
+ var fs = require('@mongez/fs');
12
+ var logger = require('@warlock.js/logger');
13
+
14
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
+
16
+ var events__default = /*#__PURE__*/_interopDefault(events);
17
+
18
+ // ../../warlock.js/auth/src/commands/auth-cleanup-command.ts
19
+ var accessTokenSchema = seal.v.object({
20
+ token: seal.v.string().required(),
21
+ lastAccess: seal.v.date().default(() => /* @__PURE__ */ new Date()),
22
+ user: seal.v.object({
23
+ id: seal.v.number().required(),
24
+ userType: seal.v.string()
25
+ }).allowUnknown().required()
26
+ });
27
+ var AccessToken = class extends cascade.Model {
28
+ /**
29
+ * {@inheritDoc}
30
+ */
31
+ static table = "accessTokens";
32
+ static schema = accessTokenSchema;
33
+ };
34
+ cascade.migrate(AccessToken, {
35
+ name: "accessToken",
36
+ up() {
37
+ this.string("accessToken").index();
38
+ this.date("lastAccess");
39
+ },
40
+ down() {
41
+ this.dropIndex("token");
42
+ }
43
+ });
44
+ var refreshTokenSchema = seal.v.object({
45
+ token: seal.v.string().required(),
46
+ userId: seal.v.number().required(),
47
+ userType: seal.v.string().required(),
48
+ familyId: seal.v.string().required(),
49
+ expiresAt: seal.v.date().required(),
50
+ lastUsedAt: seal.v.date().default(() => /* @__PURE__ */ new Date()),
51
+ revokedAt: seal.v.date(),
52
+ deviceInfo: seal.v.record(seal.v.any())
53
+ });
54
+ var RefreshToken = class extends cascade.Model {
55
+ /**
56
+ * {@inheritDoc}
57
+ */
58
+ static table = "refreshTokens";
59
+ /**
60
+ * {@inheritDoc}
61
+ */
62
+ static schema = refreshTokenSchema;
63
+ /**
64
+ * Check if token is expired
65
+ */
66
+ get isExpired() {
67
+ const expiresAt = this.get("expiresAt");
68
+ if (!expiresAt) return false;
69
+ return /* @__PURE__ */ new Date() > new Date(expiresAt);
70
+ }
71
+ /**
72
+ * Check if token is revoked
73
+ */
74
+ get isRevoked() {
75
+ return !!this.get("revokedAt");
76
+ }
77
+ /**
78
+ * Check if token is valid (not expired and not revoked)
79
+ */
80
+ get isValid() {
81
+ return !this.isExpired && !this.isRevoked;
82
+ }
83
+ /**
84
+ * Revoke this token
85
+ */
86
+ async revoke() {
87
+ return this.merge({ revokedAt: /* @__PURE__ */ new Date() }).save();
88
+ }
89
+ /**
90
+ * Mark token as used (update lastUsedAt)
91
+ */
92
+ async markAsUsed() {
93
+ await this.merge({ lastUsedAt: /* @__PURE__ */ new Date() }).save();
94
+ }
95
+ };
96
+
97
+ // ../../warlock.js/auth/src/contracts/types.ts
98
+ var NO_EXPIRATION = /* @__PURE__ */ Symbol("NO_EXPIRATION");
99
+
100
+ // ../../warlock.js/auth/src/utils/duration.ts
101
+ function parseExpirationToMs(expiration, defaultMs = 36e5) {
102
+ if (expiration === void 0) {
103
+ return defaultMs;
104
+ }
105
+ if (expiration === NO_EXPIRATION) {
106
+ return void 0;
107
+ }
108
+ if (typeof expiration === "number") {
109
+ return expiration;
110
+ }
111
+ if (typeof expiration === "string") {
112
+ return parseStringDuration(expiration);
113
+ }
114
+ return parseDurationObject(expiration);
115
+ }
116
+ function parseDurationObject(duration) {
117
+ let ms = 0;
118
+ if (duration.milliseconds) ms += duration.milliseconds;
119
+ if (duration.seconds) ms += duration.seconds * 1e3;
120
+ if (duration.minutes) ms += duration.minutes * 60 * 1e3;
121
+ if (duration.hours) ms += duration.hours * 60 * 60 * 1e3;
122
+ if (duration.days) ms += duration.days * 24 * 60 * 60 * 1e3;
123
+ if (duration.weeks) ms += duration.weeks * 7 * 24 * 60 * 60 * 1e3;
124
+ return ms;
125
+ }
126
+ function parseStringDuration(str) {
127
+ let totalMs = 0;
128
+ const parts = str.trim().split(/\s+/);
129
+ for (const part of parts) {
130
+ const match = part.match(/^(\d+(?:\.\d+)?)([smhdw])$/i);
131
+ if (!match) continue;
132
+ const value = parseFloat(match[1]);
133
+ const unit = match[2].toLowerCase();
134
+ switch (unit) {
135
+ case "s":
136
+ totalMs += value * 1e3;
137
+ break;
138
+ case "m":
139
+ totalMs += value * 60 * 1e3;
140
+ break;
141
+ case "h":
142
+ totalMs += value * 60 * 60 * 1e3;
143
+ break;
144
+ case "d":
145
+ totalMs += value * 24 * 60 * 60 * 1e3;
146
+ break;
147
+ case "w":
148
+ totalMs += value * 7 * 24 * 60 * 60 * 1e3;
149
+ break;
150
+ }
151
+ }
152
+ return totalMs || 36e5;
153
+ }
154
+ function toJwtExpiresIn(expiration, defaultMs = 36e5) {
155
+ const ms = parseExpirationToMs(expiration, defaultMs);
156
+ if (ms === void 0) return void 0;
157
+ return Math.floor(ms / 1e3) + "s";
158
+ }
159
+ var AUTH_EVENT_PREFIX = "auth.";
160
+ var authEvents = {
161
+ /**
162
+ * Subscribe to an auth event
163
+ */
164
+ on(event, callback) {
165
+ return events__default.default.subscribe(AUTH_EVENT_PREFIX + event, callback);
166
+ },
167
+ /**
168
+ * Subscribe to an auth event (alias for `on`)
169
+ */
170
+ subscribe(event, callback) {
171
+ return this.on(event, callback);
172
+ },
173
+ /**
174
+ * Emit an auth event
175
+ */
176
+ emit(event, ...args) {
177
+ events__default.default.trigger(AUTH_EVENT_PREFIX + event, ...args);
178
+ },
179
+ /**
180
+ * Emit an auth event (alias for `emit`)
181
+ */
182
+ trigger(event, ...args) {
183
+ this.emit(event, ...args);
184
+ },
185
+ /**
186
+ * Unsubscribe from all auth events
187
+ */
188
+ unsubscribeAll() {
189
+ events__default.default.unsubscribeNamespace(AUTH_EVENT_PREFIX.slice(0, -1));
190
+ },
191
+ /**
192
+ * Unsubscribe from a specific auth event
193
+ */
194
+ off(event) {
195
+ if (event) {
196
+ events__default.default.unsubscribe(AUTH_EVENT_PREFIX + event);
197
+ } else {
198
+ this.unsubscribeAll();
199
+ }
200
+ }
201
+ };
202
+ var getSecretKey = () => core.config.key("auth.jwt.secret");
203
+ var getAlgorithm = () => core.config.key("auth.jwt.algorithm");
204
+ var getRefreshSecretKey = () => core.config.key("auth.jwt.refresh.secret");
205
+ var getRefreshTokenValidity = () => core.config.key("auth.jwt.refresh.expiresIn");
206
+ var jwt = {
207
+ /**
208
+ * Generate a new JWT token for the user.
209
+ * @param payload The payload to encode in the JWT token.
210
+ */
211
+ async generate(payload, {
212
+ key = getSecretKey(),
213
+ algorithm = getAlgorithm(),
214
+ ...options
215
+ } = {}) {
216
+ const sign = fastJwt.createSigner({ key, ...options, algorithm });
217
+ return sign({ ...payload });
218
+ },
219
+ /**
220
+ * Verify the given token.
221
+ * @param token The JWT token to verify.
222
+ * @returns The decoded token payload if verification is successful.
223
+ */
224
+ async verify(token, {
225
+ key = getSecretKey(),
226
+ algorithms = getAlgorithm() ? [getAlgorithm()] : void 0,
227
+ ...options
228
+ } = {}) {
229
+ const verify2 = fastJwt.createVerifier({ key, ...options, algorithms });
230
+ return await verify2(token);
231
+ },
232
+ /**
233
+ * Generate a new refresh token for the user.
234
+ */
235
+ async generateRefreshToken(payload, {
236
+ key = getRefreshSecretKey(),
237
+ expiresIn = getRefreshTokenValidity(),
238
+ algorithm = getAlgorithm(),
239
+ ...options
240
+ } = {}) {
241
+ const sign = fastJwt.createSigner({ key, expiresIn, algorithm, ...options });
242
+ return sign({ ...payload });
243
+ },
244
+ /**
245
+ * Verify the given refresh token.
246
+ */
247
+ async verifyRefreshToken(token, {
248
+ key = getRefreshSecretKey(),
249
+ algorithms = [getAlgorithm()],
250
+ ...options
251
+ } = {}) {
252
+ const verify2 = fastJwt.createVerifier({ key, algorithms, ...options });
253
+ return await verify2(token);
254
+ }
255
+ };
256
+
257
+ // ../../warlock.js/auth/src/services/auth.service.ts
258
+ var AuthService = class {
259
+ /**
260
+ * Build access token payload from user
261
+ */
262
+ buildAccessTokenPayload(user) {
263
+ return {
264
+ id: user.id,
265
+ _id: user.get("_id"),
266
+ userType: user.userType,
267
+ createdAt: Date.now()
268
+ };
269
+ }
270
+ /**
271
+ * Generate access token for user
272
+ */
273
+ async generateAccessToken(user, payload) {
274
+ const data = payload || this.buildAccessTokenPayload(user);
275
+ const expiresInConfig = core.config.key("auth.jwt.expiresIn");
276
+ const expiresIn = toJwtExpiresIn(expiresInConfig, 36e5);
277
+ const token = expiresIn ? await jwt.generate(data, { expiresIn }) : await jwt.generate(data);
278
+ await AccessToken.create({
279
+ token,
280
+ user: data
281
+ });
282
+ return token;
283
+ }
284
+ /**
285
+ * Create refresh token for user
286
+ */
287
+ async createRefreshToken(user, deviceInfo) {
288
+ const familyId = deviceInfo?.familyId || reinforcements.Random.string(32);
289
+ const expiresInConfig = core.config.key("auth.jwt.refresh.expiresIn");
290
+ const expiresInMs = parseExpirationToMs(expiresInConfig, 7 * 24 * 60 * 60 * 1e3);
291
+ const payload = {
292
+ userId: user.id,
293
+ userType: user.userType,
294
+ familyId
295
+ };
296
+ const token = await jwt.generateRefreshToken(payload);
297
+ await this.enforceMaxRefreshTokens(user);
298
+ const expiresAt = expiresInMs ? new Date(Date.now() + expiresInMs) : new Date(Date.now() + 100 * 365 * 24 * 60 * 60 * 1e3);
299
+ return RefreshToken.create({
300
+ token,
301
+ userId: user.id,
302
+ userType: user.userType,
303
+ familyId,
304
+ expiresAt,
305
+ deviceInfo: deviceInfo ? {
306
+ userAgent: deviceInfo.userAgent,
307
+ ip: deviceInfo.ip,
308
+ deviceId: deviceInfo.deviceId
309
+ } : void 0
310
+ });
311
+ }
312
+ /**
313
+ * Create both access and refresh tokens
314
+ */
315
+ async createTokenPair(user, deviceInfo) {
316
+ const accessToken = await this.generateAccessToken(user, deviceInfo?.payload);
317
+ const refreshToken = await this.createRefreshToken(user, deviceInfo);
318
+ const tokenPair = {
319
+ accessToken,
320
+ refreshToken: refreshToken.get("token"),
321
+ expiresIn: core.config.key("auth.jwt.expiresIn", "1h")
322
+ };
323
+ authEvents.emit("token.created", user, tokenPair);
324
+ authEvents.emit("session.created", user, refreshToken, deviceInfo);
325
+ return tokenPair;
326
+ }
327
+ /**
328
+ * Refresh tokens using a refresh token
329
+ */
330
+ async refreshTokens(refreshTokenString, deviceInfo) {
331
+ try {
332
+ const decoded = await jwt.verifyRefreshToken(refreshTokenString);
333
+ if (!decoded) return null;
334
+ const refreshToken = await RefreshToken.first({ token: refreshTokenString });
335
+ if (!refreshToken?.isValid) {
336
+ if (refreshToken) {
337
+ await this.revokeTokenFamily(refreshToken.get("familyId"));
338
+ }
339
+ return null;
340
+ }
341
+ const UserModel = core.config.key(`auth.userType.${decoded.userType}`);
342
+ if (!UserModel) return null;
343
+ const user = await UserModel.find(decoded.userId);
344
+ if (!user) return null;
345
+ const rotationEnabled = core.config.key("auth.jwt.refresh.rotation", true);
346
+ if (rotationEnabled) {
347
+ await refreshToken.revoke();
348
+ } else {
349
+ await refreshToken.markAsUsed();
350
+ }
351
+ const newTokenPair = await this.createTokenPair(user, {
352
+ ...deviceInfo,
353
+ familyId: refreshToken.get("familyId")
354
+ });
355
+ authEvents.emit("token.refreshed", user, newTokenPair, refreshToken);
356
+ return newTokenPair;
357
+ } catch {
358
+ return null;
359
+ }
360
+ }
361
+ /**
362
+ * Verify password
363
+ */
364
+ verifyPassword(hashedPassword, plainPassword) {
365
+ return password.verify(String(hashedPassword), String(plainPassword));
366
+ }
367
+ /**
368
+ * Hash password
369
+ */
370
+ hashPassword(password$1) {
371
+ return password.hash(String(password$1), core.config.key("auth.password.salt", 12));
372
+ }
373
+ /**
374
+ * Attempt to login user with given credentials
375
+ */
376
+ async attemptLogin(Model4, data) {
377
+ const { password, ...otherData } = data;
378
+ authEvents.emit("login.attempt", otherData);
379
+ const user = await Model4.first(otherData);
380
+ if (!user) {
381
+ authEvents.emit("login.failed", otherData, "User not found");
382
+ return null;
383
+ }
384
+ if (!this.verifyPassword(user.string("password"), password)) {
385
+ authEvents.emit("login.failed", otherData, "Invalid password");
386
+ return null;
387
+ }
388
+ return user;
389
+ }
390
+ /**
391
+ * Full login flow: validate credentials, create tokens, emit events
392
+ * Returns token pair on success, null on failure
393
+ */
394
+ async login(Model4, credentials, deviceInfo) {
395
+ const user = await this.attemptLogin(Model4, credentials);
396
+ if (!user) {
397
+ return null;
398
+ }
399
+ if (!core.config.key("auth.jwt.refresh.enabled", true)) {
400
+ const accessToken = await this.generateAccessToken(user, deviceInfo?.payload);
401
+ return { user, accessToken };
402
+ }
403
+ const tokens = await this.createTokenPair(user, deviceInfo);
404
+ authEvents.emit("login.success", user, tokens, deviceInfo);
405
+ return { user, tokens };
406
+ }
407
+ /**
408
+ * Logout user
409
+ * @param user - The authenticated user
410
+ * @param accessToken - Optional access token string to revoke
411
+ * @param refreshToken - Optional refresh token string to revoke
412
+ * If refresh token is not provided, behavior is determined by config:
413
+ * - "revoke-all" (default): Revoke ALL refresh tokens for security
414
+ * - "error": Throw error requiring refresh token
415
+ */
416
+ async logout(user, accessToken, refreshToken) {
417
+ if (accessToken) {
418
+ await this.removeAccessToken(user, accessToken);
419
+ }
420
+ if (refreshToken) {
421
+ const token = await RefreshToken.first({
422
+ token: refreshToken,
423
+ userId: user.id
424
+ // Security: ensure token belongs to this user
425
+ });
426
+ if (token) {
427
+ await token.revoke();
428
+ authEvents.emit("session.destroyed", user, token);
429
+ }
430
+ } else {
431
+ const behavior = core.config.key("auth.jwt.refresh.logoutWithoutToken", "revoke-all");
432
+ if (behavior === "error") {
433
+ throw new Error("Refresh token required for logout");
434
+ }
435
+ await this.revokeAllTokens(user);
436
+ authEvents.emit("logout.failsafe", user);
437
+ }
438
+ authEvents.emit("logout", user);
439
+ }
440
+ /**
441
+ * Remove specific access token
442
+ */
443
+ async removeAccessToken(user, token) {
444
+ AccessToken.delete({
445
+ token,
446
+ "user.id": user.id
447
+ });
448
+ }
449
+ /**
450
+ * Revoke all tokens for a user
451
+ */
452
+ async revokeAllTokens(user) {
453
+ const refreshTokens = await RefreshToken.query().where("userId", user.id).where("userType", user.userType).where("revokedAt", null).get();
454
+ for (const token of refreshTokens) {
455
+ await token.revoke();
456
+ authEvents.emit("token.revoked", user, token);
457
+ }
458
+ await AccessToken.delete({
459
+ "user.id": user.id,
460
+ "user.userType": user.userType
461
+ });
462
+ authEvents.emit("logout.all", user);
463
+ }
464
+ /**
465
+ * Revoke entire token family (for rotation breach detection)
466
+ */
467
+ async revokeTokenFamily(familyId) {
468
+ const tokens = await RefreshToken.query().where("familyId", familyId).where("revokedAt", null).get();
469
+ for (const token of tokens) {
470
+ await token.revoke();
471
+ }
472
+ authEvents.emit("token.familyRevoked", familyId, tokens);
473
+ }
474
+ /**
475
+ * Cleanup expired tokens
476
+ */
477
+ async cleanupExpiredTokens() {
478
+ const expiredTokens = await RefreshToken.query().where("expiresAt", "<", /* @__PURE__ */ new Date()).get();
479
+ for (const token of expiredTokens) {
480
+ authEvents.emit("token.expired", token);
481
+ await token.destroy();
482
+ }
483
+ authEvents.emit("cleanup.completed", expiredTokens.length);
484
+ return expiredTokens.length;
485
+ }
486
+ /**
487
+ * Enforce max refresh tokens per user
488
+ */
489
+ async enforceMaxRefreshTokens(user) {
490
+ const maxPerUser = core.config.key("auth.jwt.refresh.maxPerUser", 5);
491
+ const activeTokens = await RefreshToken.query().where("userId", user.id).where("userType", user.userType).where("revokedAt", null).orderBy("createdAt", "asc").get();
492
+ if (activeTokens.length >= maxPerUser) {
493
+ const tokensToRevoke = activeTokens.slice(0, activeTokens.length - maxPerUser + 1);
494
+ for (const token of tokensToRevoke) {
495
+ await token.revoke();
496
+ }
497
+ }
498
+ }
499
+ /**
500
+ * Get active sessions for user
501
+ */
502
+ async getActiveSessions(user) {
503
+ return RefreshToken.query().where("userId", user.id).where("userType", user.userType).where("revokedAt", null).where("expiresAt", ">", /* @__PURE__ */ new Date()).orderBy("createdAt", "desc").get();
504
+ }
505
+ };
506
+ var authService = new AuthService();
507
+
508
+ // ../../warlock.js/auth/src/commands/auth-cleanup-command.ts
509
+ function registerAuthCleanupCommand() {
510
+ return core.command({
511
+ name: "auth.cleanup",
512
+ description: "Remove expired refresh tokens from the database",
513
+ preload: {
514
+ env: true,
515
+ config: ["auth", "database"],
516
+ connectors: ["database"]
517
+ },
518
+ action: async () => {
519
+ console.log(copper.colors.cyan("\u{1F9F9} Cleaning up expired tokens..."));
520
+ const count = await authService.cleanupExpiredTokens();
521
+ if (count === 0) {
522
+ console.log(copper.colors.green("\u2705 No expired tokens found."));
523
+ } else {
524
+ console.log(copper.colors.green(`\u2705 Removed ${count} expired token(s).`));
525
+ }
526
+ }
527
+ });
528
+ }
529
+ async function generateJWTSecret() {
530
+ let envFile = core.rootPath(".env");
531
+ logger.log.info("jwt", "generating", "Generating JWT secrets");
532
+ const environmentMode = core.environment();
533
+ if (!await fs.fileExistsAsync(envFile)) {
534
+ const envFileType = environmentMode === "production" ? ".env.production" : ".env.development";
535
+ envFile = core.rootPath(envFileType);
536
+ }
537
+ if (!await fs.fileExistsAsync(envFile)) {
538
+ logger.log.error("jwt", "error", ".env file not found");
539
+ return;
540
+ }
541
+ let contents = await fs.getFileAsync(envFile);
542
+ const hasJwtSecret = contents.includes("JWT_SECRET");
543
+ const hasJwtRefreshSecret = contents.includes("JWT_REFRESH_SECRET");
544
+ if (hasJwtSecret && hasJwtRefreshSecret) {
545
+ logger.log.warn("jwt", "exists", "JWT secrets already exist in the .env file.");
546
+ return;
547
+ }
548
+ let secretsToAdd = "";
549
+ if (!hasJwtSecret) {
550
+ const jwtSecret = reinforcements.Random.string(32);
551
+ secretsToAdd += `
552
+ # JWT Secret
553
+ JWT_SECRET=${jwtSecret}
554
+ `;
555
+ logger.log.success("jwt", "generated", "JWT_SECRET generated and added to the .env file.");
556
+ } else {
557
+ logger.log.info("jwt", "exists", "JWT_SECRET already exists in the .env file.");
558
+ }
559
+ if (!hasJwtRefreshSecret) {
560
+ const jwtRefreshSecret = reinforcements.Random.string(32);
561
+ secretsToAdd += `
562
+ # JWT Refresh Secret
563
+ JWT_REFRESH_SECRET=${jwtRefreshSecret}
564
+ `;
565
+ logger.log.success("jwt", "generated", "JWT_REFRESH_SECRET generated and added to the .env file.");
566
+ } else {
567
+ logger.log.info("jwt", "exists", "JWT_REFRESH_SECRET already exists in the .env file.");
568
+ }
569
+ if (secretsToAdd) {
570
+ contents += secretsToAdd;
571
+ await fs.putFileAsync(envFile, contents);
572
+ }
573
+ }
574
+
575
+ // ../../warlock.js/auth/src/commands/jwt-secret-generator-command.ts
576
+ function registerJWTSecretGeneratorCommand() {
577
+ return core.command({
578
+ name: "jwt.generate",
579
+ description: "Generate JWT Secret key in .env file",
580
+ action: generateJWTSecret
581
+ });
582
+ }
583
+
584
+ // ../../warlock.js/auth/src/utils/auth-error-codes.ts
585
+ var AuthErrorCodes = /* @__PURE__ */ ((AuthErrorCodes2) => {
586
+ AuthErrorCodes2["MissingAccessToken"] = "EC001";
587
+ AuthErrorCodes2["InvalidAccessToken"] = "EC002";
588
+ AuthErrorCodes2["Unauthorized"] = "EC003";
589
+ return AuthErrorCodes2;
590
+ })(AuthErrorCodes || {});
591
+
592
+ // ../../warlock.js/auth/src/middleware/auth.middleware.ts
593
+ function authMiddleware(allowedUserType) {
594
+ const allowedTypes = !allowedUserType ? [] : Array.isArray(allowedUserType) ? allowedUserType : [allowedUserType];
595
+ const auth = async (request, response) => {
596
+ try {
597
+ const authorizationValue = request.authorizationValue;
598
+ if (!allowedTypes.length && !authorizationValue) return;
599
+ if (!authorizationValue) {
600
+ return response.unauthorized({
601
+ error: core.t("auth.errors.missingAccessToken"),
602
+ errorCode: "EC001" /* MissingAccessToken */
603
+ });
604
+ }
605
+ const user = await jwt.verify(authorizationValue);
606
+ request.decodedAccessToken = user;
607
+ const accessToken = await AccessToken.first({
608
+ token: authorizationValue
609
+ });
610
+ if (!accessToken) {
611
+ return response.unauthorized({
612
+ error: core.t("auth.errors.invalidAccessToken"),
613
+ errorCode: "EC002" /* InvalidAccessToken */
614
+ });
615
+ }
616
+ const userType = user.userType || accessToken.get("userType");
617
+ if (allowedTypes.length && !allowedTypes.includes(userType)) {
618
+ return response.unauthorized({
619
+ error: core.t("auth.errors.unauthorized"),
620
+ errorCode: "EC003" /* Unauthorized */
621
+ });
622
+ }
623
+ const UserModel = core.config.key(`auth.userType.${userType}`);
624
+ if (!UserModel) {
625
+ throw new Error(`User type ${userType} is unknown type.`);
626
+ }
627
+ const currentUser = await UserModel.find(user.id);
628
+ if (!currentUser) {
629
+ accessToken.destroy();
630
+ return response.unauthorized({
631
+ error: core.t("auth.errors.invalidAccessToken"),
632
+ errorCode: "EC002" /* InvalidAccessToken */
633
+ });
634
+ }
635
+ accessToken.set("lastAccess", /* @__PURE__ */ new Date());
636
+ await accessToken.save({ skipEvents: true });
637
+ request.user = currentUser;
638
+ } catch (err) {
639
+ logger.log.error("http", "auth", err);
640
+ request.clearCurrentUser();
641
+ return response.unauthorized({
642
+ error: core.t("auth.errors.invalidAccessToken"),
643
+ errorCode: "EC002" /* InvalidAccessToken */
644
+ });
645
+ }
646
+ };
647
+ return auth;
648
+ }
649
+ var Auth = class extends cascade.Model {
650
+ /**
651
+ * Get access token payload
652
+ */
653
+ accessTokenPayload() {
654
+ return authService.buildAccessTokenPayload(this);
655
+ }
656
+ /**
657
+ * Create both access and refresh tokens
658
+ */
659
+ async createTokenPair(deviceInfo) {
660
+ return authService.createTokenPair(this, deviceInfo);
661
+ }
662
+ /**
663
+ * Generate access token
664
+ */
665
+ async generateAccessToken(data) {
666
+ return authService.generateAccessToken(this, data);
667
+ }
668
+ /**
669
+ * Generate refresh token
670
+ */
671
+ async generateRefreshToken(deviceInfo) {
672
+ return authService.createRefreshToken(this, deviceInfo);
673
+ }
674
+ /**
675
+ * Remove current access token
676
+ */
677
+ async removeAccessToken(token) {
678
+ return authService.removeAccessToken(this, token);
679
+ }
680
+ /**
681
+ * Revoke all tokens (logout from all devices)
682
+ */
683
+ async revokeAllTokens() {
684
+ return authService.revokeAllTokens(this);
685
+ }
686
+ /**
687
+ * Get active sessions
688
+ */
689
+ async activeSessions() {
690
+ return authService.getActiveSessions(this);
691
+ }
692
+ /**
693
+ * Attempt to login the user
694
+ */
695
+ static async attempt(data) {
696
+ return authService.attemptLogin(this, data);
697
+ }
698
+ /**
699
+ * Confirm password
700
+ */
701
+ confirmPassword(password) {
702
+ return authService.verifyPassword(this.string("password"), password);
703
+ }
704
+ };
705
+ function castPassword(value, column, model) {
706
+ return value ? password.hash(String(value), core.config.key("auth.password.salt", 12)) : model.getInitial(column);
707
+ }
708
+
709
+ exports.AccessToken = AccessToken;
710
+ exports.Auth = Auth;
711
+ exports.AuthErrorCodes = AuthErrorCodes;
712
+ exports.NO_EXPIRATION = NO_EXPIRATION;
713
+ exports.RefreshToken = RefreshToken;
714
+ exports.authEvents = authEvents;
715
+ exports.authMiddleware = authMiddleware;
716
+ exports.authService = authService;
717
+ exports.castPassword = castPassword;
718
+ exports.generateJWTSecret = generateJWTSecret;
719
+ exports.jwt = jwt;
720
+ exports.parseExpirationToMs = parseExpirationToMs;
721
+ exports.registerAuthCleanupCommand = registerAuthCleanupCommand;
722
+ exports.registerJWTSecretGeneratorCommand = registerJWTSecretGeneratorCommand;
723
+ exports.toJwtExpiresIn = toJwtExpiresIn;
724
+ //# sourceMappingURL=index.js.map
725
+ //# sourceMappingURL=index.js.map