alp-node-auth 11.0.0 → 12.0.1
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 +20 -0
- package/dist/definitions/services/user/UserAccountGoogleService.d.ts.map +1 -1
- package/dist/definitions/services/user/UserAccountSlackService.d.ts.map +1 -1
- package/dist/{index-node20.mjs → index-node.mjs} +247 -235
- package/dist/index-node.mjs.map +1 -0
- package/package.json +15 -14
- package/src/services/user/UserAccountGoogleService.ts +0 -1
- package/src/services/user/UserAccountSlackService.ts +0 -1
- package/dist/index-node20.mjs.map +0 -1
|
@@ -16,7 +16,7 @@ function createAuthController({
|
|
|
16
16
|
async login(ctx) {
|
|
17
17
|
const strategy = ctx.namedRouteParam("strategy") || defaultStrategy;
|
|
18
18
|
if (!strategy) throw new Error("Strategy missing");
|
|
19
|
-
const params = authHooks.paramsForLogin &&
|
|
19
|
+
const params = authHooks.paramsForLogin && await authHooks.paramsForLogin(strategy, ctx) || {};
|
|
20
20
|
await authenticationService.redirectAuthUrl(ctx, strategy, {}, params);
|
|
21
21
|
},
|
|
22
22
|
/**
|
|
@@ -32,17 +32,22 @@ function createAuthController({
|
|
|
32
32
|
if (!strategy) throw new Error("Strategy missing");
|
|
33
33
|
const scopeKey = ctx.namedRouteParam("scopeKey");
|
|
34
34
|
if (!scopeKey) throw new Error("Scope missing");
|
|
35
|
-
await authenticationService.redirectAuthUrl(ctx, strategy, {
|
|
36
|
-
scopeKey
|
|
37
|
-
});
|
|
35
|
+
await authenticationService.redirectAuthUrl(ctx, strategy, { scopeKey });
|
|
38
36
|
},
|
|
39
37
|
async response(ctx) {
|
|
40
|
-
const strategy = ctx.namedRouteParam(
|
|
38
|
+
const strategy = ctx.namedRouteParam(
|
|
39
|
+
"strategy"
|
|
40
|
+
);
|
|
41
41
|
ctx.assert(strategy);
|
|
42
|
-
const loggedInUser = await authenticationService.accessResponse(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const loggedInUser = await authenticationService.accessResponse(
|
|
43
|
+
ctx,
|
|
44
|
+
strategy,
|
|
45
|
+
!!ctx.state.loggedInUser,
|
|
46
|
+
{
|
|
47
|
+
afterLoginSuccess: authHooks.afterLoginSuccess,
|
|
48
|
+
afterScopeUpdate: authHooks.afterScopeUpdate
|
|
49
|
+
}
|
|
50
|
+
);
|
|
46
51
|
const keyPath = usersManager.store.keyPath;
|
|
47
52
|
await ctx.setLoggedIn(loggedInUser[keyPath], loggedInUser);
|
|
48
53
|
ctx.redirectTo(homeRouterKey);
|
|
@@ -55,11 +60,14 @@ function createAuthController({
|
|
|
55
60
|
};
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
const createRoutes = controller => ({
|
|
59
|
-
login: [
|
|
60
|
-
|
|
61
|
-
segment
|
|
62
|
-
|
|
63
|
+
const createRoutes = (controller) => ({
|
|
64
|
+
login: [
|
|
65
|
+
"/login/:strategy?",
|
|
66
|
+
(segment) => {
|
|
67
|
+
segment.add("/response", controller.response, "authResponse");
|
|
68
|
+
segment.defaultRoute(controller.login, "login");
|
|
69
|
+
}
|
|
70
|
+
],
|
|
63
71
|
addScope: ["/add-scope/:strategy/:scopeKey", controller.addScope],
|
|
64
72
|
logout: ["/logout", controller.logout]
|
|
65
73
|
});
|
|
@@ -70,12 +78,11 @@ async function randomHex(size) {
|
|
|
70
78
|
return buffer.toString("hex");
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
74
|
-
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
75
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
76
|
-
/* eslint-disable camelcase */
|
|
77
81
|
const logger$4 = new Logger("alp:auth:authentication");
|
|
78
82
|
class AuthenticationService extends EventEmitter {
|
|
83
|
+
config;
|
|
84
|
+
strategies;
|
|
85
|
+
userAccountsService;
|
|
79
86
|
constructor(config, strategies, userAccountsService) {
|
|
80
87
|
super();
|
|
81
88
|
this.config = config;
|
|
@@ -83,10 +90,7 @@ class AuthenticationService extends EventEmitter {
|
|
|
83
90
|
this.userAccountsService = userAccountsService;
|
|
84
91
|
}
|
|
85
92
|
generateAuthUrl(strategy, params) {
|
|
86
|
-
logger$4.debug("generateAuthUrl", {
|
|
87
|
-
strategy,
|
|
88
|
-
params
|
|
89
|
-
});
|
|
93
|
+
logger$4.debug("generateAuthUrl", { strategy, params });
|
|
90
94
|
const strategyInstance = this.strategies[strategy];
|
|
91
95
|
switch (strategyInstance.type) {
|
|
92
96
|
case "oauth2":
|
|
@@ -96,68 +100,62 @@ class AuthenticationService extends EventEmitter {
|
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
102
|
async getTokens(strategy, options) {
|
|
99
|
-
logger$4.debug("getTokens", {
|
|
100
|
-
strategy,
|
|
101
|
-
options
|
|
102
|
-
});
|
|
103
|
+
logger$4.debug("getTokens", { strategy, options });
|
|
103
104
|
const strategyInstance = this.strategies[strategy];
|
|
104
105
|
switch (strategyInstance.type) {
|
|
105
|
-
case "oauth2":
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
case "oauth2": {
|
|
107
|
+
const result = await strategyInstance.oauth2.authorizationCode.getToken(
|
|
108
|
+
{
|
|
108
109
|
code: options.code,
|
|
109
110
|
redirect_uri: options.redirectUri
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
if (!result) return result;
|
|
114
|
+
const tokens = result.token;
|
|
115
|
+
return {
|
|
116
|
+
accessToken: tokens.access_token,
|
|
117
|
+
refreshToken: tokens.refresh_token,
|
|
118
|
+
tokenType: tokens.token_type,
|
|
119
|
+
expiresIn: tokens.expires_in,
|
|
120
|
+
expireDate: (() => {
|
|
121
|
+
if (tokens.expires_in == null) return null;
|
|
122
|
+
const d = /* @__PURE__ */ new Date();
|
|
123
|
+
d.setTime(d.getTime() + tokens.expires_in * 1e3);
|
|
124
|
+
return d;
|
|
125
|
+
})(),
|
|
126
|
+
idToken: tokens.id_token
|
|
127
|
+
};
|
|
128
|
+
}
|
|
128
129
|
default:
|
|
129
130
|
throw new Error("Invalid stategy");
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
async refreshToken(strategy, tokensParam) {
|
|
133
|
-
logger$4.debug("refreshToken", {
|
|
134
|
-
strategy
|
|
135
|
-
});
|
|
134
|
+
logger$4.debug("refreshToken", { strategy });
|
|
136
135
|
if (!tokensParam.refreshToken) {
|
|
137
136
|
throw new Error("Missing refresh token");
|
|
138
137
|
}
|
|
139
138
|
const strategyInstance = this.strategies[strategy];
|
|
140
139
|
switch (strategyInstance.type) {
|
|
141
|
-
case "oauth2":
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
140
|
+
case "oauth2": {
|
|
141
|
+
const token = strategyInstance.oauth2.clientCredentials.createToken({
|
|
142
|
+
refresh_token: tokensParam.refreshToken
|
|
143
|
+
});
|
|
144
|
+
const result = await token.refresh();
|
|
145
|
+
const tokens = result.token;
|
|
146
|
+
return {
|
|
147
|
+
accessToken: tokens.access_token,
|
|
148
|
+
tokenType: tokens.token_type,
|
|
149
|
+
expiresIn: tokens.expires_in,
|
|
150
|
+
expireDate: (() => {
|
|
151
|
+
if (tokens.expires_in == null) return null;
|
|
152
|
+
const d = /* @__PURE__ */ new Date();
|
|
153
|
+
d.setTime(d.getTime() + tokens.expires_in * 1e3);
|
|
154
|
+
return d;
|
|
155
|
+
})(),
|
|
156
|
+
idToken: tokens.id_token
|
|
157
|
+
};
|
|
158
|
+
}
|
|
161
159
|
default:
|
|
162
160
|
throw new Error("Invalid stategy");
|
|
163
161
|
}
|
|
@@ -174,25 +172,31 @@ class AuthenticationService extends EventEmitter {
|
|
|
174
172
|
user,
|
|
175
173
|
accountId
|
|
176
174
|
}, params) {
|
|
177
|
-
logger$4.debug("redirectAuthUrl", {
|
|
178
|
-
strategy,
|
|
179
|
-
scopeKey,
|
|
180
|
-
refreshToken
|
|
181
|
-
});
|
|
175
|
+
logger$4.debug("redirectAuthUrl", { strategy, scopeKey, refreshToken });
|
|
182
176
|
const state = await randomHex(8);
|
|
183
|
-
const
|
|
177
|
+
const isLoginAccess = !scopeKey || scopeKey === "login";
|
|
178
|
+
const scope = this.userAccountsService.getScope(
|
|
179
|
+
strategy,
|
|
180
|
+
scopeKey || "login",
|
|
181
|
+
user,
|
|
182
|
+
accountId
|
|
183
|
+
);
|
|
184
184
|
if (!scope) {
|
|
185
185
|
throw new Error("Invalid empty scope");
|
|
186
186
|
}
|
|
187
|
-
ctx.cookies.set(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
187
|
+
ctx.cookies.set(
|
|
188
|
+
`auth_${strategy}_${state}`,
|
|
189
|
+
JSON.stringify({
|
|
190
|
+
scopeKey,
|
|
191
|
+
scope,
|
|
192
|
+
isLoginAccess
|
|
193
|
+
}),
|
|
194
|
+
{
|
|
195
|
+
maxAge: 10 * 60 * 1e3,
|
|
196
|
+
httpOnly: true,
|
|
197
|
+
secure: this.config.get("allowHttps")
|
|
198
|
+
}
|
|
199
|
+
);
|
|
196
200
|
const redirectUri = this.generateAuthUrl(strategy, {
|
|
197
201
|
redirect_uri: this.redirectUri(ctx, strategy),
|
|
198
202
|
scope,
|
|
@@ -211,9 +215,7 @@ class AuthenticationService extends EventEmitter {
|
|
|
211
215
|
const state = ctx.validParams.queryParam("state").notEmpty().value;
|
|
212
216
|
const cookieName = `auth_${strategy}_${state}`;
|
|
213
217
|
const cookie = ctx.cookies.get(cookieName);
|
|
214
|
-
ctx.cookies.set(cookieName, "", {
|
|
215
|
-
expires: new Date(1)
|
|
216
|
-
});
|
|
218
|
+
ctx.cookies.set(cookieName, "", { expires: /* @__PURE__ */ new Date(1) });
|
|
217
219
|
if (!cookie) {
|
|
218
220
|
throw new Error("No cookie for this state");
|
|
219
221
|
}
|
|
@@ -231,19 +233,32 @@ class AuthenticationService extends EventEmitter {
|
|
|
231
233
|
redirectUri: this.redirectUri(ctx, strategy)
|
|
232
234
|
});
|
|
233
235
|
if (parsedCookie.isLoginAccess) {
|
|
234
|
-
const
|
|
236
|
+
const user2 = await this.userAccountsService.findOrCreateFromStrategy(
|
|
237
|
+
strategy,
|
|
238
|
+
tokens,
|
|
239
|
+
parsedCookie.scope,
|
|
240
|
+
parsedCookie.scopeKey
|
|
241
|
+
);
|
|
235
242
|
if (hooks.afterLoginSuccess) {
|
|
236
|
-
await hooks.afterLoginSuccess(strategy,
|
|
243
|
+
await hooks.afterLoginSuccess(strategy, user2);
|
|
237
244
|
}
|
|
238
|
-
return
|
|
245
|
+
return user2;
|
|
239
246
|
}
|
|
240
247
|
const loggedInUser = ctx.state.loggedInUser;
|
|
241
|
-
const {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
248
|
+
const { account, user } = await this.userAccountsService.update(
|
|
249
|
+
loggedInUser,
|
|
250
|
+
strategy,
|
|
251
|
+
tokens,
|
|
252
|
+
parsedCookie.scope,
|
|
253
|
+
parsedCookie.scopeKey
|
|
254
|
+
);
|
|
245
255
|
if (hooks.afterScopeUpdate) {
|
|
246
|
-
await hooks.afterScopeUpdate(
|
|
256
|
+
await hooks.afterScopeUpdate(
|
|
257
|
+
strategy,
|
|
258
|
+
parsedCookie.scopeKey,
|
|
259
|
+
account,
|
|
260
|
+
user
|
|
261
|
+
);
|
|
247
262
|
}
|
|
248
263
|
return loggedInUser;
|
|
249
264
|
}
|
|
@@ -254,9 +269,8 @@ class AuthenticationService extends EventEmitter {
|
|
|
254
269
|
return this.refreshToken(account.provider, {
|
|
255
270
|
// accessToken: account.accessToken,
|
|
256
271
|
refreshToken: account.refreshToken
|
|
257
|
-
}).then(tokens => {
|
|
272
|
+
}).then((tokens) => {
|
|
258
273
|
if (!tokens) {
|
|
259
|
-
// serviceGoogle.updateFields({ accessToken:null, refreshToken:null, status: .OUTDATED });
|
|
260
274
|
return false;
|
|
261
275
|
}
|
|
262
276
|
account.accessToken = tokens.accessToken;
|
|
@@ -272,16 +286,15 @@ const STATUSES = {
|
|
|
272
286
|
DELETED: "deleted"
|
|
273
287
|
};
|
|
274
288
|
class UserAccountsService extends EventEmitter {
|
|
289
|
+
strategyToService;
|
|
290
|
+
usersManager;
|
|
275
291
|
constructor(usersManager, strategyToService) {
|
|
276
292
|
super();
|
|
277
293
|
this.usersManager = usersManager;
|
|
278
294
|
this.strategyToService = strategyToService;
|
|
279
295
|
}
|
|
280
296
|
getScope(strategy, scopeKey, user, accountId) {
|
|
281
|
-
logger$3.debug("getScope", {
|
|
282
|
-
strategy,
|
|
283
|
-
userId: user?._id
|
|
284
|
-
});
|
|
297
|
+
logger$3.debug("getScope", { strategy, userId: user?._id });
|
|
285
298
|
const service = this.strategyToService[strategy];
|
|
286
299
|
if (!service) {
|
|
287
300
|
throw new Error("Strategy not supported");
|
|
@@ -290,7 +303,9 @@ class UserAccountsService extends EventEmitter {
|
|
|
290
303
|
if (!user || !accountId) {
|
|
291
304
|
return newScope;
|
|
292
305
|
}
|
|
293
|
-
const account = user.accounts.find(
|
|
306
|
+
const account = user.accounts.find(
|
|
307
|
+
(account2) => account2.provider === strategy && account2.accountId === accountId
|
|
308
|
+
);
|
|
294
309
|
if (!account) {
|
|
295
310
|
throw new Error("Could not found associated account");
|
|
296
311
|
}
|
|
@@ -300,10 +315,10 @@ class UserAccountsService extends EventEmitter {
|
|
|
300
315
|
const service = this.strategyToService[strategy];
|
|
301
316
|
const profile = await service.getProfile(tokens);
|
|
302
317
|
const accountId = service.getId(profile);
|
|
303
|
-
const account = user.accounts.find(
|
|
318
|
+
const account = user.accounts.find(
|
|
319
|
+
(account2) => account2.provider === strategy && account2.accountId === accountId
|
|
320
|
+
);
|
|
304
321
|
if (!account) {
|
|
305
|
-
// TODO check if already exists in other user => merge
|
|
306
|
-
// TODO else add a new account in this user
|
|
307
322
|
throw new Error("Could not found associated account");
|
|
308
323
|
}
|
|
309
324
|
account.status = "valid";
|
|
@@ -311,7 +326,7 @@ class UserAccountsService extends EventEmitter {
|
|
|
311
326
|
if (tokens.refreshToken) {
|
|
312
327
|
account.refreshToken = tokens.refreshToken;
|
|
313
328
|
}
|
|
314
|
-
if (tokens.expireDate !==
|
|
329
|
+
if (tokens.expireDate !== void 0) {
|
|
315
330
|
account.tokenExpireDate = tokens.expireDate;
|
|
316
331
|
}
|
|
317
332
|
account.scope = service.getScope(account.scope, scope);
|
|
@@ -320,10 +335,7 @@ class UserAccountsService extends EventEmitter {
|
|
|
320
335
|
account.subservices.push(subservice);
|
|
321
336
|
}
|
|
322
337
|
await this.usersManager.replaceOne(user);
|
|
323
|
-
return {
|
|
324
|
-
user,
|
|
325
|
-
account
|
|
326
|
-
};
|
|
338
|
+
return { user, account };
|
|
327
339
|
}
|
|
328
340
|
async findOrCreateFromStrategy(strategy, tokens, scope, subservice) {
|
|
329
341
|
const service = this.strategyToService[strategy];
|
|
@@ -351,12 +363,11 @@ class UserAccountsService extends EventEmitter {
|
|
|
351
363
|
status: STATUSES.VALIDATED
|
|
352
364
|
});
|
|
353
365
|
if (!user.accounts) user.accounts = [];
|
|
354
|
-
let account = user.accounts.find(
|
|
366
|
+
let account = user.accounts.find(
|
|
367
|
+
(account2) => account2.provider === strategy && account2.accountId === accountId
|
|
368
|
+
);
|
|
355
369
|
if (!account) {
|
|
356
|
-
account = {
|
|
357
|
-
provider: strategy,
|
|
358
|
-
accountId
|
|
359
|
-
};
|
|
370
|
+
account = { provider: strategy, accountId };
|
|
360
371
|
user.accounts.push(account);
|
|
361
372
|
}
|
|
362
373
|
account.name = service.getAccountName(profile);
|
|
@@ -366,7 +377,7 @@ class UserAccountsService extends EventEmitter {
|
|
|
366
377
|
if (tokens.refreshToken) {
|
|
367
378
|
account.refreshToken = tokens.refreshToken;
|
|
368
379
|
}
|
|
369
|
-
if (tokens.expireDate !==
|
|
380
|
+
if (tokens.expireDate !== void 0) {
|
|
370
381
|
account.tokenExpireDate = tokens.expireDate;
|
|
371
382
|
}
|
|
372
383
|
account.scope = service.getScope(account.scope, scope);
|
|
@@ -376,14 +387,18 @@ class UserAccountsService extends EventEmitter {
|
|
|
376
387
|
}
|
|
377
388
|
if (!user.emails) user.emails = [];
|
|
378
389
|
const userEmails = user.emails;
|
|
379
|
-
emails.forEach(email => {
|
|
390
|
+
emails.forEach((email) => {
|
|
380
391
|
if (!userEmails.includes(email)) {
|
|
381
392
|
userEmails.push(email);
|
|
382
393
|
}
|
|
383
394
|
});
|
|
384
395
|
user.emailDomains = [
|
|
385
|
-
|
|
386
|
-
|
|
396
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
397
|
+
...user.emails.reduce(
|
|
398
|
+
(domains, email) => domains.add(email.split("@", 2)[1]),
|
|
399
|
+
/* @__PURE__ */ new Set()
|
|
400
|
+
)
|
|
401
|
+
];
|
|
387
402
|
const keyPath = this.usersManager.store.keyPath;
|
|
388
403
|
if (user[keyPath]) {
|
|
389
404
|
await this.usersManager.replaceOne(user);
|
|
@@ -402,10 +417,8 @@ const COOKIE_NAME_TOKEN = "loggedInUserToken";
|
|
|
402
417
|
const COOKIE_NAME_STATE = "loggedInUserState";
|
|
403
418
|
const getTokenFromRequest = (req, options) => {
|
|
404
419
|
if (req.headers.authorization?.startsWith("Bearer ")) {
|
|
405
|
-
return req.headers.authorization.slice(
|
|
420
|
+
return req.headers.authorization.slice("Bearer ".length);
|
|
406
421
|
}
|
|
407
|
-
|
|
408
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
409
422
|
const cookies = new Cookies(req, null, {
|
|
410
423
|
...options,
|
|
411
424
|
secure: true
|
|
@@ -414,7 +427,7 @@ const getTokenFromRequest = (req, options) => {
|
|
|
414
427
|
};
|
|
415
428
|
|
|
416
429
|
const verifyPromisified = promisify(jsonwebtoken.verify);
|
|
417
|
-
const createDecodeJWT = secretKey => async (token, jwtAudience) => {
|
|
430
|
+
const createDecodeJWT = (secretKey) => async (token, jwtAudience) => {
|
|
418
431
|
const result = await verifyPromisified(token, secretKey, {
|
|
419
432
|
algorithms: ["HS512"],
|
|
420
433
|
audience: jwtAudience
|
|
@@ -423,28 +436,27 @@ const createDecodeJWT = secretKey => async (token, jwtAudience) => {
|
|
|
423
436
|
};
|
|
424
437
|
const createFindLoggedInUser = (secretKey, usersManager, logger) => {
|
|
425
438
|
const decodeJwt = createDecodeJWT(secretKey);
|
|
426
|
-
|
|
439
|
+
const findLoggedInUser = async (jwtAudience, token) => {
|
|
427
440
|
if (!token || !jwtAudience) return [null, null];
|
|
428
441
|
let loggedInUserId;
|
|
429
442
|
try {
|
|
430
443
|
loggedInUserId = await decodeJwt(token, jwtAudience);
|
|
431
444
|
} catch (error) {
|
|
432
|
-
logger.debug("failed to verify authentification", {
|
|
433
|
-
err: error
|
|
434
|
-
});
|
|
445
|
+
logger.debug("failed to verify authentification", { err: error });
|
|
435
446
|
}
|
|
436
447
|
if (loggedInUserId == null) return [null, null];
|
|
437
448
|
const loggedInUser = await usersManager.findById(loggedInUserId);
|
|
438
449
|
if (!loggedInUser) return [null, null];
|
|
439
450
|
return [loggedInUserId, loggedInUser];
|
|
440
451
|
};
|
|
452
|
+
return findLoggedInUser;
|
|
441
453
|
};
|
|
442
454
|
|
|
443
455
|
class MongoUsersManager {
|
|
456
|
+
store;
|
|
444
457
|
constructor(store) {
|
|
445
458
|
this.store = store;
|
|
446
459
|
}
|
|
447
|
-
|
|
448
460
|
/** @deprecated use findById instead */
|
|
449
461
|
findConnected(connected) {
|
|
450
462
|
return this.store.findByKey(connected);
|
|
@@ -472,15 +484,14 @@ class MongoUsersManager {
|
|
|
472
484
|
};
|
|
473
485
|
if (emails && emails.length > 0) {
|
|
474
486
|
query = {
|
|
475
|
-
$or: [
|
|
476
|
-
|
|
477
|
-
|
|
487
|
+
$or: [
|
|
488
|
+
query,
|
|
489
|
+
{
|
|
490
|
+
emails: { $in: emails }
|
|
478
491
|
}
|
|
479
|
-
|
|
492
|
+
]
|
|
480
493
|
};
|
|
481
494
|
}
|
|
482
|
-
|
|
483
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
484
495
|
return this.store.findOne(query);
|
|
485
496
|
}
|
|
486
497
|
updateAccount(user, account) {
|
|
@@ -504,7 +515,7 @@ class MongoUsersManager {
|
|
|
504
515
|
status: user.status,
|
|
505
516
|
emails: user.emails,
|
|
506
517
|
emailDomains: user.emailDomains,
|
|
507
|
-
accounts: user.accounts.map(account => ({
|
|
518
|
+
accounts: user.accounts.map((account) => ({
|
|
508
519
|
provider: account.provider,
|
|
509
520
|
accountId: account.accountId,
|
|
510
521
|
name: account.name,
|
|
@@ -515,10 +526,8 @@ class MongoUsersManager {
|
|
|
515
526
|
}
|
|
516
527
|
}
|
|
517
528
|
|
|
518
|
-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
519
|
-
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
520
|
-
|
|
521
529
|
class UserAccountGoogleService {
|
|
530
|
+
scopeKeyToScope;
|
|
522
531
|
constructor(scopeKeyToScope) {
|
|
523
532
|
this.scopeKeyToScope = {
|
|
524
533
|
...scopeKeyToScope,
|
|
@@ -527,8 +536,9 @@ class UserAccountGoogleService {
|
|
|
527
536
|
}
|
|
528
537
|
providerKey = "google";
|
|
529
538
|
getProfile(tokens) {
|
|
530
|
-
|
|
531
|
-
|
|
539
|
+
return fetch(
|
|
540
|
+
`https://www.googleapis.com/oauth2/v1/userinfo?access_token=${tokens.accessToken}`
|
|
541
|
+
).then((response) => response.json());
|
|
532
542
|
}
|
|
533
543
|
getId(profile) {
|
|
534
544
|
return profile.id;
|
|
@@ -553,18 +563,17 @@ class UserAccountGoogleService {
|
|
|
553
563
|
};
|
|
554
564
|
}
|
|
555
565
|
getDefaultScope(newScope) {
|
|
556
|
-
return this.getScope(
|
|
566
|
+
return this.getScope(void 0, newScope);
|
|
557
567
|
}
|
|
558
568
|
getScope(oldScope, newScope) {
|
|
559
|
-
return !oldScope ? newScope.split(" ") : [...oldScope, ...newScope.split(" ")].filter(
|
|
569
|
+
return !oldScope ? newScope.split(" ") : [...oldScope, ...newScope.split(" ")].filter(
|
|
570
|
+
(item, i, ar) => ar.indexOf(item) === i
|
|
571
|
+
);
|
|
560
572
|
}
|
|
561
573
|
}
|
|
562
574
|
|
|
563
|
-
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
564
|
-
|
|
565
|
-
// https://api.slack.com/methods/users.identity
|
|
566
|
-
|
|
567
575
|
class UserAccountSlackService {
|
|
576
|
+
scopeKeyToScope;
|
|
568
577
|
constructor(scopeKeyToScope) {
|
|
569
578
|
this.scopeKeyToScope = {
|
|
570
579
|
...scopeKeyToScope,
|
|
@@ -573,8 +582,9 @@ class UserAccountSlackService {
|
|
|
573
582
|
}
|
|
574
583
|
providerKey = "google";
|
|
575
584
|
getProfile(tokens) {
|
|
576
|
-
|
|
577
|
-
|
|
585
|
+
return fetch(
|
|
586
|
+
`https://slack.com/api/users.identity?token=${tokens.accessToken}`
|
|
587
|
+
).then((response) => response.json());
|
|
578
588
|
}
|
|
579
589
|
getId(profile) {
|
|
580
590
|
if (!profile?.team?.id || !profile.user?.id) {
|
|
@@ -591,30 +601,37 @@ class UserAccountSlackService {
|
|
|
591
601
|
getDisplayName(profile) {
|
|
592
602
|
return profile.user.name;
|
|
593
603
|
}
|
|
594
|
-
getFullName() {
|
|
604
|
+
getFullName(profile) {
|
|
595
605
|
return null;
|
|
596
606
|
}
|
|
597
607
|
getDefaultScope(newScope) {
|
|
598
|
-
return this.getScope(
|
|
608
|
+
return this.getScope(void 0, newScope);
|
|
599
609
|
}
|
|
600
610
|
getScope(oldScope, newScope) {
|
|
601
|
-
return !oldScope ? newScope.split(" ") : [...oldScope, ...newScope.split(" ")].filter(
|
|
611
|
+
return !oldScope ? newScope.split(" ") : [...oldScope, ...newScope.split(" ")].filter(
|
|
612
|
+
(item, i, ar) => ar.indexOf(item) === i
|
|
613
|
+
);
|
|
602
614
|
}
|
|
603
615
|
}
|
|
604
616
|
|
|
605
617
|
const logger$2 = new Logger("alp:auth");
|
|
606
618
|
const authSocketIO = (app, usersManager, io, jwtAudience) => {
|
|
607
|
-
const findLoggedInUser = createFindLoggedInUser(
|
|
608
|
-
|
|
619
|
+
const findLoggedInUser = createFindLoggedInUser(
|
|
620
|
+
app.config.get("authentication").secretKey,
|
|
621
|
+
usersManager,
|
|
622
|
+
logger$2
|
|
623
|
+
);
|
|
624
|
+
const users = /* @__PURE__ */ new Map();
|
|
609
625
|
io.users = users;
|
|
610
626
|
io.use(async (socket, next) => {
|
|
611
627
|
const handshakeData = socket.request;
|
|
612
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
613
628
|
const token = getTokenFromRequest(handshakeData);
|
|
614
629
|
if (!token) return next();
|
|
615
630
|
const [loggedInUserId, loggedInUser] = await findLoggedInUser(
|
|
616
|
-
|
|
617
|
-
|
|
631
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
632
|
+
jwtAudience || handshakeData.headers["user-agent"],
|
|
633
|
+
token
|
|
634
|
+
);
|
|
618
635
|
if (!loggedInUserId || !loggedInUser) return next();
|
|
619
636
|
socket.user = loggedInUser;
|
|
620
637
|
users.set(socket.client.id, loggedInUser);
|
|
@@ -624,39 +641,29 @@ const authSocketIO = (app, usersManager, io, jwtAudience) => {
|
|
|
624
641
|
};
|
|
625
642
|
|
|
626
643
|
const logger$1 = new Logger("alp:auth");
|
|
627
|
-
const getTokenFromReq = req => {
|
|
644
|
+
const getTokenFromReq = (req) => {
|
|
628
645
|
if (req.cookies) return req.cookies[COOKIE_NAME_TOKEN];
|
|
629
646
|
return getTokenFromRequest(req);
|
|
630
647
|
};
|
|
631
|
-
|
|
632
|
-
/*
|
|
633
|
-
* Not tested yet.
|
|
634
|
-
* @internal
|
|
635
|
-
*/
|
|
636
648
|
const createAuthApolloContext = (config, usersManager) => {
|
|
637
|
-
const findLoggedInUser = createFindLoggedInUser(
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
649
|
+
const findLoggedInUser = createFindLoggedInUser(
|
|
650
|
+
config.get("authentication").secretKey,
|
|
651
|
+
usersManager,
|
|
652
|
+
logger$1
|
|
653
|
+
);
|
|
654
|
+
return async ({ req, connection }) => {
|
|
642
655
|
if (connection?.loggedInUser) {
|
|
643
|
-
return {
|
|
644
|
-
user: connection.loggedInUser
|
|
645
|
-
};
|
|
656
|
+
return { user: connection.loggedInUser };
|
|
646
657
|
}
|
|
647
658
|
if (!req) return null;
|
|
648
|
-
|
|
649
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
650
659
|
const token = getTokenFromReq(req);
|
|
651
|
-
if (!token) return {
|
|
652
|
-
user: undefined
|
|
653
|
-
};
|
|
660
|
+
if (!token) return { user: void 0 };
|
|
654
661
|
const [, loggedInUser] = await findLoggedInUser(
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
};
|
|
662
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
663
|
+
req.headers["user-agent"],
|
|
664
|
+
token
|
|
665
|
+
);
|
|
666
|
+
return { user: loggedInUser };
|
|
660
667
|
};
|
|
661
668
|
};
|
|
662
669
|
|
|
@@ -671,10 +678,16 @@ function init({
|
|
|
671
678
|
authHooks,
|
|
672
679
|
jwtAudience
|
|
673
680
|
}) {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
681
|
+
return (app) => {
|
|
682
|
+
const userAccountsService = new UserAccountsService(
|
|
683
|
+
usersManager,
|
|
684
|
+
strategyToService
|
|
685
|
+
);
|
|
686
|
+
const authenticationService = new AuthenticationService(
|
|
687
|
+
app.config,
|
|
688
|
+
strategies,
|
|
689
|
+
userAccountsService
|
|
690
|
+
);
|
|
678
691
|
const controller = createAuthController({
|
|
679
692
|
usersManager,
|
|
680
693
|
authenticationService,
|
|
@@ -683,80 +696,79 @@ function init({
|
|
|
683
696
|
authHooks
|
|
684
697
|
});
|
|
685
698
|
app.context.setLoggedIn = async function setLoggedIn(loggedInUserId, loggedInUser) {
|
|
686
|
-
logger.debug("setLoggedIn", {
|
|
687
|
-
loggedInUser
|
|
688
|
-
});
|
|
699
|
+
logger.debug("setLoggedIn", { loggedInUser });
|
|
689
700
|
if (!loggedInUserId) {
|
|
690
701
|
throw new Error("Illegal value for setLoggedIn");
|
|
691
702
|
}
|
|
692
703
|
this.state.loggedInUserId = loggedInUserId;
|
|
693
704
|
this.state.loggedInUser = loggedInUser;
|
|
694
|
-
const token = await signPromisified(
|
|
695
|
-
loggedInUserId,
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
705
|
+
const token = await signPromisified(
|
|
706
|
+
{ loggedInUserId, time: Date.now() },
|
|
707
|
+
this.config.get("authentication").get("secretKey"),
|
|
708
|
+
{
|
|
709
|
+
algorithm: "HS512",
|
|
710
|
+
audience: jwtAudience || this.request.headers["user-agent"],
|
|
711
|
+
expiresIn: "30 days"
|
|
712
|
+
}
|
|
713
|
+
);
|
|
714
|
+
const calcExpiresTime = () => {
|
|
715
|
+
const date = /* @__PURE__ */ new Date();
|
|
716
|
+
date.setDate(date.getDate() + 30);
|
|
717
|
+
return date.getTime();
|
|
718
|
+
};
|
|
702
719
|
this.cookies.set(COOKIE_NAME_TOKEN, token, {
|
|
703
720
|
httpOnly: true,
|
|
704
721
|
secure: this.config.get("allowHttps")
|
|
705
722
|
});
|
|
706
|
-
this.cookies.set(
|
|
707
|
-
|
|
708
|
-
expiresIn: (
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
httpOnly: false,
|
|
715
|
-
secure: this.config.get("allowHttps")
|
|
716
|
-
});
|
|
723
|
+
this.cookies.set(
|
|
724
|
+
COOKIE_NAME_STATE,
|
|
725
|
+
JSON.stringify({ loggedInUserId, expiresIn: calcExpiresTime() }),
|
|
726
|
+
{
|
|
727
|
+
httpOnly: false,
|
|
728
|
+
secure: this.config.get("allowHttps")
|
|
729
|
+
}
|
|
730
|
+
);
|
|
717
731
|
};
|
|
718
732
|
app.context.logout = function logout() {
|
|
719
733
|
delete this.state.loggedInUserId;
|
|
720
734
|
delete this.state.loggedInUser;
|
|
721
|
-
this.cookies.set(COOKIE_NAME_TOKEN, "", {
|
|
722
|
-
|
|
723
|
-
});
|
|
724
|
-
this.cookies.set(COOKIE_NAME_STATE, "", {
|
|
725
|
-
expires: new Date(1)
|
|
726
|
-
});
|
|
735
|
+
this.cookies.set(COOKIE_NAME_TOKEN, "", { expires: /* @__PURE__ */ new Date(1) });
|
|
736
|
+
this.cookies.set(COOKIE_NAME_STATE, "", { expires: /* @__PURE__ */ new Date(1) });
|
|
727
737
|
};
|
|
728
|
-
const findLoggedInUser = createFindLoggedInUser(
|
|
738
|
+
const findLoggedInUser = createFindLoggedInUser(
|
|
739
|
+
app.config.get("authentication").secretKey,
|
|
740
|
+
usersManager,
|
|
741
|
+
logger
|
|
742
|
+
);
|
|
729
743
|
return {
|
|
730
744
|
routes: createRoutes(controller),
|
|
731
|
-
findLoggedInUserFromRequest: req => {
|
|
745
|
+
findLoggedInUserFromRequest: (req) => {
|
|
732
746
|
const token = getTokenFromRequest(req);
|
|
733
|
-
return findLoggedInUser(
|
|
747
|
+
return findLoggedInUser(
|
|
748
|
+
jwtAudience || req.headers["user-agent"],
|
|
749
|
+
token
|
|
750
|
+
);
|
|
734
751
|
},
|
|
735
752
|
findLoggedInUser,
|
|
736
753
|
middleware: async (ctx, next) => {
|
|
737
754
|
const token = ctx.cookies.get(COOKIE_NAME_TOKEN);
|
|
738
755
|
const userAgent = ctx.request.headers["user-agent"];
|
|
739
|
-
logger.debug("middleware", {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
ctx.
|
|
744
|
-
ctx.
|
|
745
|
-
ctx.sanitizedState.loggedInUserId = loggedInUserId;
|
|
746
|
-
ctx.sanitizedState.loggedInUser = loggedInUser && usersManager.sanitize(loggedInUser);
|
|
756
|
+
logger.debug("middleware", { token });
|
|
757
|
+
const setState = (loggedInUserId2, loggedInUser2) => {
|
|
758
|
+
ctx.state.loggedInUserId = loggedInUserId2;
|
|
759
|
+
ctx.state.user = loggedInUser2;
|
|
760
|
+
ctx.sanitizedState.loggedInUserId = loggedInUserId2;
|
|
761
|
+
ctx.sanitizedState.loggedInUser = loggedInUser2 && usersManager.sanitize(loggedInUser2);
|
|
747
762
|
};
|
|
748
|
-
const [loggedInUserId, loggedInUser] = await findLoggedInUser(
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
763
|
+
const [loggedInUserId, loggedInUser] = await findLoggedInUser(
|
|
764
|
+
jwtAudience || userAgent,
|
|
765
|
+
token
|
|
766
|
+
);
|
|
767
|
+
logger.debug("middleware", { loggedInUserId });
|
|
752
768
|
if (loggedInUserId == null || loggedInUser == null) {
|
|
753
769
|
if (token) {
|
|
754
|
-
ctx.cookies.set(COOKIE_NAME_TOKEN, "", {
|
|
755
|
-
|
|
756
|
-
});
|
|
757
|
-
ctx.cookies.set(COOKIE_NAME_STATE, "", {
|
|
758
|
-
expires: new Date(1)
|
|
759
|
-
});
|
|
770
|
+
ctx.cookies.set(COOKIE_NAME_TOKEN, "", { expires: /* @__PURE__ */ new Date(1) });
|
|
771
|
+
ctx.cookies.set(COOKIE_NAME_STATE, "", { expires: /* @__PURE__ */ new Date(1) });
|
|
760
772
|
}
|
|
761
773
|
setState(null, null);
|
|
762
774
|
return next();
|
|
@@ -769,4 +781,4 @@ function init({
|
|
|
769
781
|
}
|
|
770
782
|
|
|
771
783
|
export { AuthenticationService, MongoUsersManager, STATUSES, UserAccountGoogleService, UserAccountSlackService, authSocketIO, createAuthApolloContext, init as default };
|
|
772
|
-
//# sourceMappingURL=index-
|
|
784
|
+
//# sourceMappingURL=index-node.mjs.map
|