@xtaskjs/security 1.0.0 → 1.0.2
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 +16 -0
- package/dist/authentication.d.ts +6 -0
- package/dist/authentication.js +20 -0
- package/dist/authorization.d.ts +6 -0
- package/dist/authorization.js +51 -0
- package/dist/configuration.d.ts +8 -0
- package/dist/configuration.js +70 -0
- package/dist/decorators.d.ts +5 -0
- package/dist/decorators.js +54 -0
- package/dist/guards.d.ts +3 -0
- package/dist/guards.js +50 -0
- package/{src/index.ts → dist/index.d.ts} +1 -2
- package/dist/index.js +25 -0
- package/dist/lifecycle.d.ts +25 -0
- package/dist/lifecycle.js +314 -0
- package/dist/metadata.d.ts +6 -0
- package/dist/metadata.js +103 -0
- package/dist/strategies.d.ts +16 -0
- package/dist/strategies.js +173 -0
- package/dist/tokens.d.ts +8 -0
- package/dist/tokens.js +19 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.js +2 -0
- package/package.json +11 -5
- package/babel.config.js +0 -3
- package/index.ts +0 -1
- package/jest.config.js +0 -18
- package/src/authentication.ts +0 -27
- package/src/authorization.ts +0 -66
- package/src/configuration.ts +0 -90
- package/src/decorators.ts +0 -79
- package/src/guards.ts +0 -58
- package/src/lifecycle.ts +0 -403
- package/src/metadata.ts +0 -136
- package/src/passport-ambient.d.ts +0 -22
- package/src/strategies.ts +0 -227
- package/src/tokens.ts +0 -16
- package/src/types.ts +0 -94
- package/test/security.integration.test.ts +0 -325
- package/tsconfig.json +0 -21
- package/tsconfig.test.json +0 -17
package/src/lifecycle.ts
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
import { RouteExecutionContext } from "@xtaskjs/common";
|
|
2
|
-
import { AutoWired, Container, Qualifier } from "@xtaskjs/core";
|
|
3
|
-
import passport from "passport";
|
|
4
|
-
import { ExtractJwt, Strategy as JwtStrategy } from "passport-jwt";
|
|
5
|
-
import {
|
|
6
|
-
clearRegisteredSecurityStrategies,
|
|
7
|
-
getDefaultSecurityStrategyName,
|
|
8
|
-
getRegisteredSecurityStrategies,
|
|
9
|
-
} from "./configuration";
|
|
10
|
-
import {
|
|
11
|
-
getAuthenticationServiceToken,
|
|
12
|
-
getAuthorizationServiceToken,
|
|
13
|
-
getPassportToken,
|
|
14
|
-
getSecurityLifecycleToken,
|
|
15
|
-
} from "./tokens";
|
|
16
|
-
import { SecurityAuthorizationService } from "./authorization";
|
|
17
|
-
import { SecurityAuthenticationService } from "./authentication";
|
|
18
|
-
import {
|
|
19
|
-
RegisteredJwtSecurityStrategyOptions,
|
|
20
|
-
RegisteredSecurityStrategyOptions,
|
|
21
|
-
SecurityAuthenticationResult,
|
|
22
|
-
} from "./types";
|
|
23
|
-
import { JweStrategy, defaultBearerTokenExtractor, resolveValidatedUser } from "./strategies";
|
|
24
|
-
|
|
25
|
-
type PassportOutcome =
|
|
26
|
-
| { type: "success"; user: any; info?: any }
|
|
27
|
-
| { type: "fail"; challenge?: any; statusCode?: number }
|
|
28
|
-
| { type: "pass" };
|
|
29
|
-
|
|
30
|
-
const createPassportInstance = (): any => {
|
|
31
|
-
const PassportConstructor = (passport as any).Passport || (passport as any).Authenticator;
|
|
32
|
-
return new PassportConstructor();
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const createSafeExtractor = (extractor: (request: any) => any) => {
|
|
36
|
-
return (request: any) => {
|
|
37
|
-
try {
|
|
38
|
-
return extractor(request);
|
|
39
|
-
} catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const toRecord = (value: any): Record<string, any> => {
|
|
46
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
47
|
-
return value;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {};
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const uniqueRoles = (roles: string[]): string[] => {
|
|
54
|
-
return Array.from(new Set(roles.filter((value) => value.length > 0)));
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const resolveClaims = (user: any, info: any): Record<string, any> => {
|
|
58
|
-
if (info?.claims) {
|
|
59
|
-
return toRecord(info.claims);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (user?.claims) {
|
|
63
|
-
return toRecord(user.claims);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return {};
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const resolveRoles = (
|
|
70
|
-
definition: RegisteredSecurityStrategyOptions,
|
|
71
|
-
claims: Record<string, any>,
|
|
72
|
-
user: any
|
|
73
|
-
): string[] => {
|
|
74
|
-
const extracted = definition.extractRoles?.(claims, user);
|
|
75
|
-
if (Array.isArray(extracted)) {
|
|
76
|
-
return uniqueRoles(extracted.map((value) => String(value).trim()));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (Array.isArray(user?.roles)) {
|
|
80
|
-
return uniqueRoles(user.roles.map((value: any) => String(value).trim()));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (Array.isArray(claims.roles)) {
|
|
84
|
-
return uniqueRoles(claims.roles.map((value: any) => String(value).trim()));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (typeof claims.scope === "string") {
|
|
88
|
-
return uniqueRoles(
|
|
89
|
-
claims.scope
|
|
90
|
-
.split(/\s+/)
|
|
91
|
-
.map((value: string) => value.trim())
|
|
92
|
-
.filter((value: string) => value.length > 0)
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return [];
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export class SecurityLifecycleManager {
|
|
100
|
-
private passportInstance: any = createPassportInstance();
|
|
101
|
-
private readonly strategyDefinitions = new Map<string, RegisteredSecurityStrategyOptions>();
|
|
102
|
-
private container?: Container;
|
|
103
|
-
|
|
104
|
-
async initialize(container?: Container): Promise<void> {
|
|
105
|
-
this.passportInstance = createPassportInstance();
|
|
106
|
-
this.strategyDefinitions.clear();
|
|
107
|
-
this.container = container;
|
|
108
|
-
|
|
109
|
-
for (const definition of getRegisteredSecurityStrategies()) {
|
|
110
|
-
this.strategyDefinitions.set(definition.name, definition);
|
|
111
|
-
if (definition.kind === "jwt") {
|
|
112
|
-
this.registerJwtStrategy(definition);
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
this.passportInstance.use(
|
|
117
|
-
definition.name,
|
|
118
|
-
new JweStrategy(definition, () => ({ container: this.container }))
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
this.registerContainerBindings(container);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async destroy(): Promise<void> {
|
|
126
|
-
this.passportInstance = createPassportInstance();
|
|
127
|
-
this.strategyDefinitions.clear();
|
|
128
|
-
this.container = undefined;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
getPassport(): any {
|
|
132
|
-
return this.passportInstance;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async authenticateContext(
|
|
136
|
-
context: RouteExecutionContext,
|
|
137
|
-
strategyNames?: string | string[]
|
|
138
|
-
): Promise<SecurityAuthenticationResult> {
|
|
139
|
-
const result = await this.authenticateRequest(context.request, context.response, strategyNames);
|
|
140
|
-
if (!result.success) {
|
|
141
|
-
return result;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
context.auth = {
|
|
145
|
-
isAuthenticated: true,
|
|
146
|
-
strategy: result.strategy,
|
|
147
|
-
token: result.token,
|
|
148
|
-
user: result.user,
|
|
149
|
-
claims: result.claims,
|
|
150
|
-
roles: [...result.roles],
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
if (context.request && typeof context.request === "object") {
|
|
154
|
-
context.request.user = result.user;
|
|
155
|
-
context.request.auth = context.auth;
|
|
156
|
-
context.request.authInfo = result.info;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (context.response && typeof context.response === "object") {
|
|
160
|
-
context.response.locals = context.response.locals || {};
|
|
161
|
-
context.response.locals.auth = context.auth;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return result;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async authenticateRequest(
|
|
168
|
-
request: any,
|
|
169
|
-
_response?: any,
|
|
170
|
-
strategyNames?: string | string[]
|
|
171
|
-
): Promise<SecurityAuthenticationResult> {
|
|
172
|
-
const selectedStrategies = this.resolveStrategyNames(strategyNames);
|
|
173
|
-
let lastFailure: { statusCode?: number; challenge?: any } = {
|
|
174
|
-
statusCode: 401,
|
|
175
|
-
challenge: { message: "Unauthorized" },
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
for (const strategyName of selectedStrategies) {
|
|
179
|
-
const definition = this.strategyDefinitions.get(strategyName);
|
|
180
|
-
if (!definition) {
|
|
181
|
-
throw new Error(`Security strategy '${strategyName}' is not registered`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const extractor = definition.jwtFromRequest || defaultBearerTokenExtractor;
|
|
185
|
-
const token = extractor(request) || undefined;
|
|
186
|
-
const outcome = await this.runPassportStrategy(strategyName, request);
|
|
187
|
-
|
|
188
|
-
if (outcome.type === "success") {
|
|
189
|
-
const claims = resolveClaims(outcome.user, outcome.info);
|
|
190
|
-
return {
|
|
191
|
-
success: true,
|
|
192
|
-
strategy: strategyName,
|
|
193
|
-
token,
|
|
194
|
-
user: outcome.user,
|
|
195
|
-
claims,
|
|
196
|
-
roles: resolveRoles(definition, claims, outcome.user),
|
|
197
|
-
info: outcome.info,
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (outcome.type === "fail") {
|
|
202
|
-
lastFailure = { statusCode: outcome.statusCode, challenge: outcome.challenge };
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return {
|
|
207
|
-
success: false,
|
|
208
|
-
statusCode: lastFailure.statusCode || 401,
|
|
209
|
-
challenge: lastFailure.challenge || { message: "Unauthorized" },
|
|
210
|
-
roles: [],
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
private resolveStrategyNames(strategyNames?: string | string[]): string[] {
|
|
215
|
-
if (Array.isArray(strategyNames) && strategyNames.length > 0) {
|
|
216
|
-
return strategyNames;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (typeof strategyNames === "string" && strategyNames.trim().length > 0) {
|
|
220
|
-
return [strategyNames.trim()];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const defaultStrategy = getDefaultSecurityStrategyName();
|
|
224
|
-
if (defaultStrategy) {
|
|
225
|
-
return [defaultStrategy];
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
throw new Error("No security strategy registered. Call registerJwtStrategy() or registerJweStrategy().");
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
private registerJwtStrategy(definition: RegisteredJwtSecurityStrategyOptions): void {
|
|
232
|
-
const extractor = createSafeExtractor(
|
|
233
|
-
definition.jwtFromRequest || ExtractJwt.fromAuthHeaderAsBearerToken()
|
|
234
|
-
);
|
|
235
|
-
const options: any = {
|
|
236
|
-
jwtFromRequest: extractor,
|
|
237
|
-
secretOrKey: definition.secretOrKey,
|
|
238
|
-
secretOrKeyProvider: definition.secretOrKeyProvider,
|
|
239
|
-
issuer: definition.issuer,
|
|
240
|
-
audience: definition.audience,
|
|
241
|
-
algorithms: definition.algorithms,
|
|
242
|
-
ignoreExpiration: definition.ignoreExpiration,
|
|
243
|
-
jsonWebTokenOptions: definition.jsonWebTokenOptions,
|
|
244
|
-
passReqToCallback: definition.passReqToCallback === true,
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
const verify = async (...args: any[]) => {
|
|
248
|
-
const done = args[args.length - 1];
|
|
249
|
-
const request = definition.passReqToCallback ? args[0] : undefined;
|
|
250
|
-
const payload = toRecord(definition.passReqToCallback ? args[1] : args[0]);
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
const token = extractor(request) || "";
|
|
254
|
-
const user = await resolveValidatedUser(definition, payload, {
|
|
255
|
-
container: this.container,
|
|
256
|
-
request,
|
|
257
|
-
token,
|
|
258
|
-
strategyName: definition.name,
|
|
259
|
-
kind: definition.kind,
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
if (!user) {
|
|
263
|
-
done(null, false, { message: "Unauthorized", claims: payload });
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
done(null, user, {
|
|
268
|
-
claims: payload,
|
|
269
|
-
strategy: definition.name,
|
|
270
|
-
kind: definition.kind,
|
|
271
|
-
});
|
|
272
|
-
} catch (error) {
|
|
273
|
-
done(error);
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
this.passportInstance.use(definition.name, new JwtStrategy(options, verify));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
private runPassportStrategy(strategyName: string, request: any): Promise<PassportOutcome> {
|
|
281
|
-
const strategy = this.passportInstance._strategy(strategyName);
|
|
282
|
-
if (!strategy) {
|
|
283
|
-
throw new Error(`Passport strategy '${strategyName}' is not registered`);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return new Promise<PassportOutcome>((resolve, reject) => {
|
|
287
|
-
const delegate = Object.create(strategy);
|
|
288
|
-
Object.assign(delegate, strategy);
|
|
289
|
-
delegate.success = (user: any, info?: any) => resolve({ type: "success", user, info });
|
|
290
|
-
delegate.fail = (challenge?: any, statusCode?: number) =>
|
|
291
|
-
resolve({ type: "fail", challenge, statusCode });
|
|
292
|
-
delegate.pass = () => resolve({ type: "pass" });
|
|
293
|
-
delegate.error = (error: Error) => reject(error);
|
|
294
|
-
delegate.redirect = (_url: string, statusCode?: number) =>
|
|
295
|
-
resolve({
|
|
296
|
-
type: "fail",
|
|
297
|
-
challenge: { message: "Redirect responses are not supported by xtaskjs security guards" },
|
|
298
|
-
statusCode: statusCode || 401,
|
|
299
|
-
});
|
|
300
|
-
delegate.authenticate(request, {});
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
private registerContainerBindings(container?: Container): void {
|
|
305
|
-
if (!container) {
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const anyContainer = container as any;
|
|
310
|
-
if (typeof anyContainer.registerWithName === "function") {
|
|
311
|
-
anyContainer.registerWithName(
|
|
312
|
-
SecurityAuthenticationService,
|
|
313
|
-
{ scope: "singleton" },
|
|
314
|
-
getAuthenticationServiceToken()
|
|
315
|
-
);
|
|
316
|
-
anyContainer.registerWithName(
|
|
317
|
-
SecurityAuthorizationService,
|
|
318
|
-
{ scope: "singleton" },
|
|
319
|
-
getAuthorizationServiceToken()
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
if (typeof anyContainer.registerNamedInstance === "function") {
|
|
324
|
-
anyContainer.registerNamedInstance(getPassportToken(), this.passportInstance);
|
|
325
|
-
anyContainer.registerNamedInstance(getSecurityLifecycleToken(), this);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const lifecycleManager = new SecurityLifecycleManager();
|
|
331
|
-
|
|
332
|
-
export const initializeSecurityIntegration = async (container?: Container): Promise<void> => {
|
|
333
|
-
await lifecycleManager.initialize(container);
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
export const shutdownSecurityIntegration = async (): Promise<void> => {
|
|
337
|
-
await lifecycleManager.destroy();
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
export const getSecurityLifecycleManager = (): SecurityLifecycleManager => {
|
|
341
|
-
return lifecycleManager;
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
export const resetSecurityIntegration = async (): Promise<void> => {
|
|
345
|
-
await shutdownSecurityIntegration();
|
|
346
|
-
clearRegisteredSecurityStrategies();
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
export const InjectAuthenticationService = (): ParameterDecorator & PropertyDecorator => {
|
|
350
|
-
return (target: any, propertyKey: string | symbol | undefined, parameterIndex?: number) => {
|
|
351
|
-
const token = getAuthenticationServiceToken();
|
|
352
|
-
if (typeof parameterIndex === "number") {
|
|
353
|
-
Qualifier(token)(target, propertyKey, parameterIndex);
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (propertyKey !== undefined) {
|
|
358
|
-
AutoWired({ qualifier: token })(target, propertyKey);
|
|
359
|
-
}
|
|
360
|
-
};
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
export const InjectAuthorizationService = (): ParameterDecorator & PropertyDecorator => {
|
|
364
|
-
return (target: any, propertyKey: string | symbol | undefined, parameterIndex?: number) => {
|
|
365
|
-
const token = getAuthorizationServiceToken();
|
|
366
|
-
if (typeof parameterIndex === "number") {
|
|
367
|
-
Qualifier(token)(target, propertyKey, parameterIndex);
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if (propertyKey !== undefined) {
|
|
372
|
-
AutoWired({ qualifier: token })(target, propertyKey);
|
|
373
|
-
}
|
|
374
|
-
};
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
export const InjectPassport = (): ParameterDecorator & PropertyDecorator => {
|
|
378
|
-
return (target: any, propertyKey: string | symbol | undefined, parameterIndex?: number) => {
|
|
379
|
-
const token = getPassportToken();
|
|
380
|
-
if (typeof parameterIndex === "number") {
|
|
381
|
-
Qualifier(token)(target, propertyKey, parameterIndex);
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (propertyKey !== undefined) {
|
|
386
|
-
AutoWired({ qualifier: token })(target, propertyKey);
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
export const InjectSecurityLifecycleManager = (): ParameterDecorator & PropertyDecorator => {
|
|
392
|
-
return (target: any, propertyKey: string | symbol | undefined, parameterIndex?: number) => {
|
|
393
|
-
const token = getSecurityLifecycleToken();
|
|
394
|
-
if (typeof parameterIndex === "number") {
|
|
395
|
-
Qualifier(token)(target, propertyKey, parameterIndex);
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (propertyKey !== undefined) {
|
|
400
|
-
AutoWired({ qualifier: token })(target, propertyKey);
|
|
401
|
-
}
|
|
402
|
-
};
|
|
403
|
-
};
|
package/src/metadata.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { ResolvedSecurityMetadata, RolesOptions, SecurityRoleMatchingMode } from "./types";
|
|
2
|
-
|
|
3
|
-
const CLASS_SECURITY_METADATA_KEY = Symbol("xtask:security:class");
|
|
4
|
-
const METHOD_SECURITY_METADATA_KEY = Symbol("xtask:security:method");
|
|
5
|
-
|
|
6
|
-
type MutableSecurityMetadata = Partial<ResolvedSecurityMetadata>;
|
|
7
|
-
|
|
8
|
-
const emptyMetadata = (): MutableSecurityMetadata => ({
|
|
9
|
-
allowAnonymous: false,
|
|
10
|
-
strategies: [],
|
|
11
|
-
roles: [],
|
|
12
|
-
roleMode: "any",
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const uniqueStrings = (values: string[]): string[] => {
|
|
16
|
-
return Array.from(
|
|
17
|
-
new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))
|
|
18
|
-
);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const getClassMetadata = (target: any): MutableSecurityMetadata => {
|
|
22
|
-
return Reflect.getMetadata(CLASS_SECURITY_METADATA_KEY, target) || emptyMetadata();
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const setClassMetadata = (target: any, metadata: MutableSecurityMetadata): void => {
|
|
26
|
-
Reflect.defineMetadata(CLASS_SECURITY_METADATA_KEY, metadata, target);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const getMethodMetadataMap = (target: any): Map<PropertyKey, MutableSecurityMetadata> => {
|
|
30
|
-
const stored = Reflect.getMetadata(METHOD_SECURITY_METADATA_KEY, target) as
|
|
31
|
-
| Map<PropertyKey, MutableSecurityMetadata>
|
|
32
|
-
| undefined;
|
|
33
|
-
return stored || new Map<PropertyKey, MutableSecurityMetadata>();
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const setMethodMetadataMap = (target: any, metadataMap: Map<PropertyKey, MutableSecurityMetadata>): void => {
|
|
37
|
-
Reflect.defineMetadata(METHOD_SECURITY_METADATA_KEY, metadataMap, target);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const getOrCreateMethodMetadata = (target: any, propertyKey: PropertyKey): MutableSecurityMetadata => {
|
|
41
|
-
const metadataMap = getMethodMetadataMap(target.constructor);
|
|
42
|
-
const current = metadataMap.get(propertyKey) || emptyMetadata();
|
|
43
|
-
metadataMap.set(propertyKey, current);
|
|
44
|
-
setMethodMetadataMap(target.constructor, metadataMap);
|
|
45
|
-
return current;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export const normalizeStrategies = (strategies?: string | string[]): string[] => {
|
|
49
|
-
if (!strategies) {
|
|
50
|
-
return [];
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return uniqueStrings(Array.isArray(strategies) ? strategies : [strategies]);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export const setAuthenticatedMetadata = (
|
|
57
|
-
target: any,
|
|
58
|
-
propertyKey: PropertyKey | undefined,
|
|
59
|
-
strategies?: string | string[]
|
|
60
|
-
): void => {
|
|
61
|
-
const normalizedStrategies = normalizeStrategies(strategies);
|
|
62
|
-
if (propertyKey === undefined) {
|
|
63
|
-
const current = getClassMetadata(target);
|
|
64
|
-
current.allowAnonymous = false;
|
|
65
|
-
current.strategies = uniqueStrings([...(current.strategies || []), ...normalizedStrategies]);
|
|
66
|
-
setClassMetadata(target, current);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const current = getOrCreateMethodMetadata(target, propertyKey);
|
|
71
|
-
current.allowAnonymous = false;
|
|
72
|
-
current.strategies = uniqueStrings([...(current.strategies || []), ...normalizedStrategies]);
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export const setRolesMetadata = (
|
|
76
|
-
target: any,
|
|
77
|
-
propertyKey: PropertyKey | undefined,
|
|
78
|
-
options: RolesOptions
|
|
79
|
-
): void => {
|
|
80
|
-
const roles = uniqueStrings(options.roles || []);
|
|
81
|
-
const strategies = normalizeStrategies(options.strategies);
|
|
82
|
-
const roleMode: SecurityRoleMatchingMode = options.mode || "any";
|
|
83
|
-
|
|
84
|
-
if (propertyKey === undefined) {
|
|
85
|
-
const current = getClassMetadata(target);
|
|
86
|
-
current.roles = uniqueStrings([...(current.roles || []), ...roles]);
|
|
87
|
-
current.strategies = uniqueStrings([...(current.strategies || []), ...strategies]);
|
|
88
|
-
current.roleMode = roleMode;
|
|
89
|
-
setClassMetadata(target, current);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const current = getOrCreateMethodMetadata(target, propertyKey);
|
|
94
|
-
current.roles = uniqueStrings([...(current.roles || []), ...roles]);
|
|
95
|
-
current.strategies = uniqueStrings([...(current.strategies || []), ...strategies]);
|
|
96
|
-
current.roleMode = roleMode;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export const setAllowAnonymousMetadata = (target: any, propertyKey?: PropertyKey): void => {
|
|
100
|
-
if (propertyKey === undefined) {
|
|
101
|
-
const current = getClassMetadata(target);
|
|
102
|
-
current.allowAnonymous = true;
|
|
103
|
-
setClassMetadata(target, current);
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const current = getOrCreateMethodMetadata(target, propertyKey);
|
|
108
|
-
current.allowAnonymous = true;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export const resolveSecurityMetadata = (
|
|
112
|
-
controllerType: any,
|
|
113
|
-
handler?: PropertyKey
|
|
114
|
-
): ResolvedSecurityMetadata => {
|
|
115
|
-
const classMetadata = controllerType ? getClassMetadata(controllerType) : emptyMetadata();
|
|
116
|
-
const methodMetadata =
|
|
117
|
-
controllerType && handler !== undefined
|
|
118
|
-
? getMethodMetadataMap(controllerType).get(handler) || emptyMetadata()
|
|
119
|
-
: emptyMetadata();
|
|
120
|
-
|
|
121
|
-
const allowAnonymous = Boolean(
|
|
122
|
-
methodMetadata.allowAnonymous ?? classMetadata.allowAnonymous ?? false
|
|
123
|
-
);
|
|
124
|
-
const strategies = uniqueStrings([
|
|
125
|
-
...(classMetadata.strategies || []),
|
|
126
|
-
...(methodMetadata.strategies || []),
|
|
127
|
-
]);
|
|
128
|
-
const roles = uniqueStrings([...(classMetadata.roles || []), ...(methodMetadata.roles || [])]);
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
allowAnonymous,
|
|
132
|
-
strategies,
|
|
133
|
-
roles,
|
|
134
|
-
roleMode: methodMetadata.roleMode || classMetadata.roleMode || "any",
|
|
135
|
-
};
|
|
136
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
declare module "passport" {
|
|
2
|
-
const passport: any;
|
|
3
|
-
export = passport;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
declare module "passport-jwt" {
|
|
7
|
-
export const ExtractJwt: any;
|
|
8
|
-
export class Strategy {
|
|
9
|
-
constructor(options: any, verify: (...args: any[]) => void);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
declare module "passport-strategy" {
|
|
14
|
-
export class Strategy {
|
|
15
|
-
name: string;
|
|
16
|
-
success(user: any, info?: any): void;
|
|
17
|
-
fail(challenge?: any, status?: number): void;
|
|
18
|
-
error(error: Error): void;
|
|
19
|
-
pass(): void;
|
|
20
|
-
authenticate(request: any, options?: any): void;
|
|
21
|
-
}
|
|
22
|
-
}
|