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