From 45db28a7e6037499c6e859502d2581f8a70a8408 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sat, 12 Nov 2022 16:51:10 +0100 Subject: [PATCH 1/9] config.example.yml: Fix indentation and comments --- config.example.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/config.example.yml b/config.example.yml index 54253b6..c03c98a 100644 --- a/config.example.yml +++ b/config.example.yml @@ -1,40 +1,40 @@ server: port: 1389 ip: 0.0.0.0 - updateinterval: 600 // intervall in seconds + updateinterval: 600 # interval in seconds cert: certs/ldap.crt key: certs/ldap.key sites: ccf: site: name: sitename - user: username // User needs rights to the api in CT + user: username # user needs API permissions in ChurchTools password: secret1 url: https://sitename.church.tools/ ldap: o: Organisation Name - dc: dc=myorg,dc=tld // domain components + dc: dc=myorg,dc=tld # domain components admincn: admin password: secret2 - attributes: // fields to add to user + attributes: # fields to add to user - name: key1 default: defaultvalue1 - replacements: // add value to user with id + replacements: # add value to user with id - id: id value: extra - name: key2 default: defaultvalue2 adminGroup: - cn: "admin" // - members: // personid s of users to put in admin group + cn: "admin" + members: # person ID of users to put in admin group - id - selectionGroupIds: // ChurchTools Group Ids - only members of these groups will be served by ldap + selectionGroupIds: # ChurchTools group IDs - only members of these groups will be served by LDAP - gid - gid - tranformedGroups: // ChurchTools Group Ids with the group name which will be served by Ldap + tranformedGroups: # ChurchTools group IDs with the group name which will be served by LDAP - gid: gid name: Groupname - objectClass: usrObjClass // additionally set objectClass of User to that value if in group + objectClass: usrObjClass # additionally set objectClass of user to that value if in group - gid: gid name: Groupname -// further ChurchTools sites to serve - following the same schema above \ No newline at end of file + # further ChurchTools sites to serve - following the same schema as above \ No newline at end of file From b1feeb482117db6c227998cead140ae3da8c01c3 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sat, 12 Nov 2022 22:03:16 +0100 Subject: [PATCH 2/9] Fix typo in transformGroup --- src/transform.js | 4 ++-- test/transform.test.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/transform.js b/src/transform.js index 37e7646..1d504af 100644 --- a/src/transform.js +++ b/src/transform.js @@ -164,7 +164,7 @@ exports.transformUser = (ctpserson, attributes, dc) => { return result; }; -exports.trsansformGroup = (ctgroup, grtransform, dc) => { +exports.transformGroup = (ctgroup, grtransform, dc) => { if (!ctgroup || !ctgroup.id) throw new DataFormatError('Group from CT was emtpy'); var cn = grtransform && grtransform.name ? grtransform.name : ctgroup.name; @@ -225,7 +225,7 @@ exports.getLdapGroupsWithoutMembers = (ctgroups, tranformedGroups, dc) => { const groups = []; ctgroups.forEach((element) => { grptransform = tranformedGroups.find((t) => t.gid == element.id); - const grp = this.trsansformGroup(element, grptransform, dc); + const grp = this.transformGroup(element, grptransform, dc); groups.push(grp); }); return groups; diff --git a/test/transform.test.js b/test/transform.test.js index 61f1f9c..cf0ade3 100644 --- a/test/transform.test.js +++ b/test/transform.test.js @@ -9,11 +9,11 @@ DataFormatError = transform.DataFormatError; describe("Transorm API results to Ldap", () => { - it("trsansformGroup from empty json object throws exception", () => { - expect(() => transform.trsansformGroup({}, {}, "")).to.throw(DataFormatError); + it("transformGroup from empty json object throws exception", () => { + expect(() => transform.transformGroup({}, {}, "")).to.throw(DataFormatError); }); - it("trsansformGroup json object does contain data", () => { - actual = transform.trsansformGroup( + it("transformGroup json object does contain data", () => { + actual = transform.transformGroup( { id: 2, guid: 'FC8ED-B948-46AA-A48C-2CFD7DED910C', From b3d4c10ae6d9ea6d0f0ec4cc1d24403d9ab055aa Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sun, 13 Nov 2022 14:13:11 +0100 Subject: [PATCH 3/9] Add linting through ESLint with AirBnB style guide --- .eslintrc.yml | 10 ++++++++++ package.json | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 .eslintrc.yml diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..cc17ef2 --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,10 @@ +env: + node: true + mocha: true + es2021: true +extends: airbnb-base +overrides: [] +parserOptions: + ecmaVersion: latest + sourceType: module +rules: {} diff --git a/package.json b/package.json index bc247fa..f10e757 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "test": "mocha ./test/*.test.js", - "integration": "mocha ./test/*.integration.js" + "integration": "mocha ./test/*.integration.js", + "lint": "npx eslint src/* test/* index.js" }, "author": "Alex Röhm", "license": "GPL-3.0-or-later", @@ -15,6 +16,9 @@ "chai-as-promised": "^7.1.1", "chai-string": "^1.5.0", "deep-equal-in-any-order": "^2.0.0", + "eslint": "^8.27.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.26.0", "mocha": "^8.3.2", "pino-pretty": "^9.1.0" }, @@ -26,6 +30,5 @@ "pino": "^8.6.0", "yamljs": "^0.3.0", "pino-pretty": "^9.1.0" - } } From cf0b5bba99cba3b90beda66a2d52950fdbe395fa Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sun, 13 Nov 2022 14:17:17 +0100 Subject: [PATCH 4/9] ci: Use more generic name for common yaml file that includes multiple jobs --- .github/workflows/{unittests.yml => ci-jobs.yml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{unittests.yml => ci-jobs.yml} (94%) diff --git a/.github/workflows/unittests.yml b/.github/workflows/ci-jobs.yml similarity index 94% rename from .github/workflows/unittests.yml rename to .github/workflows/ci-jobs.yml index 95b3b1b..6159420 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/ci-jobs.yml @@ -1,4 +1,4 @@ -name: Unit Tests +name: CI Jobs on: push: @@ -7,7 +7,7 @@ on: branches: [ main ] jobs: - build: + unit-tests: runs-on: ubuntu-latest From b64cc1f4e695156ff88363349b9488c3e287330e Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sun, 13 Nov 2022 14:19:01 +0100 Subject: [PATCH 5/9] ci-jobs.yml: Improve unit-tests job * Remove matrix as long as only one build config is needed * Upgrade checkout and setup-node actions to v3 * Use 'npm ci' instead of 'npm install' --- .github/workflows/ci-jobs.yml | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci-jobs.yml b/.github/workflows/ci-jobs.yml index 6159420..88aaab6 100644 --- a/.github/workflows/ci-jobs.yml +++ b/.github/workflows/ci-jobs.yml @@ -6,21 +6,19 @@ on: pull_request: branches: [ main ] +env: + NODE_VERSION: 16.x + jobs: unit-tests: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [16.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - name: Use Node.js $NODE_VERSION + uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} - - run: npm install - - run: npm run test \ No newline at end of file + node-version: ${{ env.NODE_VERSION }} + - name: Install Modules + run: npm ci + - name: Run Unit Tests + run: npm run test \ No newline at end of file From 9a45fb8984a583a12bba5c897a40391446f6ff93 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sun, 13 Nov 2022 14:20:43 +0100 Subject: [PATCH 6/9] ci-jobs.yml: Run on every push regardless of branch This allows to get CI test results even on feature branches, etc. --- .github/workflows/ci-jobs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci-jobs.yml b/.github/workflows/ci-jobs.yml index 88aaab6..2cd27c9 100644 --- a/.github/workflows/ci-jobs.yml +++ b/.github/workflows/ci-jobs.yml @@ -2,7 +2,6 @@ name: CI Jobs on: push: - branches: [ main ] pull_request: branches: [ main ] From 4373aeceab7289f753f50ce6f86c6ab22194acf9 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sun, 13 Nov 2022 14:22:16 +0100 Subject: [PATCH 7/9] ci-jobs.yml: Add job for linting --- .github/workflows/ci-jobs.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci-jobs.yml b/.github/workflows/ci-jobs.yml index 2cd27c9..a266a7f 100644 --- a/.github/workflows/ci-jobs.yml +++ b/.github/workflows/ci-jobs.yml @@ -9,6 +9,19 @@ env: NODE_VERSION: 16.x jobs: + eslint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Use Node.js $NODE_VERSION + uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Install Modules + run: npm ci + - name: Run ESLint + run: npm run lint + unit-tests: runs-on: ubuntu-latest steps: From 8cd757b602467c557d293348599b07fd3155137c Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Sun, 13 Nov 2022 14:27:02 +0100 Subject: [PATCH 8/9] Apply automatic ESLint fixes for all source files --- index.js | 60 +++--- src/constants.js | 30 +-- src/ctapi.js | 52 +++-- src/ctconnection.js | 139 ++++++------- src/ctservice.js | 77 ++++--- src/ldapcache.js | 181 ++++++++-------- src/ldapserver.js | 111 +++++----- src/logging.js | 54 +++-- src/main.js | 48 ++--- src/nextcloud.js | 182 ++++++++-------- src/transform.js | 142 ++++++------- test/ctconnection.integration.js | 46 ++-- test/ctconnection.test.js | 175 ++++++++-------- test/ctservice.integration.js | 60 +++--- test/ctservice.test.js | 37 ++-- test/e2e.integration.js | 346 ++++++++++++++++--------------- test/ldapcache.test.js | 204 +++++++++--------- test/main.integration.js | 17 +- test/transform.integration.js | 25 +-- test/transform.test.js | 188 ++++++++--------- 20 files changed, 1062 insertions(+), 1112 deletions(-) diff --git a/index.js b/index.js index f6b16a5..052d9b9 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,12 @@ +const fs = require('fs'); +const { argv } = require('process'); +const pino = require('pino'); +const pretty = require('pino-pretty'); const c = require('./src/constants'); const main = require('./src/main'); const ctservice = require('./src/ctservice'); const log = require('./src/logging'); const nc = require('./src/nextcloud'); -const fs = require('fs'); -const { argv } = require('process'); -const pino = require('pino') -const pretty = require('pino-pretty') function write(name, data) { try { @@ -24,12 +24,12 @@ async function sanpshot() { write('ldap.json', JSON.stringify(result.ldap)); } -var restart = () => {}; +let restart = () => {}; -var initialized = false; +let initialized = false; -startedServer = (ip,port) => { - log.info('LDAP listening @ ' + ip + ":"+ port); +startedServer = (ip, port) => { + log.info(`LDAP listening @ ${ip}:${port}`); initialized = true; }; process.on('uncaughtException', (err) => { @@ -40,51 +40,47 @@ process.on('uncaughtException', (err) => { } }); -exports.getTestConfig = () => { - return require('./production/config.json'); -} +exports.getTestConfig = () => require('./production/config.json'); run = async () => { if (process.argv.includes('--configsql')) { - var vcount = process.argv.indexOf('--configsql') - if (argv.length < vcount+2) { - log.error("Parameters missing --configsql ") - process.exit() - } - var set = process.argv[vcount+1] - var sitename = process.argv[vcount+2] - var objectclass = c.LDAP_OBJCLASS_USER - if (process.argv.length > vcount + 2) - objectclass = process.argv[vcount+3] + const vcount = process.argv.indexOf('--configsql'); + if (argv.length < vcount + 2) { + log.error('Parameters missing --configsql '); + process.exit(); + } + const set = process.argv[vcount + 1]; + const sitename = process.argv[vcount + 2]; + let objectclass = c.LDAP_OBJCLASS_USER; + if (process.argv.length > vcount + 2) objectclass = process.argv[vcount + 3]; const data = require('./production/ldap.json'); log.logger.level = 'silent'; - const testconfig = this.getTestConfig() + const testconfig = this.getTestConfig(); nc.getNextcloudLdapConfig(testconfig, sitename, set, objectclass); nc.getNextcloudMappingTables(data, testconfig.sites[sitename].ldap.dc); } else if (process.argv.includes('--testdata')) { - const testconfig = this.getTestConfig() + const testconfig = this.getTestConfig(); const start = await main.start( testconfig, async () => require('./production/ctdata.json'), (site) => async (user, password) => password === 'alex', - startedServer + startedServer, ); - restart = start.restart + restart = start.restart; } else if (process.argv.includes('--testsnapshot')) { sanpshot(); } else { - log.logger = pino({ level: 'info', transport: { target: 'pino-pretty' } }) - const config = main.getConfig(c.CONFIG_FILE) - if (config.server.loglevel) - log.logger.level = config.server.loglevel + log.logger = pino({ level: 'info', transport: { target: 'pino-pretty' } }); + const config = main.getConfig(c.CONFIG_FILE); + if (config.server.loglevel) log.logger.level = config.server.loglevel; start = await main.start( config, ctservice.getChurchToolsData, ctservice.authWithChurchTools, - startedServer + startedServer, ); - restart = start.restart - setInterval(() => main.update(start.updaters), config.server.updateinterval*1000) + restart = start.restart; + setInterval(() => main.update(start.updaters), config.server.updateinterval * 1000); } }; diff --git a/src/constants.js b/src/constants.js index de47920..9b0042d 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,15 +1,15 @@ -exports.CONFIG_FILE = "/ldap/config/config.yml" -exports.API_SLUG = "api" -exports.WHOAMI_AP = "/whoami?only_allow_authenticated=true" -exports.CSRF_AP = "/csrftoken" -exports.LOGIN_AP = "/login" -exports.INFO_AP = "/info" -exports.GROUPMEMBERS_AP = "/groups/members?with_deleted=false" -exports.IDS = "&ids[]=" -exports.PERSONS_AP = "/persons" -exports.GROUPS_AP = "/groups" -exports.LDAPID_FIELD = "ncuid" -exports.LDAP_OU_USERS = "users" -exports.LDAP_OU_GROUPS = "groups" -exports.LDAP_OBJCLASS_USER = "CTPerson"; -exports.LDAP_OBJCLASS_GROUP = "group"; +exports.CONFIG_FILE = '/ldap/config/config.yml'; +exports.API_SLUG = 'api'; +exports.WHOAMI_AP = '/whoami?only_allow_authenticated=true'; +exports.CSRF_AP = '/csrftoken'; +exports.LOGIN_AP = '/login'; +exports.INFO_AP = '/info'; +exports.GROUPMEMBERS_AP = '/groups/members?with_deleted=false'; +exports.IDS = '&ids[]='; +exports.PERSONS_AP = '/persons'; +exports.GROUPS_AP = '/groups'; +exports.LDAPID_FIELD = 'ncuid'; +exports.LDAP_OU_USERS = 'users'; +exports.LDAP_OU_GROUPS = 'groups'; +exports.LDAP_OBJCLASS_USER = 'CTPerson'; +exports.LDAP_OBJCLASS_GROUP = 'group'; diff --git a/src/ctapi.js b/src/ctapi.js index cc13685..55161c7 100644 --- a/src/ctapi.js +++ b/src/ctapi.js @@ -1,54 +1,52 @@ -const log = require("./logging"); -const c = require("./constants"); -const axios = require("axios").default; - +const log = require('./logging'); +const c = require('./constants'); +const axios = require('axios').default; exports.ChurchToolsError = (message) => { - err = new Error(message) + err = new Error(message); log.error(message); - err.name = "ChurchToolsError" + err.name = 'ChurchToolsError'; return err; -} +}; exports.ChurchToolsFatalError = (message) => { - err = new Error(message) + err = new Error(message); log.error(message); - err.name = "ChurchToolsFatalError" + err.name = 'ChurchToolsFatalError'; return err; -} - -uriTrailingSlash = (uri) => (uri.slice(-1) !== "/" ? uri + "/" : uri); +}; +uriTrailingSlash = (uri) => (uri.slice(-1) !== '/' ? `${uri}/` : uri); exports.result = (result, success, failed) => { - if (result && result.hasOwnProperty("data")) { + if (result && result.hasOwnProperty('data')) { if (success) success(result); log.debug(JSON.stringify(result.data)); - return result.data - } else if (result && result.hasOwnProperty("status") && result.status === "success") { + return result.data; + } if (result && result.hasOwnProperty('status') && result.status === 'success') { if (success) success(result); log.debug(JSON.stringify(result.data)); - return result.data - } else if (result && result.hasOwnProperty("message")) { + return result.data; + } if (result && result.hasOwnProperty('message')) { if (failed) failed(); throw this.ChurchToolsError(result.message); - } else if (result && result.hasOwnProperty("status") && - [400, 401, 403, 404, 405, 500, 501, 502, 503, 504].includes(result.status)) { + } else if (result && result.hasOwnProperty('status') + && [400, 401, 403, 404, 405, 500, 501, 502, 503, 504].includes(result.status)) { if (failed) failed(); - throw this.ChurchToolsError("No Session or connection problems"); + throw this.ChurchToolsError('No Session or connection problems'); } else { log.error(JSON.stringify(result)); - throw this.ChurchToolsFatalError("Unexpected Error"); + throw this.ChurchToolsFatalError('Unexpected Error'); } -} +}; exports.request = async (request, success, failed) => { - log.debug(JSON.stringify(request)) - var result = {} + log.debug(JSON.stringify(request)); + let result = {}; try { - result = await axios(request) + result = await axios(request); } catch (err) { throw this.ChurchToolsError(err.message); } - return this.result(result, success, failed) -} + return this.result(result, success, failed); +}; diff --git a/src/ctconnection.js b/src/ctconnection.js index 6ee09a8..5a7d000 100644 --- a/src/ctconnection.js +++ b/src/ctconnection.js @@ -1,17 +1,16 @@ -const log = require("./logging"); -const c = require("./constants"); -const ctapi = require("./ctapi"); -const axiosReal = require("axios").default; +const log = require('./logging'); +const c = require('./constants'); +const ctapi = require('./ctapi'); +const axiosReal = require('axios').default; - -var connectionPool = {}; +const connectionPool = {}; exports.getEmptyConnection = (sitename, baseurl) => { - var connection = {}; + const connection = {}; connection.name = sitename; - connection.baseurl = (baseurl ? baseurl : ""); - connection.cookie = ""; - connection.csrfToken = ""; + connection.baseurl = (baseurl || ''); + connection.cookie = ''; + connection.csrfToken = ''; connection.loginPromise = null; connection.loginErrorCount = 0; connection.connected = false; @@ -33,7 +32,7 @@ exports.isConnected = (sitename) => { }; exports.disconnect = (connection) => { - connection.csrfToken = "" + connection.csrfToken = ''; }; /** @@ -41,120 +40,114 @@ exports.disconnect = (connection) => { * If a pending login promise already exists, it is returned right away. */ exports.login = async (site) => { - - var conn = this.getConnection(site); + const conn = this.getConnection(site); if (conn.loginPromise) return Promise.resolve(conn.loginPromise); - if (conn.loginErrorCount >= 3) - throw ctapi.ChurchToolsFatalError("Too many failed logins in a row"); + if (conn.loginErrorCount >= 3) throw ctapi.ChurchToolsFatalError('Too many failed logins in a row'); - var result = {} + let result = {}; try { - conn.loginPromise = loginPromise(conn, site.user, site.password) + conn.loginPromise = loginPromise(conn, site.user, site.password); result = await conn.loginPromise; } catch (err) { - result = err.response + result = err.response; } conn.loginPromise = null; - return ctapi.result(result, + return ctapi.result( + result, () => conn.loginErrorCount = 0, - () => conn.loginErrorCount = conn.loginErrorCount + 1) + () => conn.loginErrorCount += 1, + ); }; exports.infoReal = async (baseurl) => { const request = { - method: "get", - url: baseurl + c.API_SLUG + c.INFO_AP + method: 'get', + url: baseurl + c.API_SLUG + c.INFO_AP, }; - return await ctapi.request(request) + return await ctapi.request(request); }; - exports.getCsrfTokenReal = async (baseurl, cookie) => { const request = { - method: "get", + method: 'get', url: baseurl + c.API_SLUG + c.CSRF_AP, headers: { Cookie: cookie, }, json: true, - } - return await ctapi.request(request) + }; + return await ctapi.request(request); }; -getCookie = (result) => { - return result.headers["set-cookie"][0]; +getCookie = (result) => result.headers['set-cookie'][0]; + +getLoginRequest = (baseurl, user, password) => ({ + method: 'post', + url: baseurl + c.API_SLUG + c.LOGIN_AP, + data: { + username: user, + rememberMe: false, + password, + }, +}); + +exports.authenticate = async (baseurl, user, password) => { + log.debug(`Auth on ${baseurl} for ${user}`); + const { data } = await ctapi.request(getLoginRequest(baseurl, user, password)); + return (data.status == 'success'); }; -getLoginRequest = (baseurl, user, password) => { - return { - method: "post", - url: baseurl + c.API_SLUG + c.LOGIN_AP, - data: { - "username": user, - "rememberMe": false, - "password": password - } - } -} - -exports.authenticate = async ( baseurl, user, password ) => { - log.debug("Auth on "+ baseurl + " for " + user) - const { data } = await ctapi.request(getLoginRequest( baseurl, user, password )) - return (data.status == "success"); -} - const loginfunc = async (conn, user, password) => { - conn.csrfToken = ""; - const request = getLoginRequest(conn.baseurl, user, password) + conn.csrfToken = ''; + const request = getLoginRequest(conn.baseurl, user, password); const successfunc = (result) => { conn.cookie = getCookie(result); - } - const { data } = await ctapi.request(request, successfunc) + }; + const { data } = await ctapi.request(request, successfunc); conn.csrfToken = await getCsrfToken(conn.baseurl, conn.cookie); conn.loginPromise = null; - log.debug(conn.baseurl + " - CT API login completed"); + log.debug(`${conn.baseurl} - CT API login completed`); return data; -} +}; exports.loginPromiseReal = (conn, user, password) => { - conn.loginPromise = loginfunc(conn, user, password) + conn.loginPromise = loginfunc(conn, user, password); return conn.loginPromise; }; exports.getPromiseReal = async (url, site) => { const conn = this.getConnection(site); - var retryWithAuth = true - var result = {} + let retryWithAuth = true; + let result = {}; while (retryWithAuth) { - retryWithAuth = false + retryWithAuth = false; try { if (!this.isConnected(site.name)) { - log.debug("Try again to log in") - await this.login(site) + log.debug('Try again to log in'); + await this.login(site); } const reqest = { - url: url, + url, headers: { - 'Cookie': conn.cookie, - 'CSRF-Token': (conn.csrftoken ? conn.csrftoken : "") + Cookie: conn.cookie, + 'CSRF-Token': (conn.csrftoken ? conn.csrftoken : ''), }, json: true, - } - log.debug(JSON.stringify(reqest)) - result = await axios(reqest) - return ctapi.result(result) + }; + log.debug(JSON.stringify(reqest)); + result = await axios(reqest); + return ctapi.result(result); } catch (err) { - if (err.name === "ChurchToolsError" || (err.response && err.response.status == 401)) { - this.disconnect(conn) + if (err.name === 'ChurchToolsError' || (err.response && err.response.status == 401)) { + this.disconnect(conn); retryWithAuth = true; - } else - throw err + } else throw err; } } - return result -} + return result; +}; exports.get = (url, site) => getPromise(url, site); @@ -173,4 +166,4 @@ exports.resetMocks = () => { getPromise = this.getPromiseReal; loginPromise = this.loginPromiseReal; getCsrfToken = this.getCsrfTokenReal; -} \ No newline at end of file +}; diff --git a/src/ctservice.js b/src/ctservice.js index 071dab4..4727aab 100644 --- a/src/ctservice.js +++ b/src/ctservice.js @@ -4,19 +4,18 @@ const t = require('./transform'); const ctconn = require('./ctconnection'); getGroupsPromiseReal = async (groupIds, ap, site) => { - var url = site.url + c.API_SLUG + ap; - var first = !url.includes("?"); + let url = site.url + c.API_SLUG + ap; + let first = !url.includes('?'); groupIds.forEach((id) => { if (first) { - url = url + "?" + c.IDS.substring(1) + id - first = false - } else - url = url + c.IDS + id; + url = `${url}?${c.IDS.substring(1)}${id}`; + first = false; + } else url = url + c.IDS + id; }); return await ctconn.get(url, site); }; -var getGroupsPromise = getGroupsPromiseReal -exports.mockGetGroups= (mock) => getGroupsPromise=mock; +let getGroupsPromise = getGroupsPromiseReal; +exports.mockGetGroups = (mock) => getGroupsPromise = mock; exports.getPersonsInGroups = async (groupIds, site) => { const result = await getGroupsPromise(groupIds, c.GROUPMEMBERS_AP, site); @@ -28,7 +27,7 @@ exports.getPersonsInGroups = async (groupIds, site) => { }; exports.getGroupMemberships = async (groupIds, site) => { - const result = await getGroupsPromise(groupIds, c.GROUPMEMBERS_AP, site); + const result = await getGroupsPromise(groupIds, c.GROUPMEMBERS_AP, site); const members = []; result.data.forEach((el) => { members.push({ @@ -40,7 +39,7 @@ exports.getGroupMemberships = async (groupIds, site) => { }; exports.getGroups = async (groupIds, site) => { - const result = await getGroupsPromise(groupIds, c.GROUPS_AP, site); + const result = await getGroupsPromise(groupIds, c.GROUPS_AP, site); const groups = []; result.data.forEach((el) => { groups.push({ @@ -53,7 +52,7 @@ exports.getGroups = async (groupIds, site) => { }; getPersonRecord = (data) => { - var person = { + const person = { id: data.id, guid: data.guid, firstName: data.firstName, @@ -64,62 +63,56 @@ getPersonRecord = (data) => { phonePrivate: data.phonePrivate, zip: data.zip, city: data.city, - cmsuserid: (data.cmsUserId ? data.cmsUserId : ""), - email: data.email, + cmsuserid: (data.cmsUserId ? data.cmsUserId : ''), + email: data.email, }; - if (data[c.LDAPID_FIELD] && data[c.LDAPID_FIELD].length > 0) - person[c.LDAPID_FIELD] = data[c.LDAPID_FIELD] + if (data[c.LDAPID_FIELD] && data[c.LDAPID_FIELD].length > 0) person[c.LDAPID_FIELD] = data[c.LDAPID_FIELD]; return person; -} +}; exports.getPersonRecordForId = async (id, site) => { - var url = site.url + c.API_SLUG + c.PERSONS_AP + '/' + id; + const url = `${site.url + c.API_SLUG + c.PERSONS_AP}/${id}`; const { data } = await ctconn.get(url, site); return getPersonRecord(data); }; exports.getPersonsForIds = async (ids, site) => { - const persons= [] + const persons = []; const clonedIds = [...ids]; const chunkedIds = []; - const chunkSize = clonedIds.length/10; - for(var i=0; i { - persons.push(getPersonRecord(person)) - }) + for await (idarray of chunkedIds) { + const result = await getGroupsPromise(idarray, c.PERSONS_AP, site); + result.data.forEach((person) => { + persons.push(getPersonRecord(person)); + }); } - return persons -} + return persons; +}; -exports.authWithChurchTools = (site) => { - return ( user, password ) => - ctconn.authenticate(site.site.url, user, password) -} +exports.authWithChurchTools = (site) => (user, password) => ctconn.authenticate(site.site.url, user, password); exports.getChurchToolsData = async (selectionGroupIds, tranformedGroups, site) => { - const allGoupsIds = selectionGroupIds.map((id) => id); tranformedGroups.forEach((element) => { - if (!allGoupsIds.includes(element.gid)) - allGoupsIds.push(element.gid); + if (!allGoupsIds.includes(element.gid)) allGoupsIds.push(element.gid); }); - - log.info("Get Persons from ChurchTools") + + log.info('Get Persons from ChurchTools'); const ctPersonIds = await this.getPersonsInGroups(selectionGroupIds, site); - log.info("Get Groups from ChurchTools") + log.info('Get Groups from ChurchTools'); const ctGroups = await this.getGroups(allGoupsIds, site); - log.info("Get Person Details from ChurchTools") + log.info('Get Person Details from ChurchTools'); const ctPersons = await this.getPersonsForIds(ctPersonIds, site); - log.info("Get Group Memberships from ChurchTools") + log.info('Get Group Memberships from ChurchTools'); const ctGroupMembership = await this.getGroupMemberships(allGoupsIds, site); return { - groups: ctGroups, - persons: ctPersons, - memberships: ctGroupMembership, + groups: ctGroups, + persons: ctPersons, + memberships: ctGroupMembership, }; }; diff --git a/src/ldapcache.js b/src/ldapcache.js index debd452..9c995cb 100644 --- a/src/ldapcache.js +++ b/src/ldapcache.js @@ -1,129 +1,116 @@ -const c = require('./constants') -const log = require('./logging') -var ldapEsc = require('ldap-escape'); +const ldapEsc = require('ldap-escape'); +const c = require('./constants'); +const log = require('./logging'); -ldapcache = [] +ldapcache = []; const normalize = (astring) => { - const str = astring - return str.replace(", ",",").replace(", ",",").replace(", ",",") -} + const str = astring; + return str.replace(', ', ',').replace(', ', ',').replace(', ', ','); +}; exports.init = (sitename, rootobjects, admin, password, ctAuthenticate) => { ldapcache[sitename] = {}; - ldapcache[sitename].rootobj = rootobjects.dsn - ldapcache[sitename].admin = admin - ldapcache[sitename].passwords = new Map() - const admindn = normalize(admin.dn) - ldapcache[sitename].passwords.set(admindn, password) - ldapcache[sitename].blocks = new Map() - ldapcache[sitename].users = rootobjects.users - ldapcache[sitename].groups = rootobjects.groups - ldapcache[sitename].ctAuthenticate = ctAuthenticate + ldapcache[sitename].rootobj = rootobjects.dsn; + ldapcache[sitename].admin = admin; + ldapcache[sitename].passwords = new Map(); + const admindn = normalize(admin.dn); + ldapcache[sitename].passwords.set(admindn, password); + ldapcache[sitename].blocks = new Map(); + ldapcache[sitename].users = rootobjects.users; + ldapcache[sitename].groups = rootobjects.groups; + ldapcache[sitename].ctAuthenticate = ctAuthenticate; return { getGroups: () => ldapcache[sitename].groups.attributes.elements, getUsers: () => ldapcache[sitename].users.attributes.elements, - setData: (users, groups) => addData(sitename,users,groups), - getGlobals: () => getGlobals(sitename), - checkAuthentication: async (user, password) => await checkPassword(sitename, user, password) - } -} + setData: (users, groups) => addData(sitename, users, groups), + getGlobals: () => getGlobals(sitename), + checkAuthentication: async (user, password) => await checkPassword(sitename, user, password), + }; +}; addData = (sitename, users, groups) => { - ldapcache[sitename].users.attributes.elements = users - ldapcache[sitename].groups.attributes.elements = groups -} + ldapcache[sitename].users.attributes.elements = users; + ldapcache[sitename].groups.attributes.elements = groups; +}; -exports.getUserById = (sitename,id) => { - const users = ldapcache[sitename].users.attributes.elements - const user = users.find((u)=>u.attributes.id==id) +exports.getUserById = (sitename, id) => { + const users = ldapcache[sitename].users.attributes.elements; + const user = users.find((u) => u.attributes.id == id); return user; -} -exports.getGroupById = (sitename,id) => { - const group = ldapcache[sitename].groups.attributes.elements.find((g)=>g.attributes.id==id) - return group -} +}; +exports.getGroupById = (sitename, id) => { + const group = ldapcache[sitename].groups.attributes.elements.find((g) => g.attributes.id == id); + return group; +}; -const getGlobals = (sitename) => { - return { - rootDn: ldapcache[sitename].rootobj, - userRoot: ldapcache[sitename].users, - groupRoot: ldapcache[sitename].groups, - adminDn: ldapcache[sitename].admin, - schemaDn: { - "dn": "cn=Subschema", - "attributes": { - "name": "SubschemaSubentry", - "equality": "distinguishedNameMatch", - "objectClass": ["top", "subschemaSubentry"], - "attributeType": [], - //"namingContexts": "o=" + req.dn.o, - } - } - } -} +const getGlobals = (sitename) => ({ + rootDn: ldapcache[sitename].rootobj, + userRoot: ldapcache[sitename].users, + groupRoot: ldapcache[sitename].groups, + adminDn: ldapcache[sitename].admin, + schemaDn: { + dn: 'cn=Subschema', + attributes: { + name: 'SubschemaSubentry', + equality: 'distinguishedNameMatch', + objectClass: ['top', 'subschemaSubentry'], + attributeType: [], + // "namingContexts": "o=" + req.dn.o, + }, + }, +}); exports.getUserPropertyForAuth = (userdn, sitename) => { - const users = ldapcache[sitename].users.attributes.elements - if (!users || !Array.isArray(users)) - return userdn - const user = users.find((u)=>u.dn===userdn) - if (!user) - return userdn - return user.attributes.entryUUID -} + const users = ldapcache[sitename].users.attributes.elements; + if (!users || !Array.isArray(users)) return userdn; + const user = users.find((u) => u.dn === userdn); + if (!user) return userdn; + return user.attributes.entryUUID; +}; checkPassword = async (sitename, userDn, password) => { - const sitecache = ldapcache[sitename] - const userdn = normalize(userDn) + const sitecache = ldapcache[sitename]; + const userdn = normalize(userDn); - if (isBlocked(sitecache.blocks, userdn)) - return false; - var valid = false; - if (sitecache.passwords.has(userdn)) { - valid = sitecache.passwords.get(userdn) === password - } - if (!valid && userdn!=sitecache.admin.dn) { - const login = this.getUserPropertyForAuth(userdn, sitename) - valid = (login?await sitecache.ctAuthenticate(login, password):false) - if (valid) - sitecache.passwords.set(userdn,password) - } - if (valid) - removeBlock(sitecache.blocks, userdn) - else - setBlock(sitecache.blocks, userdn) - return valid -} + if (isBlocked(sitecache.blocks, userdn)) return false; + let valid = false; + if (sitecache.passwords.has(userdn)) { + valid = sitecache.passwords.get(userdn) === password; + } + if (!valid && userdn != sitecache.admin.dn) { + const login = this.getUserPropertyForAuth(userdn, sitename); + valid = (login ? await sitecache.ctAuthenticate(login, password) : false); + if (valid) sitecache.passwords.set(userdn, password); + } + if (valid) removeBlock(sitecache.blocks, userdn); + else setBlock(sitecache.blocks, userdn); + return valid; +}; isBlocked = (blocks, userDn) => { - if (!blocks.has(userDn)) - return false; - const block = blocks.get(userDn) + if (!blocks.has(userDn)) return false; + const block = blocks.get(userDn); if (block.loginBlockedDate) { - var now = new Date(); - var checkDate = new Date( - block.loginBlockedDate.getTime() + 1000 * 3600 * 2 + const now = new Date(); + const checkDate = new Date( + block.loginBlockedDate.getTime() + 1000 * 3600 * 2, ); // two hours - if (now < checkDate) - return true; - blocks.delete(userDn) + if (now < checkDate) { return true; } + blocks.delete(userDn); } return false; -} +}; removeBlock = (blocks, userDn) => { - blocks.delete(userDn) -} + blocks.delete(userDn); +}; setBlock = (blocks, userDn) => { - var block = { loginErrorCount: 0 } - if (blocks.has(userDn)) - block = blocks.get(userDn) - else - blocks.set(userDn,block) + let block = { loginErrorCount: 0 }; + if (blocks.has(userDn)) { block = blocks.get(userDn); } else { blocks.set(userDn, block); } block.loginErrorCount += 1; if (block.loginErrorCount > 5) { - block.loginBlockedDate = new Date(); - } + block.loginBlockedDate = new Date(); } +}; diff --git a/src/ldapserver.js b/src/ldapserver.js index 60e1bd7..ca5b088 100644 --- a/src/ldapserver.js +++ b/src/ldapserver.js @@ -1,8 +1,8 @@ -var ldap = require('ldapjs'); -var parseDN = require('ldapjs').parseDN; +const ldap = require('ldapjs'); +const { parseDN } = require('ldapjs'); +const fs = require('fs'); const c = require('./constants'); const log = require('./logging'); -const fs = require('fs'); log.loglevel = log.loglevels.debug; @@ -15,14 +15,14 @@ stopServer = () => { }; startUp = (server, ldapjs, cb) => { - var port = parseInt(server.port); + const port = parseInt(server.port); ldapjs.listen(port, server.ip, cb(server.ip, port)); }; exports.getLdapServer = (server) => { if (server.cert && server.key) { - var ldapCert = fs.readFileSync(server.cert, { encoding: 'utf8' }); - var ldapKey = fs.readFileSync(server.key, { encoding: 'utf8' }); + const ldapCert = fs.readFileSync(server.cert, { encoding: 'utf8' }); + const ldapKey = fs.readFileSync(server.key, { encoding: 'utf8' }); ldapjs = ldap.createServer({ log: log.logger, certificate: ldapCert, @@ -43,7 +43,7 @@ exports.getLdapServer = (server) => { initSite = (site, cacheFunctions, ldapjs) => { const sitename = site.site.name; - const dc = site.ldap.dc; + const { dc } = site.ldap; function authorize(req, _res, next) { const adminDn = cacheFunctions.getGlobals().adminDn.dn; @@ -58,9 +58,9 @@ initSite = (site, cacheFunctions, ldapjs) => { try { log.debugSite( sitename, - 'SEARCH base object: ' + req.dn.toString() + ' scope: ' + req.scope + `SEARCH base object: ${req.dn.toString()} scope: ${req.scope}`, ); - log.debugSite(sitename, 'Filter: ' + req.filter.toString()); + log.debugSite(sitename, `Filter: ${req.filter.toString()}`); } catch (err) { log.debug(req); log.debug(err); @@ -69,14 +69,14 @@ initSite = (site, cacheFunctions, ldapjs) => { } function sendUsers(req, res, next) { - var strDn = req.dn.toString(); + const strDn = req.dn.toString(); try { cacheFunctions.getUsers().forEach((user) => { if ( - parseDN(strDn).equals(parseDN(user.dn)) || - (!req.checkAll && req.filter.matches(user.attributes)) + parseDN(strDn).equals(parseDN(user.dn)) + || (!req.checkAll && req.filter.matches(user.attributes)) ) { - log.debugSite(sitename, 'MatchUser: ' + user.dn); + log.debugSite(sitename, `MatchUser: ${user.dn}`); res.send(user); } }); @@ -87,14 +87,14 @@ initSite = (site, cacheFunctions, ldapjs) => { } function sendGroups(req, res, next) { - var strDn = req.dn.toString(); + const strDn = req.dn.toString(); try { cacheFunctions.getGroups().forEach((group) => { if ( - parseDN(strDn).equals(parseDN(group.dn)) || - (!req.checkAll && req.filter.matches(group.attributes)) + parseDN(strDn).equals(parseDN(group.dn)) + || (!req.checkAll && req.filter.matches(group.attributes)) ) { - log.debugSite(sitename, 'MatchGroup: ' + group.dn); + log.debugSite(sitename, `MatchGroup: ${group.dn}`); res.send(group); } }); @@ -105,15 +105,12 @@ initSite = (site, cacheFunctions, ldapjs) => { } function sendOrga(req, res, next) { - var strDn = req.dn.toString(); + const strDn = req.dn.toString(); try { const glob = cacheFunctions.getGlobals(); - if (req.checkAll && parseDN(strDn).equals(parseDN(glob.rootDn.dn))) - res.send(glob.rootDn); - if (req.checkAll && parseDN(strDn).equals(parseDN(glob.groupRoot.dn))) - res.send(glob.groupRoot); - if (req.checkAll && parseDN(strDn).equals(parseDN(glob.userRoot.dn))) - res.send(glob.userRoot); + if (req.checkAll && parseDN(strDn).equals(parseDN(glob.rootDn.dn))) res.send(glob.rootDn); + if (req.checkAll && parseDN(strDn).equals(parseDN(glob.groupRoot.dn))) res.send(glob.groupRoot); + if (req.checkAll && parseDN(strDn).equals(parseDN(glob.userRoot.dn))) res.send(glob.userRoot); } catch (error) { log.errorSite(sitename, 'Error while retrieving groups: ', error); } @@ -127,80 +124,78 @@ initSite = (site, cacheFunctions, ldapjs) => { async function authenticate(req, _res, next) { try { - var valid = await cacheFunctions.checkAuthentication( + const valid = await cacheFunctions.checkAuthentication( req.dn.toString(), - req.credentials + req.credentials, ); if (valid) { log.infoSite( - sitename, - 'Authentication successful for ' + req.dn.toString() - ); + sitename, + `Authentication successful for ${req.dn.toString()}`, + ); return next(); } } catch (err) { - log.debug(err) + log.debug(err); } log.infoSite( sitename, - 'Authentication error ' + req.dn.toString() + `Authentication error ${req.dn.toString()}`, ); -return next(new ldap.InvalidCredentialsError()); + return next(new ldap.InvalidCredentialsError()); } log.debugSite(sitename, 'Resgistering routes'); // Login bind for user ldapjs.bind( - 'ou=' + c.LDAP_OU_USERS + ',' + dc, + `ou=${c.LDAP_OU_USERS},${dc}`, (req, res, next) => { - log.debugSite(sitename, 'BIND dn: ' + req.dn.toString()); + log.debugSite(sitename, `BIND dn: ${req.dn.toString()}`); next(); }, authenticate, - endSuccess + endSuccess, ); ldapjs.bind( - //"cn=admin,dc=ccfreiburg,dc=de", + // "cn=admin,dc=ccfreiburg,dc=de", cacheFunctions.getGlobals().adminDn.dn, (req, res, next) => { - log.debugSite(sitename, 'BIND dn: ' + req.dn); + log.debugSite(sitename, `BIND dn: ${req.dn}`); next(); }, authenticate, - endSuccess + endSuccess, ); // Search implementation for user search ldapjs.search( - 'ou=' + c.LDAP_OU_USERS + ',' + dc, + `ou=${c.LDAP_OU_USERS},${dc}`, searchLogging, authorize, - function (req, _res, next) { + (req, _res, next) => { log.debugSite(sitename, 'Search for users'); - req.checkAll = - (req.scope !== 'base' && req.scope !== 'sub') || - req.dn.rdns.length > parseDN(dc).rdns.length + 1; + req.checkAll = (req.scope !== 'base' && req.scope !== 'sub') + || req.dn.rdns.length > parseDN(dc).rdns.length + 1; return next(); }, sendUsers, - endSuccess + endSuccess, ); // Search implementation for group search ldapjs.search( - 'ou=' + c.LDAP_OU_GROUPS + ',' + dc, + `ou=${c.LDAP_OU_GROUPS},${dc}`, searchLogging, authorize, - function (req, _res, next) { + (req, _res, next) => { log.debugSite(sitename, 'Search for groups'); - req.checkAll = - (req.scope !== 'base' && req.scope !== 'sub') || - req.dn.rdns.length > parseDN(dc).rdns.length + 1; + req.checkAll = (req.scope !== 'base' && req.scope !== 'sub') + || req.dn.rdns.length > parseDN(dc).rdns.length + 1; return next(); }, sendGroups, - endSuccess + endSuccess, ); // Search implementation for user and group search @@ -208,7 +203,7 @@ return next(new ldap.InvalidCredentialsError()); dc, searchLogging, authorize, - function (req, _res, next) { + (req, _res, next) => { log.debugSite(sitename, 'Search for users and groups combined'); req.checkAll = req.scope !== 'base' && req.scope !== 'sub'; return next(); @@ -216,39 +211,39 @@ return next(new ldap.InvalidCredentialsError()); sendUsers, sendGroups, sendOrga, - endSuccess + endSuccess, ); // Search the schema from LDAP Root DSE ldapjs.search( 'cn=schema', - function (req, res) { + (req, res) => { log.debug('Get subschema information'); console.log(JSON.stringify(req)); res.send(cacheFunctions.getGlobals().schemaDn); res.end(); }, - endSuccess + endSuccess, ); // Search implementation for basic search for Directory Information Tree and the LDAP Root DSE ldapjs.search( '', - function (req, res) { + (req, res) => { log.debug('empty request, return directory information'); res.send(cacheFunctions.getGlobals().rootDn); res.end(); }, - endSuccess + endSuccess, ); // throw exception during search ldapjs.search( 'cn=eroor,ou=error,dc=error,o=error', - function (req, res) { + (req, res) => { throw new Error('for testing'); }, - endSuccess + endSuccess, ); log.debugSite(sitename, 'Routes registered'); diff --git a/src/logging.js b/src/logging.js index a3c12a2..26e4117 100644 --- a/src/logging.js +++ b/src/logging.js @@ -1,4 +1,4 @@ -const pino = require('pino') +const pino = require('pino'); exports.loglevel = true; exports.loglevels = { @@ -6,74 +6,70 @@ exports.loglevels = { error: 1, warn: 2, info: 3, - debug: 4 -} + debug: 4, +}; -exports.logger = pino({ level: 'debug' }) +exports.logger = pino({ level: 'debug' }); getSite = (site) => { - if (site && site.hasOwnProperty("name")) - return site.name; - if (typeof site === "string") - return site; - else - return JSON.stringify(site); -} + if (site && site.hasOwnProperty('name')) return site.name; + if (typeof site === 'string') return site; + return JSON.stringify(site); +}; exports.debugSite = (site, msg) => { - this.logger.debug(getSite(site) + " - " + msg) + this.logger.debug(`${getSite(site)} - ${msg}`); // if (this.loglevel == this.loglevels.debug) { // console.log("[DEBUG] " + getSite(site) + " - " + msg); // } -} +}; exports.infoSite = (site, msg) => { - this.logger.info(getSite(site) + " - " + msg) - } + this.logger.info(`${getSite(site)} - ${msg}`); +}; exports.warnSite = (site, msg) => { - this.logger.warn(getSite(site) + " - " + msg) + this.logger.warn(`${getSite(site)} - ${msg}`); // if (this.loglevel >= this.loglevels.warn) // console.log("[WARN] " + getSite(site) + " - " + msg); -} +}; exports.errorSite = (site, msg, error) => { - this.logger.error(getSite(site) + " - " + msg) - if (error) - this.logger.error(error) + this.logger.error(`${getSite(site)} - ${msg}`); + if (error) this.logger.error(error); // if (this.loglevel >= this.loglevels.error) { // console.log("[ERROR] " + getSite(site) + " - " + msg); // if (error !== undefined) { // console.log(error.stack); // } // } -} +}; exports.debug = (msg) => { - this.logger.debug(msg) + this.logger.debug(msg); // if (this.loglevel == this.loglevels.debug) { // console.log("[DEBUG] - " + msg); // } -} +}; exports.warn = (msg) => { - this.logger.warn(msg) + this.logger.warn(msg); // if (this.loglevel >= this.loglevels.warn) // console.log("[WARN] - " + msg); -} +}; exports.error = (msg, error) => { - this.logger.error(msg) + this.logger.error(msg); // if (this.loglevel >= this.loglevels.error) { // console.log("[ERROR] - " + msg); // if (error !== undefined) { // console.log(error.stack); // } // } -} +}; exports.info = (msg) => { - this.logger.info(msg) + this.logger.info(msg); // if (this.loglevel >= this.loglevels.info) // console.log("[INFO] - " + msg); -} \ No newline at end of file +}; diff --git a/src/main.js b/src/main.js index 35f808d..f8ad92c 100644 --- a/src/main.js +++ b/src/main.js @@ -1,5 +1,5 @@ -const log = require('./logging'); const YAML = require('yamljs'); +const log = require('./logging'); const ctservice = require('./ctservice'); const transform = require('./transform'); const ldapcache = require('./ldapcache'); @@ -15,17 +15,17 @@ const initCache = async (site, getChurchToolsDataFunc, authChurchToolsFunc) => { transform.getRootObj(site.ldap.dc, site.ldap.admin, site.ldap.o), adminuser, site.ldap.password, - authChurchToolsFunc + authChurchToolsFunc, ); const churchtoolsdata = await getChurchToolsDataFunc( site.selectionGroupIds, site.tranformedGroups, - site.site + site.site, ); const { users, groups } = transform.getLdapData( site, churchtoolsdata, - adminuser + adminuser, ); siteCacheFunctions.setData(users, groups); @@ -35,25 +35,21 @@ const initCache = async (site, getChurchToolsDataFunc, authChurchToolsFunc) => { const updateSiteData = ( site, getChurchToolsDataFunc, - siteCacheFunctionsSetData -) => { - return new Promise(async (resolve) => { - log.infoSite(site.site, 'Updating data from Church Tools'); - const data = await getChurchToolsDataFunc( - site.selectionGroupIds, - site.tranformedGroups, - site.site - ); - const adminuser = transform.getAdmin(site.ldap.admincn, site.ldap.dc); - const ldap = transform.getLdapData(site, data, adminuser); - siteCacheFunctionsSetData(ldap.users, ldap.groups); - resolve(); - }); -}; + siteCacheFunctionsSetData, +) => new Promise(async (resolve) => { + log.infoSite(site.site, 'Updating data from Church Tools'); + const data = await getChurchToolsDataFunc( + site.selectionGroupIds, + site.tranformedGroups, + site.site, + ); + const adminuser = transform.getAdmin(site.ldap.admincn, site.ldap.dc); + const ldap = transform.getLdapData(site, data, adminuser); + siteCacheFunctionsSetData(ldap.users, ldap.groups); + resolve(); +}); -exports.getConfig = (file) => { - return YAML.load(file); -}; +exports.getConfig = (file) => YAML.load(file); exports.ldapjs = {}; @@ -61,7 +57,7 @@ exports.start = async ( config, getChurchToolsDataFunc, authWithChurchToolsFunc, - callback + callback, ) => { log.info('Starting up CCF Ldap wrapper for ChurchTools ....'); const updaters = new Map(); @@ -73,12 +69,12 @@ exports.start = async ( const cacheFunctions = await initCache( site, getChurchToolsDataFunc, - authWithChurchToolsFunc(site) + authWithChurchToolsFunc(site), ); await this.ldapjs.initSite(site, cacheFunctions); updaters.set( site.site.name, - () => updateSiteData(site, getChurchToolsDataFunc, cacheFunctions.setData) + () => updateSiteData(site, getChurchToolsDataFunc, cacheFunctions.setData), ); } log.debug('Done initializing data'); @@ -103,7 +99,7 @@ exports.snapshot = async (site) => { const data = await ctservice.getChurchToolsData( site.selectionGroupIds, site.tranformedGroups, - site.site + site.site, ); const adminuser = transform.getAdmin(site.ldap.admincn, site.ldap.dc); const ldap = transform.getLdapData(site, data, adminuser); diff --git a/src/nextcloud.js b/src/nextcloud.js index 423e4c9..4252b63 100644 --- a/src/nextcloud.js +++ b/src/nextcloud.js @@ -1,109 +1,107 @@ const c = require('./constants'); exports.getNextcloudMappingTables = (churchToolsData, dc) => { - var insertSql = - "REPLACE INTO `oc_ldap_group_mapping` VALUES ('cn=admin,ou=groups," + - dc + - "', 'admin', 'g0'); REPLACE INTO `oc_ldap_user_mapping` VALUES "; + let insertSql = `REPLACE INTO \`oc_ldap_group_mapping\` VALUES ('cn=admin,ou=groups,${ + dc + }', 'admin', 'g0'); REPLACE INTO \`oc_ldap_user_mapping\` VALUES `; churchToolsData.users.forEach((user) => { - insertSql += - "('" + - user.dn + - "', '" + - user.attributes.uid + - "', '" + - user.attributes.entryUUID + - "'),"; + insertSql + += `('${ + user.dn + }', '${ + user.attributes.uid + }', '${ + user.attributes.entryUUID + }'),`; }); - insertSql = insertSql.slice(0, -1) + ';'; + insertSql = `${insertSql.slice(0, -1)};`; - //INSERT INTO `oc_ldap_group_mapping` (`ldap_dn`, `owncloud_name`, `directory_uuid`) VALUES ('cn=admin,ou=groups,dc=ccfreiburg,dc=de', 'admin', 'admingruop0'); + // INSERT INTO `oc_ldap_group_mapping` (`ldap_dn`, `owncloud_name`, `directory_uuid`) VALUES ('cn=admin,ou=groups,dc=ccfreiburg,dc=de', 'admin', 'admingruop0'); console.log(insertSql); -} +}; -exports.getNextcloudLdapConfig = (config, ncAccessObjClass ,externalLdapIp) => { - const ldapip = externalLdapIp ? externalLdapIp : '127.0.0.1'; - const port = config.server.port; +exports.getNextcloudLdapConfig = (config, ncAccessObjClass, externalLdapIp) => { + const ldapip = externalLdapIp || '127.0.0.1'; + const { port } = config.server; const site = config.sites.ccf; const Orga = site.ldap.dc; - const Group = 'ou=' + c.LDAP_OU_GROUPS + ','; - const Users = 'ou=' + c.LDAP_OU_USERS + ','; - const ncOC = (ncAccessObjClass && ncAccessObjClass.length>1?ncAccessObjClass:c.LDAP_OBJCLASS_USER) + const Group = `ou=${c.LDAP_OU_GROUPS},`; + const Users = `ou=${c.LDAP_OU_USERS},`; + const ncOC = (ncAccessObjClass && ncAccessObjClass.length > 1 ? ncAccessObjClass : c.LDAP_OBJCLASS_USER); - const set = "s01"; + const set = 's01'; function getLdapAppSetting(key, val) { - return "('user_ldap', '" + set + key + "', '" + val + "'),"; + return `('user_ldap', '${set}${key}', '${val}'),`; } - - settingSql = - 'REPLACE INTO `oc_appconfig` VALUES ' + - getLdapAppSetting( - 'ldap_dn', - 'cn=' + site.ldap.admincn + ',' + Orga - ) + - getLdapAppSetting('ldap_agent_password', site.ldap.password) + - getLdapAppSetting('ldap_host', ldapip) + - getLdapAppSetting('ldap_port', port) + - getLdapAppSetting('ldap_base', Orga) + - getLdapAppSetting('ldap_base_groups', Group + Orga) + - getLdapAppSetting('ldap_base_users', Users + Orga) + - getLdapAppSetting( - 's01', - 'ldap_userlist_filter', - '(&(objectclass=' + ncOC + '))' - ) + - getLdapAppSetting('ldap_display_name', 'displayname') + - getLdapAppSetting('ldap_expert_username_attr', 'uid') + - getLdapAppSetting('ldap_expert_uuid_group_attr', 'entryUUID') + - getLdapAppSetting('ldap_expert_uuid_user_attr', 'entryUUID') + - getLdapAppSetting('ldap_configuration_active', '1') + - getLdapAppSetting('ldap_group_display_name', 'displayname') + - getLdapAppSetting( - 's01', - 'ldap_group_filter', - '(&(objectclass=' + c.LDAP_OBJCLASS_GROUP + '))' - ) + - getLdapAppSetting('ldap_group_filter_mode', '1') + - getLdapAppSetting( - 's01', - 'ldap_group_member_assoc_attribute', - 'uniqueMember' - ) + - getLdapAppSetting( - 's01', - 'ldap_groupfilter_objectclass', - c.LDAP_OBJCLASS_GROUP - ) + - getLdapAppSetting('ldap_expert_uuid_user_attr', 'entryUUID') + - getLdapAppSetting( - 's01', - 'ldap_login_filter', - '(&(objectclass=' + ncOC + ')(uid=%uid))' - ) + - getLdapAppSetting('ldap_loginfilter_attributes', 'uid') + - getLdapAppSetting('ldap_user_filter_mode', '1') + + + settingSql = `REPLACE INTO \`oc_appconfig\` VALUES ${ getLdapAppSetting( - 's01', - 'ldap_userfilter_objectclass', - c.LDAP_OBJCLASS_USER - ) + - getLdapAppSetting('ldap_use_memberof_to_detect_membership', '1') + + 'ldap_dn', + `cn=${site.ldap.admincn},${Orga}`, + ) + }${getLdapAppSetting('ldap_agent_password', site.ldap.password) + }${getLdapAppSetting('ldap_host', ldapip) + }${getLdapAppSetting('ldap_port', port) + }${getLdapAppSetting('ldap_base', Orga) + }${getLdapAppSetting('ldap_base_groups', Group + Orga) + }${getLdapAppSetting('ldap_base_users', Users + Orga) + }${getLdapAppSetting( + 's01', + 'ldap_userlist_filter', + `(&(objectclass=${ncOC}))`, + ) + }${getLdapAppSetting('ldap_display_name', 'displayname') + }${getLdapAppSetting('ldap_expert_username_attr', 'uid') + }${getLdapAppSetting('ldap_expert_uuid_group_attr', 'entryUUID') + }${getLdapAppSetting('ldap_expert_uuid_user_attr', 'entryUUID') + }${getLdapAppSetting('ldap_configuration_active', '1') + }${getLdapAppSetting('ldap_group_display_name', 'displayname') + }${getLdapAppSetting( + 's01', + 'ldap_group_filter', + `(&(objectclass=${c.LDAP_OBJCLASS_GROUP}))`, + ) + }${getLdapAppSetting('ldap_group_filter_mode', '1') + }${getLdapAppSetting( + 's01', + 'ldap_group_member_assoc_attribute', + 'uniqueMember', + ) + }${getLdapAppSetting( + 's01', + 'ldap_groupfilter_objectclass', + c.LDAP_OBJCLASS_GROUP, + ) + }${getLdapAppSetting('ldap_expert_uuid_user_attr', 'entryUUID') + }${getLdapAppSetting( + 's01', + 'ldap_login_filter', + `(&(objectclass=${ncOC})(uid=%uid))`, + ) + }${getLdapAppSetting('ldap_loginfilter_attributes', 'uid') + }${getLdapAppSetting('ldap_user_filter_mode', '1') + }${getLdapAppSetting( + 's01', + 'ldap_userfilter_objectclass', + c.LDAP_OBJCLASS_USER, + ) + }${getLdapAppSetting('ldap_use_memberof_to_detect_membership', '1') // Ab hier muss nicht angepasst werden. - "('user_ldap', '"+set+"has_memberof_filter_support', '1'),('user_ldap', '"+set+"home_folder_naming_rule', '')," + - "('user_ldap', '"+set+"last_jpegPhoto_lookup', '0'),('user_ldap', '"+set+"ldap_attributes_for_group_search', '')," + - "('user_ldap', '"+set+"ldap_attributes_for_user_search', ''),('user_ldap', '"+set+"ldap_backup_host', '')," + - "('user_ldap', '"+set+"ldap_backup_port', ''),('user_ldap', '"+set+"ldap_cache_ttl', '600')," + - "('user_ldap', '"+set+"ldap_default_ppolicy_dn', ''),('user_ldap', '"+set+"ldap_dynamic_group_member_url', '')," + - "('user_ldap', '"+set+"ldap_email_attr', 'mail'),('user_ldap', '"+set+"ldap_experienced_admin', '0')," + - "('user_ldap', '"+set+"ldap_ext_storage_home_attribute', ''),('user_ldap', '"+set+"ldap_gid_number', 'gidNumber')," + - "('user_ldap', '"+set+"ldap_groupfilter_groups', ''),('user_ldap', '"+set+"ldap_login_filter_mode', '0')," + - "('user_ldap', '"+set+"ldap_loginfilter_email', '0'),('user_ldap', '"+set+"ldap_loginfilter_username', '1')," + - "('user_ldap', '"+set+"ldap_nested_groups', '0'),('user_ldap', '"+set+"ldap_override_main_server', '')," + - "('user_ldap', '"+set+"ldap_paging_size', '500')," + - "('user_ldap', '"+set+"ldap_quota_attr', ''),('user_ldap', '"+set+"ldap_quota_def', '')," + - "('user_ldap', '"+set+"ldap_tls', '0'),('user_ldap', '"+set+"ldap_turn_off_cert_check', '0')," + - "('user_ldap', '"+set+"ldap_turn_on_pwd_change', '0'),('user_ldap', '"+set+"ldap_user_avatar_rule', 'default')," + - "('user_ldap', '"+set+"ldap_user_display_name_2', ''),('user_ldap', '"+set+"ldap_userfilter_groups', '');"; + }('user_ldap', '${set}has_memberof_filter_support', '1'),('user_ldap', '${set}home_folder_naming_rule', ''),` + + `('user_ldap', '${set}last_jpegPhoto_lookup', '0'),('user_ldap', '${set}ldap_attributes_for_group_search', ''),` + + `('user_ldap', '${set}ldap_attributes_for_user_search', ''),('user_ldap', '${set}ldap_backup_host', ''),` + + `('user_ldap', '${set}ldap_backup_port', ''),('user_ldap', '${set}ldap_cache_ttl', '600'),` + + `('user_ldap', '${set}ldap_default_ppolicy_dn', ''),('user_ldap', '${set}ldap_dynamic_group_member_url', ''),` + + `('user_ldap', '${set}ldap_email_attr', 'mail'),('user_ldap', '${set}ldap_experienced_admin', '0'),` + + `('user_ldap', '${set}ldap_ext_storage_home_attribute', ''),('user_ldap', '${set}ldap_gid_number', 'gidNumber'),` + + `('user_ldap', '${set}ldap_groupfilter_groups', ''),('user_ldap', '${set}ldap_login_filter_mode', '0'),` + + `('user_ldap', '${set}ldap_loginfilter_email', '0'),('user_ldap', '${set}ldap_loginfilter_username', '1'),` + + `('user_ldap', '${set}ldap_nested_groups', '0'),('user_ldap', '${set}ldap_override_main_server', ''),` + + `('user_ldap', '${set}ldap_paging_size', '500'),` + + `('user_ldap', '${set}ldap_quota_attr', ''),('user_ldap', '${set}ldap_quota_def', ''),` + + `('user_ldap', '${set}ldap_tls', '0'),('user_ldap', '${set}ldap_turn_off_cert_check', '0'),` + + `('user_ldap', '${set}ldap_turn_on_pwd_change', '0'),('user_ldap', '${set}ldap_user_avatar_rule', 'default'),` + + `('user_ldap', '${set}ldap_user_display_name_2', ''),('user_ldap', '${set}ldap_userfilter_groups', '');`; console.log(settingSql); -} +}; diff --git a/src/transform.js b/src/transform.js index 1d504af..4f07466 100644 --- a/src/transform.js +++ b/src/transform.js @@ -1,6 +1,6 @@ const ldapEsc = require('ldap-escape'); -const c = require('./constants'); const crypto = require('crypto'); +const c = require('./constants'); const { result } = require('./ctapi'); class DataFormatError extends Error { @@ -11,51 +11,47 @@ class DataFormatError extends Error { } exports.lowercase = (s) => (typeof s === 'string' ? s.toLowerCase() : s); exports.identity = (s) => s; -exports.stringConvLowercaseUmlaut = (str) => { - return str - .toLowerCase() - .replace('ö', 'oe') - .replace('ä', 'ae') - .replace('ü', 'ue') - .replace('ß', 'ss'); -}; -exports.generateUUID = () => { - return crypto.randomUUID(); -}; +exports.stringConvLowercaseUmlaut = (str) => str + .toLowerCase() + .replace('ö', 'oe') + .replace('ä', 'ae') + .replace('ü', 'ue') + .replace('ß', 'ss'); +exports.generateUUID = () => crypto.randomUUID(); exports.uniqueEmails = (users) => { - var mails = {}; + const mails = {}; return users.filter((user) => { if (!user.attributes.email) { return false; } - var result = !(user.attributes.email in mails); + const result = !(user.attributes.email in mails); mails[user.attributes.email] = true; return result; }); }; exports.getRootObj = (dc, admin, o) => { - var dn = dc; - //ldapEsc.dn`cn=root`; - var result = { + const dn = dc; + // ldapEsc.dn`cn=root`; + const result = { users: { - dn: "ou="+c.LDAP_OU_USERS+","+dc, + dn: `ou=${c.LDAP_OU_USERS},${dc}`, attributes: { - o: o, + o, ou: c.LDAP_OU_USERS, cn: c.LDAP_OU_USERS, elements: [], - } + }, }, groups: { - dn: "ou="+c.LDAP_OU_GROUPS+","+dc, + dn: `ou=${c.LDAP_OU_GROUPS},${dc}`, attributes: { - o: o, + o, ou: c.LDAP_OU_GROUPS, cn: c.LDAP_OU_GROUPS, elements: [], - } + }, }, dsn: { dn: dc, @@ -63,25 +59,25 @@ exports.getRootObj = (dc, admin, o) => { creatorsname: admin, entrydn: dc, entryuuid: this.generateUUID(), - o: o, - namingContexts: [ dc ], + o, + namingContexts: [dc], objectclass: ['top', 'RootDSE', 'organization'], structuralobjectclass: 'organization', subschemasubentry: 'cn=Subschema', - elements: [] - } - } - } - result.dsn.attributes.elements.push(result.users, result.groups) - return result + elements: [], + }, + }, + }; + result.dsn.attributes.elements.push(result.users, result.groups); + return result; }; exports.getAdmin = (cn, dc) => { - const dn = ldapEsc.dn`cn=${cn}` + ',' + dc; + const dn = `${ldapEsc.dn`cn=${cn}`},${dc}`; return { - dn: dn, + dn, attributes: { - cn: cn, + cn, displayname: 'Admin', id: 0, uid: 'Admin', @@ -93,31 +89,30 @@ exports.getAdmin = (cn, dc) => { 'simpleSecurityObject', 'organizationalRole', ], - memberOf: [] + memberOf: [], }, }; }; exports.getAdminGroup = (cn, dc) => { - const dn = ldapEsc.dn`cn=${cn}` + ",ou=" +c.LDAP_OU_GROUPS+ ',' + dc; + const dn = `${ldapEsc.dn`cn=${cn}`},ou=${c.LDAP_OU_GROUPS},${dc}`; return { - dn: dn, + dn, attributes: { - cn: cn, + cn, id: 0, - displayname: "Administrators", + displayname: 'Administrators', entryUUID: 'admingroup0', objectClass: [c.LDAP_OBJCLASS_GROUP], - uniqueMember: [ ] - } - } + uniqueMember: [], + }, + }; }; exports.setUid = (ctpserson) => { - if (ctpserson[c.LDAPID_FIELD] && ctpserson[c.LDAPID_FIELD].length > 0) - return ctpserson[c.LDAPID_FIELD]; + if (ctpserson[c.LDAPID_FIELD] && ctpserson[c.LDAPID_FIELD].length > 0) return ctpserson[c.LDAPID_FIELD]; return this.stringConvLowercaseUmlaut( - ctpserson.firstName + '.' + ctpserson.lastName + `${ctpserson.firstName}.${ctpserson.lastName}`, ); }; @@ -125,25 +120,24 @@ exports.addConfigAttributes = (ctperson, attributes) => { attributes.forEach((attribute) => { ctperson.attributes[attribute.name] = attribute.default; const replacment = attribute.replacements.find( - (rep) => rep.id == ctperson.attributes.id + (rep) => rep.id == ctperson.attributes.id, ); if (replacment) ctperson.attributes[attribute.name] = replacment.value; }); }; exports.transformUser = (ctpserson, attributes, dc) => { - var result = {}; - if (!ctpserson || !ctpserson.id) - throw new DataFormatError('Empty user object'); + let result = {}; + if (!ctpserson || !ctpserson.id) throw new DataFormatError('Empty user object'); - var cn = this.setUid(ctpserson); - var dn = ldapEsc.dn`cn=${cn}` + ',ou=' + c.LDAP_OU_USERS + ',' + dc; + const cn = this.setUid(ctpserson); + const dn = `${ldapEsc.dn`cn=${cn}`},ou=${c.LDAP_OU_USERS},${dc}`; result = { dn: this.lowercase(dn), attributes: { - cn: cn, + cn, id: ctpserson.id, - displayname: ctpserson.firstName + ' ' + ctpserson.lastName, + displayname: `${ctpserson.firstName} ${ctpserson.lastName}`, uid: cn, guid: ctpserson.guid, entryUUID: ctpserson.guid, @@ -156,7 +150,7 @@ exports.transformUser = (ctpserson, attributes, dc) => { sn: ctpserson.lastName, email: this.lowercase(ctpserson.email), mail: this.lowercase(ctpserson.email), - objectClass: [c.LDAP_OBJCLASS_USER,"person","organizationalPerson","user"], + objectClass: [c.LDAP_OBJCLASS_USER, 'person', 'organizationalPerson', 'user'], memberOf: [], }, }; @@ -165,19 +159,18 @@ exports.transformUser = (ctpserson, attributes, dc) => { }; exports.transformGroup = (ctgroup, grtransform, dc) => { - if (!ctgroup || !ctgroup.id) - throw new DataFormatError('Group from CT was emtpy'); - var cn = grtransform && grtransform.name ? grtransform.name : ctgroup.name; - var dn = ldapEsc.dn`cn=${cn}` + ',ou=' + c.LDAP_OU_GROUPS + ',' + dc; + if (!ctgroup || !ctgroup.id) throw new DataFormatError('Group from CT was emtpy'); + const cn = grtransform && grtransform.name ? grtransform.name : ctgroup.name; + const dn = `${ldapEsc.dn`cn=${cn}`},ou=${c.LDAP_OU_GROUPS},${dc}`; return { dn: this.lowercase(dn), attributes: { - cn: cn, + cn, displayname: cn, id: ctgroup.id, guid: ctgroup.guid, entryUUID: ctgroup.guid, - nsuniqueid: 'g' + ctgroup.id, + nsuniqueid: `g${ctgroup.id}`, objectClass: [c.LDAP_OBJCLASS_GROUP], uniqueMember: [], }, @@ -185,17 +178,17 @@ exports.transformGroup = (ctgroup, grtransform, dc) => { }; exports.addUsersAdminGroup = (users, ldapadmin, ids, cn, dc) => { - const admingroup = this.getAdminGroup(cn,dc) - users.forEach( (user) => { + const admingroup = this.getAdminGroup(cn, dc); + users.forEach((user) => { if (ids.includes(user.attributes.id)) { - admingroup.attributes.uniqueMember.push(user.dn) - user.attributes.memberOf.push(admingroup.dn) + admingroup.attributes.uniqueMember.push(user.dn); + user.attributes.memberOf.push(admingroup.dn); } - }) - admingroup.attributes.uniqueMember.push(ldapadmin.dn) - ldapadmin.attributes.memberOf.push(admingroup.dn) + }); + admingroup.attributes.uniqueMember.push(ldapadmin.dn); + ldapadmin.attributes.memberOf.push(admingroup.dn); return admingroup; -} +}; exports.connectUsersAndGroups = ( memberships, @@ -205,7 +198,7 @@ exports.connectUsersAndGroups = ( ) => { groups.forEach((group) => { const objClassGrpMem = tranformedGroups.find( - (t) => t.gid == group.attributes.id + (t) => t.gid == group.attributes.id, ); memberships .filter((m) => m.groupId == group.attributes.id) @@ -213,8 +206,7 @@ exports.connectUsersAndGroups = ( const user = users.find((u) => u.attributes.id == memberhip.personId); if (user) { user.attributes.memberOf.push(group.dn); - if (objClassGrpMem && objClassGrpMem.hasOwnProperty('objectClass')) - user.attributes.objectClass.push(objClassGrpMem.objectClass); + if (objClassGrpMem && objClassGrpMem.hasOwnProperty('objectClass')) user.attributes.objectClass.push(objClassGrpMem.objectClass); group.attributes.uniqueMember.push(user.dn); } }); @@ -244,21 +236,21 @@ exports.getLdapData = (site, churchtoolsdata, adminuser) => { const groups = this.getLdapGroupsWithoutMembers( churchtoolsdata.groups, site.tranformedGroups, - site.ldap.dc + site.ldap.dc, ); const users = this.getLdapUsers( churchtoolsdata.persons, site.attributes, - site.ldap.dc + site.ldap.dc, ); this.connectUsersAndGroups( churchtoolsdata.memberships, groups, users, - site.tranformedGroups + site.tranformedGroups, ); - groups.push(this.addUsersAdminGroup(users, adminuser ,site.adminGroup.members,site.adminGroup.cn,site.ldap.dc)) + groups.push(this.addUsersAdminGroup(users, adminuser, site.adminGroup.members, site.adminGroup.cn, site.ldap.dc)); return { users, diff --git a/test/ctconnection.integration.js b/test/ctconnection.integration.js index 28dcc3a..dcdb9a7 100644 --- a/test/ctconnection.integration.js +++ b/test/ctconnection.integration.js @@ -1,45 +1,45 @@ -const ctconn = require("../src/ctconnection"); -const log = require("../src/logging"); +const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); +const ctconn = require('../src/ctconnection'); +const log = require('../src/logging'); -const chai = require("chai"); -var chaiAsPromised = require("chai-as-promised"); -const expect = chai.expect; +const { expect } = chai; chai.use(chaiAsPromised); ChurchToolsError = ctconn.ChurchToolsError; -const config = require('../production/config.json') -const site = config.sites.ccf.site +const config = require('../production/config.json'); -describe("API call integration ctconnection", () => { - before( () => { - log.logger.level = 'silent' - }) +const { site } = config.sites.ccf; - it("Info: gets info object", async () => { - const result = await ctconn.infoReal(site.url) - expect(result.shortName).to.equal("CCF") +describe('API call integration ctconnection', () => { + before(() => { + log.logger.level = 'silent'; + }); + + it('Info: gets info object', async () => { + const result = await ctconn.infoReal(site.url); + expect(result.shortName).to.equal('CCF'); }).timeout(4000); - it("getCsrfTokenReal: throws exception", async () => { - const cookie = ""; + it('getCsrfTokenReal: throws exception', async () => { + const cookie = ''; expect(ctconn.getCsrfTokenReal(site.url, cookie)) - .to.eventually.rejectedWith(ChurchToolsError) + .to.eventually.rejectedWith(ChurchToolsError); }).timeout(2000); - it("loginPromise: login without helpfull data throws error", () => { + it('loginPromise: login without helpfull data throws error', () => { con = ctconn.getEmptyConnection(site.name); con.baseurl = site.url; expect( - ctconn.loginPromiseReal(con, "", "", "") + ctconn.loginPromiseReal(con, '', '', ''), ).to.be.eventually.rejectedWith(ChurchToolsError); }); - it("loginPromise: login works with real church tools access", async () => { + it('loginPromise: login works with real church tools access', async () => { con = ctconn.getEmptyConnection(site.name); con.baseurl = site.url; - const result = await ctconn.loginPromiseReal(con, site.user, site.password) - expect(result.status).to.be.equal("success"); + const result = await ctconn.loginPromiseReal(con, site.user, site.password); + expect(result.status).to.be.equal('success'); }).timeout(6000); - }); diff --git a/test/ctconnection.test.js b/test/ctconnection.test.js index bdcc07c..c0ff5c7 100644 --- a/test/ctconnection.test.js +++ b/test/ctconnection.test.js @@ -1,146 +1,139 @@ -const chai = require("chai"); -const expect = chai.expect; -var chaiAsPromised = require("chai-as-promised"); +const chai = require('chai'); + +const { expect } = chai; +const chaiAsPromised = require('chai-as-promised'); + chai.use(chaiAsPromised); -const log = require("../src/logging"); -const ctapi = require("../src/ctapi"); -const ctconn = require("../src/ctconnection"); +const log = require('../src/logging'); +const ctapi = require('../src/ctapi'); +const ctconn = require('../src/ctconnection'); + ChurchToolsError = ctapi.ChurchToolsError; ChurchToolsFatalError = ctapi.ChurchToolsFatalError; const site = { - name: "nopf", - user: "user", - password: "pass", - url: "https://nopf.church.toys/", + name: 'nopf', + user: 'user', + password: 'pass', + url: 'https://nopf.church.toys/', }; -describe("Church Tools Connection", () => { - before( () => { - log.logger.level = 'silent' - }) +describe('Church Tools Connection', () => { + before(() => { + log.logger.level = 'silent'; + }); - it("getConnection for new site returns empty connection object", () => { - var mysite = { ...site }; - mysite.name = "asdfgggg"; + it('getConnection for new site returns empty connection object', () => { + const mysite = { ...site }; + mysite.name = 'asdfgggg'; actual = ctconn.getConnection(mysite); - expect(actual).to.have.property("loginPromise"); - expect(actual.loginPromise).to.equal(null) + expect(actual).to.have.property('loginPromise'); + expect(actual.loginPromise).to.equal(null); expect(actual.name).to.equal(mysite.name); }); - it("getConnection returns existing connection object", () => { - var mysite = { ...site }; - mysite.name = "asdfggg"; + it('getConnection returns existing connection object', () => { + const mysite = { ...site }; + mysite.name = 'asdfggg'; expected = ctconn.getConnection(mysite); actual = ctconn.getConnection(mysite); expect(actual).to.equal(expected); }); - it("getConnection returns new one even if there is an existing connection object", () => { - var mysite = { ...site }; - mysite.name = "asdggg"; + it('getConnection returns new one even if there is an existing connection object', () => { + const mysite = { ...site }; + mysite.name = 'asdggg'; notexpected = ctconn.getConnection(site); actual = ctconn.getConnection(mysite); expect(actual).to.not.equal(notexpected); }); - it("login failed - throws ChurchToolsError", () => { - var mysite = { ...site }; - mysite.name = "ola"; - ctconn.setLoginMock((c, b, u, p) => { - return new Promise((resolve) => { - resolve({ message: "login failed" }); - }) - }) - expect(ctconn.login(mysite)).to.eventually.throw(ChurchToolsError) + it('login failed - throws ChurchToolsError', () => { + const mysite = { ...site }; + mysite.name = 'ola'; + ctconn.setLoginMock((c, b, u, p) => new Promise((resolve) => { + resolve({ message: 'login failed' }); + })); + expect(ctconn.login(mysite)).to.eventually.throw(ChurchToolsError); }).timeout(2000); - it("login - prevents from too many login attempts", () => { - var mysite = { ...site }; - mysite.name = "ola"; - ctconn.setLoginMock((c, b, u, p) => { - return new Promise((resolve) => { - resolve({ message: "login failed" }); - }) - }) + it('login - prevents from too many login attempts', () => { + const mysite = { ...site }; + mysite.name = 'ola'; + ctconn.setLoginMock((c, b, u, p) => new Promise((resolve) => { + resolve({ message: 'login failed' }); + })); expect( new Promise(async (resolve) => { - var i = 0; + let i = 0; while (i < 5 && failed) { try { - await ctconn.login(mysite) + await ctconn.login(mysite); } catch (ChurchToolsError) { } i++; } - resolve() - } - )).to.eventually.throw(ChurchToolsFatalError) + resolve(); + }), + ).to.eventually.throw(ChurchToolsFatalError); }).timeout(2000); - it("get - logs in, if no session", async () => { - const expected = { data: { status: "success", data: { test: "test" } } }; - const site = ctconn.getEmptyConnection("amprf", "url") - var loginCalled = false; + it('get - logs in, if no session', async () => { + const expected = { data: { status: 'success', data: { test: 'test' } } }; + const site = ctconn.getEmptyConnection('amprf', 'url'); + let loginCalled = false; ctconn.setLoginMock((c, b, u, p) => { loginCalled = true; return Promise.resolve({ data: {} }); - }) - ctconn.setAxiosMock((obj) => { - return Promise.resolve(expected) - }) - const actual = await ctconn.get("url", site) - expect(loginCalled).to.equal(true) + }); + ctconn.setAxiosMock((obj) => Promise.resolve(expected)); + const actual = await ctconn.get('url', site); + expect(loginCalled).to.equal(true); expect(actual).to.equal(expected.data); }); - it("get - trys to log in multiple times", async () => { - const expected = { data: { status: "success", data: { test: "test" } } }; - var newsite = { ...site } - newsite.name = "amprf"; - var loginCalls = 0; - var axiosCalled = false; + it('get - trys to log in multiple times', async () => { + const expected = { data: { status: 'success', data: { test: 'test' } } }; + const newsite = { ...site }; + newsite.name = 'amprf'; + let loginCalls = 0; + let axiosCalled = false; function LoginException() { - const err = new Error("Kommst net rein") - err.response = { status: 400 } - return err + const err = new Error('Kommst net rein'); + err.response = { status: 400 }; + return err; } ctconn.setLoginMock((c, b, u, p) => { loginCalls++; - if (loginCalls < 3) - throw new LoginException(); - return Promise.resolve({ data: {} }) - }) + if (loginCalls < 3) throw new LoginException(); + return Promise.resolve({ data: {} }); + }); ctconn.setAxiosMock((obj) => { axiosCalled = true; - if (loginCalls < 2) - return Promise.resolve(false); - return Promise.resolve(expected) - }) - const actual = await ctconn.get("url", newsite) - expect(loginCalls).to.equal(3) - expect(axiosCalled).to.equal(true) + if (loginCalls < 2) return Promise.resolve(false); + return Promise.resolve(expected); + }); + const actual = await ctconn.get('url', newsite); + expect(loginCalls).to.equal(3); + expect(axiosCalled).to.equal(true); expect(actual).to.equal(expected.data); }); - it("get - trys to log in gives up after n times", async () => { - const expected = { data: { status: "success", data: { test: "test" } } }; - var newsite = { ...site } - newsite.name = "amprdff"; + it('get - trys to log in gives up after n times', async () => { + const expected = { data: { status: 'success', data: { test: 'test' } } }; + const newsite = { ...site }; + newsite.name = 'amprdff'; loginCalls = 0; function LoginException() { - const err = new Error("Kommst net rein") - err.response = { status: 401 } - return err + const err = new Error('Kommst net rein'); + err.response = { status: 401 }; + return err; } ctconn.setLoginMock((c, b, u, p) => { - loginCalls++ + loginCalls++; throw new LoginException(); - }) - ctconn.setAxiosMock((obj) => { - return Promise.resolve(false); - }) - expect(ctconn.get("url", newsite)).to.eventually.throw(ChurchToolsFatalError) + }); + ctconn.setAxiosMock((obj) => Promise.resolve(false)); + expect(ctconn.get('url', newsite)).to.eventually.throw(ChurchToolsFatalError); }); -}) \ No newline at end of file +}); diff --git a/test/ctservice.integration.js b/test/ctservice.integration.js index 4988234..bc7b9f3 100644 --- a/test/ctservice.integration.js +++ b/test/ctservice.integration.js @@ -1,37 +1,35 @@ -const ctserv = require("../src/ctservice"); -const { expect } = require("chai"); +const { expect } = require('chai'); +const ctserv = require('../src/ctservice'); -const log = require("../src/logging"); -const config = require('../production/config.json') -const site = config.sites.ccf +const log = require('../src/logging'); +const config = require('../production/config.json'); +const site = config.sites.ccf; - - - -describe("CT API calls from service", () => { - before( () => { - log.logger.level = 'silent' - }) - it("Selection Group returns the group info and personIds", async () => { +describe('CT API calls from service', () => { + before(() => { + log.logger.level = 'silent'; + }); + it('Selection Group returns the group info and personIds', async () => { const personIds = await ctserv.getPersonsInGroups(site.selectionGroupIds, site.site); - expect(personIds.length).to.be.above(15) - expect(personIds).to.contain(3) - expect(personIds).to.contain(3041) - }) - it("getPersonRecordsForId returns the detail info for a personId with ncuid set", async () => { + expect(personIds.length).to.be.above(15); + expect(personIds).to.contain(3); + expect(personIds).to.contain(3041); + }); + it('getPersonRecordsForId returns the detail info for a personId with ncuid set', async () => { const person = await ctserv.getPersonRecordForId(5, site.site); - expect(person.id).to.be.equal(5) - expect(person.ncuid).to.be.equal("alex.roehm") - }) - it("getChurchToolsData - returns all the data", async () => { + expect(person.id).to.be.equal(5); + expect(person.ncuid).to.be.equal('alex.roehm'); + }); + it('getChurchToolsData - returns all the data', async () => { const data = await ctserv.getChurchToolsData( - site.selectionGroupIds, - site.tranformedGroups.map((v)=>v.gid), - site.site); - expect(data.groups.map((r)=>r.id)).to.contain(692) - expect(data.persons.map((r)=>r.id)).to.contain(5) - expect(data.persons.length).to.be.above(15) - expect(data.memberships.find((r)=>(r.personIds=5 && r.groupId==692))) - }).timeout(10000) -}) \ No newline at end of file + site.selectionGroupIds, + site.tranformedGroups.map((v) => v.gid), + site.site, + ); + expect(data.groups.map((r) => r.id)).to.contain(692); + expect(data.persons.map((r) => r.id)).to.contain(5); + expect(data.persons.length).to.be.above(15); + expect(data.memberships.find((r) => (r.personIds = 5 && r.groupId == 692))); + }).timeout(10000); +}); diff --git a/test/ctservice.test.js b/test/ctservice.test.js index 454923b..880e9d8 100644 --- a/test/ctservice.test.js +++ b/test/ctservice.test.js @@ -1,7 +1,8 @@ const chai = require('chai'); const assertArrays = require('chai-arrays'); + chai.use(assertArrays); -const expect = chai.expect; +const { expect } = chai; const log = require('../src/logging'); const ctservice = require('../src/ctservice'); @@ -13,21 +14,19 @@ const site = { }; describe('Church Tools Services', () => { - before( () => { - log.logger.level = 'silent' - }) + before(() => { + log.logger.level = 'silent'; + }); it('getPersonsInGroups - gets unique person ids', async () => { - ctservice.mockGetGroups((g, a, s) => { - return { - data: [ - { personId: 1 }, - { personId: 3 }, - { personId: 2 }, - { personId: 3 }, - { personId: 1 }, - ], - }; - }); + ctservice.mockGetGroups((g, a, s) => ({ + data: [ + { personId: 1 }, + { personId: 3 }, + { personId: 2 }, + { personId: 3 }, + { personId: 1 }, + ], + })); const actual = await ctservice.getPersonsInGroups([], {}); expect(actual).to.be.containingAllOf([1, 3, 2]); }); @@ -39,9 +38,7 @@ describe('Church Tools Services', () => { { personId: 3, groupId: 1 }, { personId: 1, groupId: 2 }, ]; - ctservice.mockGetGroups((g, a, s) => { - return { data: expected }; - }); + ctservice.mockGetGroups((g, a, s) => ({ data: expected })); const actual = await ctservice.getGroupMemberships([], {}); expect(actual).to.be.ofSize(5); expect(actual[3].personId).to.be.equal(3); @@ -52,9 +49,7 @@ describe('Church Tools Services', () => { { id: 1, guid: 1, name: 'ab' }, { id: 3, guid: 2, name: 'cb' }, ]; - ctservice.mockGetGroups((g, a, s) => { - return { data: expected }; - }); + ctservice.mockGetGroups((g, a, s) => ({ data: expected })); const actual = await ctservice.getGroups([], {}); expect(actual).to.be.ofSize(2); expect(actual[1].id).to.be.equal(expected[1].id); diff --git a/test/e2e.integration.js b/test/e2e.integration.js index 4e1ac0d..401f350 100644 --- a/test/e2e.integration.js +++ b/test/e2e.integration.js @@ -1,231 +1,247 @@ -const chai = require("chai") -const expect = chai.expect -chai.use(require("chai-as-promised")); - -const log = require("../src/logging") -const config = require("../production/config.json") -const data = require("../production/ctdata.json") -const main = require("../src/main") -const ldap = require('ldapjs'); +const chai = require('chai'); + +const { expect } = chai; +chai.use(require('chai-as-promised')); -var client = {}; +const ldap = require('ldapjs'); +const log = require('../src/logging'); +const config = require('../production/config.json'); +const data = require('../production/ctdata.json'); +const main = require('../src/main'); +let client = {}; function searchWrapper(search, expectEntries, done, options) { -const entries = []; -const searchOptions = (options?options:{ scope: "base"}) -client.search(search, searchOptions, (err,res)=>{ - res.on('searchEntry', - (entry) => { - entries.push(entry); - }); - res.on('error', (err) => { - log.debug(err) - done() - chai.assert.fail(err.lde_message) - }); - res.on('end', (result) => { - expect(result.status).to.equal(0) - expectEntries(entries) - done() + const entries = []; + const searchOptions = (options || { scope: 'base' }); + client.search(search, searchOptions, (err, res) => { + res.on( + 'searchEntry', + (entry) => { + entries.push(entry); + }, + ); + res.on('error', (err) => { + log.debug(err); + done(); + chai.assert.fail(err.lde_message); }); - }) + res.on('end', (result) => { + expect(result.status).to.equal(0); + expectEntries(entries); + done(); + }); + }); } function boundSearchWrapper(search, expectEntries, done, options) { - client.bind("cn=admin,dc=ccfreiburg,dc=de", "adminpw", (err) => { + client.bind('cn=admin,dc=ccfreiburg,dc=de', 'adminpw', (err) => { if (err) { - done() - chai.assert.fail(err.lde_message) + done(); + chai.assert.fail(err.lde_message); } else { - searchWrapper(search, expectEntries, - done, options ) + searchWrapper( + search, + expectEntries, + done, + options, + ); } - }) + }); } +describe('LDAP Client Server E2E Tests (e2e.integration)', () => { + before(async () => { + log.logger.level = 'silent'; -describe("LDAP Client Server E2E Tests (e2e.integration)", () => { - - before( async () => { - log.logger.level = 'silent' - - await main.start(config, - async () => data, // data func mock - (site) => async (u,p) => { return p==="alex" }, // pasword check mock - (ip,port) => {}); + await main.start( + config, + async () => data, // data func mock + (site) => async (u, p) => p === 'alex', // pasword check mock + (ip, port) => {}, + ); client = ldap.createClient({ - url: ['ldap://127.0.0.1:1389'] + url: ['ldap://127.0.0.1:1389'], }); - + client.on('error', (err) => { - log.debug(err) - }) - - }) + log.debug(err); + }); + }); - after( () => { + after(() => { main.ldapjs.stopServer(); client.destroy(); - } - ) - it("LDAP server started and LDAP Client connected", (done) => { + }); + it('LDAP server started and LDAP Client connected', (done) => { const callback = (err, count) => { - expect(count).to.equal(1) - done() - } - main.ldapjs.getConnections(callback) + expect(count).to.equal(1); + done(); + }; + main.ldapjs.getConnections(callback); }); - it("Get Schema", (done) => { + it('Get Schema', (done) => { searchWrapper( - "dn=schema", + 'dn=schema', (entries) => { - expect(entries[0].dn).to.equal("dc=ccfreiburg,dc=de")//"cn=root") - }, - done) - }) + expect(entries[0].dn).to.equal('dc=ccfreiburg,dc=de');// "cn=root") + }, + done, + ); + }); - it("Auth Admin User", (done) => { - client.bind("cn=admin,dc=ccfreiburg,dc=de", "adminpw", (err) => { + it('Auth Admin User', (done) => { + client.bind('cn=admin,dc=ccfreiburg,dc=de', 'adminpw', (err) => { if (err) { - chai.assert.fail(err.lde_message) + chai.assert.fail(err.lde_message); } else { - chai.assert(true) + chai.assert(true); } - done() - }) - }) + done(); + }); + }); - it("Auth Directory User", (done) => { - client.bind("cn=alex.roehm,ou=users,dc=ccfreiburg,dc=de", "alex", (err) => { + it('Auth Directory User', (done) => { + client.bind('cn=alex.roehm,ou=users,dc=ccfreiburg,dc=de', 'alex', (err) => { if (err) { - chai.assert.fail(err.lde_message) + chai.assert.fail(err.lde_message); } else { - chai.assert(true) + chai.assert(true); } - done() - }) - }) + done(); + }); + }); - it("Get dc - groups fails with insuff rights", (done) => { - client.search("ou=groups,dc=ccfreiburg,dc=de", (err,res)=>{ + it('Get dc - groups fails with insuff rights', (done) => { + client.search('ou=groups,dc=ccfreiburg,dc=de', (err, res) => { res.on('searchEntry', (entry) => { - chai.assert.fail("Should not receive entry") - done() - }) + chai.assert.fail('Should not receive entry'); + done(); + }); res.on('error', (err) => { - expect(err).instanceOf(ldap.InsufficientAccessRightsError) - done() - }) - }) - }) + expect(err).instanceOf(ldap.InsufficientAccessRightsError); + done(); + }); + }); + }); - it("Get dc - groups", (done) => { + it('Get dc - groups', (done) => { boundSearchWrapper( - "ou=groups,dc=ccfreiburg,dc=de", + 'ou=groups,dc=ccfreiburg,dc=de', (entries) => { - expect(entries).to.have.length.above(3) - }, - done) - }) + expect(entries).to.have.length.above(3); + }, + done, + ); + }); - it("Get dc - group detail", (done) => { + it('Get dc - group detail', (done) => { boundSearchWrapper( - "cn=kleingruppen,ou=groups,dc=ccfreiburg,dc=de", + 'cn=kleingruppen,ou=groups,dc=ccfreiburg,dc=de', (entries) => { - expect(entries).to.have.length(1) - expect(entries[0].dn).to.equal("cn=kleingruppen,ou=groups,dc=ccfreiburg,dc=de") - }, - done) - }) + expect(entries).to.have.length(1); + expect(entries[0].dn).to.equal('cn=kleingruppen,ou=groups,dc=ccfreiburg,dc=de'); + }, + done, + ); + }); - it("Get dc - users", (done) => { + it('Get dc - users', (done) => { boundSearchWrapper( - "ou=users,dc=ccfreiburg,dc=de", + 'ou=users,dc=ccfreiburg,dc=de', (entries) => { - expect(entries).to.have.length.above(10) - }, - done, { scope:"sub" }) - }) - - it("Get dc - a user", (done) => { + expect(entries).to.have.length.above(10); + }, + done, + { scope: 'sub' }, + ); + }); + + it('Get dc - a user', (done) => { boundSearchWrapper( - "cn=alex.roehm,ou=users,dc=ccfreiburg,dc=de", + 'cn=alex.roehm,ou=users,dc=ccfreiburg,dc=de', (entries) => { - expect(entries).to.have.length(1) - }, - done) - }) + expect(entries).to.have.length(1); + }, + done, + ); + }); - it("Get dc - groups and users", (done) => { + it('Get dc - groups and users', (done) => { boundSearchWrapper( - "dc=ccfreiburg,dc=de", + 'dc=ccfreiburg,dc=de', (entries) => { - expect(entries).to.have.length.above(13) - }, - done) - }) + expect(entries).to.have.length.above(13); + }, + done, + ); + }); - it("Get dc - query base dn", (done) => { + it('Get dc - query base dn', (done) => { boundSearchWrapper( - "dc=ccfreiburg,dc=de", + 'dc=ccfreiburg,dc=de', (entries) => { - expect(entries).to.have.length(1) - expect(entries[0].dn).to.equal("dc=ccfreiburg,dc=de") - }, - done, { scope:"one" }) - }) + expect(entries).to.have.length(1); + expect(entries[0].dn).to.equal('dc=ccfreiburg,dc=de'); + }, + done, + { scope: 'one' }, + ); + }); - it("Get dc - query base dn like nextcloud for users", (done) => { + it('Get dc - query base dn like nextcloud for users', (done) => { boundSearchWrapper( - "dc=ccfreiburg,dc=de", + 'dc=ccfreiburg,dc=de', (entries) => { - expect(entries).to.have.length.above(13) - }, - done, { scope:"sub", filter: "(&(objectclass=nextclouduser)(displayname=*))" }) - }) + expect(entries).to.have.length.above(13); + }, + done, + { scope: 'sub', filter: '(&(objectclass=nextclouduser)(displayname=*))' }, + ); + }); - it("Get dc - query admin group", (done) => { + it('Get dc - query admin group', (done) => { boundSearchWrapper( - "cn=admin,ou=groups,dc=ccfreiburg,dc=de", + 'cn=admin,ou=groups,dc=ccfreiburg,dc=de', (entries) => { - expect(entries).to.have.length(1) - }, - done, { scope:"sub", filter: "(objectclass=group)" }) - }) - - xit("Get dc - query throws", (done) => { - searchWrapper( - 'cn=eroor,ou=error,dc=error,o=error', () => {}, done) - }) + expect(entries).to.have.length(1); + }, + done, + { scope: 'sub', filter: '(objectclass=group)' }, + ); + }); + xit('Get dc - query throws', (done) => { + searchWrapper('cn=eroor,ou=error,dc=error,o=error', () => {}, done); + }); - it("Get dc - query base dn like nextcloud", (done) => { + it('Get dc - query base dn like nextcloud', (done) => { const entries = []; - const searchOptions = {scope: "sub", filter: "(&(|(objectclass=nextclouduser)))"} - client.bind("cn=admin,dc=ccfreiburg,dc=de", "adminpw", (err) => { + const searchOptions = { scope: 'sub', filter: '(&(|(objectclass=nextclouduser)))' }; + client.bind('cn=admin,dc=ccfreiburg,dc=de', 'adminpw', (err) => { if (err) { - done() - chai.assert.fail(err.lde_message) + done(); + chai.assert.fail(err.lde_message); } else { - client.search("dc=ccfreiburg,dc=de", searchOptions, (err,res)=>{ - res.on('searchEntry', - (entry) => { - entries.push(entry); - }); - res.on('error', (err) => { - log.debug(err) - done() - chai.assert.fail(err.lde_message) - }); - res.on('end', (result) => { - expect(result.status).to.equal(0) - done() + client.search('dc=ccfreiburg,dc=de', searchOptions, (err, res) => { + res.on( + 'searchEntry', + (entry) => { + entries.push(entry); + }, + ); + res.on('error', (err) => { + log.debug(err); + done(); + chai.assert.fail(err.lde_message); + }); + res.on('end', (result) => { + expect(result.status).to.equal(0); + done(); + }); }); - }) - - }}) - }) + } + }); + }); }); - diff --git a/test/ldapcache.test.js b/test/ldapcache.test.js index 3e2c5c5..7b1c70e 100644 --- a/test/ldapcache.test.js +++ b/test/ldapcache.test.js @@ -1,121 +1,121 @@ -const chai = require("chai") -const log = require('../src/logging') -const cache = require("../src/ldapcache") -const deepEqualInAnyOrder = require('deep-equal-in-any-order') -chai.use(deepEqualInAnyOrder) -const expect = chai.expect +const chai = require('chai'); +const deepEqualInAnyOrder = require('deep-equal-in-any-order'); +const log = require('../src/logging'); +const cache = require('../src/ldapcache'); -const emptyRoots = {dsn: {}, users: {}, gropups: {}} +chai.use(deepEqualInAnyOrder); +const { expect } = chai; -describe("LDAP Cache", () => { - before( () => { - log.logger.level = 'silent' - }) - it("init - makes them available through returned functions", () => { +const emptyRoots = { dsn: {}, users: {}, gropups: {} }; + +describe('LDAP Cache', () => { + before(() => { + log.logger.level = 'silent'; + }); + it('init - makes them available through returned functions', () => { const roots = emptyRoots; - const myRoot = {dn: "MyRoot"} + const myRoot = { dn: 'MyRoot' }; roots.dsn = myRoot; - const myAdmin = { dn: "MyAdmin" } - const cachefunct = cache.init("vip", roots, myAdmin ) - expect(cachefunct.getGlobals().rootDn).to.deep.equalInAnyOrder(myRoot) - expect(cachefunct.getGlobals().adminDn).to.deep.equalInAnyOrder(myAdmin) - expect(cachefunct.getGlobals().schemaDn.dn).to.equals("cn=Subschema") - }) - it("checkAuthentication - works for admin", async () => { - const myAdmin = "MyAdmin" - const password = "pass1234" - var wasCalled = false + const myAdmin = { dn: 'MyAdmin' }; + const cachefunct = cache.init('vip', roots, myAdmin); + expect(cachefunct.getGlobals().rootDn).to.deep.equalInAnyOrder(myRoot); + expect(cachefunct.getGlobals().adminDn).to.deep.equalInAnyOrder(myAdmin); + expect(cachefunct.getGlobals().schemaDn.dn).to.equals('cn=Subschema'); + }); + it('checkAuthentication - works for admin', async () => { + const myAdmin = 'MyAdmin'; + const password = 'pass1234'; + let wasCalled = false; const ctAuthMock = () => { - wasCalled = true - } - const cachefunct = cache.init("vip", emptyRoots, { dn: myAdmin }, password, ctAuthMock ) - const actual = await cachefunct.checkAuthentication(myAdmin, password) - expect(actual).to.equal(true) - expect(wasCalled).to.equal(false) - }) - it("checkAuthentication - rejected for wrong admin password", async () => { - const myAdmin = "MyAdmin" - const password = "pass1234" - var wasCalled = false + wasCalled = true; + }; + const cachefunct = cache.init('vip', emptyRoots, { dn: myAdmin }, password, ctAuthMock); + const actual = await cachefunct.checkAuthentication(myAdmin, password); + expect(actual).to.equal(true); + expect(wasCalled).to.equal(false); + }); + it('checkAuthentication - rejected for wrong admin password', async () => { + const myAdmin = 'MyAdmin'; + const password = 'pass1234'; + let wasCalled = false; const ctAuthMock = () => { - wasCalled = true - } - const cachefunct = cache.init("vip", {}, { dn: myAdmin }, password, ctAuthMock ) - const actual = await cachefunct.checkAuthentication(myAdmin, "wrongpassword") - expect(actual).to.equal(false) - expect(wasCalled).to.equal(false) - }) - it("checkAuthentication - blocks admin after 5 trys even when password is then right", async () => { - const myAdmin = "MyAdmin" - const password = "pass1234" - var wasCalled = false + wasCalled = true; + }; + const cachefunct = cache.init('vip', {}, { dn: myAdmin }, password, ctAuthMock); + const actual = await cachefunct.checkAuthentication(myAdmin, 'wrongpassword'); + expect(actual).to.equal(false); + expect(wasCalled).to.equal(false); + }); + it('checkAuthentication - blocks admin after 5 trys even when password is then right', async () => { + const myAdmin = 'MyAdmin'; + const password = 'pass1234'; + let wasCalled = false; const ctAuthMock = () => { - wasCalled = true - } - const cachefunct = cache.init("vip", {}, { dn: myAdmin }, password, ctAuthMock ) - var actual = false - var count = 0; + wasCalled = true; + }; + const cachefunct = cache.init('vip', {}, { dn: myAdmin }, password, ctAuthMock); + let actual = false; + let count = 0; while (!actual && count < 6) { - actual = await cachefunct.checkAuthentication(myAdmin, "wrongpassword") - count ++; - expect(actual).to.equal(false) + actual = await cachefunct.checkAuthentication(myAdmin, 'wrongpassword'); + count++; + expect(actual).to.equal(false); } - expect(wasCalled).to.equal(false) - actual = await cachefunct.checkAuthentication(myAdmin, password) - expect(actual).to.equal(false) + expect(wasCalled).to.equal(false); + actual = await cachefunct.checkAuthentication(myAdmin, password); + expect(actual).to.equal(false); }); - it("checkAuthentication - does not block admin 4 trys when password is then right", async () => { - const myAdmin = "MyAdmin" - const password = "pass1234" - var wasCalled = false + it('checkAuthentication - does not block admin 4 trys when password is then right', async () => { + const myAdmin = 'MyAdmin'; + const password = 'pass1234'; + let wasCalled = false; const ctAuthMock = () => { - wasCalled = true - } - cache.getUserPropertyForAuth = (u,s) => u - const cachefunct = cache.init("vip", {}, { dn: myAdmin }, password, ctAuthMock ) - var actual = false - var count = 0; + wasCalled = true; + }; + cache.getUserPropertyForAuth = (u, s) => u; + const cachefunct = cache.init('vip', {}, { dn: myAdmin }, password, ctAuthMock); + let actual = false; + let count = 0; while (!actual && count < 3) { - actual = await cachefunct.checkAuthentication(myAdmin, "wrongpassword") - count ++; - expect(actual).to.equal(false) + actual = await cachefunct.checkAuthentication(myAdmin, 'wrongpassword'); + count++; + expect(actual).to.equal(false); } - actual = await cachefunct.checkAuthentication(myAdmin, password) - expect(wasCalled).to.equal(false) - expect(actual).to.equal(true) + actual = await cachefunct.checkAuthentication(myAdmin, password); + expect(wasCalled).to.equal(false); + expect(actual).to.equal(true); }); - it("checkAuthentication - for non admin calls handed function", async () => { - const myAdmin = "MyAdmn" - var wasCalled = false - var user = "user1" - var password = "password2" + it('checkAuthentication - for non admin calls handed function', async () => { + const myAdmin = 'MyAdmn'; + let wasCalled = false; + const user = 'user1'; + const password = 'password2'; const ctAuthMock = (u, p) => { - wasCalled = true - expect(u).to.equal(user) - expect(p).to.equal(password) - } - const cachefunct = cache.init("vip", {}, { dn: "asdfas" }, "", ctAuthMock ) - const actual = await cachefunct.checkAuthentication(user, password) - expect(wasCalled).to.equal(true) - }) - it("checkAuthentication - blocks multiple failed auths also on external auth funct", async () => { - const user = "usrar" - const trys = 10 - var count = 0 + wasCalled = true; + expect(u).to.equal(user); + expect(p).to.equal(password); + }; + const cachefunct = cache.init('vip', {}, { dn: 'asdfas' }, '', ctAuthMock); + const actual = await cachefunct.checkAuthentication(user, password); + expect(wasCalled).to.equal(true); + }); + it('checkAuthentication - blocks multiple failed auths also on external auth funct', async () => { + const user = 'usrar'; + const trys = 10; + let count = 0; const ctAuthMock = (u, p) => { - count++ - return false - } - cache.getUserPropertyForAuth = (u,s) => u - const cachefunct = cache.init("vip", {}, { dn: "myAdmin" }, "", ctAuthMock ) - var actual = await cachefunct.checkAuthentication(user, " adfsas") - var i = 0 + count++; + return false; + }; + cache.getUserPropertyForAuth = (u, s) => u; + const cachefunct = cache.init('vip', {}, { dn: 'myAdmin' }, '', ctAuthMock); + let actual = await cachefunct.checkAuthentication(user, ' adfsas'); + let i = 0; while (i < trys) { - i++ - actual = await cachefunct.checkAuthentication(user, "pas") + i++; + actual = await cachefunct.checkAuthentication(user, 'pas'); } - expect(actual).to.equal(false) - expect(count).to.be.lessThan(trys) - }) + expect(actual).to.equal(false); + expect(count).to.be.lessThan(trys); + }); }); - \ No newline at end of file diff --git a/test/main.integration.js b/test/main.integration.js index ee344b4..8ae0ab1 100644 --- a/test/main.integration.js +++ b/test/main.integration.js @@ -1,7 +1,8 @@ const chai = require('chai'); const deepEqualInAnyOrder = require('deep-equal-in-any-order'); + chai.use(deepEqualInAnyOrder); -const expect = chai.expect; +const { expect } = chai; const main = require('../src/main'); const log = require('../src/logging'); const ldapcache = require('../src/ldapcache'); @@ -38,22 +39,22 @@ describe('Main: Production data to Ldap', () => { ], memberships: [{ personId: 2, groupId: 1 }], }; - const {updaters, stop} = await main.start( + const { updaters, stop } = await main.start( config, - async () => data, // data func mock - () => {}, // pasword check mock - () => { log.debug("Started") } // server started cb - ); + async () => data, // data func mock + () => {}, // pasword check mock + () => { log.debug('Started'); }, // server started cb + ); data.persons[0].lastName = 'Lustig'; data.groups[0].name = 'updated'; // simulate timer - await main.update(updaters) + await main.update(updaters); expect(ldapcache.getUserById('ccf', 2).attributes.sn).to.equal('Lustig'); expect(ldapcache.getGroupById('ccf', 1).attributes.cn).to.equal('updated'); - + // test works but doesnot finsch - is in some async wait thing }); }); diff --git a/test/transform.integration.js b/test/transform.integration.js index b87cec9..66f9b95 100644 --- a/test/transform.integration.js +++ b/test/transform.integration.js @@ -1,17 +1,18 @@ -const chai = require("chai"); +const chai = require('chai'); const deepEqualInAnyOrder = require('deep-equal-in-any-order'); + chai.use(deepEqualInAnyOrder); -const expect = chai.expect -const transform = require("../src/transform.js"); -const ctdata = require("../production/ctdata.json"); -const site = require("../production/config.json"); -const ldap = require("../production/ldap.json"); +const { expect } = chai; +const transform = require('../src/transform.js'); +const ctdata = require('../production/ctdata.json'); +const site = require('../production/config.json'); +const ldap = require('../production/ldap.json'); -describe("Transorm Production data to Ldap", () => { - it("Equals Snapshot", () => { - const ldapconf = site.sites.ccf.ldap - const adminuser = transform.getAdmin(ldapconf.admincn, ldapconf.dc) - const ldapData = transform.getLdapData(site.sites.ccf, ctdata, adminuser) +describe('Transorm Production data to Ldap', () => { + it('Equals Snapshot', () => { + const ldapconf = site.sites.ccf.ldap; + const adminuser = transform.getAdmin(ldapconf.admincn, ldapconf.dc); + const ldapData = transform.getLdapData(site.sites.ccf, ctdata, adminuser); expect(ldapData).to.deep.equalInAnyOrder(ldap); - }) + }); }); diff --git a/test/transform.test.js b/test/transform.test.js index cf0ade3..dbbff3b 100644 --- a/test/transform.test.js +++ b/test/transform.test.js @@ -1,78 +1,80 @@ -const chai = require("chai"); +const chai = require('chai'); chai.use(require('chai-arrays')); chai.use(require('chai-string')); -const expect = chai.expect -const transform = require("../src/transform.js"); -//const userMockData = require("./data/getUsersData.json"); -DataFormatError = transform.DataFormatError; +const { expect } = chai; +const transform = require('../src/transform.js'); +// const userMockData = require("./data/getUsersData.json"); +DataFormatError = transform.DataFormatError; -describe("Transorm API results to Ldap", () => { - it("transformGroup from empty json object throws exception", () => { - expect(() => transform.transformGroup({}, {}, "")).to.throw(DataFormatError); +describe('Transorm API results to Ldap', () => { + it('transformGroup from empty json object throws exception', () => { + expect(() => transform.transformGroup({}, {}, '')).to.throw(DataFormatError); }); - it("transformGroup json object does contain data", () => { + it('transformGroup json object does contain data', () => { actual = transform.transformGroup( { id: 2, guid: 'FC8ED-B948-46AA-A48C-2CFD7DED910C', - name: 'This Group' + name: 'This Group', }, { - "gid": 2, - "name": "newGRoupname" + gid: 2, + name: 'newGRoupname', }, - "sitename" + 'sitename', ); - expect(actual.dn).to.startsWith("cn=newgroupname"); - expect(actual.attributes.cn).to.be.equal("newGRoupname"); + expect(actual.dn).to.startsWith('cn=newgroupname'); + expect(actual.attributes.cn).to.be.equal('newGRoupname'); expect(actual.attributes.id).to.be.equal(2); - expect(actual.attributes).to.haveOwnProperty("guid"); - }) - it("transformUser from empty json object throws exception", () => { - expect(() => transform.transformUser({}, "")).to.throw(DataFormatError); + expect(actual.attributes).to.haveOwnProperty('guid'); + }); + it('transformUser from empty json object throws exception', () => { + expect(() => transform.transformUser({}, '')).to.throw(DataFormatError); }); - it("addConfigAttributes adds the attribute to any id", () => { + it('addConfigAttributes adds the attribute to any id', () => { const attributes = [{ - "name": "bbbrole", - "default": "user", - "replacements": [ - { - "id": 5, - "value": "admin" - } - ]}] + name: 'bbbrole', + default: 'user', + replacements: [ + { + id: 5, + value: 'admin', + }, + ], + }]; const ctperson = { - attributes: { - id: 1 - } - } - transform.addConfigAttributes(ctperson,attributes) - expect(ctperson.attributes).to.haveOwnProperty("bbbrole") - expect(ctperson.attributes.bbbrole).to.be.equal("user") - }) - it("addConfigAttributes adds the replacment value", () => { + attributes: { + id: 1, + }, + }; + transform.addConfigAttributes(ctperson, attributes); + expect(ctperson.attributes).to.haveOwnProperty('bbbrole'); + expect(ctperson.attributes.bbbrole).to.be.equal('user'); + }); + it('addConfigAttributes adds the replacment value', () => { const attributes = [{ - "name": "bbbrole", - "default": "user", - "replacements": [ - { - "id": 5, - "value": "admin" - } - ]}] + name: 'bbbrole', + default: 'user', + replacements: [ + { + id: 5, + value: 'admin', + }, + ], + }]; const ctperson = { - attributes: { - id: 5 - } - } - transform.addConfigAttributes(ctperson,attributes) - expect(ctperson.attributes).to.haveOwnProperty("bbbrole") - expect(ctperson.attributes.bbbrole).to.be.equal("admin") - }) - it("transformUser minmal json object does not throw", () => { - const person = { + attributes: { + id: 5, + }, + }; + transform.addConfigAttributes(ctperson, attributes); + expect(ctperson.attributes).to.haveOwnProperty('bbbrole'); + expect(ctperson.attributes.bbbrole).to.be.equal('admin'); + }); + it('transformUser minmal json object does not throw', () => { + const person = { id: 144, guid: '274401F0-637A-4089-98DB-9345AF3B19D8', firstName: 'Peter', @@ -84,44 +86,44 @@ describe("Transorm API results to Ldap", () => { zip: '', city: '', email: 'peter.pan@pan-demi.org', - ncuid: 'peter.pan' - } - const actual = transform.transformUser(person, [], "site") - expect(actual.dn).to.startsWith("cn=peter.pan"); - expect(actual.attributes.cn).to.be.equal("peter.pan"); - expect(actual.attributes.uid).to.be.equal("peter.pan"); + ncuid: 'peter.pan', + }; + const actual = transform.transformUser(person, [], 'site'); + expect(actual.dn).to.startsWith('cn=peter.pan'); + expect(actual.attributes.cn).to.be.equal('peter.pan'); + expect(actual.attributes.uid).to.be.equal('peter.pan'); expect(actual.attributes.id).to.be.equal(144); }); - it("connectUsersAndGroups adds group to person and person to group", () => { - const membership = { personId: 12, groupId: 692 } - const person = { dn: "ab", attributes: { id: 12, memberOf: [] } } - const group = { dn: "cd", attributes: { id: 692, uniqueMember: [] } } - transform.connectUsersAndGroups([membership], [group], [person], []) - expect(person.attributes.memberOf).to.include("cd") - expect(group.attributes.uniqueMember).to.include("ab") - }) - it("connectUsersAndGroups adds objectClass to user for configured group", () => { - const membership = { personId: 12, groupId: 692 } - const person = { dn: "ab", attributes: { id: 12, objectClass: [], memberOf: [] } } - const group = { dn: "cd", attributes: { id: 692, uniqueMember: [] } } - const grptransf = { gid: 692, objectClass: "ef" } - transform.connectUsersAndGroups([membership], [group], [person], [grptransf]) - expect(person.attributes.objectClass).to.include("ef") - }) - it("addUsersAdminGroup - adds Ldap admin user", () => { - const users = [] - const ldapad = { dn: "hey", attributes: {memberOf: []}} - const actual = transform.addUsersAdminGroup(users,ldapad,[4],"admin","dcdc") - expect(actual.dn).to.equal("cn=admin,ou=groups,dcdc") - expect(actual.attributes.uniqueMember).to.have.length(1) - expect(actual.attributes.uniqueMember[0]).to.equal(ldapad.dn) - }) - it("addUsersAdminGroup - adds users with matching ids", () => { - const users = [{ dn: "hho", attributes: { id: 4, memberOf: []}}] - const ldapad = { dn: "hey", attributes: {memberOf: []}} - const actual = transform.addUsersAdminGroup(users,ldapad,[4],"admin","dcdc") - expect(actual.dn).to.equal("cn=admin,ou=groups,dcdc") - expect(actual.attributes.uniqueMember).to.have.length(2) - expect(actual.attributes.uniqueMember).to.include("hho") - }) + it('connectUsersAndGroups adds group to person and person to group', () => { + const membership = { personId: 12, groupId: 692 }; + const person = { dn: 'ab', attributes: { id: 12, memberOf: [] } }; + const group = { dn: 'cd', attributes: { id: 692, uniqueMember: [] } }; + transform.connectUsersAndGroups([membership], [group], [person], []); + expect(person.attributes.memberOf).to.include('cd'); + expect(group.attributes.uniqueMember).to.include('ab'); + }); + it('connectUsersAndGroups adds objectClass to user for configured group', () => { + const membership = { personId: 12, groupId: 692 }; + const person = { dn: 'ab', attributes: { id: 12, objectClass: [], memberOf: [] } }; + const group = { dn: 'cd', attributes: { id: 692, uniqueMember: [] } }; + const grptransf = { gid: 692, objectClass: 'ef' }; + transform.connectUsersAndGroups([membership], [group], [person], [grptransf]); + expect(person.attributes.objectClass).to.include('ef'); + }); + it('addUsersAdminGroup - adds Ldap admin user', () => { + const users = []; + const ldapad = { dn: 'hey', attributes: { memberOf: [] } }; + const actual = transform.addUsersAdminGroup(users, ldapad, [4], 'admin', 'dcdc'); + expect(actual.dn).to.equal('cn=admin,ou=groups,dcdc'); + expect(actual.attributes.uniqueMember).to.have.length(1); + expect(actual.attributes.uniqueMember[0]).to.equal(ldapad.dn); + }); + it('addUsersAdminGroup - adds users with matching ids', () => { + const users = [{ dn: 'hho', attributes: { id: 4, memberOf: [] } }]; + const ldapad = { dn: 'hey', attributes: { memberOf: [] } }; + const actual = transform.addUsersAdminGroup(users, ldapad, [4], 'admin', 'dcdc'); + expect(actual.dn).to.equal('cn=admin,ou=groups,dcdc'); + expect(actual.attributes.uniqueMember).to.have.length(2); + expect(actual.attributes.uniqueMember).to.include('hho'); + }); }); From 218f29e5c3b22d06f9292bf234df179e1adaf493 Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Fri, 16 Dec 2022 16:13:14 +0100 Subject: [PATCH 9/9] Track package-lock.json in git as recommended --- package-lock.json | 4901 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4901 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f8eb3ff --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4901 @@ +{ + "name": "ccf-ctldap", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "ccf-ctldap", + "version": "1.0.0", + "license": "GPL-3.0-or-later", + "dependencies": { + "axios": "^0.21.4", + "ldap-escape": "^2.0.5", + "ldapjs": "^2.3.1", + "path": "^0.12.7", + "pino": "^8.6.0", + "pino-pretty": "^9.1.0", + "yamljs": "^0.3.0" + }, + "devDependencies": { + "chai": "^4.3.4", + "chai-arrays": "^2.2.0", + "chai-as-promised": "^7.1.1", + "chai-string": "^1.5.0", + "deep-equal-in-any-order": "^2.0.0", + "eslint": "^8.27.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.26.0", + "mocha": "^8.3.2", + "pino-pretty": "^9.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.7", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "dev": true, + "license": "ISC" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.8.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-includes": { + "version": "3.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/axios": { + "version": "0.21.4", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/backoff": { + "version": "2.5.0", + "license": "MIT", + "dependencies": { + "precond": "0.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/buffer": { + "version": "6.0.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-arrays": { + "version": "2.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "dev": true, + "license": "WTFPL", + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, + "node_modules/chai-string": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "peerDependencies": { + "chai": "^4.1.2" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.1" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.19", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal-in-any-order": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.mapvalues": "^4.6.0", + "sort-any": "^2.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/define-properties": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-abstract": { + "version": "1.20.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.27.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, + "node_modules/fast-copy": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-redact": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.13.0", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.17.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/growl": { + "version": "1.10.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/help-me": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^8.0.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/help-me/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/help-me/node_modules/glob": { + "version": "8.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/help-me/node_modules/minimatch": { + "version": "5.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/help-me/node_modules/readable-stream": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/joycon": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/js-sdsl": { + "version": "4.1.5", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/ldap-escape": { + "version": "2.0.6", + "license": "ISC" + }, + "node_modules/ldap-filter": { + "version": "0.3.3", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ldapjs": { + "version": "2.3.3", + "license": "MIT", + "dependencies": { + "abstract-logging": "^2.0.0", + "asn1": "^0.2.4", + "assert-plus": "^1.0.0", + "backoff": "^2.5.0", + "ldap-filter": "^0.3.3", + "once": "^1.4.0", + "vasync": "^2.2.0", + "verror": "^1.8.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.mapvalues": { + "version": "4.6.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mocha": { + "version": "8.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "3.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.1.20", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.0", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path": { + "version": "0.12.7", + "license": "MIT", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "8.7.0", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.0.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^2.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.1.0", + "thread-stream": "^2.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "9.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^4.0.1", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "6.0.0", + "license": "MIT" + }, + "node_modules/precond": { + "version": "0.2.3", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "4.2.0", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "3.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.1", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/secure-json-parse": { + "version": "2.5.0", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "5.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sonic-boom": { + "version": "3.2.0", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/sort-any": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/split2": { + "version": "4.1.0", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "license": "BSD-3-Clause" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/thread-stream": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "license": "ISC" + }, + "node_modules/vasync": { + "version": "2.2.1", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "verror": "1.10.0" + } + }, + "node_modules/vasync/node_modules/verror": { + "version": "1.10.0", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror": { + "version": "1.10.1", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.1.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yamljs": { + "version": "0.3.0", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "bin": { + "json2yaml": "bin/json2yaml", + "yaml2json": "bin/yaml2json" + } + }, + "node_modules/yamljs/node_modules/argparse": { + "version": "1.0.10", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "20.2.9", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@eslint/eslintrc": { + "version": "1.3.3", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.11.7", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@types/json5": { + "version": "0.0.29", + "dev": true + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "abstract-logging": { + "version": "2.0.1" + }, + "acorn": { + "version": "8.8.1", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "2.0.1", + "dev": true + }, + "array-includes": { + "version": "3.1.6", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array.prototype.flat": { + "version": "1.3.1", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "asn1": { + "version": "0.2.6", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0" + }, + "assertion-error": { + "version": "1.1.0", + "dev": true + }, + "atomic-sleep": { + "version": "1.0.0" + }, + "axios": { + "version": "0.21.4", + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "backoff": { + "version": "2.5.0", + "requires": { + "precond": "0.2" + } + }, + "balanced-match": { + "version": "1.0.2" + }, + "base64-js": { + "version": "1.5.1" + }, + "binary-extensions": { + "version": "2.2.0", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "dev": true + }, + "buffer": { + "version": "6.0.3", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "call-bind": { + "version": "1.0.2", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "dev": true + }, + "chai": { + "version": "4.3.7", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chai-arrays": { + "version": "2.2.0", + "dev": true + }, + "chai-as-promised": { + "version": "7.1.1", + "dev": true, + "requires": { + "check-error": "^1.0.2" + } + }, + "chai-string": { + "version": "1.5.0", + "dev": true, + "requires": {} + }, + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "dev": true + }, + "chokidar": { + "version": "3.5.1", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "cliui": { + "version": "7.0.4", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "dev": true + }, + "concat-map": { + "version": "0.0.1" + }, + "confusing-browser-globals": { + "version": "1.0.11", + "dev": true + }, + "core-util-is": { + "version": "1.0.2" + }, + "cross-spawn": { + "version": "7.0.3", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "dateformat": { + "version": "4.6.3", + "dev": true + }, + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "dev": true + }, + "deep-eql": { + "version": "4.1.2", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-equal-in-any-order": { + "version": "2.0.0", + "dev": true, + "requires": { + "lodash.mapvalues": "^4.6.0", + "sort-any": "^2.0.0" + } + }, + "deep-is": { + "version": "0.1.4", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "diff": { + "version": "5.0.0", + "dev": true + }, + "doctrine": { + "version": "2.1.0", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "es-abstract": { + "version": "1.20.4", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "dev": true + }, + "eslint": { + "version": "8.27.0", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "doctrine": { + "version": "3.0.0", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-config-airbnb-base": { + "version": "15.0.0", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.7.4", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.26.0", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "dev": true + } + } + }, + "eslint-scope": { + "version": "7.1.1", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "dev": true + }, + "espree": { + "version": "9.4.1", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "dev": true + }, + "event-target-shim": { + "version": "5.0.1" + }, + "events": { + "version": "3.3.0" + }, + "extsprintf": { + "version": "1.4.1" + }, + "fast-copy": { + "version": "3.0.0", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "dev": true + }, + "fast-redact": { + "version": "3.1.2" + }, + "fast-safe-stringify": { + "version": "2.1.1", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2" + }, + "fs.realpath": { + "version": "1.0.0" + }, + "function-bind": { + "version": "1.1.1", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.3", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.3", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.17.0", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "grapheme-splitter": { + "version": "1.0.4", + "dev": true + }, + "growl": { + "version": "1.10.5", + "dev": true + }, + "has": { + "version": "1.0.3", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "he": { + "version": "1.2.0", + "dev": true + }, + "help-me": { + "version": "4.1.0", + "dev": true, + "requires": { + "glob": "^8.0.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "ieee754": { + "version": "1.2.1" + }, + "ignore": { + "version": "5.2.0", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4" + }, + "internal-slot": { + "version": "1.0.3", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "is-bigint": { + "version": "1.0.4", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "dev": true + }, + "is-core-module": { + "version": "2.11.0", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "dev": true + }, + "joycon": { + "version": "3.1.1", + "dev": true + }, + "js-sdsl": { + "version": "4.1.5", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true + }, + "json5": { + "version": "1.0.1", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "ldap-escape": { + "version": "2.0.6" + }, + "ldap-filter": { + "version": "0.3.3", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ldapjs": { + "version": "2.3.3", + "requires": { + "abstract-logging": "^2.0.0", + "asn1": "^0.2.4", + "assert-plus": "^1.0.0", + "backoff": "^2.5.0", + "ldap-filter": "^0.3.3", + "once": "^1.4.0", + "vasync": "^2.2.0", + "verror": "^1.8.1" + } + }, + "levn": { + "version": "0.4.1", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "dev": true + }, + "lodash.mapvalues": { + "version": "4.6.0", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "dev": true + }, + "log-symbols": { + "version": "4.0.0", + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "loupe": { + "version": "2.3.6", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "dev": true + }, + "mocha": { + "version": "8.4.0", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "dev": true + } + } + }, + "glob": { + "version": "7.1.6", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "js-yaml": { + "version": "4.0.0", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "minimatch": { + "version": "3.0.4", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "dev": true + } + } + }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "nanoid": { + "version": "3.1.20", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "dev": true + }, + "object-inspect": { + "version": "1.12.2", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "on-exit-leak-free": { + "version": "2.1.0" + }, + "once": { + "version": "1.4.0", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path": { + "version": "0.12.7", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-exists": { + "version": "4.0.0", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1" + }, + "path-key": { + "version": "3.1.1", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "dev": true + }, + "pino": { + "version": "8.7.0", + "requires": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "v1.0.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^2.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.1.0", + "thread-stream": "^2.0.0" + } + }, + "pino-abstract-transport": { + "version": "1.0.0", + "requires": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "pino-pretty": { + "version": "9.1.1", + "dev": true, + "requires": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^4.0.1", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "pino-std-serializers": { + "version": "6.0.0" + }, + "precond": { + "version": "0.2.3" + }, + "prelude-ls": { + "version": "1.2.1", + "dev": true + }, + "process": { + "version": "0.11.10" + }, + "process-warning": { + "version": "2.0.0" + }, + "pump": { + "version": "3.0.0", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "dev": true + }, + "quick-format-unescaped": { + "version": "4.0.4" + }, + "randombytes": { + "version": "2.1.0", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "4.2.0", + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + } + }, + "readdirp": { + "version": "3.5.0", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "real-require": { + "version": "0.2.0" + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "dev": true + }, + "safe-regex-test": { + "version": "1.0.0", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safe-stable-stringify": { + "version": "2.4.1" + }, + "safer-buffer": { + "version": "2.1.2" + }, + "secure-json-parse": { + "version": "2.5.0", + "dev": true + }, + "semver": { + "version": "6.3.0", + "dev": true + }, + "serialize-javascript": { + "version": "5.0.1", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sonic-boom": { + "version": "3.2.0", + "requires": { + "atomic-sleep": "^1.0.0" + } + }, + "sort-any": { + "version": "2.0.0", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "split2": { + "version": "4.1.0" + }, + "sprintf-js": { + "version": "1.0.3" + }, + "string_decoder": { + "version": "1.3.0", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "4.2.3", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "6.0.1", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "dev": true + }, + "thread-stream": { + "version": "2.2.0", + "requires": { + "real-require": "^0.2.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tsconfig-paths": { + "version": "3.14.1", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "uri-js": { + "version": "4.4.1", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util": { + "version": "0.10.4", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "dev": true + }, + "vasync": { + "version": "2.2.1", + "requires": { + "verror": "1.10.0" + }, + "dependencies": { + "verror": { + "version": "1.10.0", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + } + } + }, + "verror": { + "version": "1.10.1", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which": { + "version": "2.0.2", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "wide-align": { + "version": "1.1.3", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "word-wrap": { + "version": "1.2.3", + "dev": true + }, + "workerpool": { + "version": "6.1.0", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2" + }, + "y18n": { + "version": "5.0.8", + "dev": true + }, + "yamljs": { + "version": "0.3.0", + "requires": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "requires": { + "sprintf-js": "~1.0.2" + } + } + } + }, + "yargs": { + "version": "16.2.0", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "dependencies": { + "yargs-parser": { + "version": "20.2.9", + "dev": true + } + } + }, + "yargs-parser": { + "version": "20.2.4", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "dev": true + } + } +}