alp-node-auth 9.3.0 → 11.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/CHANGELOG.md +42 -0
- package/README.md +13 -13
- package/dist/definitions/MongoUsersManager.d.ts +2 -2
- package/dist/definitions/MongoUsersManager.d.ts.map +1 -1
- package/dist/definitions/authApolloContext.d.ts +4 -4
- package/dist/definitions/authApolloContext.d.ts.map +1 -1
- package/dist/definitions/authSocketIO.d.ts +4 -4
- package/dist/definitions/authSocketIO.d.ts.map +1 -1
- package/dist/definitions/createAuthController.d.ts +6 -9
- package/dist/definitions/createAuthController.d.ts.map +1 -1
- package/dist/definitions/createRoutes.d.ts +3 -3
- package/dist/definitions/createRoutes.d.ts.map +1 -1
- package/dist/definitions/index.d.ts +24 -26
- package/dist/definitions/index.d.ts.map +1 -1
- package/dist/definitions/services/authentification/AuthenticationService.d.ts +6 -8
- package/dist/definitions/services/authentification/AuthenticationService.d.ts.map +1 -1
- package/dist/definitions/services/authentification/types.d.ts +3 -2
- package/dist/definitions/services/authentification/types.d.ts.map +1 -1
- package/dist/definitions/services/user/UserAccountGoogleService.d.ts +4 -4
- package/dist/definitions/services/user/UserAccountGoogleService.d.ts.map +1 -1
- package/dist/definitions/services/user/UserAccountSlackService.d.ts +4 -4
- package/dist/definitions/services/user/UserAccountSlackService.d.ts.map +1 -1
- package/dist/definitions/services/user/UserAccountsService.d.ts +6 -7
- package/dist/definitions/services/user/UserAccountsService.d.ts.map +1 -1
- package/dist/definitions/services/user/types.d.ts +1 -1
- package/dist/definitions/types.d.ts +1 -1
- package/dist/definitions/utils/cookies.d.ts +3 -4
- package/dist/definitions/utils/cookies.d.ts.map +1 -1
- package/dist/definitions/utils/createFindLoggedInUser.d.ts +4 -4
- package/dist/definitions/utils/createFindLoggedInUser.d.ts.map +1 -1
- package/dist/{index-node18.mjs → index-node20.mjs} +115 -124
- package/dist/index-node20.mjs.map +1 -0
- package/package.json +24 -26
- package/src/MongoUsersManager.ts +5 -6
- package/src/authApolloContext.ts +10 -10
- package/src/authSocketIO.ts +10 -10
- package/src/createAuthController.ts +22 -20
- package/src/createRoutes.ts +8 -8
- package/src/index.ts +58 -64
- package/src/services/authentification/AuthenticationService.ts +56 -53
- package/src/services/authentification/types.ts +7 -2
- package/src/services/user/UserAccountGoogleService.ts +9 -9
- package/src/services/user/UserAccountSlackService.ts +9 -9
- package/src/services/user/UserAccountsService.ts +23 -25
- package/src/services/user/types.ts +1 -1
- package/src/types.ts +1 -1
- package/src/utils/cookies.ts +8 -8
- package/src/utils/createFindLoggedInUser.ts +9 -9
- package/src/utils/generators.ts +4 -4
- package/strategies/dropbox.js +7 -7
- package/strategies/facebook.js +7 -7
- package/strategies/foursquare.js +7 -7
- package/strategies/github.js +7 -7
- package/strategies/google.js +7 -7
- package/strategies/slack.js +7 -7
- package/strategies/strategies.d.ts +8 -3
- package/dist/index-node18.mjs.map +0 -1
- package/src/.eslintrc.json +0 -38
- package/strategies/.eslintrc.json +0 -3
|
@@ -2,21 +2,20 @@ import { promisify } from 'node:util';
|
|
|
2
2
|
import jsonwebtoken from 'jsonwebtoken';
|
|
3
3
|
import { Logger } from 'nightingale-logger';
|
|
4
4
|
import { EventEmitter } from 'node:events';
|
|
5
|
-
import 'alp-router';
|
|
6
5
|
import { randomBytes } from 'node:crypto';
|
|
7
6
|
import Cookies from 'cookies';
|
|
8
7
|
|
|
9
8
|
function createAuthController({
|
|
10
9
|
usersManager,
|
|
11
10
|
authenticationService,
|
|
12
|
-
homeRouterKey =
|
|
11
|
+
homeRouterKey = "/",
|
|
13
12
|
defaultStrategy,
|
|
14
13
|
authHooks = {}
|
|
15
14
|
}) {
|
|
16
15
|
return {
|
|
17
16
|
async login(ctx) {
|
|
18
|
-
const strategy = ctx.
|
|
19
|
-
if (!strategy) throw new Error(
|
|
17
|
+
const strategy = ctx.namedRouteParam("strategy") || defaultStrategy;
|
|
18
|
+
if (!strategy) throw new Error("Strategy missing");
|
|
20
19
|
const params = authHooks.paramsForLogin && (await authHooks.paramsForLogin(strategy, ctx)) || {};
|
|
21
20
|
await authenticationService.redirectAuthUrl(ctx, strategy, {}, params);
|
|
22
21
|
},
|
|
@@ -26,19 +25,19 @@ function createAuthController({
|
|
|
26
25
|
*/
|
|
27
26
|
async addScope(ctx) {
|
|
28
27
|
if (!ctx.state.loggedInUser) {
|
|
29
|
-
|
|
28
|
+
ctx.redirectTo(homeRouterKey);
|
|
30
29
|
return;
|
|
31
30
|
}
|
|
32
|
-
const strategy = ctx.
|
|
33
|
-
if (!strategy) throw new Error(
|
|
34
|
-
const scopeKey = ctx.
|
|
35
|
-
if (!scopeKey) throw new Error(
|
|
31
|
+
const strategy = ctx.namedRouteParam("strategy") || defaultStrategy;
|
|
32
|
+
if (!strategy) throw new Error("Strategy missing");
|
|
33
|
+
const scopeKey = ctx.namedRouteParam("scopeKey");
|
|
34
|
+
if (!scopeKey) throw new Error("Scope missing");
|
|
36
35
|
await authenticationService.redirectAuthUrl(ctx, strategy, {
|
|
37
36
|
scopeKey
|
|
38
37
|
});
|
|
39
38
|
},
|
|
40
39
|
async response(ctx) {
|
|
41
|
-
const strategy = ctx.
|
|
40
|
+
const strategy = ctx.namedRouteParam("strategy");
|
|
42
41
|
ctx.assert(strategy);
|
|
43
42
|
const loggedInUser = await authenticationService.accessResponse(ctx, strategy, !!ctx.state.loggedInUser, {
|
|
44
43
|
afterLoginSuccess: authHooks.afterLoginSuccess,
|
|
@@ -46,35 +45,36 @@ function createAuthController({
|
|
|
46
45
|
});
|
|
47
46
|
const keyPath = usersManager.store.keyPath;
|
|
48
47
|
await ctx.setLoggedIn(loggedInUser[keyPath], loggedInUser);
|
|
49
|
-
|
|
48
|
+
ctx.redirectTo(homeRouterKey);
|
|
50
49
|
},
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/require-await -- keep async in case i later need await in this method
|
|
51
51
|
async logout(ctx) {
|
|
52
52
|
ctx.logout();
|
|
53
|
-
|
|
53
|
+
ctx.redirectTo(homeRouterKey);
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
const createRoutes = controller => ({
|
|
59
|
-
login: [
|
|
60
|
-
segment.add(
|
|
61
|
-
segment.defaultRoute(controller.login,
|
|
59
|
+
login: ["/login/:strategy?", segment => {
|
|
60
|
+
segment.add("/response", controller.response, "authResponse");
|
|
61
|
+
segment.defaultRoute(controller.login, "login");
|
|
62
62
|
}],
|
|
63
|
-
addScope: [
|
|
64
|
-
logout: [
|
|
63
|
+
addScope: ["/add-scope/:strategy/:scopeKey", controller.addScope],
|
|
64
|
+
logout: ["/logout", controller.logout]
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
const randomBytesPromisified = promisify(randomBytes);
|
|
68
68
|
async function randomHex(size) {
|
|
69
69
|
const buffer = await randomBytesPromisified(size);
|
|
70
|
-
return buffer.toString(
|
|
70
|
+
return buffer.toString("hex");
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
74
74
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
75
75
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
76
|
-
/* eslint-disable camelcase
|
|
77
|
-
const logger$4 = new Logger(
|
|
76
|
+
/* eslint-disable camelcase */
|
|
77
|
+
const logger$4 = new Logger("alp:auth:authentication");
|
|
78
78
|
class AuthenticationService extends EventEmitter {
|
|
79
79
|
constructor(config, strategies, userAccountsService) {
|
|
80
80
|
super();
|
|
@@ -83,26 +83,26 @@ class AuthenticationService extends EventEmitter {
|
|
|
83
83
|
this.userAccountsService = userAccountsService;
|
|
84
84
|
}
|
|
85
85
|
generateAuthUrl(strategy, params) {
|
|
86
|
-
logger$4.debug(
|
|
86
|
+
logger$4.debug("generateAuthUrl", {
|
|
87
87
|
strategy,
|
|
88
88
|
params
|
|
89
89
|
});
|
|
90
90
|
const strategyInstance = this.strategies[strategy];
|
|
91
91
|
switch (strategyInstance.type) {
|
|
92
|
-
case
|
|
92
|
+
case "oauth2":
|
|
93
93
|
return strategyInstance.oauth2.authorizationCode.authorizeURL(params);
|
|
94
94
|
default:
|
|
95
|
-
throw new Error(
|
|
95
|
+
throw new Error("Invalid strategy");
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
async getTokens(strategy, options) {
|
|
99
|
-
logger$4.debug(
|
|
99
|
+
logger$4.debug("getTokens", {
|
|
100
100
|
strategy,
|
|
101
101
|
options
|
|
102
102
|
});
|
|
103
103
|
const strategyInstance = this.strategies[strategy];
|
|
104
104
|
switch (strategyInstance.type) {
|
|
105
|
-
case
|
|
105
|
+
case "oauth2":
|
|
106
106
|
{
|
|
107
107
|
const result = await strategyInstance.oauth2.authorizationCode.getToken({
|
|
108
108
|
code: options.code,
|
|
@@ -126,19 +126,19 @@ class AuthenticationService extends EventEmitter {
|
|
|
126
126
|
// return strategyInstance.accessToken.create(result);
|
|
127
127
|
}
|
|
128
128
|
default:
|
|
129
|
-
throw new Error(
|
|
129
|
+
throw new Error("Invalid stategy");
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
async refreshToken(strategy, tokensParam) {
|
|
133
|
-
logger$4.debug(
|
|
133
|
+
logger$4.debug("refreshToken", {
|
|
134
134
|
strategy
|
|
135
135
|
});
|
|
136
136
|
if (!tokensParam.refreshToken) {
|
|
137
|
-
throw new Error(
|
|
137
|
+
throw new Error("Missing refresh token");
|
|
138
138
|
}
|
|
139
139
|
const strategyInstance = this.strategies[strategy];
|
|
140
140
|
switch (strategyInstance.type) {
|
|
141
|
-
case
|
|
141
|
+
case "oauth2":
|
|
142
142
|
{
|
|
143
143
|
const token = strategyInstance.oauth2.clientCredentials.createToken({
|
|
144
144
|
refresh_token: tokensParam.refreshToken
|
|
@@ -159,12 +159,12 @@ class AuthenticationService extends EventEmitter {
|
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
161
|
default:
|
|
162
|
-
throw new Error(
|
|
162
|
+
throw new Error("Invalid stategy");
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
redirectUri(ctx, strategy) {
|
|
166
|
-
const host = `http${this.config.get(
|
|
167
|
-
return `${host}${ctx.urlGenerator(
|
|
166
|
+
const host = `http${this.config.get("allowHttps") ? "s" : ""}://${ctx.request.host}`;
|
|
167
|
+
return `${host}${ctx.urlGenerator("authResponse", {
|
|
168
168
|
strategy
|
|
169
169
|
})}`;
|
|
170
170
|
}
|
|
@@ -174,66 +174,64 @@ class AuthenticationService extends EventEmitter {
|
|
|
174
174
|
user,
|
|
175
175
|
accountId
|
|
176
176
|
}, params) {
|
|
177
|
-
logger$4.debug(
|
|
177
|
+
logger$4.debug("redirectAuthUrl", {
|
|
178
178
|
strategy,
|
|
179
179
|
scopeKey,
|
|
180
180
|
refreshToken
|
|
181
181
|
});
|
|
182
182
|
const state = await randomHex(8);
|
|
183
|
-
const scope = this.userAccountsService.getScope(strategy, scopeKey ||
|
|
183
|
+
const scope = this.userAccountsService.getScope(strategy, scopeKey || "login", user, accountId);
|
|
184
184
|
if (!scope) {
|
|
185
|
-
throw new Error(
|
|
185
|
+
throw new Error("Invalid empty scope");
|
|
186
186
|
}
|
|
187
187
|
ctx.cookies.set(`auth_${strategy}_${state}`, JSON.stringify({
|
|
188
188
|
scopeKey,
|
|
189
189
|
scope,
|
|
190
|
-
isLoginAccess: !scopeKey || scopeKey ===
|
|
190
|
+
isLoginAccess: !scopeKey || scopeKey === "login"
|
|
191
191
|
}), {
|
|
192
192
|
maxAge: 600000,
|
|
193
193
|
httpOnly: true,
|
|
194
|
-
secure: this.config.get(
|
|
194
|
+
secure: this.config.get("allowHttps")
|
|
195
195
|
});
|
|
196
196
|
const redirectUri = this.generateAuthUrl(strategy, {
|
|
197
197
|
redirect_uri: this.redirectUri(ctx, strategy),
|
|
198
198
|
scope,
|
|
199
199
|
state,
|
|
200
|
-
access_type: refreshToken ?
|
|
200
|
+
access_type: refreshToken ? "offline" : "online",
|
|
201
201
|
...params
|
|
202
202
|
});
|
|
203
|
-
|
|
203
|
+
ctx.redirect(redirectUri);
|
|
204
204
|
}
|
|
205
205
|
async accessResponse(ctx, strategy, isLoggedIn, hooks) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const code = ctx.query.code;
|
|
213
|
-
const state = ctx.query.state;
|
|
206
|
+
const errorParam = ctx.params.queryParam("error").notEmpty();
|
|
207
|
+
if (errorParam.isValid()) {
|
|
208
|
+
ctx.throw(403, errorParam.value);
|
|
209
|
+
}
|
|
210
|
+
const code = ctx.validParams.queryParam("code").notEmpty().value;
|
|
211
|
+
const state = ctx.validParams.queryParam("state").notEmpty().value;
|
|
214
212
|
const cookieName = `auth_${strategy}_${state}`;
|
|
215
|
-
|
|
216
|
-
ctx.cookies.set(cookieName,
|
|
213
|
+
const cookie = ctx.cookies.get(cookieName);
|
|
214
|
+
ctx.cookies.set(cookieName, "", {
|
|
217
215
|
expires: new Date(1)
|
|
218
216
|
});
|
|
219
217
|
if (!cookie) {
|
|
220
|
-
throw new Error(
|
|
218
|
+
throw new Error("No cookie for this state");
|
|
221
219
|
}
|
|
222
|
-
|
|
223
|
-
if (!
|
|
224
|
-
throw new Error(
|
|
220
|
+
const parsedCookie = JSON.parse(cookie);
|
|
221
|
+
if (!parsedCookie?.scope) {
|
|
222
|
+
throw new Error("Unexpected cookie value");
|
|
225
223
|
}
|
|
226
|
-
if (!
|
|
224
|
+
if (!parsedCookie.isLoginAccess) {
|
|
227
225
|
if (!isLoggedIn) {
|
|
228
|
-
throw new Error(
|
|
226
|
+
throw new Error("You are not connected");
|
|
229
227
|
}
|
|
230
228
|
}
|
|
231
229
|
const tokens = await this.getTokens(strategy, {
|
|
232
230
|
code,
|
|
233
231
|
redirectUri: this.redirectUri(ctx, strategy)
|
|
234
232
|
});
|
|
235
|
-
if (
|
|
236
|
-
const user = await this.userAccountsService.findOrCreateFromStrategy(strategy, tokens,
|
|
233
|
+
if (parsedCookie.isLoginAccess) {
|
|
234
|
+
const user = await this.userAccountsService.findOrCreateFromStrategy(strategy, tokens, parsedCookie.scope, parsedCookie.scopeKey);
|
|
237
235
|
if (hooks.afterLoginSuccess) {
|
|
238
236
|
await hooks.afterLoginSuccess(strategy, user);
|
|
239
237
|
}
|
|
@@ -243,9 +241,9 @@ class AuthenticationService extends EventEmitter {
|
|
|
243
241
|
const {
|
|
244
242
|
account,
|
|
245
243
|
user
|
|
246
|
-
} = await this.userAccountsService.update(loggedInUser, strategy, tokens,
|
|
244
|
+
} = await this.userAccountsService.update(loggedInUser, strategy, tokens, parsedCookie.scope, parsedCookie.scopeKey);
|
|
247
245
|
if (hooks.afterScopeUpdate) {
|
|
248
|
-
await hooks.afterScopeUpdate(strategy,
|
|
246
|
+
await hooks.afterScopeUpdate(strategy, parsedCookie.scopeKey, account, user);
|
|
249
247
|
}
|
|
250
248
|
return loggedInUser;
|
|
251
249
|
}
|
|
@@ -268,11 +266,10 @@ class AuthenticationService extends EventEmitter {
|
|
|
268
266
|
}
|
|
269
267
|
}
|
|
270
268
|
|
|
271
|
-
|
|
272
|
-
const logger$3 = new Logger('alp:auth:userAccounts');
|
|
269
|
+
const logger$3 = new Logger("alp:auth:userAccounts");
|
|
273
270
|
const STATUSES = {
|
|
274
|
-
VALIDATED:
|
|
275
|
-
DELETED:
|
|
271
|
+
VALIDATED: "validated",
|
|
272
|
+
DELETED: "deleted"
|
|
276
273
|
};
|
|
277
274
|
class UserAccountsService extends EventEmitter {
|
|
278
275
|
constructor(usersManager, strategyToService) {
|
|
@@ -281,13 +278,13 @@ class UserAccountsService extends EventEmitter {
|
|
|
281
278
|
this.strategyToService = strategyToService;
|
|
282
279
|
}
|
|
283
280
|
getScope(strategy, scopeKey, user, accountId) {
|
|
284
|
-
logger$3.debug(
|
|
281
|
+
logger$3.debug("getScope", {
|
|
285
282
|
strategy,
|
|
286
283
|
userId: user?._id
|
|
287
284
|
});
|
|
288
285
|
const service = this.strategyToService[strategy];
|
|
289
286
|
if (!service) {
|
|
290
|
-
throw new Error(
|
|
287
|
+
throw new Error("Strategy not supported");
|
|
291
288
|
}
|
|
292
289
|
const newScope = service.scopeKeyToScope[scopeKey];
|
|
293
290
|
if (!user || !accountId) {
|
|
@@ -295,9 +292,9 @@ class UserAccountsService extends EventEmitter {
|
|
|
295
292
|
}
|
|
296
293
|
const account = user.accounts.find(account => account.provider === strategy && account.accountId === accountId);
|
|
297
294
|
if (!account) {
|
|
298
|
-
throw new Error(
|
|
295
|
+
throw new Error("Could not found associated account");
|
|
299
296
|
}
|
|
300
|
-
return service.getScope(account.scope, newScope).join(
|
|
297
|
+
return service.getScope(account.scope, newScope).join(" ");
|
|
301
298
|
}
|
|
302
299
|
async update(user, strategy, tokens, scope, subservice) {
|
|
303
300
|
const service = this.strategyToService[strategy];
|
|
@@ -307,9 +304,9 @@ class UserAccountsService extends EventEmitter {
|
|
|
307
304
|
if (!account) {
|
|
308
305
|
// TODO check if already exists in other user => merge
|
|
309
306
|
// TODO else add a new account in this user
|
|
310
|
-
throw new Error(
|
|
307
|
+
throw new Error("Could not found associated account");
|
|
311
308
|
}
|
|
312
|
-
account.status =
|
|
309
|
+
account.status = "valid";
|
|
313
310
|
account.accessToken = tokens.accessToken;
|
|
314
311
|
if (tokens.refreshToken) {
|
|
315
312
|
account.refreshToken = tokens.refreshToken;
|
|
@@ -330,17 +327,17 @@ class UserAccountsService extends EventEmitter {
|
|
|
330
327
|
}
|
|
331
328
|
async findOrCreateFromStrategy(strategy, tokens, scope, subservice) {
|
|
332
329
|
const service = this.strategyToService[strategy];
|
|
333
|
-
if (!service) throw new Error(
|
|
330
|
+
if (!service) throw new Error("Strategy not supported");
|
|
334
331
|
const profile = await service.getProfile(tokens);
|
|
335
332
|
const accountId = service.getId(profile);
|
|
336
|
-
if (!accountId) throw new Error(
|
|
333
|
+
if (!accountId) throw new Error("Invalid profile: no id found");
|
|
337
334
|
const emails = service.getEmails(profile);
|
|
338
335
|
let user = await this.usersManager.findOneByAccountOrEmails({
|
|
339
336
|
provider: service.providerKey,
|
|
340
337
|
accountId,
|
|
341
338
|
emails
|
|
342
339
|
});
|
|
343
|
-
logger$3.info(!user ?
|
|
340
|
+
logger$3.info(!user ? "create user" : "existing user", {
|
|
344
341
|
userId: user?._id,
|
|
345
342
|
accountId
|
|
346
343
|
/*emails , user*/
|
|
@@ -360,11 +357,10 @@ class UserAccountsService extends EventEmitter {
|
|
|
360
357
|
provider: strategy,
|
|
361
358
|
accountId
|
|
362
359
|
};
|
|
363
|
-
// @ts-expect-error well...
|
|
364
360
|
user.accounts.push(account);
|
|
365
361
|
}
|
|
366
362
|
account.name = service.getAccountName(profile);
|
|
367
|
-
account.status =
|
|
363
|
+
account.status = "valid";
|
|
368
364
|
account.profile = profile;
|
|
369
365
|
account.accessToken = tokens.accessToken;
|
|
370
366
|
if (tokens.refreshToken) {
|
|
@@ -387,7 +383,7 @@ class UserAccountsService extends EventEmitter {
|
|
|
387
383
|
});
|
|
388
384
|
user.emailDomains = [
|
|
389
385
|
// eslint-disable-next-line unicorn/no-array-reduce
|
|
390
|
-
...user.emails.reduce((domains, email) => domains.add(email.split(
|
|
386
|
+
...user.emails.reduce((domains, email) => domains.add(email.split("@", 2)[1]), new Set())];
|
|
391
387
|
const keyPath = this.usersManager.store.keyPath;
|
|
392
388
|
if (user[keyPath]) {
|
|
393
389
|
await this.usersManager.replaceOne(user);
|
|
@@ -402,10 +398,10 @@ class UserAccountsService extends EventEmitter {
|
|
|
402
398
|
}
|
|
403
399
|
}
|
|
404
400
|
|
|
405
|
-
const COOKIE_NAME_TOKEN =
|
|
406
|
-
const COOKIE_NAME_STATE =
|
|
401
|
+
const COOKIE_NAME_TOKEN = "loggedInUserToken";
|
|
402
|
+
const COOKIE_NAME_STATE = "loggedInUserState";
|
|
407
403
|
const getTokenFromRequest = (req, options) => {
|
|
408
|
-
if (req.headers.authorization?.startsWith(
|
|
404
|
+
if (req.headers.authorization?.startsWith("Bearer ")) {
|
|
409
405
|
return req.headers.authorization.slice(7);
|
|
410
406
|
}
|
|
411
407
|
|
|
@@ -420,7 +416,7 @@ const getTokenFromRequest = (req, options) => {
|
|
|
420
416
|
const verifyPromisified = promisify(jsonwebtoken.verify);
|
|
421
417
|
const createDecodeJWT = secretKey => async (token, jwtAudience) => {
|
|
422
418
|
const result = await verifyPromisified(token, secretKey, {
|
|
423
|
-
algorithms: [
|
|
419
|
+
algorithms: ["HS512"],
|
|
424
420
|
audience: jwtAudience
|
|
425
421
|
});
|
|
426
422
|
return result?.loggedInUserId;
|
|
@@ -433,7 +429,7 @@ const createFindLoggedInUser = (secretKey, usersManager, logger) => {
|
|
|
433
429
|
try {
|
|
434
430
|
loggedInUserId = await decodeJwt(token, jwtAudience);
|
|
435
431
|
} catch (error) {
|
|
436
|
-
logger.debug(
|
|
432
|
+
logger.debug("failed to verify authentification", {
|
|
437
433
|
err: error
|
|
438
434
|
});
|
|
439
435
|
}
|
|
@@ -471,8 +467,8 @@ class MongoUsersManager {
|
|
|
471
467
|
provider
|
|
472
468
|
}) {
|
|
473
469
|
let query = {
|
|
474
|
-
|
|
475
|
-
|
|
470
|
+
"accounts.provider": provider,
|
|
471
|
+
"accounts.accountId": accountId
|
|
476
472
|
};
|
|
477
473
|
if (emails && emails.length > 0) {
|
|
478
474
|
query = {
|
|
@@ -490,7 +486,7 @@ class MongoUsersManager {
|
|
|
490
486
|
updateAccount(user, account) {
|
|
491
487
|
const accountIndex = user.accounts.indexOf(account);
|
|
492
488
|
if (accountIndex === -1) {
|
|
493
|
-
throw new Error(
|
|
489
|
+
throw new Error("Invalid account");
|
|
494
490
|
}
|
|
495
491
|
return this.store.partialUpdateOne(user, {
|
|
496
492
|
$set: {
|
|
@@ -498,8 +494,6 @@ class MongoUsersManager {
|
|
|
498
494
|
}
|
|
499
495
|
});
|
|
500
496
|
}
|
|
501
|
-
|
|
502
|
-
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
503
497
|
sanitizeBaseUser(user) {
|
|
504
498
|
return {
|
|
505
499
|
_id: user._id,
|
|
@@ -521,7 +515,6 @@ class MongoUsersManager {
|
|
|
521
515
|
}
|
|
522
516
|
}
|
|
523
517
|
|
|
524
|
-
/* eslint-disable @typescript-eslint/class-methods-use-this */
|
|
525
518
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
526
519
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
527
520
|
|
|
@@ -529,11 +522,12 @@ class UserAccountGoogleService {
|
|
|
529
522
|
constructor(scopeKeyToScope) {
|
|
530
523
|
this.scopeKeyToScope = {
|
|
531
524
|
...scopeKeyToScope,
|
|
532
|
-
login:
|
|
525
|
+
login: "openid profile email"
|
|
533
526
|
};
|
|
534
527
|
}
|
|
535
|
-
providerKey =
|
|
528
|
+
providerKey = "google";
|
|
536
529
|
getProfile(tokens) {
|
|
530
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
537
531
|
return fetch(`https://www.googleapis.com/oauth2/v1/userinfo?access_token=${tokens.accessToken}`).then(response => response.json());
|
|
538
532
|
}
|
|
539
533
|
getId(profile) {
|
|
@@ -562,11 +556,10 @@ class UserAccountGoogleService {
|
|
|
562
556
|
return this.getScope(undefined, newScope);
|
|
563
557
|
}
|
|
564
558
|
getScope(oldScope, newScope) {
|
|
565
|
-
return !oldScope ? newScope.split(
|
|
559
|
+
return !oldScope ? newScope.split(" ") : [...oldScope, ...newScope.split(" ")].filter((item, i, ar) => ar.indexOf(item) === i);
|
|
566
560
|
}
|
|
567
561
|
}
|
|
568
562
|
|
|
569
|
-
/* eslint-disable @typescript-eslint/class-methods-use-this */
|
|
570
563
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
571
564
|
|
|
572
565
|
// https://api.slack.com/methods/users.identity
|
|
@@ -575,11 +568,12 @@ class UserAccountSlackService {
|
|
|
575
568
|
constructor(scopeKeyToScope) {
|
|
576
569
|
this.scopeKeyToScope = {
|
|
577
570
|
...scopeKeyToScope,
|
|
578
|
-
login:
|
|
571
|
+
login: "identity.basic identity.email identity.avatar"
|
|
579
572
|
};
|
|
580
573
|
}
|
|
581
|
-
providerKey =
|
|
574
|
+
providerKey = "google";
|
|
582
575
|
getProfile(tokens) {
|
|
576
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
583
577
|
return fetch(`https://slack.com/api/users.identity?token=${tokens.accessToken}`).then(response => response.json());
|
|
584
578
|
}
|
|
585
579
|
getId(profile) {
|
|
@@ -604,13 +598,13 @@ class UserAccountSlackService {
|
|
|
604
598
|
return this.getScope(undefined, newScope);
|
|
605
599
|
}
|
|
606
600
|
getScope(oldScope, newScope) {
|
|
607
|
-
return !oldScope ? newScope.split(
|
|
601
|
+
return !oldScope ? newScope.split(" ") : [...oldScope, ...newScope.split(" ")].filter((item, i, ar) => ar.indexOf(item) === i);
|
|
608
602
|
}
|
|
609
603
|
}
|
|
610
604
|
|
|
611
|
-
const logger$2 = new Logger(
|
|
605
|
+
const logger$2 = new Logger("alp:auth");
|
|
612
606
|
const authSocketIO = (app, usersManager, io, jwtAudience) => {
|
|
613
|
-
const findLoggedInUser = createFindLoggedInUser(app.config.get(
|
|
607
|
+
const findLoggedInUser = createFindLoggedInUser(app.config.get("authentication").secretKey, usersManager, logger$2);
|
|
614
608
|
const users = new Map();
|
|
615
609
|
io.users = users;
|
|
616
610
|
io.use(async (socket, next) => {
|
|
@@ -620,16 +614,16 @@ const authSocketIO = (app, usersManager, io, jwtAudience) => {
|
|
|
620
614
|
if (!token) return next();
|
|
621
615
|
const [loggedInUserId, loggedInUser] = await findLoggedInUser(
|
|
622
616
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
623
|
-
jwtAudience || handshakeData.headers[
|
|
617
|
+
jwtAudience || handshakeData.headers["user-agent"], token);
|
|
624
618
|
if (!loggedInUserId || !loggedInUser) return next();
|
|
625
619
|
socket.user = loggedInUser;
|
|
626
620
|
users.set(socket.client.id, loggedInUser);
|
|
627
|
-
socket.on(
|
|
621
|
+
socket.on("disconnected", () => users.delete(socket.client.id));
|
|
628
622
|
await next();
|
|
629
623
|
});
|
|
630
624
|
};
|
|
631
625
|
|
|
632
|
-
const logger$1 = new Logger(
|
|
626
|
+
const logger$1 = new Logger("alp:auth");
|
|
633
627
|
const getTokenFromReq = req => {
|
|
634
628
|
if (req.cookies) return req.cookies[COOKIE_NAME_TOKEN];
|
|
635
629
|
return getTokenFromRequest(req);
|
|
@@ -640,7 +634,7 @@ const getTokenFromReq = req => {
|
|
|
640
634
|
* @internal
|
|
641
635
|
*/
|
|
642
636
|
const createAuthApolloContext = (config, usersManager) => {
|
|
643
|
-
const findLoggedInUser = createFindLoggedInUser(config.get(
|
|
637
|
+
const findLoggedInUser = createFindLoggedInUser(config.get("authentication").secretKey, usersManager, logger$1);
|
|
644
638
|
return async ({
|
|
645
639
|
req,
|
|
646
640
|
connection
|
|
@@ -659,16 +653,14 @@ const createAuthApolloContext = (config, usersManager) => {
|
|
|
659
653
|
};
|
|
660
654
|
const [, loggedInUser] = await findLoggedInUser(
|
|
661
655
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
662
|
-
req.headers[
|
|
656
|
+
req.headers["user-agent"], token);
|
|
663
657
|
return {
|
|
664
658
|
user: loggedInUser
|
|
665
659
|
};
|
|
666
660
|
};
|
|
667
661
|
};
|
|
668
662
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
const logger = new Logger('alp:auth');
|
|
663
|
+
const logger = new Logger("alp:auth");
|
|
672
664
|
const signPromisified = promisify(jsonwebtoken.sign);
|
|
673
665
|
function init({
|
|
674
666
|
homeRouterKey,
|
|
@@ -690,27 +682,26 @@ function init({
|
|
|
690
682
|
defaultStrategy,
|
|
691
683
|
authHooks
|
|
692
684
|
});
|
|
693
|
-
app.context.setLoggedIn = async function (loggedInUserId, loggedInUser) {
|
|
694
|
-
logger.debug(
|
|
685
|
+
app.context.setLoggedIn = async function setLoggedIn(loggedInUserId, loggedInUser) {
|
|
686
|
+
logger.debug("setLoggedIn", {
|
|
695
687
|
loggedInUser
|
|
696
688
|
});
|
|
697
689
|
if (!loggedInUserId) {
|
|
698
|
-
throw new Error(
|
|
690
|
+
throw new Error("Illegal value for setLoggedIn");
|
|
699
691
|
}
|
|
700
692
|
this.state.loggedInUserId = loggedInUserId;
|
|
701
693
|
this.state.loggedInUser = loggedInUser;
|
|
702
694
|
const token = await signPromisified({
|
|
703
695
|
loggedInUserId,
|
|
704
696
|
time: Date.now()
|
|
705
|
-
}, this.config.get(
|
|
706
|
-
algorithm:
|
|
707
|
-
audience: jwtAudience || this.request.headers[
|
|
708
|
-
expiresIn:
|
|
697
|
+
}, this.config.get("authentication").get("secretKey"), {
|
|
698
|
+
algorithm: "HS512",
|
|
699
|
+
audience: jwtAudience || this.request.headers["user-agent"],
|
|
700
|
+
expiresIn: "30 days"
|
|
709
701
|
});
|
|
710
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
711
702
|
this.cookies.set(COOKIE_NAME_TOKEN, token, {
|
|
712
703
|
httpOnly: true,
|
|
713
|
-
secure: this.config.get(
|
|
704
|
+
secure: this.config.get("allowHttps")
|
|
714
705
|
});
|
|
715
706
|
this.cookies.set(COOKIE_NAME_STATE, JSON.stringify({
|
|
716
707
|
loggedInUserId,
|
|
@@ -721,31 +712,31 @@ function init({
|
|
|
721
712
|
})()
|
|
722
713
|
}), {
|
|
723
714
|
httpOnly: false,
|
|
724
|
-
secure: this.config.get(
|
|
715
|
+
secure: this.config.get("allowHttps")
|
|
725
716
|
});
|
|
726
717
|
};
|
|
727
|
-
app.context.logout = function () {
|
|
718
|
+
app.context.logout = function logout() {
|
|
728
719
|
delete this.state.loggedInUserId;
|
|
729
720
|
delete this.state.loggedInUser;
|
|
730
|
-
this.cookies.set(COOKIE_NAME_TOKEN,
|
|
721
|
+
this.cookies.set(COOKIE_NAME_TOKEN, "", {
|
|
731
722
|
expires: new Date(1)
|
|
732
723
|
});
|
|
733
|
-
this.cookies.set(COOKIE_NAME_STATE,
|
|
724
|
+
this.cookies.set(COOKIE_NAME_STATE, "", {
|
|
734
725
|
expires: new Date(1)
|
|
735
726
|
});
|
|
736
727
|
};
|
|
737
|
-
const findLoggedInUser = createFindLoggedInUser(app.config.get(
|
|
728
|
+
const findLoggedInUser = createFindLoggedInUser(app.config.get("authentication").secretKey, usersManager, logger);
|
|
738
729
|
return {
|
|
739
730
|
routes: createRoutes(controller),
|
|
740
731
|
findLoggedInUserFromRequest: req => {
|
|
741
732
|
const token = getTokenFromRequest(req);
|
|
742
|
-
return findLoggedInUser(jwtAudience || req.headers[
|
|
733
|
+
return findLoggedInUser(jwtAudience || req.headers["user-agent"], token);
|
|
743
734
|
},
|
|
744
735
|
findLoggedInUser,
|
|
745
736
|
middleware: async (ctx, next) => {
|
|
746
737
|
const token = ctx.cookies.get(COOKIE_NAME_TOKEN);
|
|
747
|
-
const userAgent = ctx.request.headers[
|
|
748
|
-
logger.debug(
|
|
738
|
+
const userAgent = ctx.request.headers["user-agent"];
|
|
739
|
+
logger.debug("middleware", {
|
|
749
740
|
token
|
|
750
741
|
});
|
|
751
742
|
const setState = (loggedInUserId, loggedInUser) => {
|
|
@@ -755,15 +746,15 @@ function init({
|
|
|
755
746
|
ctx.sanitizedState.loggedInUser = loggedInUser && usersManager.sanitize(loggedInUser);
|
|
756
747
|
};
|
|
757
748
|
const [loggedInUserId, loggedInUser] = await findLoggedInUser(jwtAudience || userAgent, token);
|
|
758
|
-
logger.debug(
|
|
749
|
+
logger.debug("middleware", {
|
|
759
750
|
loggedInUserId
|
|
760
751
|
});
|
|
761
752
|
if (loggedInUserId == null || loggedInUser == null) {
|
|
762
753
|
if (token) {
|
|
763
|
-
ctx.cookies.set(COOKIE_NAME_TOKEN,
|
|
754
|
+
ctx.cookies.set(COOKIE_NAME_TOKEN, "", {
|
|
764
755
|
expires: new Date(1)
|
|
765
756
|
});
|
|
766
|
-
ctx.cookies.set(COOKIE_NAME_STATE,
|
|
757
|
+
ctx.cookies.set(COOKIE_NAME_STATE, "", {
|
|
767
758
|
expires: new Date(1)
|
|
768
759
|
});
|
|
769
760
|
}
|
|
@@ -778,4 +769,4 @@ function init({
|
|
|
778
769
|
}
|
|
779
770
|
|
|
780
771
|
export { AuthenticationService, MongoUsersManager, STATUSES, UserAccountGoogleService, UserAccountSlackService, authSocketIO, createAuthApolloContext, init as default };
|
|
781
|
-
//# sourceMappingURL=index-
|
|
772
|
+
//# sourceMappingURL=index-node20.mjs.map
|