@adonisjs/auth 9.0.0-9 → 9.0.0
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.
- package/build/chunk-3HZHOWKL.js +8 -0
- package/build/chunk-3HZHOWKL.js.map +1 -0
- package/build/chunk-52DVKHJR.js +246 -0
- package/build/chunk-52DVKHJR.js.map +1 -0
- package/build/chunk-BHB55PBJ.js +197 -0
- package/build/chunk-BHB55PBJ.js.map +1 -0
- package/build/chunk-CZCFTIBB.js +21 -0
- package/build/chunk-CZCFTIBB.js.map +1 -0
- package/build/index.d.ts +7 -6
- package/build/index.js +146 -15
- package/build/index.js.map +1 -0
- package/build/modules/access_tokens_guard/access_token.d.ts +137 -0
- package/build/modules/access_tokens_guard/crc32.d.ts +16 -0
- package/build/modules/access_tokens_guard/define_config.d.ts +17 -0
- package/build/modules/access_tokens_guard/guard.d.ts +81 -0
- package/build/modules/access_tokens_guard/main.d.ts +5 -0
- package/build/modules/access_tokens_guard/main.js +929 -0
- package/build/modules/access_tokens_guard/main.js.map +1 -0
- package/build/modules/access_tokens_guard/token_providers/db.d.ts +76 -0
- package/build/modules/access_tokens_guard/types.d.ts +208 -0
- package/build/modules/access_tokens_guard/types.js +1 -0
- package/build/modules/access_tokens_guard/types.js.map +1 -0
- package/build/modules/access_tokens_guard/user_providers/lucid.d.ts +53 -0
- package/build/modules/session_guard/define_config.d.ts +17 -0
- package/build/modules/session_guard/guard.d.ts +98 -0
- package/build/modules/session_guard/main.d.ts +5 -0
- package/build/modules/session_guard/main.js +741 -0
- package/build/modules/session_guard/main.js.map +1 -0
- package/build/modules/session_guard/remember_me_token.d.ts +88 -0
- package/build/modules/session_guard/token_providers/db.d.ts +69 -0
- package/build/modules/session_guard/types.d.ts +243 -0
- package/build/modules/session_guard/types.js +1 -0
- package/build/modules/session_guard/types.js.map +1 -0
- package/build/modules/session_guard/user_providers/lucid.d.ts +57 -0
- package/build/providers/auth_provider.d.ts +1 -1
- package/build/providers/auth_provider.js +31 -27
- package/build/providers/auth_provider.js.map +1 -0
- package/build/services/auth.d.ts +1 -1
- package/build/services/auth.js +10 -15
- package/build/services/auth.js.map +1 -0
- package/build/src/{auth/auth_manager.d.ts → auth_manager.d.ts} +8 -3
- package/build/src/authenticator.d.ts +81 -0
- package/build/src/{auth/authenticator_client.d.ts → authenticator_client.d.ts} +4 -4
- package/build/src/{auth/define_config.d.ts → define_config.d.ts} +0 -10
- package/build/src/errors.d.ts +105 -0
- package/build/src/{auth/middleware → middleware}/initialize_auth_middleware.d.ts +3 -2
- package/build/src/middleware/initialize_auth_middleware.js +17 -0
- package/build/src/middleware/initialize_auth_middleware.js.map +1 -0
- package/build/src/mixins/with_auth_finder.d.ts +156 -0
- package/build/src/{auth/plugins → plugins}/japa/api_client.d.ts +8 -8
- package/build/src/plugins/japa/api_client.js +59 -0
- package/build/src/plugins/japa/api_client.js.map +1 -0
- package/build/src/{auth/plugins → plugins}/japa/browser_client.d.ts +10 -7
- package/build/src/plugins/japa/browser_client.js +67 -0
- package/build/src/plugins/japa/browser_client.js.map +1 -0
- package/build/src/{auth/types.d.ts → types.d.ts} +31 -26
- package/build/src/types.js +1 -0
- package/build/src/types.js.map +1 -0
- package/package.json +88 -68
- package/build/configure.js +0 -47
- package/build/factories/basic_auth_guard_factory.d.ts +0 -12
- package/build/factories/basic_auth_guard_factory.js +0 -22
- package/build/factories/database_token_factory.d.ts +0 -36
- package/build/factories/database_token_factory.js +0 -54
- package/build/factories/database_user_provider.d.ts +0 -14
- package/build/factories/database_user_provider.js +0 -27
- package/build/factories/lucid_user_provider.d.ts +0 -28
- package/build/factories/lucid_user_provider.js +0 -68
- package/build/factories/main.d.ts +0 -4
- package/build/factories/main.js +0 -12
- package/build/factories/session_guard_factory.d.ts +0 -13
- package/build/factories/session_guard_factory.js +0 -24
- package/build/src/auth/auth_manager.js +0 -41
- package/build/src/auth/authenticator.d.ts +0 -63
- package/build/src/auth/authenticator.js +0 -129
- package/build/src/auth/authenticator_client.js +0 -59
- package/build/src/auth/debug.js +0 -10
- package/build/src/auth/define_config.js +0 -54
- package/build/src/auth/errors.d.ts +0 -90
- package/build/src/auth/errors.js +0 -201
- package/build/src/auth/middleware/initialize_auth_middleware.js +0 -25
- package/build/src/auth/plugins/japa/api_client.js +0 -63
- package/build/src/auth/plugins/japa/browser_client.js +0 -64
- package/build/src/auth/symbols.js +0 -17
- package/build/src/auth/types.js +0 -9
- package/build/src/auth/user_providers/main.d.ts +0 -15
- package/build/src/auth/user_providers/main.js +0 -22
- package/build/src/core/guard_user.d.ts +0 -26
- package/build/src/core/guard_user.js +0 -29
- package/build/src/core/token.d.ts +0 -89
- package/build/src/core/token.js +0 -114
- package/build/src/core/token_providers/database.d.ts +0 -77
- package/build/src/core/token_providers/database.js +0 -113
- package/build/src/core/types.d.ts +0 -178
- package/build/src/core/types.js +0 -9
- package/build/src/core/user_providers/database.d.ts +0 -78
- package/build/src/core/user_providers/database.js +0 -117
- package/build/src/core/user_providers/lucid.d.ts +0 -61
- package/build/src/core/user_providers/lucid.js +0 -122
- package/build/src/guards/basic_auth/define_config.d.ts +0 -16
- package/build/src/guards/basic_auth/define_config.js +0 -38
- package/build/src/guards/basic_auth/guard.d.ts +0 -70
- package/build/src/guards/basic_auth/guard.js +0 -190
- package/build/src/guards/basic_auth/main.d.ts +0 -2
- package/build/src/guards/basic_auth/main.js +0 -10
- package/build/src/guards/basic_auth/types.d.ts +0 -35
- package/build/src/guards/basic_auth/types.js +0 -9
- package/build/src/guards/session/define_config.d.ts +0 -23
- package/build/src/guards/session/define_config.js +0 -56
- package/build/src/guards/session/guard.d.ts +0 -123
- package/build/src/guards/session/guard.js +0 -510
- package/build/src/guards/session/main.d.ts +0 -3
- package/build/src/guards/session/main.js +0 -11
- package/build/src/guards/session/token.d.ts +0 -57
- package/build/src/guards/session/token.js +0 -58
- package/build/src/guards/session/token_providers/main.d.ts +0 -33
- package/build/src/guards/session/token_providers/main.js +0 -42
- package/build/src/guards/session/types.d.ts +0 -104
- package/build/src/guards/session/types.js +0 -9
- package/build/stubs/main.d.ts +0 -1
- package/build/stubs/main.js +0 -10
- package/build/stubs/middleware/auth_middleware.stub +0 -30
- package/build/stubs/middleware/guest_middleware.stub +0 -36
- /package/build/src/{auth/debug.d.ts → debug.d.ts} +0 -0
- /package/build/src/{auth/symbols.d.ts → symbols.d.ts} +0 -0
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
import {
|
|
2
|
+
E_UNAUTHORIZED_ACCESS
|
|
3
|
+
} from "../../chunk-BHB55PBJ.js";
|
|
4
|
+
import "../../chunk-CZCFTIBB.js";
|
|
5
|
+
|
|
6
|
+
// modules/session_guard/remember_me_token.ts
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import string from "@adonisjs/core/helpers/string";
|
|
9
|
+
import { Secret, base64, safeEqual } from "@adonisjs/core/helpers";
|
|
10
|
+
var RememberMeToken = class {
|
|
11
|
+
/**
|
|
12
|
+
* Decodes a publicly shared token and return the series
|
|
13
|
+
* and the token value from it.
|
|
14
|
+
*
|
|
15
|
+
* Returns null when unable to decode the token because of
|
|
16
|
+
* invalid format or encoding.
|
|
17
|
+
*/
|
|
18
|
+
static decode(value) {
|
|
19
|
+
if (typeof value !== "string") {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
if (!value) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const [identifier, ...tokenValue] = value.split(".");
|
|
26
|
+
if (!identifier || tokenValue.length === 0) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const decodedIdentifier = base64.urlDecode(identifier);
|
|
30
|
+
const decodedSecret = base64.urlDecode(tokenValue.join("."));
|
|
31
|
+
if (!decodedIdentifier || !decodedSecret) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
identifier: decodedIdentifier,
|
|
36
|
+
secret: new Secret(decodedSecret)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a transient token that can be shared with the persistence
|
|
41
|
+
* layer.
|
|
42
|
+
*/
|
|
43
|
+
static createTransientToken(userId, size, expiresIn) {
|
|
44
|
+
const expiresAt = /* @__PURE__ */ new Date();
|
|
45
|
+
expiresAt.setSeconds(expiresAt.getSeconds() + string.seconds.parse(expiresIn));
|
|
46
|
+
return {
|
|
47
|
+
userId,
|
|
48
|
+
expiresAt,
|
|
49
|
+
...this.seed(size)
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Creates a secret opaque token and its hash.
|
|
54
|
+
*/
|
|
55
|
+
static seed(size) {
|
|
56
|
+
const seed = string.random(size);
|
|
57
|
+
const secret = new Secret(seed);
|
|
58
|
+
const hash = createHash("sha256").update(secret.release()).digest("hex");
|
|
59
|
+
return { secret, hash };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Identifer is a unique sequence to identify the
|
|
63
|
+
* token within database. It should be the
|
|
64
|
+
* primary/unique key
|
|
65
|
+
*/
|
|
66
|
+
identifier;
|
|
67
|
+
/**
|
|
68
|
+
* Reference to the user id for whom the token
|
|
69
|
+
* is generated.
|
|
70
|
+
*/
|
|
71
|
+
tokenableId;
|
|
72
|
+
/**
|
|
73
|
+
* The value is a public representation of a token. It is created
|
|
74
|
+
* by combining the "identifier"."secret"
|
|
75
|
+
*/
|
|
76
|
+
value;
|
|
77
|
+
/**
|
|
78
|
+
* Hash is computed from the seed to later verify the validity
|
|
79
|
+
* of seed
|
|
80
|
+
*/
|
|
81
|
+
hash;
|
|
82
|
+
/**
|
|
83
|
+
* Date/time when the token instance was created
|
|
84
|
+
*/
|
|
85
|
+
createdAt;
|
|
86
|
+
/**
|
|
87
|
+
* Date/time when the token was updated
|
|
88
|
+
*/
|
|
89
|
+
updatedAt;
|
|
90
|
+
/**
|
|
91
|
+
* Timestamp at which the token will expire
|
|
92
|
+
*/
|
|
93
|
+
expiresAt;
|
|
94
|
+
constructor(attributes) {
|
|
95
|
+
this.identifier = attributes.identifier;
|
|
96
|
+
this.tokenableId = attributes.tokenableId;
|
|
97
|
+
this.hash = attributes.hash;
|
|
98
|
+
this.createdAt = attributes.createdAt;
|
|
99
|
+
this.updatedAt = attributes.updatedAt;
|
|
100
|
+
this.expiresAt = attributes.expiresAt;
|
|
101
|
+
if (attributes.secret) {
|
|
102
|
+
this.value = new Secret(
|
|
103
|
+
`${base64.urlEncode(String(this.identifier))}.${base64.urlEncode(
|
|
104
|
+
attributes.secret.release()
|
|
105
|
+
)}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if the token has been expired. Verifies
|
|
111
|
+
* the "expiresAt" timestamp with the current
|
|
112
|
+
* date.
|
|
113
|
+
*/
|
|
114
|
+
isExpired() {
|
|
115
|
+
return this.expiresAt < /* @__PURE__ */ new Date();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Verifies the value of a token against the pre-defined hash
|
|
119
|
+
*/
|
|
120
|
+
verify(secret) {
|
|
121
|
+
const newHash = createHash("sha256").update(secret.release()).digest("hex");
|
|
122
|
+
return safeEqual(this.hash, newHash);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// modules/session_guard/guard.ts
|
|
127
|
+
import { Secret as Secret2 } from "@adonisjs/core/helpers";
|
|
128
|
+
import { RuntimeException } from "@adonisjs/core/exceptions";
|
|
129
|
+
var SessionGuard = class {
|
|
130
|
+
/**
|
|
131
|
+
* A unique name for the guard.
|
|
132
|
+
*/
|
|
133
|
+
#name;
|
|
134
|
+
/**
|
|
135
|
+
* Reference to the current HTTP context
|
|
136
|
+
*/
|
|
137
|
+
#ctx;
|
|
138
|
+
/**
|
|
139
|
+
* Options accepted by the session guard
|
|
140
|
+
*/
|
|
141
|
+
#options;
|
|
142
|
+
/**
|
|
143
|
+
* Provider to lookup user details
|
|
144
|
+
*/
|
|
145
|
+
#userProvider;
|
|
146
|
+
/**
|
|
147
|
+
* Emitter to emit events
|
|
148
|
+
*/
|
|
149
|
+
#emitter;
|
|
150
|
+
/**
|
|
151
|
+
* Driver name of the guard
|
|
152
|
+
*/
|
|
153
|
+
driverName = "session";
|
|
154
|
+
/**
|
|
155
|
+
* Whether or not the authentication has been attempted
|
|
156
|
+
* during the current request.
|
|
157
|
+
*/
|
|
158
|
+
authenticationAttempted = false;
|
|
159
|
+
/**
|
|
160
|
+
* A boolean to know if a remember me token was used in attempt
|
|
161
|
+
* to login a user.
|
|
162
|
+
*/
|
|
163
|
+
attemptedViaRemember = false;
|
|
164
|
+
/**
|
|
165
|
+
* A boolean to know if the current request has
|
|
166
|
+
* been authenticated
|
|
167
|
+
*/
|
|
168
|
+
isAuthenticated = false;
|
|
169
|
+
/**
|
|
170
|
+
* A boolean to know if the current request is authenticated
|
|
171
|
+
* using the "rememember_me" token.
|
|
172
|
+
*/
|
|
173
|
+
viaRemember = false;
|
|
174
|
+
/**
|
|
175
|
+
* Find if the user has been logged out during
|
|
176
|
+
* the current request
|
|
177
|
+
*/
|
|
178
|
+
isLoggedOut = false;
|
|
179
|
+
/**
|
|
180
|
+
* Reference to an instance of the authenticated user.
|
|
181
|
+
* The value only exists after calling one of the
|
|
182
|
+
* following methods.
|
|
183
|
+
*
|
|
184
|
+
* - authenticate
|
|
185
|
+
* - check
|
|
186
|
+
*
|
|
187
|
+
* You can use the "getUserOrFail" method to throw an exception if
|
|
188
|
+
* the request is not authenticated.
|
|
189
|
+
*/
|
|
190
|
+
user;
|
|
191
|
+
/**
|
|
192
|
+
* The key used to store the logged-in user id inside
|
|
193
|
+
* session
|
|
194
|
+
*/
|
|
195
|
+
get sessionKeyName() {
|
|
196
|
+
return `auth_${this.#name}`;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The key used to store the remember me token cookie
|
|
200
|
+
*/
|
|
201
|
+
get rememberMeKeyName() {
|
|
202
|
+
return `remember_${this.#name}`;
|
|
203
|
+
}
|
|
204
|
+
constructor(name, ctx, options, emitter, userProvider) {
|
|
205
|
+
this.#name = name;
|
|
206
|
+
this.#ctx = ctx;
|
|
207
|
+
this.#options = { rememberMeTokensAge: "2 years", ...options };
|
|
208
|
+
this.#emitter = emitter;
|
|
209
|
+
this.#userProvider = userProvider;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Returns the session instance for the given request,
|
|
213
|
+
* ensuring the property exists
|
|
214
|
+
*/
|
|
215
|
+
#getSession() {
|
|
216
|
+
if (!("session" in this.#ctx)) {
|
|
217
|
+
throw new RuntimeException(
|
|
218
|
+
'Cannot authenticate user. Install and configure "@adonisjs/session" package'
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
return this.#ctx.session;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Emits authentication failure, updates the local state,
|
|
225
|
+
* and returns an exception to end the authentication
|
|
226
|
+
* cycle.
|
|
227
|
+
*/
|
|
228
|
+
#authenticationFailed(sessionId) {
|
|
229
|
+
this.isAuthenticated = false;
|
|
230
|
+
this.viaRemember = false;
|
|
231
|
+
this.user = void 0;
|
|
232
|
+
this.isLoggedOut = false;
|
|
233
|
+
const error = new E_UNAUTHORIZED_ACCESS("Invalid or expired user session", {
|
|
234
|
+
guardDriverName: this.driverName
|
|
235
|
+
});
|
|
236
|
+
this.#emitter.emit("session_auth:authentication_failed", {
|
|
237
|
+
ctx: this.#ctx,
|
|
238
|
+
guardName: this.#name,
|
|
239
|
+
error,
|
|
240
|
+
sessionId
|
|
241
|
+
});
|
|
242
|
+
return error;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Emits the authentication succeeded event and updates
|
|
246
|
+
* the local state to reflect successful authentication
|
|
247
|
+
*/
|
|
248
|
+
#authenticationSucceeded(sessionId, user, rememberMeToken) {
|
|
249
|
+
this.isAuthenticated = true;
|
|
250
|
+
this.viaRemember = !!rememberMeToken;
|
|
251
|
+
this.user = user;
|
|
252
|
+
this.isLoggedOut = false;
|
|
253
|
+
this.#emitter.emit("session_auth:authentication_succeeded", {
|
|
254
|
+
ctx: this.#ctx,
|
|
255
|
+
guardName: this.#name,
|
|
256
|
+
sessionId,
|
|
257
|
+
user,
|
|
258
|
+
rememberMeToken
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Emits the login succeeded event and updates the login
|
|
263
|
+
* state
|
|
264
|
+
*/
|
|
265
|
+
#loginSucceeded(sessionId, user, rememberMeToken) {
|
|
266
|
+
this.user = user;
|
|
267
|
+
this.isLoggedOut = false;
|
|
268
|
+
this.#emitter.emit("session_auth:login_succeeded", {
|
|
269
|
+
ctx: this.#ctx,
|
|
270
|
+
guardName: this.#name,
|
|
271
|
+
sessionId,
|
|
272
|
+
user,
|
|
273
|
+
rememberMeToken
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Creates session for a given user by their user id.
|
|
278
|
+
*/
|
|
279
|
+
#createSessionForUser(userId) {
|
|
280
|
+
const session = this.#getSession();
|
|
281
|
+
session.put(this.sessionKeyName, userId);
|
|
282
|
+
session.regenerate();
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Creates the remember me cookie
|
|
286
|
+
*/
|
|
287
|
+
#createRememberMeCookie(value) {
|
|
288
|
+
this.#ctx.response.encryptedCookie(this.rememberMeKeyName, value.release(), {
|
|
289
|
+
maxAge: this.#options.rememberMeTokensAge,
|
|
290
|
+
httpOnly: true
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Authenticates the user using its id read from the session
|
|
295
|
+
* store.
|
|
296
|
+
*
|
|
297
|
+
* - We check the user exists in the db
|
|
298
|
+
* - If not, throw exception.
|
|
299
|
+
* - Otherwise, update local state to mark the user as logged-in
|
|
300
|
+
*/
|
|
301
|
+
async #authenticateViaId(userId, sessionId) {
|
|
302
|
+
const providerUser = await this.#userProvider.findById(userId);
|
|
303
|
+
if (!providerUser) {
|
|
304
|
+
throw this.#authenticationFailed(sessionId);
|
|
305
|
+
}
|
|
306
|
+
this.#authenticationSucceeded(sessionId, providerUser.getOriginal());
|
|
307
|
+
return this.user;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Authenticates user from the remember me cookie. Creates a fresh
|
|
311
|
+
* session for them and recycles the remember me token as well.
|
|
312
|
+
*/
|
|
313
|
+
async #authenticateViaRememberCookie(rememberMeCookie, sessionId) {
|
|
314
|
+
const userProvider = this.#userProvider;
|
|
315
|
+
const token = await userProvider.verifyRememberToken(new Secret2(rememberMeCookie));
|
|
316
|
+
if (!token) {
|
|
317
|
+
throw this.#authenticationFailed(sessionId);
|
|
318
|
+
}
|
|
319
|
+
const providerUser = await userProvider.findById(token.tokenableId);
|
|
320
|
+
if (!providerUser) {
|
|
321
|
+
throw this.#authenticationFailed(sessionId);
|
|
322
|
+
}
|
|
323
|
+
const recycledToken = await userProvider.recycleRememberToken(
|
|
324
|
+
providerUser.getOriginal(),
|
|
325
|
+
token.identifier,
|
|
326
|
+
this.#options.rememberMeTokensAge
|
|
327
|
+
);
|
|
328
|
+
this.#createRememberMeCookie(recycledToken.value);
|
|
329
|
+
this.#createSessionForUser(providerUser.getId());
|
|
330
|
+
this.#authenticationSucceeded(sessionId, providerUser.getOriginal(), token);
|
|
331
|
+
return this.user;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Returns an instance of the authenticated user. Or throws
|
|
335
|
+
* an exception if the request is not authenticated.
|
|
336
|
+
*/
|
|
337
|
+
getUserOrFail() {
|
|
338
|
+
if (!this.user) {
|
|
339
|
+
throw new E_UNAUTHORIZED_ACCESS("Invalid or expired user session", {
|
|
340
|
+
guardDriverName: this.driverName
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
return this.user;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Login user using sessions. Optionally, you can also create
|
|
347
|
+
* a remember me token to automatically login user when their
|
|
348
|
+
* session expires.
|
|
349
|
+
*/
|
|
350
|
+
async login(user, remember = false) {
|
|
351
|
+
const session = this.#getSession();
|
|
352
|
+
const providerUser = await this.#userProvider.createUserForGuard(user);
|
|
353
|
+
this.#emitter.emit("session_auth:login_attempted", {
|
|
354
|
+
ctx: this.#ctx,
|
|
355
|
+
user,
|
|
356
|
+
guardName: this.#name
|
|
357
|
+
});
|
|
358
|
+
let token;
|
|
359
|
+
if (remember) {
|
|
360
|
+
if (!this.#options.useRememberMeTokens) {
|
|
361
|
+
throw new RuntimeException('Cannot use "rememberMe" feature. It has been disabled');
|
|
362
|
+
}
|
|
363
|
+
const userProvider = this.#userProvider;
|
|
364
|
+
token = await userProvider.createRememberToken(
|
|
365
|
+
providerUser.getOriginal(),
|
|
366
|
+
this.#options.rememberMeTokensAge
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
if (token) {
|
|
370
|
+
this.#createRememberMeCookie(token.value);
|
|
371
|
+
} else {
|
|
372
|
+
this.#ctx.response.clearCookie(this.rememberMeKeyName);
|
|
373
|
+
}
|
|
374
|
+
this.#createSessionForUser(providerUser.getId());
|
|
375
|
+
this.#loginSucceeded(session.sessionId, providerUser.getOriginal(), token);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Logout a user by removing its state from the session
|
|
379
|
+
* store and delete the remember me cookie (if any).
|
|
380
|
+
*/
|
|
381
|
+
async logout() {
|
|
382
|
+
const session = this.#getSession();
|
|
383
|
+
const rememberMeCookie = this.#ctx.request.encryptedCookie(this.rememberMeKeyName);
|
|
384
|
+
session.forget(this.sessionKeyName);
|
|
385
|
+
this.#ctx.response.clearCookie(this.rememberMeKeyName);
|
|
386
|
+
if (this.user && rememberMeCookie && this.#options.useRememberMeTokens) {
|
|
387
|
+
const userProvider = this.#userProvider;
|
|
388
|
+
const token = await userProvider.verifyRememberToken(new Secret2(rememberMeCookie));
|
|
389
|
+
if (token) {
|
|
390
|
+
await userProvider.deleteRemeberToken(this.user, token.identifier);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
this.user = void 0;
|
|
394
|
+
this.viaRemember = false;
|
|
395
|
+
this.isAuthenticated = false;
|
|
396
|
+
this.isLoggedOut = true;
|
|
397
|
+
this.#emitter.emit("session_auth:logged_out", {
|
|
398
|
+
ctx: this.#ctx,
|
|
399
|
+
guardName: this.#name,
|
|
400
|
+
user: this.user || null,
|
|
401
|
+
sessionId: session.sessionId
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Authenticate the current HTTP request by verifying the bearer
|
|
406
|
+
* token or fails with an exception
|
|
407
|
+
*/
|
|
408
|
+
async authenticate() {
|
|
409
|
+
if (this.authenticationAttempted) {
|
|
410
|
+
return this.getUserOrFail();
|
|
411
|
+
}
|
|
412
|
+
this.authenticationAttempted = true;
|
|
413
|
+
const session = this.#getSession();
|
|
414
|
+
this.#emitter.emit("session_auth:authentication_attempted", {
|
|
415
|
+
ctx: this.#ctx,
|
|
416
|
+
sessionId: session.sessionId,
|
|
417
|
+
guardName: this.#name
|
|
418
|
+
});
|
|
419
|
+
const authUserId = session.get(this.sessionKeyName);
|
|
420
|
+
if (authUserId) {
|
|
421
|
+
return this.#authenticateViaId(authUserId, session.sessionId);
|
|
422
|
+
}
|
|
423
|
+
const rememberMeCookie = this.#ctx.request.encryptedCookie(this.rememberMeKeyName);
|
|
424
|
+
if (rememberMeCookie && this.#options.useRememberMeTokens) {
|
|
425
|
+
this.attemptedViaRemember = true;
|
|
426
|
+
return this.#authenticateViaRememberCookie(rememberMeCookie, session.sessionId);
|
|
427
|
+
}
|
|
428
|
+
throw this.#authenticationFailed(session.sessionId);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Silently check if the user is authenticated or not, without
|
|
432
|
+
* throwing any exceptions
|
|
433
|
+
*/
|
|
434
|
+
async check() {
|
|
435
|
+
try {
|
|
436
|
+
await this.authenticate();
|
|
437
|
+
return true;
|
|
438
|
+
} catch (error) {
|
|
439
|
+
if (error instanceof E_UNAUTHORIZED_ACCESS) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
throw error;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Returns the session info for the clients to send during
|
|
447
|
+
* an HTTP request to mark the user as logged-in.
|
|
448
|
+
*/
|
|
449
|
+
async authenticateAsClient(user) {
|
|
450
|
+
const providerUser = await this.#userProvider.createUserForGuard(user);
|
|
451
|
+
const userId = providerUser.getId();
|
|
452
|
+
return {
|
|
453
|
+
session: {
|
|
454
|
+
[this.sessionKeyName]: userId
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// modules/session_guard/token_providers/db.ts
|
|
461
|
+
import { RuntimeException as RuntimeException2 } from "@adonisjs/core/exceptions";
|
|
462
|
+
var DbRememberMeTokensProvider = class _DbRememberMeTokensProvider {
|
|
463
|
+
constructor(options) {
|
|
464
|
+
this.options = options;
|
|
465
|
+
this.table = options.table || "remember_me_tokens";
|
|
466
|
+
this.tokenSecretLength = options.tokenSecretLength || 40;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Create tokens provider instance for a given Lucid model
|
|
470
|
+
*/
|
|
471
|
+
static forModel(model, options) {
|
|
472
|
+
return new _DbRememberMeTokensProvider({
|
|
473
|
+
tokenableModel: model,
|
|
474
|
+
...options || {}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Database table to use for querying remember me tokens
|
|
479
|
+
*/
|
|
480
|
+
table;
|
|
481
|
+
/**
|
|
482
|
+
* The length for the token secret. A secret is a cryptographically
|
|
483
|
+
* secure random string.
|
|
484
|
+
*/
|
|
485
|
+
tokenSecretLength;
|
|
486
|
+
/**
|
|
487
|
+
* Ensure the provided user is an instance of the user model and
|
|
488
|
+
* has a primary key
|
|
489
|
+
*/
|
|
490
|
+
#ensureIsPersisted(user) {
|
|
491
|
+
const model = this.options.tokenableModel;
|
|
492
|
+
if (user instanceof model === false) {
|
|
493
|
+
throw new RuntimeException2(
|
|
494
|
+
`Invalid user object. It must be an instance of the "${model.name}" model`
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
if (!user.$primaryKeyValue) {
|
|
498
|
+
throw new RuntimeException2(
|
|
499
|
+
`Cannot use "${model.name}" model for managing remember me tokens. The value of column "${model.primaryKey}" is undefined or null`
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Maps a database row to an instance token instance
|
|
505
|
+
*/
|
|
506
|
+
dbRowToRememberMeToken(dbRow) {
|
|
507
|
+
return new RememberMeToken({
|
|
508
|
+
identifier: dbRow.id,
|
|
509
|
+
tokenableId: dbRow.tokenable_id,
|
|
510
|
+
hash: dbRow.hash,
|
|
511
|
+
createdAt: typeof dbRow.created_at === "number" ? new Date(dbRow.created_at) : dbRow.created_at,
|
|
512
|
+
updatedAt: typeof dbRow.updated_at === "number" ? new Date(dbRow.updated_at) : dbRow.updated_at,
|
|
513
|
+
expiresAt: typeof dbRow.expires_at === "number" ? new Date(dbRow.expires_at) : dbRow.expires_at
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Returns a query client instance from the parent model
|
|
518
|
+
*/
|
|
519
|
+
async getDb() {
|
|
520
|
+
const model = this.options.tokenableModel;
|
|
521
|
+
return model.$adapter.query(model).client;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Create a token for a user
|
|
525
|
+
*/
|
|
526
|
+
async create(user, expiresIn) {
|
|
527
|
+
this.#ensureIsPersisted(user);
|
|
528
|
+
const queryClient = await this.getDb();
|
|
529
|
+
const transientToken = RememberMeToken.createTransientToken(
|
|
530
|
+
user.$primaryKeyValue,
|
|
531
|
+
this.tokenSecretLength,
|
|
532
|
+
expiresIn
|
|
533
|
+
);
|
|
534
|
+
const dbRow = {
|
|
535
|
+
tokenable_id: transientToken.userId,
|
|
536
|
+
hash: transientToken.hash,
|
|
537
|
+
created_at: /* @__PURE__ */ new Date(),
|
|
538
|
+
updated_at: /* @__PURE__ */ new Date(),
|
|
539
|
+
expires_at: transientToken.expiresAt
|
|
540
|
+
};
|
|
541
|
+
const [id] = await queryClient.table(this.table).insert(dbRow);
|
|
542
|
+
return new RememberMeToken({
|
|
543
|
+
identifier: id,
|
|
544
|
+
tokenableId: dbRow.tokenable_id,
|
|
545
|
+
secret: transientToken.secret,
|
|
546
|
+
hash: dbRow.hash,
|
|
547
|
+
createdAt: dbRow.created_at,
|
|
548
|
+
updatedAt: dbRow.updated_at,
|
|
549
|
+
expiresAt: dbRow.expires_at
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Find a token for a user by the token id
|
|
554
|
+
*/
|
|
555
|
+
async find(user, identifier) {
|
|
556
|
+
this.#ensureIsPersisted(user);
|
|
557
|
+
const queryClient = await this.getDb();
|
|
558
|
+
const dbRow = await queryClient.query().from(this.table).where({ id: identifier, tokenable_id: user.$primaryKeyValue }).limit(1).first();
|
|
559
|
+
if (!dbRow) {
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
return this.dbRowToRememberMeToken(dbRow);
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Delete a token by its id
|
|
566
|
+
*/
|
|
567
|
+
async delete(user, identifier) {
|
|
568
|
+
this.#ensureIsPersisted(user);
|
|
569
|
+
const queryClient = await this.getDb();
|
|
570
|
+
const affectedRows = await queryClient.query().from(this.table).where({ id: identifier, tokenable_id: user.$primaryKeyValue }).del().exec();
|
|
571
|
+
return affectedRows;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Returns all the tokens a given user
|
|
575
|
+
*/
|
|
576
|
+
async all(user) {
|
|
577
|
+
this.#ensureIsPersisted(user);
|
|
578
|
+
const queryClient = await this.getDb();
|
|
579
|
+
const dbRows = await queryClient.query().from(this.table).where({ tokenable_id: user.$primaryKeyValue }).orderBy("id", "desc").exec();
|
|
580
|
+
return dbRows.map((dbRow) => {
|
|
581
|
+
return this.dbRowToRememberMeToken(dbRow);
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Verifies a publicly shared remember me token and returns an
|
|
586
|
+
* RememberMeToken for it.
|
|
587
|
+
*
|
|
588
|
+
* Returns null when unable to verify the token or find it
|
|
589
|
+
* inside the storage
|
|
590
|
+
*/
|
|
591
|
+
async verify(tokenValue) {
|
|
592
|
+
const decodedToken = RememberMeToken.decode(tokenValue.release());
|
|
593
|
+
if (!decodedToken) {
|
|
594
|
+
return null;
|
|
595
|
+
}
|
|
596
|
+
const db = await this.getDb();
|
|
597
|
+
const dbRow = await db.query().from(this.table).where({ id: decodedToken.identifier }).limit(1).first();
|
|
598
|
+
if (!dbRow) {
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
const rememberMeToken = this.dbRowToRememberMeToken(dbRow);
|
|
602
|
+
if (!rememberMeToken.verify(decodedToken.secret) || rememberMeToken.isExpired()) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
return rememberMeToken;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Recycles a remember me token by deleting the old one and
|
|
609
|
+
* creates a new one.
|
|
610
|
+
*
|
|
611
|
+
* Ideally, the recycle should update the existing token, but we
|
|
612
|
+
* skip that for now and come back to it later and handle race
|
|
613
|
+
* conditions as well.
|
|
614
|
+
*/
|
|
615
|
+
async recycle(user, identifier, expiresIn) {
|
|
616
|
+
await this.delete(user, identifier);
|
|
617
|
+
return this.create(user, expiresIn);
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
// modules/session_guard/user_providers/lucid.ts
|
|
622
|
+
import { RuntimeException as RuntimeException3 } from "@adonisjs/core/exceptions";
|
|
623
|
+
var SessionLucidUserProvider = class {
|
|
624
|
+
constructor(options) {
|
|
625
|
+
this.options = options;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Reference to the lazily imported model
|
|
629
|
+
*/
|
|
630
|
+
model;
|
|
631
|
+
/**
|
|
632
|
+
* Imports the model from the provider, returns and caches it
|
|
633
|
+
* for further operations.
|
|
634
|
+
*/
|
|
635
|
+
async getModel() {
|
|
636
|
+
if (this.model) {
|
|
637
|
+
return this.model;
|
|
638
|
+
}
|
|
639
|
+
const importedModel = await this.options.model();
|
|
640
|
+
this.model = importedModel.default;
|
|
641
|
+
return this.model;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Returns the tokens provider associated with the user model
|
|
645
|
+
*/
|
|
646
|
+
async getTokensProvider() {
|
|
647
|
+
const model = await this.getModel();
|
|
648
|
+
if (!model.rememberMeTokens) {
|
|
649
|
+
throw new RuntimeException3(
|
|
650
|
+
`Cannot use "${model.name}" model for verifying remember me tokens. Make sure to assign a token provider to the model.`
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
return model.rememberMeTokens;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Creates an adapter user for the guard
|
|
657
|
+
*/
|
|
658
|
+
async createUserForGuard(user) {
|
|
659
|
+
const model = await this.getModel();
|
|
660
|
+
if (user instanceof model === false) {
|
|
661
|
+
throw new RuntimeException3(
|
|
662
|
+
`Invalid user object. It must be an instance of the "${model.name}" model`
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
return {
|
|
666
|
+
getId() {
|
|
667
|
+
if (!user.$primaryKeyValue) {
|
|
668
|
+
throw new RuntimeException3(
|
|
669
|
+
`Cannot use "${model.name}" model for authentication. The value of column "${model.primaryKey}" is undefined or null`
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
return user.$primaryKeyValue;
|
|
673
|
+
},
|
|
674
|
+
getOriginal() {
|
|
675
|
+
return user;
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Finds a user by their primary key value
|
|
681
|
+
*/
|
|
682
|
+
async findById(identifier) {
|
|
683
|
+
const model = await this.getModel();
|
|
684
|
+
const user = await model.find(identifier);
|
|
685
|
+
if (!user) {
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
return this.createUserForGuard(user);
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Creates a remember token for a given user
|
|
692
|
+
*/
|
|
693
|
+
async createRememberToken(user, expiresIn) {
|
|
694
|
+
const tokensProvider = await this.getTokensProvider();
|
|
695
|
+
return tokensProvider.create(user, expiresIn);
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Verify a token by its publicly shared value
|
|
699
|
+
*/
|
|
700
|
+
async verifyRememberToken(tokenValue) {
|
|
701
|
+
const tokensProvider = await this.getTokensProvider();
|
|
702
|
+
return tokensProvider.verify(tokenValue);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Delete a token for a user by the token identifier
|
|
706
|
+
*/
|
|
707
|
+
async deleteRemeberToken(user, identifier) {
|
|
708
|
+
const tokensProvider = await this.getTokensProvider();
|
|
709
|
+
return tokensProvider.delete(user, identifier);
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Recycle a token for a user by the token identifier
|
|
713
|
+
*/
|
|
714
|
+
async recycleRememberToken(user, identifier, expiresIn) {
|
|
715
|
+
const tokensProvider = await this.getTokensProvider();
|
|
716
|
+
return tokensProvider.recycle(user, identifier, expiresIn);
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
// modules/session_guard/define_config.ts
|
|
721
|
+
function sessionGuard(config) {
|
|
722
|
+
return {
|
|
723
|
+
async resolver(name, app) {
|
|
724
|
+
const emitter = await app.container.make("emitter");
|
|
725
|
+
const provider = "resolver" in config.provider ? await config.provider.resolver(app) : config.provider;
|
|
726
|
+
return (ctx) => new SessionGuard(name, ctx, config, emitter, provider);
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
function sessionUserProvider(config) {
|
|
731
|
+
return new SessionLucidUserProvider(config);
|
|
732
|
+
}
|
|
733
|
+
export {
|
|
734
|
+
DbRememberMeTokensProvider,
|
|
735
|
+
RememberMeToken,
|
|
736
|
+
SessionGuard,
|
|
737
|
+
SessionLucidUserProvider,
|
|
738
|
+
sessionGuard,
|
|
739
|
+
sessionUserProvider
|
|
740
|
+
};
|
|
741
|
+
//# sourceMappingURL=main.js.map
|