@universis/janitor 2.1.1 → 2.4.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.js CHANGED
@@ -11,10 +11,17 @@ var rateLimitRedis = require('rate-limit-redis');
11
11
  var ioredis = require('ioredis');
12
12
  require('@themost/promise-sequence');
13
13
  var url = require('url');
14
+ var janitor = require('@universis/janitor');
15
+ require('@themost/express');
14
16
  var superagent = require('superagent');
15
17
  var jwt = require('jsonwebtoken');
16
18
  var BearerStrategy = require('passport-http-bearer');
17
19
  var passport = require('passport');
20
+ var cloneDeep = require('lodash/cloneDeep');
21
+ var MD5 = require('crypto-js/md5');
22
+ var data = require('@themost/data');
23
+ var ipRangeCheck = require('ip-range-check');
24
+ var operators = require('rxjs/operators');
18
25
 
19
26
  class RateLimitService extends common.ApplicationService {
20
27
  /**
@@ -804,23 +811,106 @@ class ExtendScopeAccessConfiguration extends common.ApplicationService {
804
811
  }
805
812
  }
806
813
 
807
- function validateScope() {
808
- return (req, res, next) => {
814
+ class InvalidClientScopeError extends common.HttpForbiddenError {
815
+ constructor() {
816
+ super('Access denied due to invalid client scopes.');
817
+ }
818
+ }
819
+
820
+ class VerifyUserClientScope extends common.ApplicationService {
821
+
822
+ constructor(app) {
823
+ super(app);
824
+ // Sets the pre-defined OpenID Connect client scopes that are whitelisted and should be omitted during validation
825
+ this.options = {
826
+ whitelist: [
827
+ 'profile',
828
+ 'email',
829
+ 'openid']
830
+
831
+ };
832
+ }
833
+
834
+ /**
835
+ * Verify user scope access against its assigned groups,
836
+ * following the client scopes that are available for the user groups.
837
+ * @param {ExpressDataContext} context
838
+ * @param {boolean=} throwError
839
+ * @returns {Promise<boolean>}
840
+ */
841
+ async verify(context, throwError) {
842
+ // noinspection JSUnresolvedReference
843
+ const user = await context.getUser();
844
+ if (user == null) {
845
+ return false;
846
+ }
847
+ const groups = user.groups.map((group) => group.id);
848
+ /**
849
+ * @type {import('@themost/data').DataModel}
850
+ */
851
+ const ClientScopes = context.model('Group').convert({}).property('scopes').getBaseModel();
852
+ // set conditional caching
853
+ ClientScopes.caching = 'conditional';
854
+ /**
855
+ * get client scopes assigned to user groups
856
+ * @type {Array<{ scope: string }>}
857
+ */
858
+ const items = await ClientScopes.where('group').equal(groups).select('scope').cache(true).take(-1).silent().getItems();
809
859
  /**
810
- * @type {ScopeAccessConfiguration}
860
+ * @type {string[]}
811
861
  */
812
- let scopeAccessConfiguration = req.context.getApplication().getConfiguration().getStrategy(ScopeAccessConfiguration);
813
- if (typeof scopeAccessConfiguration === 'undefined') {
814
- return next(new Error('Invalid application configuration. Scope access configuration strategy is missing or is in accessible.'));
862
+ const assignedScopes = items.map((item) => item.scope);
863
+ const contextScopes = new janitor.ScopeString(context.user.authenticationScope).split().filter((scope) => {
864
+ return this.options.whitelist.includes(scope) === false;
865
+ });
866
+
867
+ const unassigned = contextScopes.filter((scope) => {
868
+ return !assignedScopes.includes(scope);
869
+ });
870
+ if (unassigned.length) {
871
+ if (!!throwError) {
872
+ common.TraceUtils.error(`Access denied for user "${context.user.name}" due to invalid client scope(s) "${unassigned.join(',')}"`);
873
+ throw new InvalidClientScopeError();
874
+ }
875
+ return false;
815
876
  }
816
- scopeAccessConfiguration.verify(req).then((value) => {
817
- if (value) {
877
+ return true;
878
+ }
879
+ }
880
+
881
+ class DisableUserClientScopeVerification extends VerifyUserClientScope {
882
+ constructor(app) {
883
+ super(app);
884
+ }
885
+ async verify(context, throwError) {
886
+ return true;
887
+ }
888
+ }
889
+
890
+ function validateClientScope() {
891
+ return function (req, res, next) {
892
+ try {
893
+ /**
894
+ * @type {VerifyUserClientScope}
895
+ */
896
+ const service = req.context.getApplication().getService(VerifyUserClientScope);
897
+ if (service == null) {
818
898
  return next();
819
899
  }
820
- return next(new common.HttpForbiddenError('Access denied due to authorization scopes.'));
821
- }).catch((reason) => {
822
- return next(reason);
823
- });
900
+ void service.verify(req).then(() => {
901
+ return next();
902
+ }).catch((reason) => {
903
+ return next(reason);
904
+ });
905
+ } catch (err) {
906
+ return next(err);
907
+ }
908
+ };
909
+ }
910
+
911
+ function validateScope() {
912
+ return (req, res, next) => {
913
+ return validateClientScope();
824
914
  };
825
915
  }
826
916
 
@@ -1337,9 +1427,496 @@ class PassportService extends common.ApplicationService {
1337
1427
 
1338
1428
  }
1339
1429
 
1430
+ /**
1431
+ *
1432
+ * @param {{profiles:Map<string, import('./outputCacheRouter').OutputCachingProfile>,elements: import('./outputCacheRouter').OutputCachingElement[]}} options
1433
+ * @returns {import('express').Router}
1434
+ */
1435
+ function outputCache({ profiles, elements }) {
1436
+ const router = new express.Router();
1437
+ // prepare regular expressions
1438
+ const outputCacheElements = Array.isArray(elements) ? elements : [];
1439
+ outputCacheElements.forEach((element) => {
1440
+ if (!(element.expr instanceof RegExp)) {
1441
+ element.expr = new RegExp('^' + element.resource, 'g');
1442
+ }
1443
+ });
1444
+ router.use((req, res, next) => {
1445
+ // only GET requests are cacheable
1446
+ if (req.method !== 'GET') {
1447
+ return next();
1448
+ }
1449
+ // if cache-control header is set to no-cache then skip caching
1450
+ const cacheControl = req.headers['cache-control'];
1451
+ if (cacheControl && cacheControl.includes('no-cache')) {
1452
+ return next();
1453
+ }
1454
+ for (let element of outputCacheElements) {
1455
+ if (element.expr.test(req.path)) {
1456
+ let profile;
1457
+ if (typeof element.profile === 'string') {
1458
+ profile = profiles.get(element.profile);
1459
+ } else if (typeof element.profile === 'object') {
1460
+ profile = element.profile;
1461
+ }
1462
+ if (profile) {
1463
+ // clone profile to avoid mutation
1464
+ Object.assign(req, {
1465
+ outputCaching: cloneDeep(profile)
1466
+ });
1467
+ }
1468
+ return next();
1469
+ }
1470
+ }
1471
+ return next();
1472
+ });
1473
+ router.use((req, res, next) => {
1474
+ try {
1475
+ const shouldCached = req.outputCaching && (req.outputCaching.location === 'any' || req.outputCaching.location === 'client');
1476
+ if (!shouldCached) {
1477
+ return next();
1478
+ }
1479
+ // determine cache location
1480
+ let cacheLocation = req.outputCaching.location === 'any' ? 'public' : 'private';
1481
+ if (req.headers.authorization && req.headers.authorization.length > 0) {
1482
+ // if authorization header is present, we should not cache the response publicly
1483
+ cacheLocation = 'private';
1484
+ }
1485
+ if (req.outputCaching.duration) {
1486
+ res.setHeader('Cache-Control', `${cacheLocation}, max-age=${req.outputCaching.duration}`);
1487
+ } else {
1488
+ res.setHeader('Cache-Control', cacheLocation);
1489
+ }
1490
+ const { varyByContentEncoding, varyByHeader, varyByParam, location, duration } = req.outputCaching;
1491
+ if (varyByContentEncoding) {
1492
+ res.setHeader('Vary', 'Accept-Encoding');
1493
+ }
1494
+ const varyByReqHeader = varyByHeader || [];
1495
+ if (varyByReqHeader.length) {
1496
+ res.setHeader('Vary', varyByReqHeader.join(', '));
1497
+ }
1498
+ let varyByQueryParam = varyByParam || [];
1499
+ if (varyByQueryParam.length === 1 && varyByQueryParam[0] === '*') {
1500
+ varyByQueryParam = Object.keys(req.query).sort((a, b) => {
1501
+ if (a < b) {
1502
+ return -1;
1503
+ }
1504
+ if (a > b) {
1505
+ return 1;
1506
+ }
1507
+ return 0;
1508
+ });
1509
+ }
1510
+
1511
+ const headers = varyByReqHeader.reduce((acc, val) => {
1512
+ acc[val] = req.get(val);
1513
+ return acc;
1514
+ }, {});
1515
+
1516
+ const params = varyByQueryParam.reduce((acc, val) => {
1517
+ if (req.query[val]) {
1518
+ acc[val] = req.query[val];
1519
+ }
1520
+ return acc;
1521
+ }, {});
1522
+
1523
+ // vary by query parameters is not supported by HTTP caching, but we can use it to create a cache key
1524
+ const entry = {
1525
+ path: req.path,
1526
+ location: location,
1527
+ contentEncoding: varyByContentEncoding,
1528
+ headers,
1529
+ params,
1530
+ customParams: null,
1531
+ duration: duration
1532
+ };
1533
+
1534
+ (async () => {
1535
+ const { varyByExpr } = req.outputCaching;
1536
+ if (varyByExpr && typeof varyByExpr === 'object') {
1537
+ // noinspection JSCheckFunctionSignatures
1538
+ const formatter = new data.ValueFormatter(req.context, null, req);
1539
+ entry.customParams = await formatter.format(varyByExpr);
1540
+ }
1541
+ return `W/"${MD5(JSON.stringify({
1542
+ path: entry.path,
1543
+ location: entry.location,
1544
+ contentEncoding: entry.contentEncoding,
1545
+ headers: entry.headers,
1546
+ params: entry.params,
1547
+ customParams: entry.customParams,
1548
+ duration: entry.duration
1549
+ })).toString()}"`;
1550
+ })().then((entityTag) => {
1551
+ if (req.headers['if-none-match'] === entityTag) {
1552
+ return res.status(304).end();
1553
+ }
1554
+ res.setHeader('ETag', entityTag);
1555
+ res.setHeader('Date', new Date().toUTCString());
1556
+ return next();
1557
+ }).catch((err) => {
1558
+ return next(err);
1559
+ });
1560
+ } catch (err) {
1561
+ return next(err);
1562
+ }
1563
+ });
1564
+ return router;
1565
+ }
1566
+
1567
+ class OutputCachingService extends common.ApplicationService {
1568
+ constructor(app) {
1569
+ super(app);
1570
+ let options = app.getConfiguration().getSourceAt('settings/universis/outputCaching') || {
1571
+ profiles: [],
1572
+ elements: []
1573
+ };
1574
+ if (typeof options.extends === 'string') {
1575
+ const configurationDir = this.getApplication().getConfiguration().getConfigurationPath();
1576
+ const parentOptions = require(path.resolve(configurationDir, options.extends));
1577
+ options = Object.assign({}, parentOptions, options);
1578
+ }
1579
+ /**
1580
+ * @type {Map<string, OutputCachingProfile>}
1581
+ */
1582
+ this.profiles = new Map(options.profiles || []);
1583
+ /**
1584
+ * @type {OutputCachingElement[]}
1585
+ */
1586
+ this.elements = options.elements || [];
1587
+ if (app && app.container) {
1588
+ app.container.subscribe((container) => {
1589
+ if (container == null) {
1590
+ return;
1591
+ }
1592
+ container.use(outputCache({
1593
+ profiles: this.profiles,
1594
+ elements: this.elements
1595
+ }));
1596
+ const stack = container._router && container._router.stack;
1597
+ if (Array.isArray(stack)) {
1598
+ let index = stack.findIndex((item) => item.name === 'dataContextMiddleware');
1599
+ if (index > -1) {
1600
+ stack.splice(index, 0, stack.pop());
1601
+ }
1602
+ }
1603
+ });
1604
+ }
1605
+ }
1606
+ }
1607
+
1608
+ class UserWithNetworkAddress extends data.UserService {
1609
+ constructor(app) {
1610
+ super(app);
1611
+ }
1612
+
1613
+ /**
1614
+ * @protected
1615
+ * @param {import('@themost/data').DataContext} context
1616
+ * @param {string} name
1617
+ * @return {import('@themost/data').DataQueryable}
1618
+ */
1619
+ queryUser(context, name) {
1620
+ return context.model('User').asQueryable().expand('groups', 'networkAddress').
1621
+ where('name').equal(name);
1622
+ }
1623
+
1624
+ /**
1625
+ * @protected
1626
+ * @param {import('@themost/data').DataContext} context
1627
+ * @param {string} name
1628
+ * @return {import('@themost/data').DataQueryable}
1629
+ */
1630
+ queryGroup(context, name) {
1631
+ return context.model('Group').asQueryable().expand('groups', 'networkAddress').
1632
+ where('name').equal(name);
1633
+ }
1634
+
1635
+ /**
1636
+ * Gets user by name
1637
+ * @param context
1638
+ * @param name
1639
+ * @returns {Promise<any>}
1640
+ */
1641
+ getUser(context, name) {
1642
+ // noinspection JSCheckFunctionSignatures
1643
+ /**
1644
+ * @type {import('./data-cache').DataCacheStrategy}
1645
+ */
1646
+ // noinspection JSCheckFunctionSignatures
1647
+ const cache = context.getConfiguration().getStrategy(function DataCacheStrategy() {});
1648
+ if (cache) {
1649
+ return cache.getOrDefault(`/User/${name}`, () => {
1650
+ return this.queryUser(context, name).silent().getItem().then((user) => {
1651
+ return user;
1652
+ });
1653
+ });
1654
+ }
1655
+ return this.queryUser(context, name).silent().getItem().then((user) => {
1656
+ return user;
1657
+ });
1658
+ }
1659
+
1660
+ /**
1661
+ * Gets group by name
1662
+ * @param context
1663
+ * @param name
1664
+ * @returns {Promise<any>}
1665
+ */
1666
+ getGroup(context, name) {
1667
+ // noinspection JSCheckFunctionSignatures
1668
+ /**
1669
+ * @type {import('./data-cache').DataCacheStrategy}
1670
+ */
1671
+ // noinspection JSCheckFunctionSignatures
1672
+ const cache = context.getConfiguration().getStrategy(function DataCacheStrategy() {});
1673
+ if (cache) {
1674
+ return cache.getOrDefault(`/Group/${name}`, () => {
1675
+ return this.queryGroup(context, name).silent().getItem().then((group) => {
1676
+ return group;
1677
+ });
1678
+ });
1679
+ }
1680
+ return this.queryGroup(context, name).silent().getItem().then((group) => {
1681
+ return group;
1682
+ });
1683
+ }
1684
+
1685
+ /**
1686
+ * Gets anonymous user
1687
+ * @param context
1688
+ * @returns {Promise<any>}
1689
+ */
1690
+ getAnonymousUser(context) {
1691
+ return this.getUser(context, 'anonymous');
1692
+ }
1693
+
1694
+ }
1695
+
1696
+ const AccountNetworkAddress = {
1697
+ "$schema": "https://themost-framework.github.io/themost/models/2018/2/schema.json",
1698
+ "@id": "https://universis.io/schemas/AccountNetworkAddress",
1699
+ "name": "AccountNetworkAddress",
1700
+ "hidden": true,
1701
+ "source": "AccountNetworkAddress",
1702
+ "view": "AccountNetworkAddress",
1703
+ "version": "1.0.0",
1704
+ "fields": [
1705
+ {
1706
+ "name": "id",
1707
+ "type": "Counter",
1708
+ "nullable": false,
1709
+ "primary": true,
1710
+ "many": false
1711
+ },
1712
+ {
1713
+ "name": "account",
1714
+ "type": "Account",
1715
+ "nullable": false,
1716
+ "many": false,
1717
+ "indexed": true
1718
+ },
1719
+ {
1720
+ "name": "value",
1721
+ "type": "Text",
1722
+ "nullable": false,
1723
+ "many": false,
1724
+ "indexed": false
1725
+ }],
1726
+
1727
+ "constraints": [
1728
+ {
1729
+ "type": "unique",
1730
+ "fields": [
1731
+ "account",
1732
+ "value"]
1733
+
1734
+ }],
1735
+
1736
+ "privileges": [
1737
+ {
1738
+ "mask": 15,
1739
+ "type": "global"
1740
+ },
1741
+ {
1742
+ "mask": 15,
1743
+ "type": "global",
1744
+ "account": "Administrators"
1745
+ }]
1746
+
1747
+ };
1748
+
1749
+ class HttpNetworkAccessForbiddenError extends common.HttpForbiddenError {
1750
+ constructor() {
1751
+ super('Access is denied due to network address conflict.');
1752
+ this.statusCode = 403.6;
1753
+ }
1754
+
1755
+ }
1756
+
1757
+ class NetworkRestrictAccess extends common.ApplicationService {
1758
+ constructor(app) {
1759
+ super(app);
1760
+ Object.defineProperty(this, 'proxyAddressForwarding', {
1761
+ configurable: true,
1762
+ enumerable: false,
1763
+ value: !!app.getConfiguration().getSourceAt('settings/universis/api/proxyAddressForwarding'),
1764
+ writable: false
1765
+ });
1766
+ this.apply();
1767
+ }
1768
+
1769
+ apply() {
1770
+ // get schema loader
1771
+ const schemaLoader = this.getApplication().
1772
+ getConfiguration().
1773
+ getStrategy(data.SchemaLoaderStrategy);
1774
+ const accountNetworkAddressModel = schemaLoader.getModelDefinition('AccountNetworkAddress');
1775
+ if (accountNetworkAddressModel == null) {
1776
+ schemaLoader.setModelDefinition(AccountNetworkAddress);
1777
+ }
1778
+ // get model definition
1779
+ const model = schemaLoader.getModelDefinition('Account');
1780
+ if (model == null) {
1781
+ common.TraceUtils.warn('NetworkRestrictAccess: Account model definition not found.');
1782
+ return;
1783
+ }
1784
+ const found = model.fields.find((field) => {
1785
+ return field.name === 'networkAddress';
1786
+ });
1787
+ if (!found) {
1788
+ model.fields.push({
1789
+ "name": "networkAddress",
1790
+ "type": "Text",
1791
+ "many": true,
1792
+ "mapping": {
1793
+ "parentModel": "Account",
1794
+ "parentField": "id",
1795
+ "associationType": "junction",
1796
+ "associationAdapter": "AccountNetworkAddress",
1797
+ "cascade": "delete",
1798
+ "associationObjectField": "account",
1799
+ "associationValueField": "value"
1800
+ }
1801
+ });
1802
+ }
1803
+ model.eventListeners = model.eventListeners || [];
1804
+ let index = model.eventListeners.findIndex((listener) => {
1805
+ return listener.type === '@themost/data/previous-state-listener';
1806
+ });
1807
+ if (index < 0) {
1808
+ model.eventListeners.push({
1809
+ type: '@themost/data/previous-state-listener'
1810
+ });
1811
+ index = model.eventListeners.length - 1;
1812
+ }
1813
+ let otherIndex = model.eventListeners.findIndex((listener) => {
1814
+ return listener.type === path.resolve(__dirname, './OnAccountUpdate');
1815
+ });
1816
+ if (otherIndex < 0) {
1817
+ model.eventListeners.splice(index, 0, {
1818
+ type: path.resolve(__dirname, './OnAccountUpdate')
1819
+ });
1820
+ }
1821
+ schemaLoader.setModelDefinition(model);
1822
+ }
1823
+
1824
+ /**
1825
+ * Gets remote address from request
1826
+ * @param {import('express').Request} req
1827
+ * @returns
1828
+ */
1829
+ getRemoteAddress(req) {
1830
+ let remoteAddress;
1831
+ if (this.proxyAddressForwarding) {
1832
+ // get proxy headers or remote address
1833
+ // noinspection JSDeprecatedSymbols
1834
+ remoteAddress = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || (req.connection ? req.connection.remoteAddress : req.socket.remoteAddress);
1835
+ } else {
1836
+ // noinspection JSDeprecatedSymbols
1837
+ remoteAddress = req.connection ? req.connection.remoteAddress : req.socket.remoteAddress;
1838
+ }
1839
+ return remoteAddress;
1840
+ }
1841
+ }
1842
+
1843
+
1844
+
1845
+ /**
1846
+ * Validate network address for the current request against the assigned network addresses for the user account.
1847
+ * @returns {import('express').Handler}
1848
+ */
1849
+ function validateNetworkAddress() {
1850
+ /**
1851
+ * @param {import('express').Request} req
1852
+ * @param {import('express').Response} res
1853
+ * @param {import('express').NextFunction} next
1854
+ */
1855
+ return function (req, res, next) {
1856
+ try {
1857
+ const service = req.context.getApplication().getService(NetworkRestrictAccess);
1858
+ if (service == null) {
1859
+ return next();
1860
+ }
1861
+ req.context.user$.pipe(
1862
+ operators.take(1)
1863
+ ).subscribe({
1864
+ next: (user) => {
1865
+ if (user == null) {
1866
+ return next();
1867
+ }
1868
+ if (Array.isArray(user.networkAddress)) {
1869
+ if (user.networkAddress.length > 0) {
1870
+ // get remote address
1871
+ const remoteAddress = service.getRemoteAddress(req);
1872
+ const result = ipRangeCheck(remoteAddress, user.networkAddress);
1873
+ if (result !== true) {
1874
+ return next(new HttpNetworkAccessForbiddenError());
1875
+ }
1876
+ }
1877
+ }
1878
+ return next();
1879
+ },
1880
+ error: (err) => {
1881
+ return next(err);
1882
+ }
1883
+ });
1884
+ } catch (err) {
1885
+ return next(err);
1886
+ }
1887
+
1888
+ };
1889
+ }
1890
+
1891
+ class EnableNetworkRestrictAccess extends NetworkRestrictAccess {
1892
+ constructor(app) {
1893
+ super(app);
1894
+ if (app && app.serviceRouter) {
1895
+ app.serviceRouter.subscribe((serviceRouter) => {
1896
+ if (serviceRouter == null) {
1897
+ return;
1898
+ }
1899
+ const addRouter = express.Router();
1900
+ addRouter.use(validateNetworkAddress());
1901
+ // insert router at the beginning of serviceRouter.stack
1902
+ serviceRouter.stack.unshift.apply(serviceRouter.stack, addRouter.stack);
1903
+ });
1904
+ }
1905
+ }
1906
+ }
1907
+
1908
+ class DisableNetworkRestrictAccess extends NetworkRestrictAccess {
1909
+ constructor(app) {
1910
+ super(app);
1911
+ }
1912
+ }
1913
+
1340
1914
  exports.AppRateLimitService = AppRateLimitService;
1341
1915
  exports.AppSpeedLimitService = AppSpeedLimitService;
1342
1916
  exports.DefaultScopeAccessConfiguration = DefaultScopeAccessConfiguration;
1917
+ exports.DisableNetworkRestrictAccess = DisableNetworkRestrictAccess;
1918
+ exports.DisableUserClientScopeVerification = DisableUserClientScopeVerification;
1919
+ exports.EnableNetworkRestrictAccess = EnableNetworkRestrictAccess;
1343
1920
  exports.EnableScopeAccessConfiguration = EnableScopeAccessConfiguration;
1344
1921
  exports.ExtendScopeAccessConfiguration = ExtendScopeAccessConfiguration;
1345
1922
  exports.HttpAccountDisabled = HttpAccountDisabled;
@@ -1347,8 +1924,12 @@ exports.HttpBearerStrategy = HttpBearerStrategy;
1347
1924
  exports.HttpBearerTokenExpired = HttpBearerTokenExpired;
1348
1925
  exports.HttpBearerTokenNotFound = HttpBearerTokenNotFound;
1349
1926
  exports.HttpBearerTokenRequired = HttpBearerTokenRequired;
1927
+ exports.HttpNetworkAccessForbiddenError = HttpNetworkAccessForbiddenError;
1350
1928
  exports.HttpRemoteAddrForbiddenError = HttpRemoteAddrForbiddenError;
1929
+ exports.InvalidClientScopeError = InvalidClientScopeError;
1930
+ exports.NetworkRestrictAccess = NetworkRestrictAccess;
1351
1931
  exports.OAuth2ClientService = OAuth2ClientService;
1932
+ exports.OutputCachingService = OutputCachingService;
1352
1933
  exports.PassportService = PassportService;
1353
1934
  exports.RateLimitService = RateLimitService;
1354
1935
  exports.RedisClientStore = RedisClientStore;
@@ -1356,5 +1937,10 @@ exports.RemoteAddressValidator = RemoteAddressValidator;
1356
1937
  exports.ScopeAccessConfiguration = ScopeAccessConfiguration;
1357
1938
  exports.ScopeString = ScopeString;
1358
1939
  exports.SpeedLimitService = SpeedLimitService;
1940
+ exports.UserWithNetworkAddress = UserWithNetworkAddress;
1941
+ exports.VerifyUserClientScope = VerifyUserClientScope;
1942
+ exports.outputCache = outputCache;
1943
+ exports.validateClientScope = validateClientScope;
1944
+ exports.validateNetworkAddress = validateNetworkAddress;
1359
1945
  exports.validateScope = validateScope;
1360
1946
  //# sourceMappingURL=index.js.map