@universis/janitor 1.10.0 → 1.12.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/dist/index.d.ts +132 -2
- package/dist/index.esm.js +168 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +173 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/HttpBearerStategy.js +1 -1
- package/src/PassportService.d.ts +6 -0
- package/src/PassportService.js +27 -0
- package/src/RedisClientStore.js +15 -2
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as _themost_common from '@themost/common';
|
|
2
|
-
import { ApplicationService, ApplicationBase, ConfigurationStrategy, ConfigurationBase } from '@themost/common';
|
|
2
|
+
import { ApplicationService, ApplicationBase, ConfigurationStrategy, ConfigurationBase, HttpForbiddenError, HttpError } from '@themost/common';
|
|
3
3
|
import { Router, Application, Handler, Request as Request$1 } from 'express';
|
|
4
4
|
import { Store, Options } from 'express-rate-limit';
|
|
5
5
|
import { BehaviorSubject } from 'rxjs';
|
|
6
6
|
import { Store as Store$1, Options as Options$1 } from 'express-slow-down';
|
|
7
7
|
import RedisStore from 'rate-limit-redis';
|
|
8
8
|
import { DataContext } from '@themost/data';
|
|
9
|
+
import BearerStrategy from 'passport-http-bearer';
|
|
10
|
+
import { Authenticator } from 'passport';
|
|
9
11
|
|
|
10
12
|
declare type RateLimitStoreConstructor = new (...arg: unknown[]) => Store;
|
|
11
13
|
|
|
@@ -250,5 +252,133 @@ declare class AppSpeedLimitService extends SpeedLimitService {
|
|
|
250
252
|
constructor(app: _themost_common.ApplicationBase);
|
|
251
253
|
}
|
|
252
254
|
|
|
253
|
-
|
|
255
|
+
declare class HttpBearerTokenRequired extends HttpError {
|
|
256
|
+
constructor() {
|
|
257
|
+
super(499, 'A token is required to fulfill the request.');
|
|
258
|
+
this.code = 'E_TOKEN_REQUIRED';
|
|
259
|
+
this.title = 'Token Required';
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
declare class HttpBearerTokenNotFound extends HttpError {
|
|
264
|
+
constructor() {
|
|
265
|
+
super(498, 'Token was not found.');
|
|
266
|
+
this.code = 'E_TOKEN_NOT_FOUND';
|
|
267
|
+
this.title = 'Invalid token';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
declare class HttpBearerTokenExpired extends HttpError {
|
|
272
|
+
constructor() {
|
|
273
|
+
super(498, 'Token was expired or is in invalid state.');
|
|
274
|
+
this.code = 'E_TOKEN_EXPIRED';
|
|
275
|
+
this.title = 'Invalid token';
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
declare class HttpAccountDisabled extends HttpForbiddenError {
|
|
280
|
+
constructor() {
|
|
281
|
+
super('Access is denied. User account is disabled.');
|
|
282
|
+
this.code = 'E_ACCOUNT_DISABLED';
|
|
283
|
+
this.statusCode = 403.2;
|
|
284
|
+
this.title = 'Disabled account';
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
declare class HttpBearerStrategy extends BearerStrategy {
|
|
289
|
+
constructor() {
|
|
290
|
+
super({
|
|
291
|
+
passReqToCallback: true
|
|
292
|
+
},
|
|
293
|
+
/**
|
|
294
|
+
* @param {Request} req
|
|
295
|
+
* @param {string} token
|
|
296
|
+
* @param {Function} done
|
|
297
|
+
*/
|
|
298
|
+
function(req, token, done) {
|
|
299
|
+
/**
|
|
300
|
+
* Gets OAuth2 client services
|
|
301
|
+
* @type {import('./OAuth2ClientService').OAuth2ClientService}
|
|
302
|
+
*/
|
|
303
|
+
let client = req.context.getApplication().getStrategy(function OAuth2ClientService() {});
|
|
304
|
+
// if client cannot be found
|
|
305
|
+
if (client == null) {
|
|
306
|
+
// throw configuration error
|
|
307
|
+
return done(new Error('Invalid application configuration. OAuth2 client service cannot be found.'))
|
|
308
|
+
}
|
|
309
|
+
if (token == null) {
|
|
310
|
+
// throw 499 Token Required error
|
|
311
|
+
return done(new HttpBearerTokenRequired());
|
|
312
|
+
}
|
|
313
|
+
// get token info
|
|
314
|
+
client.getTokenInfo(req.context, token).then(info => {
|
|
315
|
+
if (info == null) {
|
|
316
|
+
// the specified token cannot be found - 498 invalid token with specific code
|
|
317
|
+
return done(new HttpBearerTokenNotFound());
|
|
318
|
+
}
|
|
319
|
+
// if the given token is not active throw token expired - 498 invalid token with specific code
|
|
320
|
+
if (!info.active) {
|
|
321
|
+
return done(new HttpBearerTokenExpired());
|
|
322
|
+
}
|
|
323
|
+
// find user from token info
|
|
324
|
+
return (function () {
|
|
325
|
+
/**
|
|
326
|
+
* @type {import('./services/user-provisioning-mapper-service').UserProvisioningMapperService}
|
|
327
|
+
*/
|
|
328
|
+
const mapper = req.context.getApplication().getService(function UserProvisioningMapperService() {});
|
|
329
|
+
if (mapper == null) {
|
|
330
|
+
return req.context.model('User').where('name').equal(info.username).silent().getItem();
|
|
331
|
+
}
|
|
332
|
+
return mapper.getUser(req.context, info);
|
|
333
|
+
})().then((user) => {
|
|
334
|
+
// check if userProvisioning service is installed and try to find related user only if user not found
|
|
335
|
+
if (user == null) {
|
|
336
|
+
/**
|
|
337
|
+
* @type {import('./services/user-provisioning-service').UserProvisioningService}
|
|
338
|
+
*/
|
|
339
|
+
const service = req.context.getApplication().getService(function UserProvisioningService() {});
|
|
340
|
+
if (service == null) {
|
|
341
|
+
return user;
|
|
342
|
+
}
|
|
343
|
+
return service.validateUser(req.context, info);
|
|
344
|
+
}
|
|
345
|
+
return user;
|
|
346
|
+
}).then( user => {
|
|
347
|
+
// user cannot be found and of course cannot be authenticated (throw forbidden error)
|
|
348
|
+
if (user == null) {
|
|
349
|
+
// write access log for forbidden
|
|
350
|
+
return done(new HttpForbiddenError());
|
|
351
|
+
}
|
|
352
|
+
// check if user has enabled attribute
|
|
353
|
+
if (Object.prototype.hasOwnProperty.call(user, 'enabled') && !user.enabled) {
|
|
354
|
+
//if user.enabled is off throw forbidden error
|
|
355
|
+
return done(new HttpAccountDisabled('Access is denied. User account is disabled.'));
|
|
356
|
+
}
|
|
357
|
+
// otherwise return user data
|
|
358
|
+
return done(null, {
|
|
359
|
+
'name': user.name,
|
|
360
|
+
'authenticationProviderKey': user.id,
|
|
361
|
+
'authenticationType':'Bearer',
|
|
362
|
+
'authenticationToken': token,
|
|
363
|
+
'authenticationScope': info.scope
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
}).catch(err => {
|
|
367
|
+
// end log token info request with error
|
|
368
|
+
if (err && err.statusCode === 404) {
|
|
369
|
+
// revert 404 not found returned by auth server to 498 invalid token
|
|
370
|
+
return done(new HttpBearerTokenNotFound());
|
|
371
|
+
}
|
|
372
|
+
// otherwise continue with error
|
|
373
|
+
return done(err);
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
declare class PassportService extends ApplicationService {
|
|
380
|
+
getInstance(): Authenticator
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export { AppRateLimitService, AppSpeedLimitService, DefaultScopeAccessConfiguration, EnableScopeAccessConfiguration, ExtendScopeAccessConfiguration, HttpAccountDisabled, HttpBearerStrategy, HttpBearerTokenExpired, HttpBearerTokenNotFound, HttpBearerTokenRequired, OAuth2ClientService, PassportService, RateLimitService, RedisClientStore, RemoteAddressValidator, ScopeAccessConfiguration, ScopeString, SpeedLimitService, validateScope };
|
|
254
384
|
export type { GenericUser, OAuth2AuthorizeUser, OAuth2MethodOptions, OAuth2ServiceSettings, OAuth2User, OAuth2UserProfile, RateLimitServiceConfiguration, RateLimitStoreConstructor, ScopeAccessConfigurationElement, ScopeAccessConfigurationSection, SpeedLimitServiceConfiguration, SpeedLimitStoreConstructor, UniversisConfigurationSection };
|
package/dist/index.esm.js
CHANGED
|
@@ -11,6 +11,8 @@ import '@themost/promise-sequence';
|
|
|
11
11
|
import url, { URL } from 'url';
|
|
12
12
|
import { Request } from 'superagent';
|
|
13
13
|
import jwt from 'jsonwebtoken';
|
|
14
|
+
import BearerStrategy from 'passport-http-bearer';
|
|
15
|
+
import passport from 'passport';
|
|
14
16
|
|
|
15
17
|
class RateLimitService extends ApplicationService {
|
|
16
18
|
/**
|
|
@@ -529,12 +531,21 @@ class RedisClientStore extends RedisStore {
|
|
|
529
531
|
* @param {{windowMs: number}} options
|
|
530
532
|
*/
|
|
531
533
|
constructor(service, options) {
|
|
534
|
+
// IMPORTANT NOTE: call super with a dummy sendCommand()
|
|
535
|
+
// for implementing a custom sendCommand method
|
|
536
|
+
// which binds sendCommand to this instance
|
|
532
537
|
super({
|
|
533
|
-
|
|
538
|
+
sendCommand: function () {}
|
|
539
|
+
});
|
|
540
|
+
// create a custom sendCommand method
|
|
541
|
+
// noinspection JSCommentMatchesSignature,JSCheckFunctionSignatures
|
|
542
|
+
/**
|
|
543
|
+
* @type {import('redis').RedisClientType}
|
|
544
|
+
*/_defineProperty(this, "client", void 0);const opts = { /**
|
|
534
545
|
* @param {...string} args
|
|
535
546
|
* @returns {Promise<*>}
|
|
536
|
-
*/
|
|
537
|
-
|
|
547
|
+
*/sendCommand: function () {
|
|
548
|
+
|
|
538
549
|
const args = Array.from(arguments);
|
|
539
550
|
const [command] = args.splice(0, 1);
|
|
540
551
|
const self = this;
|
|
@@ -575,7 +586,7 @@ class RedisClientStore extends RedisStore {
|
|
|
575
586
|
// send load script commands once
|
|
576
587
|
return (() => {
|
|
577
588
|
if (self.incrementScriptSha == null) {
|
|
578
|
-
return
|
|
589
|
+
return self.postInit();
|
|
579
590
|
}
|
|
580
591
|
return Promise.resolve();
|
|
581
592
|
})().then(() => {
|
|
@@ -589,9 +600,13 @@ class RedisClientStore extends RedisStore {
|
|
|
589
600
|
});
|
|
590
601
|
});
|
|
591
602
|
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
|
|
603
|
+
};
|
|
604
|
+
// bind sendCommand to this instance, applying command array as arguments
|
|
605
|
+
// like rate-limit-redis expects
|
|
606
|
+
// noinspection JSCheckFunctionSignatures
|
|
607
|
+
this.sendCommand = async ({ command }) => opts.sendCommand.bind(this)(...command);
|
|
608
|
+
this.init(options);
|
|
609
|
+
TraceUtils.debug('RedisClientStore: Starting up and loading increment and get scripts.');
|
|
595
610
|
void this.postInit().then(() => {
|
|
596
611
|
TraceUtils.debug('RedisClientStore: Successfully loaded increment and get scripts.');
|
|
597
612
|
}).catch((err) => {
|
|
@@ -1182,5 +1197,150 @@ class AppSpeedLimitService extends SpeedLimitService {
|
|
|
1182
1197
|
}
|
|
1183
1198
|
}
|
|
1184
1199
|
|
|
1185
|
-
|
|
1200
|
+
class HttpBearerTokenRequired extends HttpError {
|
|
1201
|
+
constructor() {
|
|
1202
|
+
super(499, 'A token is required to fulfill the request.');
|
|
1203
|
+
this.code = 'E_TOKEN_REQUIRED';
|
|
1204
|
+
this.title = 'Token Required';
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
class HttpBearerTokenNotFound extends HttpError {
|
|
1209
|
+
constructor() {
|
|
1210
|
+
super(498, 'Token was not found.');
|
|
1211
|
+
this.code = 'E_TOKEN_NOT_FOUND';
|
|
1212
|
+
this.title = 'Invalid token';
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
class HttpBearerTokenExpired extends HttpError {
|
|
1217
|
+
constructor() {
|
|
1218
|
+
super(498, 'Token was expired or is in invalid state.');
|
|
1219
|
+
this.code = 'E_TOKEN_EXPIRED';
|
|
1220
|
+
this.title = 'Invalid token';
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
class HttpAccountDisabled extends HttpForbiddenError {
|
|
1225
|
+
constructor() {
|
|
1226
|
+
super('Access is denied. User account is disabled.');
|
|
1227
|
+
this.code = 'E_ACCOUNT_DISABLED';
|
|
1228
|
+
this.statusCode = 403.2;
|
|
1229
|
+
this.title = 'Disabled account';
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
class HttpBearerStrategy extends BearerStrategy {
|
|
1234
|
+
constructor() {
|
|
1235
|
+
super({
|
|
1236
|
+
passReqToCallback: true
|
|
1237
|
+
},
|
|
1238
|
+
/**
|
|
1239
|
+
* @param {Request} req
|
|
1240
|
+
* @param {string} token
|
|
1241
|
+
* @param {Function} done
|
|
1242
|
+
*/
|
|
1243
|
+
function (req, token, done) {
|
|
1244
|
+
/**
|
|
1245
|
+
* Gets OAuth2 client services
|
|
1246
|
+
* @type {import('./OAuth2ClientService').OAuth2ClientService}
|
|
1247
|
+
*/
|
|
1248
|
+
let client = req.context.getApplication().getStrategy(function OAuth2ClientService() {});
|
|
1249
|
+
// if client cannot be found
|
|
1250
|
+
if (client == null) {
|
|
1251
|
+
// throw configuration error
|
|
1252
|
+
return done(new Error('Invalid application configuration. OAuth2 client service cannot be found.'));
|
|
1253
|
+
}
|
|
1254
|
+
if (token == null) {
|
|
1255
|
+
// throw 499 Token Required error
|
|
1256
|
+
return done(new HttpBearerTokenRequired());
|
|
1257
|
+
}
|
|
1258
|
+
// get token info
|
|
1259
|
+
client.getTokenInfo(req.context, token).then((info) => {
|
|
1260
|
+
if (info == null) {
|
|
1261
|
+
// the specified token cannot be found - 498 invalid token with specific code
|
|
1262
|
+
return done(new HttpBearerTokenNotFound());
|
|
1263
|
+
}
|
|
1264
|
+
// if the given token is not active throw token expired - 498 invalid token with specific code
|
|
1265
|
+
if (!info.active) {
|
|
1266
|
+
return done(new HttpBearerTokenExpired());
|
|
1267
|
+
}
|
|
1268
|
+
// find user from token info
|
|
1269
|
+
return function () {
|
|
1270
|
+
/**
|
|
1271
|
+
* @type {import('./services/user-provisioning-mapper-service').UserProvisioningMapperService}
|
|
1272
|
+
*/
|
|
1273
|
+
const mapper = req.context.getApplication().getService(function UserProvisioningMapperService() {});
|
|
1274
|
+
if (mapper == null) {
|
|
1275
|
+
return req.context.model('User').where('name').equal(info.username).silent().getItem();
|
|
1276
|
+
}
|
|
1277
|
+
return mapper.getUser(req.context, info);
|
|
1278
|
+
}().then((user) => {
|
|
1279
|
+
// check if userProvisioning service is installed and try to find related user only if user not found
|
|
1280
|
+
if (user == null) {
|
|
1281
|
+
/**
|
|
1282
|
+
* @type {import('./services/user-provisioning-service').UserProvisioningService}
|
|
1283
|
+
*/
|
|
1284
|
+
const service = req.context.getApplication().getService(function UserProvisioningService() {});
|
|
1285
|
+
if (service == null) {
|
|
1286
|
+
return user;
|
|
1287
|
+
}
|
|
1288
|
+
return service.validateUser(req.context, info);
|
|
1289
|
+
}
|
|
1290
|
+
return user;
|
|
1291
|
+
}).then((user) => {
|
|
1292
|
+
// user cannot be found and of course cannot be authenticated (throw forbidden error)
|
|
1293
|
+
if (user == null) {
|
|
1294
|
+
// write access log for forbidden
|
|
1295
|
+
return done(new HttpForbiddenError());
|
|
1296
|
+
}
|
|
1297
|
+
// check if user has enabled attribute
|
|
1298
|
+
if (Object.prototype.hasOwnProperty.call(user, 'enabled') && !user.enabled) {
|
|
1299
|
+
//if user.enabled is off throw forbidden error
|
|
1300
|
+
return done(new HttpAccountDisabled('Access is denied. User account is disabled.'));
|
|
1301
|
+
}
|
|
1302
|
+
// otherwise return user data
|
|
1303
|
+
return done(null, {
|
|
1304
|
+
'name': user.name,
|
|
1305
|
+
'authenticationProviderKey': user.id,
|
|
1306
|
+
'authenticationType': 'Bearer',
|
|
1307
|
+
'authenticationToken': token,
|
|
1308
|
+
'authenticationScope': info.scope
|
|
1309
|
+
});
|
|
1310
|
+
});
|
|
1311
|
+
}).catch((err) => {
|
|
1312
|
+
// end log token info request with error
|
|
1313
|
+
if (err && err.statusCode === 404) {
|
|
1314
|
+
// revert 404 not found returned by auth server to 498 invalid token
|
|
1315
|
+
return done(new HttpBearerTokenNotFound());
|
|
1316
|
+
}
|
|
1317
|
+
// otherwise continue with error
|
|
1318
|
+
return done(err);
|
|
1319
|
+
});
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
class PassportService extends ApplicationService {
|
|
1325
|
+
constructor(app) {
|
|
1326
|
+
super(app);
|
|
1327
|
+
const authenticator = new passport.Authenticator();
|
|
1328
|
+
Object.defineProperty(this, 'authenticator', {
|
|
1329
|
+
configurable: true,
|
|
1330
|
+
enumerable: false,
|
|
1331
|
+
writable: false,
|
|
1332
|
+
value: authenticator
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
/**
|
|
1337
|
+
* @returns {import('passport').Authenticator}
|
|
1338
|
+
*/
|
|
1339
|
+
getInstance() {
|
|
1340
|
+
return this.authenticator;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
export { AppRateLimitService, AppSpeedLimitService, DefaultScopeAccessConfiguration, EnableScopeAccessConfiguration, ExtendScopeAccessConfiguration, HttpAccountDisabled, HttpBearerStrategy, HttpBearerTokenExpired, HttpBearerTokenNotFound, HttpBearerTokenRequired, HttpRemoteAddrForbiddenError, OAuth2ClientService, PassportService, RateLimitService, RedisClientStore, RemoteAddressValidator, ScopeAccessConfiguration, ScopeString, SpeedLimitService, validateScope };
|
|
1186
1346
|
//# sourceMappingURL=index.esm.js.map
|