From 6266b1432dfe46aad40f7a26efc1b9586ce83f69 Mon Sep 17 00:00:00 2001 From: marzavec Date: Mon, 7 Sep 2020 23:51:47 -0500 Subject: [PATCH 01/37] inital v2 commit --- package-lock.json | 696 ++++++++------------ package.json | 5 +- server/package-lock.json | 21 +- server/src/commands/admin/saveconfig.js | 2 +- server/src/commands/core/changenick.js | 12 +- server/src/commands/core/chat.js | 10 +- server/src/commands/core/emote.js | 5 +- server/src/commands/core/help.js | 2 +- server/src/commands/core/invite.js | 115 +--- server/src/commands/core/join.js | 41 +- server/src/commands/core/move.js | 6 +- server/src/commands/core/session.js | 60 +- server/src/commands/core/whisper.js | 10 +- server/src/commands/internal/disconnect.js | 3 +- server/src/commands/internal/legacylayer.js | 153 ++++- server/src/commands/internal/socketreply.js | 5 +- server/src/commands/mod/ban.js | 16 +- server/src/commands/mod/dumb.js | 20 +- server/src/commands/mod/kick.js | 13 +- server/src/commands/mod/moveuser.js | 4 +- server/src/commands/mod/speak.js | 2 +- server/src/commands/mod/unban.js | 2 +- server/src/serverLib/MainServer.js | 2 +- 23 files changed, 608 insertions(+), 597 deletions(-) diff --git a/package-lock.json b/package-lock.json index 24d0682..8d2934e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "hack.chat-v2", - "version": "2.1.9", + "version": "2.1.93", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -14,6 +14,13 @@ "semver": "^5.5.0", "shimmer": "^1.2.0", "uuid": "^3.2.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "@opencensus/propagation-b3": { @@ -36,25 +43,51 @@ "shimmer": "^1.2.0", "uuid": "^3.2.1" } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, "@pm2/agent": { - "version": "0.5.26", - "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-0.5.26.tgz", - "integrity": "sha512-pqiS87IiUprkSR7SG0RKMATuYXl4QjH1tSSUwM4wJcovRT4pD5dvnnu61w9y/4/Ur5V/+a7bqS8bZz51y3U2iA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-1.0.4.tgz", + "integrity": "sha512-cZLwaoLa45FRuetKCcoI3kHnnQ7VMLpZnmVom04MoK0cpY/RxcSarkCHSCu9V+pdARwxx96QrWdrtAJdw97dng==", "requires": { - "async": "^2.6.0", - "chalk": "^2.3.2", - "eventemitter2": "^5.0.1", - "fclone": "^1.0.11", - "moment": "^2.21.0", - "nssocket": "^0.6.0", + "async": "~3.2.0", + "chalk": "~3.0.0", + "dayjs": "~1.8.24", + "debug": "~4.1.1", + "eventemitter2": "~5.0.1", + "fclone": "~1.0.11", + "nssocket": "0.6.0", "pm2-axon": "^3.2.0", "pm2-axon-rpc": "^0.5.0", - "proxy-agent": "^3.1.0", - "semver": "^5.5.0", - "ws": "^5.1.0" + "proxy-agent": "~3.1.1", + "semver": "~7.2.0", + "ws": "~7.2.0" + }, + "dependencies": { + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "semver": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz", + "integrity": "sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig==" + } } }, "@pm2/agent-node": { @@ -79,82 +112,64 @@ } }, "@pm2/io": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@pm2/io/-/io-4.3.3.tgz", - "integrity": "sha512-ENGsdSVpnwbYMGdeB0/Xy2eZYo7oltzApoCsMD4ssqWNXDg9C4uQZy5J09iPsb0IHFwSDjU5oylXdwKDSoqODw==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-4.3.5.tgz", + "integrity": "sha512-CY/a6Nw72vrlp/FPx38l4jfEHp4gNEbo8i+WlSJ2cnWO6VE6CKmnC1zb4yQLvdP8f3EuzzoOBZVq6aGN20M82Q==", "requires": { - "@opencensus/core": "^0.0.9", - "@opencensus/propagation-b3": "^0.0.8", + "@opencensus/core": "0.0.9", + "@opencensus/propagation-b3": "0.0.8", "@pm2/agent-node": "^1.1.10", "async": "~2.6.1", - "debug": "3.1.0", - "eventemitter2": "~5.0.1", + "debug": "4.1.1", + "eventemitter2": "^6.3.1", "require-in-the-middle": "^5.0.0", - "semver": "5.5.0", - "shimmer": "~1.2.0", - "signal-exit": "3.0.2", + "semver": "6.3.0", + "shimmer": "^1.2.0", + "signal-exit": "^3.0.3", "tslib": "1.9.3" }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "eventemitter2": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.3.tgz", + "integrity": "sha512-t0A2msp6BzOf+QAcI6z9XMktLj52OjGQg+8SJH6v5+3uxNpWYRR3wQmfA+6xtMU9kOC59qk9licus5dYcrYkMQ==" }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" } } }, "@pm2/js-api": { - "version": "0.5.60", - "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.5.60.tgz", - "integrity": "sha512-CvAbpIB7ObOuwvqhDBB/E4Z4ANRx2dBk08zYpGPNg+1fDj14FJg2e7DWA8bblSGNC8QarIXPaqPDJBL1e8cRQw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.6.0.tgz", + "integrity": "sha512-ZgM/0yI8s3FRyxP01wI5UzDrVTecS/SmD98z25C9fsHo2Wz3JB1DtS4uIBlPopq2/R5HIQynTUJPDNn4qo1d/Q==", "requires": { - "async": "^2.4.1", + "async": "^2.6.3", "axios": "^0.19.0", - "debug": "^2.6.8", - "eventemitter2": "^4.1.0", - "ws": "^3.0.0" + "debug": "~3.2.6", + "eventemitter2": "^6.3.1", + "ws": "^7.0.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, "eventemitter2": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-4.1.2.tgz", - "integrity": "sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU=" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.3.tgz", + "integrity": "sha512-t0A2msp6BzOf+QAcI6z9XMktLj52OjGQg+8SJH6v5+3uxNpWYRR3wQmfA+6xtMU9kOC59qk9licus5dYcrYkMQ==" } } }, @@ -176,6 +191,11 @@ } } }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", @@ -202,17 +222,13 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "requires": { - "color-convert": "^1.9.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, "anymatch": { @@ -240,9 +256,12 @@ } }, "ast-types": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz", - "integrity": "sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.1.tgz", + "integrity": "sha512-pfSiukbt23P1qMhNnsozLzhMLBs7EEeXqPyvPmnuZM+RMfwfqwDbSVKYflgGuVI7/VehR4oMks0igzdNAg4VeQ==", + "requires": { + "tslib": "^2.0.1" + } }, "async": { "version": "2.6.3", @@ -264,6 +283,13 @@ "requires": { "semver": "^5.3.0", "shimmer": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } } }, "axios": { @@ -308,20 +334,15 @@ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" }, "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" }, "blessed": { "version": "0.1.81", "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", "integrity": "sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=" }, - "bodec": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", - "integrity": "sha1-vIUVVUMPI8n3ZQp172TGqUw0GMw=" - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -349,14 +370,18 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "charm": { @@ -365,9 +390,9 @@ "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY=" }, "chokidar": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", - "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", @@ -376,39 +401,15 @@ "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.3.0" + "readdirp": "~3.4.0" } }, - "cli-table-redemption": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli-table-redemption/-/cli-table-redemption-1.0.1.tgz", - "integrity": "sha512-SjVCciRyx01I4azo2K2rcc0NP/wOceXGzG1ZpYkEulbbIxDA/5YWv0oxG2HtQ4v8zPC6bgbRI7SbNaTZCxMNkg==", + "cli-tableau": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz", + "integrity": "sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==", "requires": { - "chalk": "^1.1.3" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } + "chalk": "3.0.0" } }, "co": { @@ -417,17 +418,17 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "colors": { "version": "1.4.0", @@ -464,27 +465,22 @@ "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=" }, "cron": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/cron/-/cron-1.7.1.tgz", - "integrity": "sha512-gmMB/pJcqUVs/NklR1sCGlNYM7TizEw+1gebz20BMc/8bTm/r7QUp3ZPSPlG8Z5XRlvb7qhjEjq/+bdIfUCL2A==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/cron/-/cron-1.8.2.tgz", + "integrity": "sha512-Gk2c4y6xKEO8FSAUTklqtfSr7oTq0CiPQeLBG5Fl0qoXpZyMcj1SG59YL+hqq04bu6/IuEA7lMkYDAplQNKkyg==", "requires": { "moment-timezone": "^0.5.x" } }, - "culvert": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", - "integrity": "sha1-lQL18BVKLVoioCPnn3HMk2+m728=" - }, "data-uri-to-buffer": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==" }, - "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + "dayjs": { + "version": "1.8.34", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.34.tgz", + "integrity": "sha512-Olb+E6EoMvdPmAMq2QoucuyZycKHjTlBXmRx8Ada+wGtq4SIXuDCdtoaX4KkK0yjf1fJLnwXQURr8gQKWKaybw==" }, "debug": { "version": "3.2.6", @@ -534,9 +530,9 @@ } }, "enquirer": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.4.tgz", - "integrity": "sha512-pkYrrDZumL2VS6VBGDhqbajCM2xpkUNLuKfGPjfKaSIBKYopQbqEFyrOkRMIb2HDR/rO1kGhEt/5twBwtzKBXw==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz", + "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==", "requires": { "ansi-colors": "^3.2.1" } @@ -559,15 +555,10 @@ "resolved": "https://registry.npmjs.org/escape-regexp/-/escape-regexp-0.0.1.tgz", "integrity": "sha1-9EvaEtRbvfnLf4Yu5+SCez3TIlQ=" }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, "escodegen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", - "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", "requires": { "esprima": "^4.0.1", "estraverse": "^4.2.0", @@ -609,9 +600,9 @@ "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=" }, "eventemitter3": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", - "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "extend": { "version": "3.0.2", @@ -642,12 +633,9 @@ } }, "follow-redirects": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.10.0.tgz", - "integrity": "sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==", - "requires": { - "debug": "^3.0.0" - } + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" }, "fs.realpath": { "version": "1.0.0", @@ -655,9 +643,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", - "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", "optional": true }, "ftp": { @@ -710,16 +698,6 @@ } } }, - "git-node-fs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", - "integrity": "sha1-SbIV4kLr5Dqkx1Ybu6SZUhdSCA8=" - }, - "git-sha1": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/git-sha1/-/git-sha1-0.1.2.tgz", - "integrity": "sha1-WZrBkrcYdYJeE6RF86bgURjC90U=" - }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -734,25 +712,17 @@ } }, "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "requires": { "is-glob": "^4.0.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "he": { "version": "1.2.0", @@ -772,9 +742,9 @@ } }, "http-proxy": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -806,18 +776,18 @@ } }, "http-server": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.1.tgz", - "integrity": "sha512-T0jB+7J7GJ2Vo+a4/T7P7SbQ3x2GPDnqRqQXdfEuPuUOmES/9NBxPnDm7dh1HGEeUWqUmLUNtGV63ZC5Uy3tGA==", + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", + "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", "requires": { "basic-auth": "^1.0.3", - "colors": "^1.3.3", + "colors": "^1.4.0", "corser": "^2.0.1", "ecstatic": "^3.3.2", - "http-proxy": "^1.17.0", + "http-proxy": "^1.18.0", + "minimist": "^1.2.5", "opener": "^1.5.1", - "optimist": "~0.6.1", - "portfinder": "^1.0.20", + "portfinder": "^1.0.25", "secure-compare": "3.0.1", "union": "~0.5.0" } @@ -853,16 +823,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" - }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -899,17 +859,6 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, - "js-git": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", - "integrity": "sha1-UvplWrYYd9bxB578ZTS1VPMeVEQ=", - "requires": { - "bodec": "^0.1.0", - "culvert": "^0.1.2", - "git-sha1": "^0.1.2", - "pako": "^0.2.5" - } - }, "lazy": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", @@ -925,29 +874,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lodash.findindex": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.findindex/-/lodash.findindex-4.6.0.tgz", - "integrity": "sha1-oyRd7mH7m24GJLU1ElYku2nBEQY=" - }, - "lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "lodash.last": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash.last/-/lodash.last-3.0.0.tgz", - "integrity": "sha1-JC9mMRLdTG5jcoxgo8kJ0b2tvUw=" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "log-driver": { "version": "1.2.7", @@ -976,23 +905,16 @@ } }, "minimist": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.4.tgz", - "integrity": "sha512-wTiNDqe4D2rbTJGZk1qcdZgFtY0/r+iuE6GDT7V0/+Gu5MLpIDm4+CssDECR79OJs/OxLPXMzdxy153b5Qy3hg==" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } + "minimist": "^1.2.5" } }, "module-details-from-path": { @@ -1001,14 +923,14 @@ "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" }, "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" }, "moment-timezone": { - "version": "0.5.28", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.28.tgz", - "integrity": "sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw==", + "version": "0.5.31", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", "requires": { "moment": ">= 2.9.0" } @@ -1072,22 +994,6 @@ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==" }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" - } - } - }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -1138,11 +1044,6 @@ "thunkify": "^2.1.2" } }, - "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1154,56 +1055,53 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "picomatch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", - "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==" + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "pidusage": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.17.tgz", - "integrity": "sha512-N8X5v18rBmlBoArfS83vrnD0gIFyZkXEo7a5pAS2aT0i2OLVymFb2AzVg+v8l/QcXnE1JwZcaXR8daJcoJqtjw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.18.tgz", + "integrity": "sha512-Y/VfKfh3poHjMEINxU+gJTeVOBjiThQeFAmzR7z56HSNiMx+etl+yBhk42nRPciPYt/VZl8DQLVXNC6P5vH11A==", "requires": { "safe-buffer": "^5.1.2" } }, "pm2": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/pm2/-/pm2-4.2.3.tgz", - "integrity": "sha512-aRTl8W6dmZ4S2hti1dX4Xvkpy/yIME1H5pMK0HEOpw1H33j4IAfdzScPoPLYaHeh1oL4biabGwxuyClOM8YUVQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-4.4.1.tgz", + "integrity": "sha512-ece2zqVvSg29tIGdznKqk07IwVaO4mX7zLBMVxbJQMfvxpQUotLLERDW0v/RYMHtzj1bX8MLsDUsmPiIbEszKg==", "requires": { - "@pm2/agent": "^0.5.26", - "@pm2/io": "^4.3.2", - "@pm2/js-api": "^0.5.60", + "@pm2/agent": "~1.0.2", + "@pm2/io": "~4.3.5", + "@pm2/js-api": "~0.6.0", "@pm2/pm2-version-check": "^1.0.3", - "async": "^3.1.0", + "async": "~3.2.0", "blessed": "0.1.81", - "chalk": "2.4.2", - "chokidar": "^3.2.0", - "cli-table-redemption": "1.0.1", + "chalk": "3.0.0", + "chokidar": "^3.3.0", + "cli-tableau": "^2.0.0", "commander": "2.15.1", - "cron": "1.7.1", - "date-fns": "1.30.1", + "cron": "1.8.2", + "dayjs": "~1.8.25", "debug": "4.1.1", - "enquirer": "^2.3.2", + "enquirer": "2.3.5", "eventemitter2": "5.0.1", "fclone": "1.0.11", - "lodash": "4.17.14", - "mkdirp": "0.5.1", - "moment": "2.24.0", + "mkdirp": "1.0.4", "needle": "2.4.0", - "pidusage": "2.0.17", + "pidusage": "2.0.18", "pm2-axon": "3.3.0", "pm2-axon-rpc": "0.5.1", - "pm2-deploy": "^0.4.0", + "pm2-deploy": "~1.0.2", "pm2-multimeter": "^0.1.2", "promptly": "^2", "ps-list": "6.3.0", - "semver": "^5.5", - "shelljs": "0.8.3", - "source-map-support": "0.5.12", + "semver": "^7.2", + "source-map-support": "0.5.16", "sprintf-js": "1.1.2", - "systeminformation": "^4.14.16", - "vizion": "~2.0.2", + "systeminformation": "^4.23.3", + "vizion": "0.2.13", "yamljs": "0.3.0" }, "dependencies": { @@ -1220,10 +1118,10 @@ "ms": "^2.1.1" } }, - "lodash": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" } } }, @@ -1247,12 +1145,12 @@ } }, "pm2-deploy": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-0.4.0.tgz", - "integrity": "sha512-3BdCghcGwMKwl3ffHZhc+j5JY5dldH9nq8m/I9W5wehJuSRZIyO96VOgKTMv3hYp7Yk5E+2lRGm8WFNlp65vOA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-1.0.2.tgz", + "integrity": "sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==", "requires": { - "async": "^2.6", - "tv4": "^1.3" + "run-series": "^1.1.8", + "tv4": "^1.3.0" } }, "pm2-multimeter": { @@ -1264,13 +1162,13 @@ } }, "portfinder": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", - "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", "requires": { "async": "^2.6.2", "debug": "^3.1.1", - "mkdirp": "^0.5.1" + "mkdirp": "^0.5.5" } }, "prelude-ls": { @@ -1327,9 +1225,9 @@ "integrity": "sha512-qau0czUSB0fzSlBOQt0bo+I2v6R+xiQdj78e1BR/Qjfl5OHWJ/urXi8+ilw1eHe+5hSeDI1wrwVTgDp2wst4oA==" }, "qs": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", - "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==" + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" }, "raw-body": { "version": "2.4.1", @@ -1342,6 +1240,14 @@ "unpipe": "1.0.0" } }, + "react-icons": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.11.0.tgz", + "integrity": "sha512-JRgiI/vdF6uyBgyZhVyYJUZAop95Sy4XDe/jmT3R/bKliFWpO/uZBwvSjWEdxwzec7SYbEPNPck0Kff2tUGM2Q==", + "requires": { + "camelcase": "^5.0.0" + } + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -1380,19 +1286,11 @@ } }, "readdirp": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", - "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", "requires": { - "picomatch": "^2.0.7" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "requires": { - "resolve": "^1.1.6" + "picomatch": "^2.2.1" } }, "require-in-the-middle": { @@ -1421,13 +1319,18 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "resolve": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", - "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", "requires": { "path-parse": "^1.0.6" } }, + "run-series": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.8.tgz", + "integrity": "sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg==" + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -1449,34 +1352,24 @@ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, - "shelljs": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", - "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, "shimmer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "smart-buffer": { "version": "4.1.0", @@ -1517,9 +1410,9 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-support": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", - "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -1540,26 +1433,18 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } }, "systeminformation": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.23.1.tgz", - "integrity": "sha512-gtqfvz5jUIMqWn0kkdkV4G8uiLmJckQ+z6aKy1uyE0OPU/6tStubahtZDiF0ajSRVJht+Vd4pX5DDwQLhAapww==", + "version": "4.27.3", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.27.3.tgz", + "integrity": "sha512-0Nc8AYEK818h7FI+bbe/kj7xXsMD5zOHvO9alUqQH/G4MHXu5tHQfWqC/bzWOk4JtoQPhnyLgxMYncDA2eeSBw==", "optional": true }, "thunkify": { @@ -1581,9 +1466,9 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", + "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==" }, "tv4": { "version": "1.3.0", @@ -1598,11 +1483,6 @@ "prelude-ls": "~1.1.2" } }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, "union": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", @@ -1632,27 +1512,17 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "vizion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/vizion/-/vizion-2.0.2.tgz", - "integrity": "sha512-UGDB/UdC1iyPkwyQaI9AFMwKcluQyD4FleEXObrlu254MEf16MV8l+AZdpFErY/iVKZVWlQ+OgJlVVJIdeMUYg==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/vizion/-/vizion-0.2.13.tgz", + "integrity": "sha1-ExTN7is0EW+fWxJIU2+V2/zW718=", "requires": { - "async": "2.6.1", - "git-node-fs": "^1.0.0", - "ini": "^1.3.4", - "js-git": "^0.7.8", - "lodash.findindex": "^4.6.0", - "lodash.foreach": "^4.5.0", - "lodash.get": "^4.4.2", - "lodash.last": "^3.0.0" + "async": "1.5" }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" - } + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" } } }, @@ -1661,23 +1531,15 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "requires": { - "async-limiter": "~1.0.0" - } + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz", + "integrity": "sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA==" }, "xregexp": { "version": "2.0.0", diff --git a/package.json b/package.json index 47dd318..0fa83fe 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "license": "WTFPL", "dependencies": { "esm": "^3.2.25", - "http-server": "^0.12.1", - "pm2": "^4.2.3" + "http-server": "^0.12.3", + "pm2": "^4.4.1", + "react-icons": "^3.11.0" } } diff --git a/server/package-lock.json b/server/package-lock.json index 6a1b8c3..8f42463 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,6 +1,6 @@ { "name": "hack.chat-v2", - "version": "2.1.9", + "version": "2.1.93", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -18,11 +18,6 @@ "color-convert": "^2.0.1" } }, - "ascii-captcha": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/ascii-captcha/-/ascii-captcha-0.0.3.tgz", - "integrity": "sha1-NAtO1oVYOHEHsJVzBC/kc4v0mPk=" - }, "async": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", @@ -202,16 +197,16 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "mute-stream": { diff --git a/server/src/commands/admin/saveconfig.js b/server/src/commands/admin/saveconfig.js index 260ff14..9031a11 100644 --- a/server/src/commands/admin/saveconfig.js +++ b/server/src/commands/admin/saveconfig.js @@ -14,7 +14,7 @@ export async function run(core, server, socket) { // attempt save, notify of failure if (!core.configManager.save()) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Failed to save config, check logs.', }, socket); } diff --git a/server/src/commands/core/changenick.js b/server/src/commands/core/changenick.js index bbd3ec3..9776024 100644 --- a/server/src/commands/core/changenick.js +++ b/server/src/commands/core/changenick.js @@ -8,7 +8,7 @@ import * as UAC from '../utility/UAC/_info'; export async function run(core, server, socket, data) { if (server.police.frisk(socket.address, 6)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are changing nicknames too fast. Wait a moment before trying again.', }, socket); } @@ -24,7 +24,7 @@ export async function run(core, server, socket, data) { const newNick = data.nick.trim(); if (!UAC.verifyNickname(newNick)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Nickname must consist of up to 24 letters, numbers, and underscores', }, socket); } @@ -35,14 +35,14 @@ export async function run(core, server, socket, data) { server.police.frisk(socket.address, 4); return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are not the admin, liar!', }, socket); } if (newNick == previousNick) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You already have that name', }, socket); } @@ -59,7 +59,7 @@ export async function run(core, server, socket, data) { if (userExists.length > 0) { // That nickname is already in that channel return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Nickname taken', }, socket); } @@ -112,7 +112,7 @@ export function nickCheck(core, server, socket, payload) { // If there is no nickname target parameter if (input[1] === undefined) { server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Refer to `/help nick` for instructions on how to use this command.', }, socket); diff --git a/server/src/commands/core/chat.js b/server/src/commands/core/chat.js index 908c205..71dbbad 100644 --- a/server/src/commands/core/chat.js +++ b/server/src/commands/core/chat.js @@ -35,7 +35,7 @@ export async function run(core, server, socket, data) { const score = text.length / 83 / 4; if (server.police.frisk(socket.address, score)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } @@ -43,7 +43,9 @@ export async function run(core, server, socket, data) { // build chat payload const payload = { cmd: 'chat', - nick: socket.nick, + nick: socket.nick, /* @legacy */ + userid: socket.userid, + channel: socket.channel, text, level: socket.level, }; @@ -55,7 +57,7 @@ export async function run(core, server, socket, data) { } if (socket.trip) { - payload.trip = socket.trip; + payload.trip = socket.trip; /* @legacy */ } // broadcast to channel peers @@ -107,7 +109,7 @@ export function finalCmdCheck(core, server, socket, payload) { } server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: `Unknown command: ${payload.text}`, }, socket); diff --git a/server/src/commands/core/emote.js b/server/src/commands/core/emote.js index 21d14d1..17f2512 100644 --- a/server/src/commands/core/emote.js +++ b/server/src/commands/core/emote.js @@ -33,7 +33,7 @@ export async function run(core, server, socket, payload) { const score = text.length / 83 / 4; if (server.police.frisk(socket.address, score)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } @@ -42,6 +42,7 @@ export async function run(core, server, socket, payload) { text = ` ${text}`; } + // @todo Change `cmd` from `info` to it's own `emote` event const newPayload = { cmd: 'info', type: 'emote', @@ -75,7 +76,7 @@ export function emoteCheck(core, server, socket, payload) { // If there is no emote target parameter if (input[1] === undefined) { server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Refer to `/help emote` for instructions on how to use this command.', }, socket); diff --git a/server/src/commands/core/help.js b/server/src/commands/core/help.js index 56fb18b..bc861bc 100644 --- a/server/src/commands/core/help.js +++ b/server/src/commands/core/help.js @@ -7,7 +7,7 @@ export async function run(core, server, socket, payload) { // check for spam if (server.police.frisk(socket.address, 2)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } diff --git a/server/src/commands/core/invite.js b/server/src/commands/core/invite.js index 00584b3..2f86d9a 100644 --- a/server/src/commands/core/invite.js +++ b/server/src/commands/core/invite.js @@ -2,24 +2,7 @@ Description: Generates a semi-unique channel name then broadcasts it to each client */ -import * as UAC from '../utility/UAC/_info'; - // module support functions -/** - * Returns a message for if it's a valid nickname to invite. Returns null if there was no error. - * @param {any} nick - * @return {(string|null)} - */ -export function checkNickname (nick, inviterNick) { - if (typeof nick !== 'string' || !UAC.verifyNickname(nick)) { - return "Nickname was invalid."; - } else if (nick === inviterNick) { - return "Why would you invite yourself?"; - } - - return null; -} - /** * Returns the channel that should be invited to. * @param {any} channel @@ -33,90 +16,56 @@ export function getChannel (channel=undefined) { } } -/** - * Creates the payload that a user who is being invited would receive. - * @param {string} inviter The user who is inviting them. - * @param {string} channel The channel they are being invited to. - * @return {Object} - */ -export function createRecipientPayload (inviter, channel) { - return { - cmd: 'info', - type: 'invite', - from: inviter, - text: `${inviter} invited you to ?${channel}`, - }; -} - -/** - * Creates the payload that a user who invited users (and succeeded) would receive. - * @param {string} nick The user who was invited. - * @param {string} channel The channel they were invited to. - */ -export function createSuccessPayload (nick, channel) { - return { - cmd: 'info', - type: 'invite', - invite: channel, - text: `You invited ${nick} to ?${channel}`, - }; -} - -/** - * Sends the invites to the recipients. - * @param {MainServer} server The server. Required to broadcast the messages. - * @param {string} recipientNick The user who is being invited. - * @param {string} inviterNick The user who is doing the inviting. - * @param {string} originalChannel The channel they have in common, and where the invite is sent in. - * @param {string} inviteChannel The channel they are being invited to. - */ -export function sendInvite (server, recipientNick, inviterNick, originalChannel, inviteChannel) { - return server.broadcast(createRecipientPayload(inviterNick, inviteChannel), { - channel: originalChannel, - nick: recipientNick, - }); -} - // module main export async function run(core, server, socket, data) { // check for spam if (server.police.frisk(socket.address, 2)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are sending invites too fast. Wait a moment before trying again.', }, socket); } // verify user input - const nickValid = checkNickname(data.nick, socket.nick); - if (nickValid !== null) { - server.reply({ - cmd: 'warn', - text: nickValid, - }, socket); + if (typeof data.userid !== 'number' || typeof data.channel !== 'string') { return true; } - const channel = getChannel(data.to); + // why would you invite yourself? + if (data.userid === socket.userid) { + return true; + } - // build and send invite - const payload = createRecipientPayload(socket.nick, channel); + // @todo Verify this socket is part of data.channel - multichannel patch + // find target user + let targetClient = server.findSockets({ channel: data.channel, userid: data.userid }); - const inviteSent = server.broadcast(payload, { - channel: socket.channel, - nick: data.nick, - }); - - // server indicates the user was not found - if (!inviteSent) { + if (targetClient.length === 0) { return server.reply({ - cmd: 'warn', - text: 'Could not find user in channel', + cmd: 'warn', // @todo Remove english and change to numeric id + text: 'Could not find user in that channel', }, socket); } - // reply with common channel - server.reply(createSuccessPayload(data.nick, channel), socket); + [targetClient] = targetClient; + + // generate common channel + const channel = getChannel(data.to); + + // build invite + const payload = { + cmd: 'invite', + channel: socket.channel, + from: socket.userid, + to: data.userid, + inviteChannel: channel, + }; + + // send invite notice to target client + server.reply(payload, targetClient); + + // send invite notice to this client + server.reply(payload, socket); // stats are fun core.stats.increment('invites-sent'); @@ -124,7 +73,7 @@ export async function run(core, server, socket, data) { return true; } -export const requiredData = ['nick']; +export const requiredData = [];//['nick']; export const info = { name: 'invite', description: 'Sends an invite to the target client with the provided channel, or a random channel.', diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index c4f4f4f..bf789c1 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -17,28 +17,19 @@ const hash = (password) => { // returns object containing user info or string if error export function parseNickname(core, data) { const userInfo = { - nick: '', + nick: data.nick, uType: 'user', /* @legacy */ trip: null, level: UAC.levels.default, }; - // seperate nick from password - const nickArray = data.nick.split('#', 2); - userInfo.nick = nickArray[0].trim(); - if (!UAC.verifyNickname(userInfo.nick)) { // return error as string + // @todo Remove english and change to numeric id return 'Nickname must consist of up to 24 letters, numbers, and underscores'; } - let password = undefined; - // prioritize hash in nick for password over password field - if (typeof nickArray[1] === 'string') { - password = nickArray[1]; - } else if (typeof data.password === 'string') { - password = data.password; - } + let password = data.pass || false; if (hash(password + core.config.tripSalt) === core.config.adminTrip) { userInfo.uType = 'admin'; /* @legacy */ @@ -46,6 +37,7 @@ export function parseNickname(core, data) { userInfo.level = UAC.levels.admin; } else if (userInfo.nick.toLowerCase() === core.config.adminName.toLowerCase()) { // they've got the main-admin name while not being an admin + // @todo Remove english and change to numeric id return 'You are not the admin, liar!'; } else if (password) { userInfo.trip = hash(password + core.config.tripSalt); @@ -68,14 +60,18 @@ export async function run(core, server, socket, data) { // check for spam if (server.police.frisk(socket.address, 3)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are joining channels too fast. Wait a moment and try again.', }, socket); } // calling socket already in a channel + // @todo Multichannel update if (typeof socket.channel !== 'undefined') { - return true; + return server.reply({ + cmd: 'warn', // @todo Remove this + text: 'Joining more than one channel is not currently supported', + }, socket); } // check user input @@ -92,7 +88,7 @@ export async function run(core, server, socket, data) { const userInfo = this.parseNickname(core, data); if (typeof userInfo === 'string') { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: userInfo, }, socket); } @@ -106,19 +102,17 @@ export async function run(core, server, socket, data) { if (userExists.length > 0) { // that nickname is already in that channel return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Nickname taken', }, socket); } + // populate final userinfo fields + // @TODO: this could be move into parseNickname, changing the function name to match userInfo.hash = server.getSocketHash(socket); + userInfo.userid = socket.userid; - // assign "unique" socket ID - if (typeof socket.userid === 'undefined') { - userInfo.userid = Math.floor(Math.random() * 9999999999999); - } - - // TODO: place this within it's own function allowing import + // @TODO: place this within it's own function allowing import // prepare to notify channel peers const newPeerList = server.findSockets({ channel: data.channel }); const nicks = []; /* @legacy */ @@ -159,7 +153,6 @@ export async function run(core, server, socket, data) { socket.channel = data.channel; /* @legacy */ socket.hash = userInfo.hash; socket.level = userInfo.level; - socket.userid = userInfo.userid; nicks.push(socket.nick); /* @legacy */ users.push({ @@ -191,5 +184,5 @@ export const info = { name: 'join', description: 'Place calling socket into target channel with target nick & broadcast event to channel', usage: ` - API: { cmd: 'join', nick: '', password: '', channel: '' }`, + API: { cmd: 'join', nick: '', pass: '', channel: '' }`, }; diff --git a/server/src/commands/core/move.js b/server/src/commands/core/move.js index fdafab4..49f3946 100644 --- a/server/src/commands/core/move.js +++ b/server/src/commands/core/move.js @@ -7,7 +7,7 @@ export async function run(core, server, socket, data) { // check for spam if (server.police.frisk(socket.address, 6)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are changing channels too fast. Wait a moment before trying again.', }, socket); } @@ -19,7 +19,7 @@ export async function run(core, server, socket, data) { if (data.channel === '') { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Cannot move to an empty channel.', }, socket); } @@ -106,7 +106,7 @@ export function moveCheck(core, server, socket, payload) { // If there is no channel target parameter if (input[1] === undefined) { server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Refer to `/help move` for instructions on how to use this command.', }, socket); diff --git a/server/src/commands/core/session.js b/server/src/commands/core/session.js index 677e9a4..cd6bba1 100644 --- a/server/src/commands/core/session.js +++ b/server/src/commands/core/session.js @@ -2,8 +2,66 @@ Description: Create a new socket session or restore previous session */ +// module support functions +const createSessionID = () => { + let sessionID = ''; + for( let i = 0, j = 32; i < j; i++) { + sessionID += Math.random().toString(36).substr(2, 9); + } + return sessionID; +} + // module main -export async function run() { } +export async function run(core, server, socket) { + // gather connection and channel count + let ips = {}; + let channels = {}; + // todo: use public channel flag + let publicChanCounts = { + lounge: 0, + meta: 0, + math: 0, + physics: 0, + chemistry: 0, + technology: 0, + programming: 0, + games: 0, + banana: 0, + chinese: 0, + }; + + // todo: code resuage between here and `morestats`, export function + server.clients.forEach((client) => { + if (client.channel) { + channels[client.channel] = true; + ips[client.address] = true; + if (typeof publicChanCounts[client.channel] !== 'undefined') { + publicChanCounts[client.channel]++; + } + } + }); + + const uniqueClientCount = Object.keys(ips).length; + const uniqueChannels = Object.keys(channels).length; + + ips = null; + channels = null; + + // @todo: restore session + socket.sessionID = createSessionID(); + socket.hcProtocol = 2; + socket.userid = Math.floor(Math.random() * 9999999999999); + + // dispatch info + server.reply({ + cmd: 'session', + users: uniqueClientCount, + chans: uniqueChannels, + public: publicChanCounts, + sessionID: socket.sessionID, + restored: false, + }, socket); +} export const info = { name: 'session', diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index 4424cd2..f0215a3 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -1,5 +1,7 @@ /* Description: Display text on targets screen that only they can see + @todo This should be changed to it's own event type, instead of `info` + and accept a `userid` rather than `nick` */ import * as UAC from '../utility/UAC/_info'; @@ -36,7 +38,7 @@ export async function run(core, server, socket, payload) { const score = text.length / 83 / 4; if (server.police.frisk(socket.address, score)) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } @@ -51,7 +53,7 @@ export async function run(core, server, socket, payload) { if (targetClient.length === 0) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Could not find user in channel', }, socket); } @@ -94,7 +96,7 @@ export function whisperCheck(core, server, socket, payload) { // If there is no nickname target parameter if (input[1] === undefined) { server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Refer to `/help whisper` for instructions on how to use this command.', }, socket); @@ -117,7 +119,7 @@ export function whisperCheck(core, server, socket, payload) { if (payload.text.startsWith('/r ')) { if (typeof socket.whisperReply === 'undefined') { server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Cannot reply to nobody', }, socket); diff --git a/server/src/commands/internal/disconnect.js b/server/src/commands/internal/disconnect.js index 07a125e..74a9ca1 100644 --- a/server/src/commands/internal/disconnect.js +++ b/server/src/commands/internal/disconnect.js @@ -14,7 +14,8 @@ export async function run(core, server, socket, data) { if (socket.channel) { server.broadcast({ cmd: 'onlineRemove', - nick: socket.nick, + userid: socket.userid, + nick: socket.nick, /* @legacy */ }, { channel: socket.channel }); } diff --git a/server/src/commands/internal/legacylayer.js b/server/src/commands/internal/legacylayer.js index c0daa13..f5772ad 100644 --- a/server/src/commands/internal/legacylayer.js +++ b/server/src/commands/internal/legacylayer.js @@ -1,18 +1,161 @@ /* Description: This module adjusts outgoing data, making it compatible with legacy clients + Dear god this module is horrifying */ +// import * as UAC from '../utility/UAC/_info'; + // module main export async function run(core, server, socket, data) { - /** - * @todo - */ + return server.police.frisk(socket.address, 20); } // module hook functions export function initHooks(server) { - // module is only a placeholder - // server.registerHook('out', '', this.); + server.registerHook('in', 'join', this.joinCheck.bind(this), 10); + server.registerHook('in', 'invite', this.inviteInCheck.bind(this), 10); + server.registerHook('out', 'invite', this.inviteOutCheck.bind(this), 10); + server.registerHook('in', 'ban', this.banCheck.bind(this), 10); + server.registerHook('in', 'dumb', this.dumbCheck.bind(this), 10); + server.registerHook('in', 'kick', this.kickCheck.bind(this), 10); +} + +// hook incoming join events, if session was not invoked, default proto to 1 +export function joinCheck(core, server, socket, payload) { + if (typeof socket.hcProtocol === 'undefined') { + socket.hcProtocol = 1; + + const nickArray = payload.nick.split('#', 2); + payload.nick = nickArray[0].trim(); + if (nickArray[1] && typeof payload.pass === 'undefined') { + payload.pass = nickArray[1]; + } + + // dunno how this happened on the legacy version + if (typeof payload.password !== 'undefined') { + payload.pass = payload.password; + } + + if (typeof socket.userid === 'undefined') { + socket.userid = Math.floor(Math.random() * 9999999999999); + } + } + + return payload; +} + +// if legacy client sent an invite, downgrade request +export function inviteInCheck(core, server, socket, payload) { + if (socket.hcProtocol === 1) { + let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + + if (targetClient.length === 0) { + server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + }, socket); + + return false; + } + + [targetClient] = targetClient; + + payload.userid = targetClient.userid; + payload.channel = socket.channel; + } + + return payload; +} + +// +export function inviteOutCheck(core, server, socket, payload) { + if (socket.hcProtocol === 1) { + payload.cmd = 'info'; + if (socket.userid === payload.from) { + let toClient = server.findSockets({ channel: socket.channel, userid: payload.from }); + [toClient] = toClient; + payload.type = 'invite'; + payload.from = toClient.nick; + payload.text = `You invited ${toClient.nick} to ?${payload.inviteChannel}`; + } else if (socket.userid === payload.to) { + let fromClient = server.findSockets({ channel: socket.channel, userid: payload.from }); + [fromClient] = fromClient; + payload.type = 'invite'; + payload.from = fromClient.nick; + payload.text = `${fromClient.nick} invited you to ?${payload.inviteChannel}`; + } + } + + return payload; +} + +export function banCheck(core, server, socket, payload) { + if (socket.hcProtocol === 1) { + let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + + if (targetClient.length === 0) { + server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + }, socket); + + return false; + } + + [targetClient] = targetClient; + + payload.userid = targetClient.userid; + payload.channel = socket.channel; + } + + return payload; +} + +export function dumbCheck(core, server, socket, payload) { + if (socket.hcProtocol === 1) { + let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + + if (targetClient.length === 0) { + server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + }, socket); + + return false; + } + + [targetClient] = targetClient; + + payload.userid = targetClient.userid; + payload.channel = socket.channel; + } + + return payload; +} + +export function kickCheck(core, server, socket, payload) { + if (socket.hcProtocol === 1) { + if (typeof payload.nick !== 'number') { + if (typeof payload.nick !== 'object' && !Array.isArray(data.nick)) { + return true; + } + } + + let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + + if (targetClient.length === 0) { + return false; + } + + payload.userid = []; + for (let i = 0, j = targetClient.length; i < j; i += 1) { + payload.userid.push(targetClient[i].userid); + } + + payload.channel = socket.channel; + } + + return payload; } export const info = { diff --git a/server/src/commands/internal/socketreply.js b/server/src/commands/internal/socketreply.js index 1ba8df2..88c28f1 100644 --- a/server/src/commands/internal/socketreply.js +++ b/server/src/commands/internal/socketreply.js @@ -10,7 +10,10 @@ export async function run(core, server, socket, data) { } // send warning to target socket - server.reply({ cmd: 'warn', text: data.text }, socket); + server.reply({ + cmd: 'warn', // @todo Remove english and change to numeric id + text: data.text + }, socket); return true; } diff --git a/server/src/commands/mod/ban.js b/server/src/commands/mod/ban.js index 994bc1c..b62beb7 100644 --- a/server/src/commands/mod/ban.js +++ b/server/src/commands/mod/ban.js @@ -12,27 +12,27 @@ export async function run(core, server, socket, data) { } // check user input - if (typeof data.nick !== 'string') { + if (typeof data.userid !== 'number') { return true; } // find target user - const targetNick = data.nick; - let badClient = server.findSockets({ channel: socket.channel, nick: targetNick }); + let badClient = server.findSockets({ channel: socket.channel, userid: data.userid }); if (badClient.length === 0) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Could not find user in channel', }, socket); } [badClient] = badClient; + const targetNick = badClient.nick; // i guess banning mods or admins isn't the best idea? if (badClient.level >= socket.level) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Cannot ban other users of the same level, how rude', }, socket); } @@ -52,8 +52,8 @@ export async function run(core, server, socket, data) { // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${socket.channel}, userhash: ${badClient.hash}`, - channel: socket.channel, + text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${data.channel}, userhash: ${badClient.hash}`, + channel: data.channel, user: UAC.getUserDetails(badClient), banner: UAC.getUserDetails(socket), }, { level: UAC.isModerator }); @@ -67,7 +67,7 @@ export async function run(core, server, socket, data) { return true; } -export const requiredData = ['nick']; +//export const requiredData = ['nick']; export const info = { name: 'ban', description: 'Disconnects the target nickname in the same channel as calling socket & adds to ratelimiter', diff --git a/server/src/commands/mod/dumb.js b/server/src/commands/mod/dumb.js index ba2886d..401f49f 100644 --- a/server/src/commands/mod/dumb.js +++ b/server/src/commands/mod/dumb.js @@ -4,7 +4,6 @@ */ import * as UAC from '../utility/UAC/_info'; -import * as Invite from '../core/invite'; // module constructor export function init(core) { @@ -21,16 +20,16 @@ export async function run(core, server, socket, data) { } // check user input - if (typeof data.nick !== 'string') { + if (typeof data.userid !== 'number') { return true; } // find target user - let badClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + let badClient = server.findSockets({ channel: data.channel, userid: data.userid }); if (badClient.length === 0) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Could not find user in channel', }, socket); } @@ -40,7 +39,7 @@ export async function run(core, server, socket, data) { // likely dont need this, muting mods and admins is fine if (badClient.level >= socket.level) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'This trick wont work on users of the same level', }, socket); } @@ -58,7 +57,7 @@ export async function run(core, server, socket, data) { // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick}#${socket.trip} muzzled ${data.nick} in ${socket.channel}, userhash: ${badClient.hash}`, + text: `${socket.nick}#${socket.trip} muzzled ${badClient.nick} in ${data.channel}, userhash: ${badClient.hash}`, }, { level: UAC.isModerator }); return true; @@ -119,10 +118,11 @@ export function chatCheck(core, server, socket, payload) { // shadow-prevent all invites from muzzled users export function inviteCheck(core, server, socket, payload) { if (core.muzzledHashes[socket.hash]) { - const nickValid = Invite.checkNickname(payload.nick); + // @todo convert to protocol 2 + /*const nickValid = Invite.checkNickname(payload.nick); if (nickValid !== null) { server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: nickValid, }, socket); return false; @@ -132,7 +132,7 @@ export function inviteCheck(core, server, socket, payload) { const channel = Invite.getChannel(); // send fake reply - server.reply(Invite.createSuccessPayload(payload.nick, channel), socket); + server.reply(Invite.createSuccessPayload(payload.nick, channel), socket);*/ return false; } @@ -168,7 +168,7 @@ export function whisperCheck(core, server, socket, payload) { return payload; } -export const requiredData = ['nick']; +// export const requiredData = ['nick']; export const info = { name: 'dumb', description: 'Globally shadow mute a connection. Optional allies array will see muted messages.', diff --git a/server/src/commands/mod/kick.js b/server/src/commands/mod/kick.js index cf1ff75..5fc38f7 100644 --- a/server/src/commands/mod/kick.js +++ b/server/src/commands/mod/kick.js @@ -12,8 +12,9 @@ export async function run(core, server, socket, data) { } // check user input - if (typeof data.nick !== 'string') { - if (typeof data.nick !== 'object' && !Array.isArray(data.nick)) { + if (typeof data.userid !== 'number') { + // @todo create multi-ban ui + if (typeof data.userid !== 'object' && !Array.isArray(data.userid)) { return true; } } @@ -26,11 +27,11 @@ export async function run(core, server, socket, data) { } // find target user(s) - const badClients = server.findSockets({ channel: socket.channel, nick: data.nick }); + const badClients = server.findSockets({ channel: data.channel, userid: data.userid }); if (badClients.length === 0) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Could not find user(s) in channel', }, socket); } @@ -40,7 +41,7 @@ export async function run(core, server, socket, data) { for (let i = 0, j = badClients.length; i < j; i += 1) { if (badClients[i].level >= socket.level) { server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Cannot kick other users with the same level, how rude', }, socket); } else { @@ -96,7 +97,7 @@ export async function run(core, server, socket, data) { return true; } -export const requiredData = ['nick']; +// export const requiredData = ['nick']; export const info = { name: 'kick', description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings', diff --git a/server/src/commands/mod/moveuser.js b/server/src/commands/mod/moveuser.js index b86edb4..ffed4b5 100644 --- a/server/src/commands/mod/moveuser.js +++ b/server/src/commands/mod/moveuser.js @@ -25,7 +25,7 @@ export async function run(core, server, socket, data) { if (badClients.length === 0) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Could not find user in channel', }, socket); } @@ -34,7 +34,7 @@ export async function run(core, server, socket, data) { if (badClient.level >= socket.level) { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: 'Cannot move other users of the same level, how rude', }, socket); } diff --git a/server/src/commands/mod/speak.js b/server/src/commands/mod/speak.js index e5ff8e2..eb3141c 100644 --- a/server/src/commands/mod/speak.js +++ b/server/src/commands/mod/speak.js @@ -22,7 +22,7 @@ export async function run(core, server, socket, data) { // check user input if (typeof data.ip !== 'string' && typeof data.hash !== 'string') { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: "hash:'targethash' or ip:'1.2.3.4' is required", }, socket); } diff --git a/server/src/commands/mod/unban.js b/server/src/commands/mod/unban.js index 3b72fdc..29840a5 100644 --- a/server/src/commands/mod/unban.js +++ b/server/src/commands/mod/unban.js @@ -14,7 +14,7 @@ export async function run(core, server, socket, data) { // check user input if (typeof data.ip !== 'string' && typeof data.hash !== 'string') { return server.reply({ - cmd: 'warn', + cmd: 'warn', // @todo Remove english and change to numeric id text: "hash:'targethash' or ip:'1.2.3.4' is required", }, socket); } diff --git a/server/src/serverLib/MainServer.js b/server/src/serverLib/MainServer.js index f985998..6095bbe 100644 --- a/server/src/serverLib/MainServer.js +++ b/server/src/serverLib/MainServer.js @@ -197,7 +197,7 @@ class MainServer extends WsServer { return; } - if (typeof socket.channel === 'undefined' && (payload.cmd !== 'join' && payload.cmd !== 'chat')) { + if (typeof socket.channel === 'undefined' && (payload.cmd !== 'join' && payload.cmd !== 'session' && payload.cmd !== 'chat')) { return; } From 72324050f5749ca443e7fb39d30721c18542f08d Mon Sep 17 00:00:00 2001 From: marzavec Date: Thu, 17 Sep 2020 00:44:32 -0500 Subject: [PATCH 02/37] normalized --- .editorconfig | 14 + .eslintrc.js | 15 + .gitattributes | 107 ++ package-lock.json | 1407 ++++++++++++++++++- package.json | 12 +- server/main.js | 2 +- server/src/commands/admin/addmod.js | 12 +- server/src/commands/admin/listusers.js | 6 +- server/src/commands/admin/reload.js | 8 +- server/src/commands/admin/removemod.js | 13 +- server/src/commands/admin/saveconfig.js | 2 +- server/src/commands/admin/shout.js | 4 +- server/src/commands/core/changenick.js | 35 +- server/src/commands/core/chat.js | 22 +- server/src/commands/core/emote.js | 17 +- server/src/commands/core/help.js | 24 +- server/src/commands/core/invite.js | 29 +- server/src/commands/core/join.js | 34 +- server/src/commands/core/morestats.js | 15 +- server/src/commands/core/move.js | 32 +- server/src/commands/core/ping.js | 1 + server/src/commands/core/session.js | 20 +- server/src/commands/core/stats.js | 2 +- server/src/commands/core/whisper.js | 32 +- server/src/commands/internal/disconnect.js | 4 +- server/src/commands/internal/legacylayer.js | 58 +- server/src/commands/internal/socketreply.js | 6 +- server/src/commands/mod/ban.js | 15 +- server/src/commands/mod/dumb.js | 34 +- server/src/commands/mod/kick.js | 17 +- server/src/commands/mod/moveuser.js | 20 +- server/src/commands/mod/speak.js | 20 +- server/src/commands/mod/unban.js | 14 +- server/src/commands/mod/unbanall.js | 4 +- server/src/scripts/configLib/SetupWizard.js | 7 + server/src/scripts/setupSchema/Banner.js | 2 + server/src/scripts/setupSchema/Footer.js | 2 + server/src/scripts/setupSchema/Questions.js | 3 + server/src/serverLib/CommandManager.js | 15 +- server/src/serverLib/ConfigManager.js | 2 + server/src/serverLib/CoreApp.js | 4 +- server/src/serverLib/ImportsManager.js | 5 +- server/src/serverLib/MainServer.js | 14 +- server/src/serverLib/RateLimiter.js | 1 + server/src/serverLib/index.js | 2 + 45 files changed, 1873 insertions(+), 241 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintrc.js create mode 100644 .gitattributes diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5370727 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..a55639c --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + env: { + browser: true, + commonjs: true, + es2021: true, + }, + extends: [ + 'airbnb-base', + ], + parserOptions: { + ecmaVersion: 12, + }, + rules: { + }, +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c917234 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,107 @@ +# From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes + +# Handle line endings automatically for files detected as text +# and leave all files detected as binary untouched. +* text=auto + +# +# The above will handle all files NOT found below +# + +# +## These files are text and should be normalized (Convert crlf => lf) +# + +# source code +*.php text +*.css text +*.sass text +*.scss text +*.less text +*.styl text +*.js text eol=lf +*.coffee text +*.json text +*.htm text +*.html text +*.xml text +*.svg text +*.txt text +*.ini text +*.inc text +*.pl text +*.rb text +*.py text +*.scm text +*.sql text +*.sh text +*.bat text + +# templates +*.ejs text +*.hbt text +*.jade text +*.haml text +*.hbs text +*.dot text +*.tmpl text +*.phtml text + +# server config +.htaccess text +.nginx.conf text + +# git config +.gitattributes text +.gitignore text +.gitconfig text + +# code analysis config +.jshintrc text +.jscsrc text +.jshintignore text +.csslintrc text + +# misc config +*.yaml text +*.yml text +.editorconfig text + +# build config +*.npmignore text +*.bowerrc text + +# Heroku +Procfile text +.slugignore text + +# Documentation +*.md text +LICENSE text +AUTHORS text + + +# +## These files are binary and should be left untouched +# + +# (binary is a macro for -text -diff) +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.mov binary +*.mp4 binary +*.mp3 binary +*.flv binary +*.fla binary +*.swf binary +*.gz binary +*.zip binary +*.7z binary +*.ttf binary +*.eot binary +*.woff binary +*.pyc binary +*.pdf binary diff --git a/package-lock.json b/package-lock.json index 8d2934e..43ea2c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,113 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", + "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, "@opencensus/core": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz", @@ -173,29 +280,29 @@ } } }, - "@pm2/pm2-version-check": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.3.tgz", - "integrity": "sha512-SBuYsh+o35knItbRW97vl5/5nEc5c5DYP7PxjyPLOfmm9bMaDsVeATXjXMBy6+KLlyrYWHZxGbfXe003NnHClg==", - "requires": { - "debug": "^4.1.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", @@ -204,6 +311,18 @@ "es6-promisify": "^5.0.0" } }, + "ajv": { + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", + "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" + } + }, "amp": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", @@ -222,6 +341,12 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -255,6 +380,69 @@ } } }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, "ast-types": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.1.tgz", @@ -263,6 +451,12 @@ "tslib": "^2.0.1" } }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", @@ -370,10 +564,11 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true }, "chalk": { "version": "3.0.0", @@ -445,6 +640,18 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "confusing-browser-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "continuation-local-storage": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", @@ -472,6 +679,17 @@ "moment-timezone": "^0.5.x" } }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, "data-uri-to-buffer": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", @@ -495,6 +713,15 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "degenerator": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", @@ -510,6 +737,15 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "ecstatic": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", @@ -529,6 +765,12 @@ "shimmer": "^1.2.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "enquirer": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz", @@ -537,6 +779,46 @@ "ansi-colors": "^3.2.1" } }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -555,6 +837,12 @@ "resolved": "https://registry.npmjs.org/escape-regexp/-/escape-regexp-0.0.1.tgz", "integrity": "sha1-9EvaEtRbvfnLf4Yu5+SCez3TIlQ=" }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, "escodegen": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", @@ -574,16 +862,310 @@ } } }, + "eslint": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.9.0.tgz", + "integrity": "sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.1.3", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.0", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^1.3.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "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" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + } + } + }, + "eslint-config-airbnb-base": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", + "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.9", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", + "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.3", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, "esm": { "version": "3.2.25", "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" }, + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + } + }, "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", @@ -609,6 +1191,18 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", @@ -619,6 +1213,15 @@ "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=" }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -632,6 +1235,32 @@ "to-regex-range": "^5.0.1" } }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, "follow-redirects": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", @@ -670,6 +1299,18 @@ } } }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-uri": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.4.tgz", @@ -719,16 +1360,52 @@ "is-glob": "^4.0.1" } }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, "http-errors": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", @@ -809,6 +1486,28 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -828,6 +1527,12 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -836,11 +1541,29 @@ "binary-extensions": "^2.0.0" } }, + "is-callable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", + "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -849,16 +1572,97 @@ "is-extglob": "^2.1.1" } }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, "lazy": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", @@ -873,6 +1677,28 @@ "type-check": "~0.3.2" } }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", @@ -945,6 +1771,12 @@ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "needle": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", @@ -960,6 +1792,26 @@ "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=" }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -981,6 +1833,95 @@ } } }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", + "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1007,6 +1948,30 @@ "word-wrap": "~1.2.3" } }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, "pac-proxy-agent": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.1.tgz", @@ -1044,16 +2009,55 @@ "thunkify": "^2.1.2" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -1067,6 +2071,21 @@ "safe-buffer": "^5.1.2" } }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, "pm2": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/pm2/-/pm2-4.4.1.tgz", @@ -1105,6 +2124,14 @@ "yamljs": "0.3.0" }, "dependencies": { + "@pm2/pm2-version-check": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.3.tgz", + "integrity": "sha512-SBuYsh+o35knItbRW97vl5/5nEc5c5DYP7PxjyPLOfmm9bMaDsVeATXjXMBy6+KLlyrYWHZxGbfXe003NnHClg==", + "requires": { + "debug": "^4.1.1" + } + }, "async": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", @@ -1181,6 +2208,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "promptly": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/promptly/-/promptly-2.2.0.tgz", @@ -1224,6 +2257,12 @@ "resolved": "https://registry.npmjs.org/ps-list/-/ps-list-6.3.0.tgz", "integrity": "sha512-qau0czUSB0fzSlBOQt0bo+I2v6R+xiQdj78e1BR/Qjfl5OHWJ/urXi8+ilw1eHe+5hSeDI1wrwVTgDp2wst4oA==" }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "qs": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", @@ -1240,14 +2279,6 @@ "unpipe": "1.0.0" } }, - "react-icons": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.11.0.tgz", - "integrity": "sha512-JRgiI/vdF6uyBgyZhVyYJUZAop95Sy4XDe/jmT3R/bKliFWpO/uZBwvSjWEdxwzec7SYbEPNPck0Kff2tUGM2Q==", - "requires": { - "camelcase": "^5.0.0" - } - }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -1256,6 +2287,27 @@ "mute-stream": "~0.0.4" } }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -1293,6 +2345,12 @@ "picomatch": "^2.2.1" } }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, "require-in-the-middle": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.0.3.tgz", @@ -1326,6 +2384,21 @@ "path-parse": "^1.0.6" } }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "run-series": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.8.tgz", @@ -1361,6 +2434,21 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "shimmer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", @@ -1371,6 +2459,43 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + } + } + }, "smart-buffer": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", @@ -1418,6 +2543,38 @@ "source-map": "^0.6.0" } }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": true + }, "sprintf-js": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", @@ -1428,11 +2585,122 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1447,6 +2715,24 @@ "integrity": "sha512-0Nc8AYEK818h7FI+bbe/kj7xXsMD5zOHvO9alUqQH/G4MHXu5tHQfWqC/bzWOk4JtoQPhnyLgxMYncDA2eeSBw==", "optional": true }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "thunkify": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", @@ -1465,6 +2751,18 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, "tslib": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", @@ -1483,6 +2781,12 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, "union": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", @@ -1496,6 +2800,15 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "url-join": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", @@ -1511,6 +2824,22 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "vizion": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/vizion/-/vizion-0.2.13.tgz", @@ -1526,6 +2855,15 @@ } } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -1536,6 +2874,15 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "ws": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz", diff --git a/package.json b/package.json index 0fa83fe..6be4671 100644 --- a/package.json +++ b/package.json @@ -18,14 +18,20 @@ "clear": "pm2 flush", "status": "pm2 list", "refresh": "pm2 flush && pm2 stop pm2.config.js && pm2 delete pm2.config.js", - "postinstall": "cd ./server && npm install && npm run config" + "postinstall": "cd ./server && npm install && npm run config", + "lint": "eslint --ignore-path .gitignore -- ./server ", + "lint:fix": "eslint --ignore-path .gitignore --fix -- ./server " }, "author": "Marzavec", "license": "WTFPL", "dependencies": { "esm": "^3.2.25", "http-server": "^0.12.3", - "pm2": "^4.4.1", - "react-icons": "^3.11.0" + "pm2": "^4.4.1" + }, + "devDependencies": { + "eslint": "^7.9.0", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-plugin-import": "^2.22.0" } } diff --git a/server/main.js b/server/main.js index b01d09d..55b116b 100644 --- a/server/main.js +++ b/server/main.js @@ -6,7 +6,7 @@ */ // import and initialize the core application -import { CoreApp } from './src/serverLib/CoreApp'; +import CoreApp from './src/serverLib/CoreApp'; const coreApp = new CoreApp(); coreApp.init(); diff --git a/server/src/commands/admin/addmod.js b/server/src/commands/admin/addmod.js index 8f934ce..db645fe 100644 --- a/server/src/commands/admin/addmod.js +++ b/server/src/commands/admin/addmod.js @@ -5,17 +5,19 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // increase rate limit chance and ignore if not admin if (!UAC.isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); } // add new trip to config - core.config.mods.push({ trip: data.trip }); + core.config.mods.push({ trip: payload.trip }); // find targets current connections - const newMod = server.findSockets({ trip: data.trip }); + const newMod = server.findSockets({ trip: payload.trip }); if (newMod.length !== 0) { for (let i = 0, l = newMod.length; i < l; i += 1) { // upgrade privilages @@ -33,13 +35,13 @@ export async function run(core, server, socket, data) { // return success message server.reply({ cmd: 'info', - text: `Added mod trip: ${data.trip}, remember to run 'saveconfig' to make it permanent`, + text: `Added mod trip: ${payload.trip}, remember to run 'saveconfig' to make it permanent`, }, socket); // notify all mods server.broadcast({ cmd: 'info', - text: `Added mod: ${data.trip}`, + text: `Added mod: ${payload.trip}`, }, { level: UAC.isModerator }); return true; diff --git a/server/src/commands/admin/listusers.js b/server/src/commands/admin/listusers.js index 54c93dc..b7f8d7c 100644 --- a/server/src/commands/admin/listusers.js +++ b/server/src/commands/admin/listusers.js @@ -1,3 +1,7 @@ +/* eslint no-unused-vars: 0 */ +/* eslint no-restricted-syntax: 0 */ +/* eslint guard-for-in: 0 */ + /* Description: Outputs all current channels and their user nicks */ @@ -5,7 +9,7 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket) { +export async function run({ server, socket }) { // increase rate limit chance and ignore if not admin if (!UAC.isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); diff --git a/server/src/commands/admin/reload.js b/server/src/commands/admin/reload.js index a1d22ac..e39fe6f 100644 --- a/server/src/commands/admin/reload.js +++ b/server/src/commands/admin/reload.js @@ -5,7 +5,9 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // increase rate limit chance and ignore if not admin if (!UAC.isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); @@ -26,8 +28,8 @@ export async function run(core, server, socket, data) { ${loadResult}`; } - if (typeof data.reason !== 'undefined') { - loadResult += `\nReason: ${data.reason}`; + if (typeof payload.reason !== 'undefined') { + loadResult += `\nReason: ${payload.reason}`; } // send results to moderators (which the user using this command is higher than) diff --git a/server/src/commands/admin/removemod.js b/server/src/commands/admin/removemod.js index f76ff13..1fff3b0 100644 --- a/server/src/commands/admin/removemod.js +++ b/server/src/commands/admin/removemod.js @@ -5,17 +5,20 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // increase rate limit chance and ignore if not admin if (!UAC.isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); } // remove trip from config - core.config.mods = core.config.mods.filter((mod) => mod.trip !== data.trip); + // eslint-disable-next-line no-param-reassign + core.config.mods = core.config.mods.filter((mod) => mod.trip !== payload.trip); // find targets current connections - const targetMod = server.findSockets({ trip: data.trip }); + const targetMod = server.findSockets({ trip: payload.trip }); if (targetMod.length !== 0) { for (let i = 0, l = targetMod.length; i < l; i += 1) { // downgrade privilages @@ -34,14 +37,14 @@ export async function run(core, server, socket, data) { server.reply({ cmd: 'info', text: `Removed mod trip: ${ - data.trip + payload.trip }, remember to run 'saveconfig' to make it permanent`, }, socket); // notify all mods server.broadcast({ cmd: 'info', - text: `Removed mod: ${data.trip}`, + text: `Removed mod: ${payload.trip}`, }, { level: UAC.isModerator }); return true; diff --git a/server/src/commands/admin/saveconfig.js b/server/src/commands/admin/saveconfig.js index 9031a11..f13bdee 100644 --- a/server/src/commands/admin/saveconfig.js +++ b/server/src/commands/admin/saveconfig.js @@ -5,7 +5,7 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket) { +export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin if (!UAC.isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); diff --git a/server/src/commands/admin/shout.js b/server/src/commands/admin/shout.js index 65695b3..27002fc 100644 --- a/server/src/commands/admin/shout.js +++ b/server/src/commands/admin/shout.js @@ -5,7 +5,7 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ server, socket, payload }) { // increase rate limit chance and ignore if not admin if (!UAC.isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); @@ -14,7 +14,7 @@ export async function run(core, server, socket, data) { // send text to all channels server.broadcast({ cmd: 'info', - text: `Server Notice: ${data.text}`, + text: `Server Notice: ${payload.text}`, }, {}); return true; diff --git a/server/src/commands/core/changenick.js b/server/src/commands/core/changenick.js index 9776024..a081a1e 100644 --- a/server/src/commands/core/changenick.js +++ b/server/src/commands/core/changenick.js @@ -1,3 +1,5 @@ +/* eslint eqeqeq: 0 */ + /* Description: Allows calling client to change their current nickname */ @@ -5,7 +7,9 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { if (server.police.frisk(socket.address, 6)) { return server.reply({ cmd: 'warn', // @todo Remove english and change to numeric id @@ -14,14 +18,14 @@ export async function run(core, server, socket, data) { } // verify user data is string - if (typeof data.nick !== 'string') { + if (typeof payload.nick !== 'string') { return true; } const previousNick = socket.nick; // make sure requested nickname meets standards - const newNick = data.nick.trim(); + const newNick = payload.nick.trim(); if (!UAC.verifyNickname(newNick)) { return server.reply({ cmd: 'warn', // @todo Remove english and change to numeric id @@ -30,7 +34,7 @@ export async function run(core, server, socket, data) { } // prevent admin impersonation - // TODO: prevent mod impersonation + // @todo prevent mod impersonation if (newNick.toLowerCase() === core.config.adminName.toLowerCase()) { server.police.frisk(socket.address, 4); @@ -50,9 +54,9 @@ export async function run(core, server, socket, data) { // find any sockets that have the same nickname const userExists = server.findSockets({ channel: socket.channel, - nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase() && + nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase() // Allow them to rename themselves to a different case - targetNick != previousNick, + && targetNick != previousNick, }); // return error if found @@ -65,7 +69,7 @@ export async function run(core, server, socket, data) { } // build join and leave notices - // TODO: this is a legacy client holdover, name changes in the future will + // @todo this is a legacy client holdover, name changes in the future will // have thieir own event const leaveNotice = { cmd: 'onlineRemove', @@ -90,7 +94,7 @@ export async function run(core, server, socket, data) { }, { channel: socket.channel }); // commit change to nickname - socket.nick = newNick; + socket.nick = newNick; // eslint-disable-line no-param-reassign return true; } @@ -101,7 +105,9 @@ export function initHooks(server) { } // hooks chat commands checking for /nick -export function nickCheck(core, server, socket, payload) { +export function nickCheck({ + core, server, socket, payload, +}) { if (typeof payload.text !== 'string') { return false; } @@ -121,9 +127,14 @@ export function nickCheck(core, server, socket, payload) { const newNick = input[1].replace(/@/g, ''); - this.run(core, server, socket, { - cmd: 'changenick', - nick: newNick, + this.run({ + core, + server, + socket, + payload: { + cmd: 'changenick', + nick: newNick, + }, }); return false; diff --git a/server/src/commands/core/chat.js b/server/src/commands/core/chat.js index 71dbbad..2c3d6e3 100644 --- a/server/src/commands/core/chat.js +++ b/server/src/commands/core/chat.js @@ -22,9 +22,11 @@ const parseText = (text) => { }; // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // check user input - const text = parseText(data.text); + const text = parseText(payload.text); if (!text) { // lets not send objects or empty text, yea? @@ -41,7 +43,7 @@ export async function run(core, server, socket, data) { } // build chat payload - const payload = { + const outgoingPayload = { cmd: 'chat', nick: socket.nick, /* @legacy */ userid: socket.userid, @@ -51,17 +53,17 @@ export async function run(core, server, socket, data) { }; if (UAC.isAdmin(socket.level)) { - payload.admin = true; + outgoingPayload.admin = true; } else if (UAC.isModerator(socket.level)) { - payload.mod = true; + outgoingPayload.mod = true; } if (socket.trip) { - payload.trip = socket.trip; /* @legacy */ + outgoingPayload.trip = socket.trip; /* @legacy */ } // broadcast to channel peers - server.broadcast(payload, { channel: socket.channel }); + server.broadcast(outgoingPayload, { channel: socket.channel }); // stats are fun core.stats.increment('messages-sent'); @@ -76,7 +78,7 @@ export function initHooks(server) { } // checks for miscellaneous '/' based commands -export function commandCheckIn(core, server, socket, payload) { +export function commandCheckIn({ server, socket, payload }) { if (typeof payload.text !== 'string') { return false; } @@ -93,7 +95,7 @@ export function commandCheckIn(core, server, socket, payload) { return payload; } -export function finalCmdCheck(core, server, socket, payload) { +export function finalCmdCheck({ server, socket, payload }) { if (typeof payload.text !== 'string') { return false; } @@ -103,7 +105,7 @@ export function finalCmdCheck(core, server, socket, payload) { } if (payload.text.startsWith('//')) { - payload.text = payload.text.substr(1); + payload.text = payload.text.substr(1); // eslint-disable-line no-param-reassign return payload; } diff --git a/server/src/commands/core/emote.js b/server/src/commands/core/emote.js index 17f2512..b21d7b6 100644 --- a/server/src/commands/core/emote.js +++ b/server/src/commands/core/emote.js @@ -20,7 +20,7 @@ const parseText = (text) => { }; // module main -export async function run(core, server, socket, payload) { +export async function run({ server, socket, payload }) { // check user input let text = parseText(payload.text); @@ -65,7 +65,9 @@ export function initHooks(server) { } // hooks chat commands checking for /me -export function emoteCheck(core, server, socket, payload) { +export function emoteCheck({ + core, server, socket, payload, +}) { if (typeof payload.text !== 'string') { return false; } @@ -86,9 +88,14 @@ export function emoteCheck(core, server, socket, payload) { input.splice(0, 1); const actionText = input.join(' '); - this.run(core, server, socket, { - cmd: 'emote', - text: actionText, + this.run({ + core, + server, + socket, + payload: { + cmd: 'emote', + text: actionText, + }, }); return false; diff --git a/server/src/commands/core/help.js b/server/src/commands/core/help.js index bc861bc..56069c5 100644 --- a/server/src/commands/core/help.js +++ b/server/src/commands/core/help.js @@ -3,7 +3,9 @@ */ // module main -export async function run(core, server, socket, payload) { +export async function run({ + core, server, socket, payload, +}) { // check for spam if (server.police.frisk(socket.address, 2)) { return server.reply({ @@ -24,7 +26,9 @@ export async function run(core, server, socket, payload) { const categories = core.commands.categoriesList.sort(); for (let i = 0, j = categories.length; i < j; i += 1) { reply += `|${categories[i].replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())}:|`; - const catCommands = core.commands.all(categories[i]).sort((a, b) => a.info.name.localeCompare(b.info.name)); + const catCommands = core.commands.all(categories[i]).sort( + (a, b) => a.info.name.localeCompare(b.info.name), + ); reply += `${catCommands.map((c) => `${c.info.name}`).join(', ')}|\n`; } @@ -40,6 +44,7 @@ export async function run(core, server, socket, payload) { reply += `|**Aliases:**|${typeof command.info.aliases !== 'undefined' ? command.info.aliases.join(', ') : 'None'}|\n`; reply += `|**Category:**|${command.info.category.replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())}|\n`; reply += `|**Required Parameters:**|${command.requiredData || 'None'}|\n`; + // eslint-disable-next-line no-useless-escape reply += `|**Description:**|${command.info.description || '¯\_(ツ)_/¯'}|\n\n`; reply += `**Usage:** ${command.info.usage || command.info.name}`; } @@ -60,7 +65,9 @@ export function initHooks(server) { } // hooks chat commands checking for /whisper -export function helpCheck(core, server, socket, payload) { +export function helpCheck({ + core, server, socket, payload, +}) { if (typeof payload.text !== 'string') { return false; } @@ -68,9 +75,14 @@ export function helpCheck(core, server, socket, payload) { if (payload.text.startsWith('/help')) { const input = payload.text.substr(1).split(' ', 2); - this.run(core, server, socket, { - cmd: input[0], - command: input[1], + this.run({ + core, + server, + socket, + payload: { + cmd: input[0], + command: input[1], + }, }); return false; diff --git a/server/src/commands/core/invite.js b/server/src/commands/core/invite.js index 2f86d9a..7136892 100644 --- a/server/src/commands/core/invite.js +++ b/server/src/commands/core/invite.js @@ -8,16 +8,17 @@ * @param {any} channel * @return {string} */ -export function getChannel (channel=undefined) { +export function getChannel(channel = undefined) { if (typeof channel === 'string') { return channel; - } else { - return Math.random().toString(36).substr(2, 8); } + return Math.random().toString(36).substr(2, 8); } // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // check for spam if (server.police.frisk(socket.address, 2)) { return server.reply({ @@ -27,18 +28,18 @@ export async function run(core, server, socket, data) { } // verify user input - if (typeof data.userid !== 'number' || typeof data.channel !== 'string') { + if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') { return true; } // why would you invite yourself? - if (data.userid === socket.userid) { + if (payload.userid === socket.userid) { return true; } - // @todo Verify this socket is part of data.channel - multichannel patch + // @todo Verify this socket is part of payload.channel - multichannel patch // find target user - let targetClient = server.findSockets({ channel: data.channel, userid: data.userid }); + let targetClient = server.findSockets({ channel: payload.channel, userid: payload.userid }); if (targetClient.length === 0) { return server.reply({ @@ -50,22 +51,22 @@ export async function run(core, server, socket, data) { [targetClient] = targetClient; // generate common channel - const channel = getChannel(data.to); + const channel = getChannel(payload.to); // build invite - const payload = { + const outgoingPayload = { cmd: 'invite', channel: socket.channel, from: socket.userid, - to: data.userid, + to: payload.userid, inviteChannel: channel, }; // send invite notice to target client - server.reply(payload, targetClient); + server.reply(outgoingPayload, targetClient); // send invite notice to this client - server.reply(payload, socket); + server.reply(outgoingPayload, socket); // stats are fun core.stats.increment('invites-sent'); @@ -73,7 +74,7 @@ export async function run(core, server, socket, data) { return true; } -export const requiredData = [];//['nick']; +export const requiredData = []; // ['nick']; export const info = { name: 'invite', description: 'Sends an invite to the target client with the provided channel, or a random channel.', diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index bf789c1..3ee6722 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -1,3 +1,5 @@ +/* eslint no-param-reassign: 0 */ + /* Description: Initial entry point, applies `channel` and `nick` to the calling socket */ @@ -29,7 +31,7 @@ export function parseNickname(core, data) { return 'Nickname must consist of up to 24 letters, numbers, and underscores'; } - let password = data.pass || false; + const password = data.pass || false; if (hash(password + core.config.tripSalt) === core.config.adminTrip) { userInfo.uType = 'admin'; /* @legacy */ @@ -43,7 +45,7 @@ export function parseNickname(core, data) { userInfo.trip = hash(password + core.config.tripSalt); } - // TODO: disallow moderator impersonation + // @todo disallow moderator impersonation // for (const mod of core.config.mods) { core.config.mods.forEach((mod) => { if (userInfo.trip === mod.trip) { @@ -56,7 +58,9 @@ export function parseNickname(core, data) { } // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // check for spam if (server.police.frisk(socket.address, 3)) { return server.reply({ @@ -75,17 +79,17 @@ export async function run(core, server, socket, data) { } // check user input - if (typeof data.channel !== 'string' || typeof data.nick !== 'string') { + if (typeof payload.channel !== 'string' || typeof payload.nick !== 'string') { return true; } - const channel = data.channel.trim(); + const channel = payload.channel.trim(); if (!channel) { // must join a non-blank channel return true; } - const userInfo = this.parseNickname(core, data); + const userInfo = this.parseNickname(core, payload); if (typeof userInfo === 'string') { return server.reply({ cmd: 'warn', // @todo Remove english and change to numeric id @@ -95,7 +99,7 @@ export async function run(core, server, socket, data) { // check if the nickname already exists in the channel const userExists = server.findSockets({ - channel: data.channel, + channel: payload.channel, nick: (targetNick) => targetNick.toLowerCase() === userInfo.nick.toLowerCase(), }); @@ -108,13 +112,13 @@ export async function run(core, server, socket, data) { } // populate final userinfo fields - // @TODO: this could be move into parseNickname, changing the function name to match + // @todo this could be move into parseNickname, changing the function name to match userInfo.hash = server.getSocketHash(socket); userInfo.userid = socket.userid; - // @TODO: place this within it's own function allowing import + // @todo place this within it's own function allowing import // prepare to notify channel peers - const newPeerList = server.findSockets({ channel: data.channel }); + const newPeerList = server.findSockets({ channel: payload.channel }); const nicks = []; /* @legacy */ const users = []; @@ -126,7 +130,7 @@ export async function run(core, server, socket, data) { hash: userInfo.hash, level: userInfo.level, userid: userInfo.userid, - channel: data.channel, + channel: payload.channel, }; // send join announcement and prep online set @@ -141,7 +145,7 @@ export async function run(core, server, socket, data) { hash: newPeerList[i].hash, level: newPeerList[i].level, userid: newPeerList[i].userid, - channel: data.channel, + channel: payload.channel, isme: false, }); } @@ -150,7 +154,7 @@ export async function run(core, server, socket, data) { socket.uType = userInfo.uType; /* @legacy */ socket.nick = userInfo.nick; socket.trip = userInfo.trip; - socket.channel = data.channel; /* @legacy */ + socket.channel = payload.channel; /* @legacy */ socket.hash = userInfo.hash; socket.level = userInfo.level; @@ -162,7 +166,7 @@ export async function run(core, server, socket, data) { hash: socket.hash, level: socket.level, userid: socket.userid, - channel: data.channel, + channel: payload.channel, isme: true, }); @@ -179,7 +183,7 @@ export async function run(core, server, socket, data) { return true; } -export const requiredData = ['channel', 'nick']; +export const requiredData = []; // ['channel', 'nick']; export const info = { name: 'join', description: 'Place calling socket into target channel with target nick & broadcast event to channel', diff --git a/server/src/commands/core/morestats.js b/server/src/commands/core/morestats.js index 3b5ceb2..e84a309 100644 --- a/server/src/commands/core/morestats.js +++ b/server/src/commands/core/morestats.js @@ -21,7 +21,7 @@ const formatTime = (time) => { }; // module main -export async function run(core, server, socket) { +export async function run({ core, server, socket }) { // gather connection and channel count let ips = {}; let channels = {}; @@ -63,14 +63,21 @@ export function initHooks(server) { } // hooks chat commands checking for /stats -export function statsCheck(core, server, socket, payload) { +export function statsCheck({ + core, server, socket, payload, +}) { if (typeof payload.text !== 'string') { return false; } if (payload.text.startsWith('/stats')) { - this.run(core, server, socket, { - cmd: 'morestats', + this.run({ + core, + server, + socket, + payload: { + cmd: 'morestats', + }, }); return false; diff --git a/server/src/commands/core/move.js b/server/src/commands/core/move.js index 49f3946..e27445c 100644 --- a/server/src/commands/core/move.js +++ b/server/src/commands/core/move.js @@ -1,9 +1,10 @@ /* Description: Changes the current channel of the calling socket + @deprecated This module will be removed or replaced */ // module main -export async function run(core, server, socket, data) { +export async function run({ server, socket, payload }) { // check for spam if (server.police.frisk(socket.address, 6)) { return server.reply({ @@ -13,18 +14,18 @@ export async function run(core, server, socket, data) { } // check user input - if (typeof data.channel !== 'string') { + if (typeof payload.channel !== 'string') { return true; } - if (data.channel === '') { + if (payload.channel === '') { return server.reply({ cmd: 'warn', // @todo Remove english and change to numeric id text: 'Cannot move to an empty channel.', }, socket); } - if (data.channel === socket.channel) { + if (payload.channel === socket.channel) { // they are trying to rejoin the channel return true; } @@ -32,7 +33,7 @@ export async function run(core, server, socket, data) { // check that the nickname isn't already in target channel const currentNick = socket.nick.toLowerCase(); const userExists = server.findSockets({ - channel: data.channel, + channel: payload.channel, nick: (targetNick) => targetNick.toLowerCase() === currentNick, }); @@ -60,9 +61,9 @@ export async function run(core, server, socket, data) { } } - // TODO: import function from join module + // @todo import function from join module // broadcast join notice to new peers - const newPeerList = server.findSockets({ channel: data.channel }); + const newPeerList = server.findSockets({ channel: payload.channel }); const moveAnnouncement = { cmd: 'onlineAdd', nick: socket.nick, @@ -85,7 +86,7 @@ export async function run(core, server, socket, data) { }, socket); // commit change - socket.channel = data.channel; + socket.channel = payload.channel; // eslint-disable-line no-param-reassign return true; } @@ -95,7 +96,9 @@ export function initHooks(server) { server.registerHook('in', 'chat', this.moveCheck.bind(this), 29); } -export function moveCheck(core, server, socket, payload) { +export function moveCheck({ + core, server, socket, payload, +}) { if (typeof payload.text !== 'string') { return false; } @@ -113,9 +116,14 @@ export function moveCheck(core, server, socket, payload) { return false; } - this.run(core, server, socket, { - cmd: 'move', - channel: input[1], + this.run({ + core, + server, + socket, + payload: { + cmd: 'move', + channel: input[1], + }, }); return false; diff --git a/server/src/commands/core/ping.js b/server/src/commands/core/ping.js index 6266f4c..642a526 100644 --- a/server/src/commands/core/ping.js +++ b/server/src/commands/core/ping.js @@ -1,3 +1,4 @@ +/* eslint no-empty-function: 0 */ /* Description: This module is only in place to supress error notices legacy sources may get */ diff --git a/server/src/commands/core/session.js b/server/src/commands/core/session.js index cd6bba1..4a4c9b4 100644 --- a/server/src/commands/core/session.js +++ b/server/src/commands/core/session.js @@ -1,3 +1,5 @@ +/* eslint no-param-reassign: 0 */ + /* Description: Create a new socket session or restore previous session */ @@ -5,19 +7,19 @@ // module support functions const createSessionID = () => { let sessionID = ''; - for( let i = 0, j = 32; i < j; i++) { + for (let i = 0, j = 32; i < j; i += 1) { sessionID += Math.random().toString(36).substr(2, 9); } return sessionID; -} +}; // module main -export async function run(core, server, socket) { +export async function run({ server, socket }) { // gather connection and channel count let ips = {}; let channels = {}; - // todo: use public channel flag - let publicChanCounts = { + // @todo use public channel flag + const publicChanCounts = { lounge: 0, meta: 0, math: 0, @@ -30,13 +32,13 @@ export async function run(core, server, socket) { chinese: 0, }; - // todo: code resuage between here and `morestats`, export function + // todo code resuage between here and `morestats`, export function server.clients.forEach((client) => { if (client.channel) { channels[client.channel] = true; ips[client.address] = true; if (typeof publicChanCounts[client.channel] !== 'undefined') { - publicChanCounts[client.channel]++; + publicChanCounts[client.channel] += 1; } } }); @@ -47,7 +49,7 @@ export async function run(core, server, socket) { ips = null; channels = null; - // @todo: restore session + // @todo restore session socket.sessionID = createSessionID(); socket.hcProtocol = 2; socket.userid = Math.floor(Math.random() * 9999999999999); @@ -67,5 +69,5 @@ export const info = { name: 'session', description: 'Restore previous state by session id or return new session id (currently unavailable)', usage: ` - API: { cmd: 'session', id: '' }` + API: { cmd: 'session', id: '' }`, }; diff --git a/server/src/commands/core/stats.js b/server/src/commands/core/stats.js index 421aec2..76bbc98 100644 --- a/server/src/commands/core/stats.js +++ b/server/src/commands/core/stats.js @@ -3,7 +3,7 @@ */ // module main -export async function run(core, server, socket) { +export async function run({ core, server, socket }) { // gather connection and channel count let ips = {}; let channels = {}; diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index f0215a3..5ed7d8f 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -25,7 +25,7 @@ const parseText = (text) => { }; // module main -export async function run(core, server, socket, payload) { +export async function run({ server, socket, payload }) { // check user input const text = parseText(payload.text); @@ -85,7 +85,9 @@ export function initHooks(server) { } // hooks chat commands checking for /whisper -export function whisperCheck(core, server, socket, payload) { +export function whisperCheck({ + core, server, socket, payload, +}) { if (typeof payload.text !== 'string') { return false; } @@ -107,10 +109,15 @@ export function whisperCheck(core, server, socket, payload) { input.splice(0, 2); const whisperText = input.join(' '); - this.run(core, server, socket, { - cmd: 'whisper', - nick: target, - text: whisperText, + this.run({ + core, + server, + socket, + payload: { + cmd: 'whisper', + nick: target, + text: whisperText, + }, }); return false; @@ -130,10 +137,15 @@ export function whisperCheck(core, server, socket, payload) { input.splice(0, 1); const whisperText = input.join(' '); - this.run(core, server, socket, { - cmd: 'whisper', - nick: socket.whisperReply, - text: whisperText, + this.run({ + core, + server, + socket, + payload: { + cmd: 'whisper', + nick: socket.whisperReply, + text: whisperText, + }, }); return false; diff --git a/server/src/commands/internal/disconnect.js b/server/src/commands/internal/disconnect.js index 74a9ca1..27280da 100644 --- a/server/src/commands/internal/disconnect.js +++ b/server/src/commands/internal/disconnect.js @@ -4,8 +4,8 @@ */ // module main -export async function run(core, server, socket, data) { - if (data.cmdKey !== server.cmdKey) { +export async function run({ server, socket, payload }) { + if (payload.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore return server.police.frisk(socket.address, 20); } diff --git a/server/src/commands/internal/legacylayer.js b/server/src/commands/internal/legacylayer.js index f5772ad..f4775b0 100644 --- a/server/src/commands/internal/legacylayer.js +++ b/server/src/commands/internal/legacylayer.js @@ -1,3 +1,5 @@ +/* eslint no-param-reassign: 0 */ + /* Description: This module adjusts outgoing data, making it compatible with legacy clients Dear god this module is horrifying @@ -6,7 +8,7 @@ // import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ server, socket }) { return server.police.frisk(socket.address, 20); } @@ -21,14 +23,14 @@ export function initHooks(server) { } // hook incoming join events, if session was not invoked, default proto to 1 -export function joinCheck(core, server, socket, payload) { +export function joinCheck({ socket, payload }) { if (typeof socket.hcProtocol === 'undefined') { socket.hcProtocol = 1; const nickArray = payload.nick.split('#', 2); payload.nick = nickArray[0].trim(); if (nickArray[1] && typeof payload.pass === 'undefined') { - payload.pass = nickArray[1]; + payload.pass = nickArray[1]; // eslint-disable-line prefer-destructuring } // dunno how this happened on the legacy version @@ -45,30 +47,30 @@ export function joinCheck(core, server, socket, payload) { } // if legacy client sent an invite, downgrade request -export function inviteInCheck(core, server, socket, payload) { +export function inviteInCheck({ server, socket, payload }) { if (socket.hcProtocol === 1) { - let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick }); if (targetClient.length === 0) { server.reply({ cmd: 'warn', text: 'Could not find user in that channel', }, socket); - + return false; } - + [targetClient] = targetClient; - + payload.userid = targetClient.userid; payload.channel = socket.channel; } - + return payload; } -// -export function inviteOutCheck(core, server, socket, payload) { +// +export function inviteOutCheck({ server, socket, payload }) { if (socket.hcProtocol === 1) { payload.cmd = 'info'; if (socket.userid === payload.from) { @@ -89,59 +91,59 @@ export function inviteOutCheck(core, server, socket, payload) { return payload; } -export function banCheck(core, server, socket, payload) { +export function banCheck({ server, socket, payload }) { if (socket.hcProtocol === 1) { - let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick }); if (targetClient.length === 0) { server.reply({ cmd: 'warn', text: 'Could not find user in that channel', }, socket); - + return false; } - + [targetClient] = targetClient; - + payload.userid = targetClient.userid; payload.channel = socket.channel; } - + return payload; } -export function dumbCheck(core, server, socket, payload) { +export function dumbCheck({ server, socket, payload }) { if (socket.hcProtocol === 1) { - let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick }); if (targetClient.length === 0) { server.reply({ cmd: 'warn', text: 'Could not find user in that channel', }, socket); - + return false; } - + [targetClient] = targetClient; - + payload.userid = targetClient.userid; payload.channel = socket.channel; } - + return payload; } -export function kickCheck(core, server, socket, payload) { +export function kickCheck({ server, socket, payload }) { if (socket.hcProtocol === 1) { if (typeof payload.nick !== 'number') { - if (typeof payload.nick !== 'object' && !Array.isArray(data.nick)) { + if (typeof payload.nick !== 'object' && !Array.isArray(payload.nick)) { return true; } } - let targetClient = server.findSockets({ channel: socket.channel, nick: data.nick }); + const targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick }); if (targetClient.length === 0) { return false; @@ -151,10 +153,10 @@ export function kickCheck(core, server, socket, payload) { for (let i = 0, j = targetClient.length; i < j; i += 1) { payload.userid.push(targetClient[i].userid); } - + payload.channel = socket.channel; } - + return payload; } diff --git a/server/src/commands/internal/socketreply.js b/server/src/commands/internal/socketreply.js index 88c28f1..4221a76 100644 --- a/server/src/commands/internal/socketreply.js +++ b/server/src/commands/internal/socketreply.js @@ -3,8 +3,8 @@ */ // module main -export async function run(core, server, socket, data) { - if (data.cmdKey !== server.cmdKey) { +export async function run({ server, socket, payload }) { + if (payload.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore return server.police.frisk(socket.address, 20); } @@ -12,7 +12,7 @@ export async function run(core, server, socket, data) { // send warning to target socket server.reply({ cmd: 'warn', // @todo Remove english and change to numeric id - text: data.text + text: payload.text, }, socket); return true; diff --git a/server/src/commands/mod/ban.js b/server/src/commands/mod/ban.js index b62beb7..ff601e8 100644 --- a/server/src/commands/mod/ban.js +++ b/server/src/commands/mod/ban.js @@ -1,3 +1,4 @@ +/* eslint no-console: 0 */ /* Description: Adds the target socket's ip to the ratelimiter */ @@ -5,19 +6,21 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // increase rate limit chance and ignore if not admin or mod if (!UAC.isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } // check user input - if (typeof data.userid !== 'number') { + if (typeof payload.userid !== 'number') { return true; } // find target user - let badClient = server.findSockets({ channel: socket.channel, userid: data.userid }); + let badClient = server.findSockets({ channel: socket.channel, userid: payload.userid }); if (badClient.length === 0) { return server.reply({ @@ -52,8 +55,8 @@ export async function run(core, server, socket, data) { // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${data.channel}, userhash: ${badClient.hash}`, - channel: data.channel, + text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${badClient.hash}`, + channel: payload.channel, user: UAC.getUserDetails(badClient), banner: UAC.getUserDetails(socket), }, { level: UAC.isModerator }); @@ -67,7 +70,7 @@ export async function run(core, server, socket, data) { return true; } -//export const requiredData = ['nick']; +// export const requiredData = ['nick']; export const info = { name: 'ban', description: 'Disconnects the target nickname in the same channel as calling socket & adds to ratelimiter', diff --git a/server/src/commands/mod/dumb.js b/server/src/commands/mod/dumb.js index 401f49f..3f8723f 100644 --- a/server/src/commands/mod/dumb.js +++ b/server/src/commands/mod/dumb.js @@ -1,3 +1,6 @@ +/* eslint no-param-reassign: 0 */ +/* eslint no-multi-assign: 0 */ + /* * Description: Make a user (spammer) dumb (mute) * Author: simple @@ -13,19 +16,21 @@ export function init(core) { } // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // increase rate limit chance and ignore if not admin or mod if (!UAC.isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } // check user input - if (typeof data.userid !== 'number') { + if (typeof payload.userid !== 'number') { return true; } // find target user - let badClient = server.findSockets({ channel: data.channel, userid: data.userid }); + let badClient = server.findSockets({ channel: payload.channel, userid: payload.userid }); if (badClient.length === 0) { return server.reply({ @@ -50,14 +55,14 @@ export async function run(core, server, socket, data) { }; // store allies if needed - if (data.allies && Array.isArray(data.allies)) { - record.allies = data.allies; + if (payload.allies && Array.isArray(payload.allies)) { + record.allies = payload.allies; } // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick}#${socket.trip} muzzled ${badClient.nick} in ${data.channel}, userhash: ${badClient.hash}`, + text: `${socket.nick}#${socket.trip} muzzled ${badClient.nick} in ${payload.channel}, userhash: ${badClient.hash}`, }, { level: UAC.isModerator }); return true; @@ -71,7 +76,9 @@ export function initHooks(server) { } // hook incoming chat commands, shadow-prevent chat if they are muzzled -export function chatCheck(core, server, socket, payload) { +export function chatCheck({ + core, server, socket, payload, +}) { if (typeof payload.text !== 'string') { return false; } @@ -116,10 +123,10 @@ export function chatCheck(core, server, socket, payload) { } // shadow-prevent all invites from muzzled users -export function inviteCheck(core, server, socket, payload) { +export function inviteCheck({ core, socket, payload }) { if (core.muzzledHashes[socket.hash]) { // @todo convert to protocol 2 - /*const nickValid = Invite.checkNickname(payload.nick); + /* const nickValid = Invite.checkNickname(payload.nick); if (nickValid !== null) { server.reply({ cmd: 'warn', // @todo Remove english and change to numeric id @@ -132,7 +139,7 @@ export function inviteCheck(core, server, socket, payload) { const channel = Invite.getChannel(); // send fake reply - server.reply(Invite.createSuccessPayload(payload.nick, channel), socket);*/ + server.reply(Invite.createSuccessPayload(payload.nick, channel), socket); */ return false; } @@ -141,7 +148,9 @@ export function inviteCheck(core, server, socket, payload) { } // shadow-prevent all whispers from muzzled users -export function whisperCheck(core, server, socket, payload) { +export function whisperCheck({ + core, server, socket, payload, +}) { if (typeof payload.nick !== 'string') { return false; } @@ -159,7 +168,8 @@ export function whisperCheck(core, server, socket, payload) { text: `You whispered to @${targetNick}: ${payload.text}`, }, socket); - // blanket "spam" protection, may expose the ratelimiting lines from `chat` and use that, TODO: one day #lazydev + // blanket "spam" protection, may expose the ratelimiting lines from + // `chat` and use that, @todo one day #lazydev server.police.frisk(socket.address, 9); return false; diff --git a/server/src/commands/mod/kick.js b/server/src/commands/mod/kick.js index 5fc38f7..0c73e2a 100644 --- a/server/src/commands/mod/kick.js +++ b/server/src/commands/mod/kick.js @@ -1,3 +1,5 @@ +/* eslint no-console: 0 */ + /* Description: Forces a change on the target(s) socket's channel, then broadcasts event */ @@ -5,29 +7,31 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // increase rate limit chance and ignore if not admin or mod if (!UAC.isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } // check user input - if (typeof data.userid !== 'number') { + if (typeof payload.userid !== 'number') { // @todo create multi-ban ui - if (typeof data.userid !== 'object' && !Array.isArray(data.userid)) { + if (typeof payload.userid !== 'object' && !Array.isArray(payload.userid)) { return true; } } let destChannel; - if (typeof data.to === 'string' && !!data.to.trim()) { - destChannel = data.to; + if (typeof payload.to === 'string' && !!payload.to.trim()) { + destChannel = payload.to; } else { destChannel = Math.random().toString(36).substr(2, 8); } // find target user(s) - const badClients = server.findSockets({ channel: data.channel, userid: data.userid }); + const badClients = server.findSockets({ channel: payload.channel, userid: payload.userid }); if (badClients.length === 0) { return server.reply({ @@ -76,7 +80,6 @@ export async function run(core, server, socket, data) { console.log(`${socket.nick} [${socket.trip}] kicked ${kicked[i].nick} in ${socket.channel} to ${destChannel} `); } - // broadcast client leave event for (let i = 0, j = kicked.length; i < j; i += 1) { server.broadcast({ diff --git a/server/src/commands/mod/moveuser.js b/server/src/commands/mod/moveuser.js index ffed4b5..331dcae 100644 --- a/server/src/commands/mod/moveuser.js +++ b/server/src/commands/mod/moveuser.js @@ -5,23 +5,23 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ server, socket, payload }) { // increase rate limit chance and ignore if not admin or mod if (!UAC.isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } // check user input - if (typeof data.nick !== 'string' || typeof data.channel !== 'string') { + if (typeof payload.nick !== 'string' || typeof payload.channel !== 'string') { return true; } - if (data.channel === socket.channel) { + if (payload.channel === socket.channel) { // moving them into the same channel? y u do this? return true; } - const badClients = server.findSockets({ channel: socket.channel, nick: data.nick }); + const badClients = server.findSockets({ channel: socket.channel, nick: payload.nick }); if (badClients.length === 0) { return server.reply({ @@ -41,7 +41,7 @@ export async function run(core, server, socket, data) { const currentNick = badClient.nick.toLowerCase(); const userExists = server.findSockets({ - channel: data.channel, + channel: payload.channel, nick: (targetNick) => targetNick.toLowerCase() === currentNick, }); @@ -68,8 +68,8 @@ export async function run(core, server, socket, data) { } } - // TODO: import from join module - const newPeerList = server.findSockets({ channel: data.channel }); + // @todo import from join module + const newPeerList = server.findSockets({ channel: payload.channel }); const moveAnnouncement = { cmd: 'onlineAdd', nick: badClient.nick, @@ -90,12 +90,12 @@ export async function run(core, server, socket, data) { nicks, }, badClient); - badClient.channel = data.channel; + badClient.channel = payload.channel; server.broadcast({ cmd: 'info', - text: `${badClient.nick} was moved into ?${data.channel}`, - }, { channel: data.channel }); + text: `${badClient.nick} was moved into ?${payload.channel}`, + }, { channel: payload.channel }); return true; } diff --git a/server/src/commands/mod/speak.js b/server/src/commands/mod/speak.js index eb3141c..19774cc 100644 --- a/server/src/commands/mod/speak.js +++ b/server/src/commands/mod/speak.js @@ -1,3 +1,5 @@ +/* eslint no-param-reassign: 0 */ + /* * Description: Pardon a dumb user to be able to speak again * Author: simple @@ -13,22 +15,24 @@ export function init(core) { } // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // increase rate limit chance and ignore if not admin or mod if (!UAC.isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } // check user input - if (typeof data.ip !== 'string' && typeof data.hash !== 'string') { + if (typeof payload.ip !== 'string' && typeof payload.hash !== 'string') { return server.reply({ cmd: 'warn', // @todo Remove english and change to numeric id text: "hash:'targethash' or ip:'1.2.3.4' is required", }, socket); } - if (typeof data.ip === 'string') { - if (data.ip === '*') { + if (typeof payload.ip === 'string') { + if (payload.ip === '*') { core.muzzledHashes = {}; return server.broadcast({ @@ -36,7 +40,7 @@ export async function run(core, server, socket, data) { text: `${socket.nick} unmuzzled all users`, }, { level: UAC.isModerator }); } - } else if (data.hash === '*') { + } else if (payload.hash === '*') { core.muzzledHashes = {}; return server.broadcast({ @@ -47,10 +51,10 @@ export async function run(core, server, socket, data) { // find target & remove mute status let target; - if (typeof data.ip === 'string') { - target = server.getSocketHash(data.ip); + if (typeof payload.ip === 'string') { + target = server.getSocketHash(payload.ip); } else { - target = data.hash; + target = payload.hash; } delete core.muzzledHashes[target]; diff --git a/server/src/commands/mod/unban.js b/server/src/commands/mod/unban.js index 29840a5..0c5cb50 100644 --- a/server/src/commands/mod/unban.js +++ b/server/src/commands/mod/unban.js @@ -1,3 +1,5 @@ +/* eslint no-console: 0 */ + /* Description: Removes a target ip from the ratelimiter */ @@ -5,14 +7,16 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket, data) { +export async function run({ + core, server, socket, payload, +}) { // increase rate limit chance and ignore if not admin or mod if (!UAC.isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } // check user input - if (typeof data.ip !== 'string' && typeof data.hash !== 'string') { + if (typeof payload.ip !== 'string' && typeof payload.hash !== 'string') { return server.reply({ cmd: 'warn', // @todo Remove english and change to numeric id text: "hash:'targethash' or ip:'1.2.3.4' is required", @@ -22,12 +26,12 @@ export async function run(core, server, socket, data) { // find target let mode; let target; - if (typeof data.ip === 'string') { + if (typeof payload.ip === 'string') { mode = 'ip'; - target = data.ip; + target = payload.ip; } else { mode = 'hash'; - target = data.hash; + target = payload.hash; } // remove arrest record diff --git a/server/src/commands/mod/unbanall.js b/server/src/commands/mod/unbanall.js index 9d417aa..b43685a 100644 --- a/server/src/commands/mod/unbanall.js +++ b/server/src/commands/mod/unbanall.js @@ -1,3 +1,5 @@ +/* eslint no-console: 0 */ + /* Description: Clears all bans and ratelimits */ @@ -5,7 +7,7 @@ import * as UAC from '../utility/UAC/_info'; // module main -export async function run(core, server, socket) { +export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin or mod if (!UAC.isModerator(socket.level)) { return server.police.frisk(socket.address, 10); diff --git a/server/src/scripts/configLib/SetupWizard.js b/server/src/scripts/configLib/SetupWizard.js index ac2f3a0..3bb0823 100644 --- a/server/src/scripts/configLib/SetupWizard.js +++ b/server/src/scripts/configLib/SetupWizard.js @@ -1,3 +1,9 @@ +/* eslint no-bitwise: 0 */ +/* eslint global-require: 0 */ +/* eslint class-methods-use-this: 0 */ +/* eslint no-param-reassign: 0 */ +/* eslint no-console: 0 */ + import { start as _start, get, @@ -8,6 +14,7 @@ import { * @author Marzavec ( https://github.com/marzavec ) * @version v2.0.0 * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) + * @todo Convert to use the `enquirer` package instead */ class SetupWizard { /** diff --git a/server/src/scripts/setupSchema/Banner.js b/server/src/scripts/setupSchema/Banner.js index f13fde7..5bb2066 100644 --- a/server/src/scripts/setupSchema/Banner.js +++ b/server/src/scripts/setupSchema/Banner.js @@ -1,3 +1,5 @@ +/* eslint no-console: 0 */ + /** * This script will be run before the package starts asking for the config data, * used to output a simple guide for the coming questions, or to spam some sexy diff --git a/server/src/scripts/setupSchema/Footer.js b/server/src/scripts/setupSchema/Footer.js index 5fb627b..98b65a5 100644 --- a/server/src/scripts/setupSchema/Footer.js +++ b/server/src/scripts/setupSchema/Footer.js @@ -1,3 +1,5 @@ +/* eslint no-console: 0 */ + /** * This script will be run once all questions have finished and no errors have * occured. You can congratulate the user on their fine choice in software usage diff --git a/server/src/scripts/setupSchema/Questions.js b/server/src/scripts/setupSchema/Questions.js index 532ba67..b62834f 100644 --- a/server/src/scripts/setupSchema/Questions.js +++ b/server/src/scripts/setupSchema/Questions.js @@ -1,3 +1,6 @@ +/* eslint no-undef: 0 */ +/* eslint global-require: 0 */ + /** * This object contains Prompt ( https://www.npmjs.com/package/prompt ) style * questions that the SetupWizard will require an answer to. Questions are asked diff --git a/server/src/serverLib/CommandManager.js b/server/src/serverLib/CommandManager.js index e715c6b..c1d9426 100644 --- a/server/src/serverLib/CommandManager.js +++ b/server/src/serverLib/CommandManager.js @@ -1,3 +1,5 @@ +/* eslint no-console: 0 */ + import { basename, join, @@ -98,6 +100,7 @@ class CommandManager { .replace(new RegExp(sep.replace('\\', '\\\\'), 'g'), '/'); } + // eslint-disable-next-line no-param-reassign command.info.category = category; if (this.categories.indexOf(category) === -1) { @@ -126,6 +129,7 @@ class CommandManager { * @private * @return {String} Module errors or null if none */ + // eslint-disable-next-line class-methods-use-this validateCommand(object) { if (typeof object !== 'object') { return 'command setup is invalid'; } if (typeof object.run !== 'function') { return 'run function is missing'; } @@ -253,11 +257,11 @@ class CommandManager { * @private * @return {*} Arbitrary module return data */ - async execute(command, server, socket, data) { + async execute(command, server, socket, payload) { if (typeof command.requiredData !== 'undefined') { const missing = []; for (let i = 0, len = command.requiredData.length; i < len; i += 1) { - if (typeof data[command.requiredData[i]] === 'undefined') { missing.push(command.requiredData[i]); } + if (typeof payload[command.requiredData[i]] === 'undefined') { missing.push(command.requiredData[i]); } } if (missing.length > 0) { @@ -278,7 +282,12 @@ class CommandManager { } try { - return await command.run(this.core, server, socket, data); + return await command.run({ + core: this.core, + server, + socket, + payload, + }); } catch (err) { const errText = `Failed to execute '${command.info.name}': `; diff --git a/server/src/serverLib/ConfigManager.js b/server/src/serverLib/ConfigManager.js index bb414be..85224f1 100644 --- a/server/src/serverLib/ConfigManager.js +++ b/server/src/serverLib/ConfigManager.js @@ -1,3 +1,5 @@ +/* eslint no-console: 0 */ + import dateFormat from 'dateformat'; import { existsSync, diff --git a/server/src/serverLib/CoreApp.js b/server/src/serverLib/CoreApp.js index 8c2225d..5fb7233 100644 --- a/server/src/serverLib/CoreApp.js +++ b/server/src/serverLib/CoreApp.js @@ -1,3 +1,5 @@ +/* eslint no-console: 0 */ + import { join } from 'path'; import { CommandManager, @@ -90,4 +92,4 @@ class CoreApp { } } -export { CoreApp }; +export { CoreApp as default }; diff --git a/server/src/serverLib/ImportsManager.js b/server/src/serverLib/ImportsManager.js index ac1fc4c..ac429a0 100644 --- a/server/src/serverLib/ImportsManager.js +++ b/server/src/serverLib/ImportsManager.js @@ -1,3 +1,6 @@ +/* eslint global-require: 0 */ +/* eslint no-console: 0 */ + import { resolve, basename as _basename, @@ -57,7 +60,7 @@ class ImportsManager { let imported; try { - imported = require(file); + imported = require(file); // eslint-disable-line import/no-dynamic-require if (!this.imports[dirName]) { this.imports[dirName] = {}; diff --git a/server/src/serverLib/MainServer.js b/server/src/serverLib/MainServer.js index 6095bbe..41af7e5 100644 --- a/server/src/serverLib/MainServer.js +++ b/server/src/serverLib/MainServer.js @@ -1,3 +1,6 @@ +/* eslint no-bitwise: 0 */ +/* eslint no-console: 0 */ + import { Server as WsServer, OPEN as SocketReady, @@ -189,10 +192,6 @@ class MainServer extends WsServer { * Issue #1: hard coded `cmd` check * Issue #2: hard coded `cmd` value checks */ - if (typeof payload.cmd === 'undefined') { - return; - } - if (typeof payload.cmd !== 'string') { return; } @@ -509,7 +508,12 @@ class MainServer extends WsServer { for (let i = 0, j = hooks.length; i < j; i += 1) { try { - newPayload = hooks[i].run(this.core, this, socket, newPayload); + newPayload = hooks[i].run({ + core: this.core, + server: this, + socket, + payload: newPayload, + }); } catch (err) { const errText = `Hook failure, '${type}', '${command}': `; if (this.core.config.logErrDetailed === true) { diff --git a/server/src/serverLib/RateLimiter.js b/server/src/serverLib/RateLimiter.js index de91e5e..9e526b7 100644 --- a/server/src/serverLib/RateLimiter.js +++ b/server/src/serverLib/RateLimiter.js @@ -77,6 +77,7 @@ class RateLimiter { return true; } + // eslint-disable-next-line no-restricted-properties record.score *= Math.pow(2, -(Date.now() - record.time) / this.halflife); record.score += deltaScore; record.time = Date.now(); diff --git a/server/src/serverLib/index.js b/server/src/serverLib/index.js index a820588..21cfa14 100644 --- a/server/src/serverLib/index.js +++ b/server/src/serverLib/index.js @@ -1,3 +1,5 @@ +/* eslint global-require: 0 */ + export const CommandManager = require('./CommandManager').default; export const ConfigManager = require('./ConfigManager').default; export const ImportsManager = require('./ImportsManager').default; From 5eb695bc535820b9127a6f2fca49c18038010ff6 Mon Sep 17 00:00:00 2001 From: marzavec Date: Tue, 22 Sep 2020 00:34:30 -0500 Subject: [PATCH 03/37] Removed legacylayer, baked into modules instead Originally I wanted the legacy layer to be a seperate module, allowing a server owner to remove legacy support by removing the module (for preformance). However, I didn't like the 39 thousand hooks that would be required and what this would do for latency. I dont like this alternative either though. /shrug Added channel helper functions. Added constants for warnings and errors. Started updating warning to have an id for i18l. Added legacy helper functions Moved the UAC module into the utility directory and renamed to _UAC. --- server/src/commands/admin/saveconfig.js | 2 +- server/src/commands/core/changenick.js | 12 +- server/src/commands/core/chat.js | 5 +- server/src/commands/core/emote.js | 4 +- server/src/commands/core/help.js | 2 +- server/src/commands/core/invite.js | 50 +++-- server/src/commands/core/join.js | 191 ++++++++---------- server/src/commands/core/move.js | 6 +- server/src/commands/core/session.js | 1 + server/src/commands/core/whisper.js | 8 +- server/src/commands/internal/legacylayer.js | 166 --------------- server/src/commands/internal/socketreply.js | 2 +- server/src/commands/mod/ban.js | 43 ++-- server/src/commands/mod/dumb.js | 37 ++-- server/src/commands/mod/kick.js | 47 +++-- server/src/commands/mod/moveuser.js | 5 +- server/src/commands/mod/speak.js | 2 +- server/src/commands/mod/unban.js | 2 +- server/src/commands/utility/UAC/_info.js | 1 + server/src/commands/utility/_Channels.js | 85 ++++++++ server/src/commands/utility/_Constants.js | 34 ++++ .../src/commands/utility/_LegacyFunctions.js | 90 +++++++++ server/src/commands/utility/_UAC.js | 186 +++++++++++++++++ 23 files changed, 624 insertions(+), 357 deletions(-) delete mode 100644 server/src/commands/internal/legacylayer.js create mode 100644 server/src/commands/utility/_Channels.js create mode 100644 server/src/commands/utility/_Constants.js create mode 100644 server/src/commands/utility/_LegacyFunctions.js create mode 100644 server/src/commands/utility/_UAC.js diff --git a/server/src/commands/admin/saveconfig.js b/server/src/commands/admin/saveconfig.js index f13bdee..bc01270 100644 --- a/server/src/commands/admin/saveconfig.js +++ b/server/src/commands/admin/saveconfig.js @@ -14,7 +14,7 @@ export async function run({ core, server, socket }) { // attempt save, notify of failure if (!core.configManager.save()) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Failed to save config, check logs.', }, socket); } diff --git a/server/src/commands/core/changenick.js b/server/src/commands/core/changenick.js index a081a1e..e520aba 100644 --- a/server/src/commands/core/changenick.js +++ b/server/src/commands/core/changenick.js @@ -12,7 +12,7 @@ export async function run({ }) { if (server.police.frisk(socket.address, 6)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing nicknames too fast. Wait a moment before trying again.', }, socket); } @@ -28,7 +28,7 @@ export async function run({ const newNick = payload.nick.trim(); if (!UAC.verifyNickname(newNick)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Nickname must consist of up to 24 letters, numbers, and underscores', }, socket); } @@ -39,14 +39,14 @@ export async function run({ server.police.frisk(socket.address, 4); return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are not the admin, liar!', }, socket); } if (newNick == previousNick) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'You already have that name', }, socket); } @@ -63,7 +63,7 @@ export async function run({ if (userExists.length > 0) { // That nickname is already in that channel return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Nickname taken', }, socket); } @@ -118,7 +118,7 @@ export function nickCheck({ // If there is no nickname target parameter if (input[1] === undefined) { server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help nick` for instructions on how to use this command.', }, socket); diff --git a/server/src/commands/core/chat.js b/server/src/commands/core/chat.js index 2c3d6e3..f8998a5 100644 --- a/server/src/commands/core/chat.js +++ b/server/src/commands/core/chat.js @@ -37,7 +37,7 @@ export async function run({ const score = text.length / 83 / 4; if (server.police.frisk(socket.address, score)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } @@ -46,6 +46,7 @@ export async function run({ const outgoingPayload = { cmd: 'chat', nick: socket.nick, /* @legacy */ + uType: socket.uType, /* @legacy */ userid: socket.userid, channel: socket.channel, text, @@ -111,7 +112,7 @@ export function finalCmdCheck({ server, socket, payload }) { } server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: `Unknown command: ${payload.text}`, }, socket); diff --git a/server/src/commands/core/emote.js b/server/src/commands/core/emote.js index b21d7b6..1939e6f 100644 --- a/server/src/commands/core/emote.js +++ b/server/src/commands/core/emote.js @@ -33,7 +33,7 @@ export async function run({ server, socket, payload }) { const score = text.length / 83 / 4; if (server.police.frisk(socket.address, score)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } @@ -78,7 +78,7 @@ export function emoteCheck({ // If there is no emote target parameter if (input[1] === undefined) { server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help emote` for instructions on how to use this command.', }, socket); diff --git a/server/src/commands/core/help.js b/server/src/commands/core/help.js index 56069c5..faebd14 100644 --- a/server/src/commands/core/help.js +++ b/server/src/commands/core/help.js @@ -9,7 +9,7 @@ export async function run({ // check for spam if (server.police.frisk(socket.address, 2)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } diff --git a/server/src/commands/core/invite.js b/server/src/commands/core/invite.js index 7136892..14fcb74 100644 --- a/server/src/commands/core/invite.js +++ b/server/src/commands/core/invite.js @@ -2,6 +2,17 @@ Description: Generates a semi-unique channel name then broadcasts it to each client */ +import { + findUser, +} from '../utility/_Channels'; +import { + Errors, +} from '../utility/_Constants'; +import { + legacyInviteOut, + legacyInviteReply, +} from '../utility/_LegacyFunctions'; + // module support functions /** * Returns the channel that should be invited to. @@ -22,34 +33,35 @@ export async function run({ // check for spam if (server.police.frisk(socket.address, 2)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', text: 'You are sending invites too fast. Wait a moment before trying again.', + id: Errors.Invite.RATELIMIT, }, socket); } // verify user input - if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') { - return true; - } + // if this is a legacy client add missing params to payload + if (socket.hcProtocol === 1) { + if (typeof socket.channel === 'undefined' || typeof payload.nick !== 'string') { + return true; + } - // why would you invite yourself? - if (payload.userid === socket.userid) { + payload.channel = socket.channel; // eslint-disable-line no-param-reassign + } else if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') { return true; } // @todo Verify this socket is part of payload.channel - multichannel patch // find target user - let targetClient = server.findSockets({ channel: payload.channel, userid: payload.userid }); - - if (targetClient.length === 0) { + const targetUser = findUser(server, payload); + if (!targetUser) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, }, socket); } - [targetClient] = targetClient; - // generate common channel const channel = getChannel(payload.to); @@ -58,15 +70,23 @@ export async function run({ cmd: 'invite', channel: socket.channel, from: socket.userid, - to: payload.userid, + to: targetUser.userid, inviteChannel: channel, }; // send invite notice to target client - server.reply(outgoingPayload, targetClient); + if (targetUser.hcProtocol === 1) { + server.reply(legacyInviteOut(outgoingPayload, socket.nick), targetUser); + } else { + server.reply(outgoingPayload, targetUser); + } // send invite notice to this client - server.reply(outgoingPayload, socket); + if (socket.hcProtocol === 1) { + server.reply(legacyInviteReply(outgoingPayload, targetUser.nick), socket); + } else { + server.reply(outgoingPayload, socket); + } // stats are fun core.stats.increment('invites-sent'); diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index 3ee6722..037eb6c 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -1,139 +1,118 @@ /* eslint no-param-reassign: 0 */ /* - Description: Initial entry point, applies `channel` and `nick` to the calling socket + Description: Adds requested channel into the calling clients "subscribed channels" */ -import * as UAC from '../utility/UAC/_info'; - -// module support functions -const crypto = require('crypto'); - -const hash = (password) => { - const sha = crypto.createHash('sha256'); - sha.update(password); - return sha.digest('base64').substr(0, 6); -}; - -// exposed "login" function to allow hooks to verify user join events -// returns object containing user info or string if error -export function parseNickname(core, data) { - const userInfo = { - nick: data.nick, - uType: 'user', /* @legacy */ - trip: null, - level: UAC.levels.default, - }; - - if (!UAC.verifyNickname(userInfo.nick)) { - // return error as string - // @todo Remove english and change to numeric id - return 'Nickname must consist of up to 24 letters, numbers, and underscores'; - } - - const password = data.pass || false; - - if (hash(password + core.config.tripSalt) === core.config.adminTrip) { - userInfo.uType = 'admin'; /* @legacy */ - userInfo.trip = 'Admin'; - userInfo.level = UAC.levels.admin; - } else if (userInfo.nick.toLowerCase() === core.config.adminName.toLowerCase()) { - // they've got the main-admin name while not being an admin - // @todo Remove english and change to numeric id - return 'You are not the admin, liar!'; - } else if (password) { - userInfo.trip = hash(password + core.config.tripSalt); - } - - // @todo disallow moderator impersonation - // for (const mod of core.config.mods) { - core.config.mods.forEach((mod) => { - if (userInfo.trip === mod.trip) { - userInfo.uType = 'mod'; /* @legacy */ - userInfo.level = UAC.levels.moderator; - } - }); - - return userInfo; -} +// import * as UAC from '../utility/UAC/_info'; +import { + canJoinChannel, +} from '../utility/_Channels'; +import { + Errors, +} from '../utility/_Constants'; +import { + upgradeLegacyJoin, + legacyLevelToLabel, +} from '../utility/_LegacyFunctions'; +import { + verifyNickname, + getUserPerms, +} from '../utility/_UAC'; // module main export async function run({ core, server, socket, payload, -}) { - // check for spam +}) { // check for spam if (server.police.frisk(socket.address, 3)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', text: 'You are joining channels too fast. Wait a moment and try again.', + id: Errors.Join.RATELIMIT, + }, socket); + } + + // `join` is the legacy entry point, check if it needs to be upgraded + if (typeof socket.hcProtocol === 'undefined') { + payload = upgradeLegacyJoin(server, socket, payload); + } + + // store payload values + const { channel, nick, pass } = payload; + + // check if a client is able to join target channel + const mayJoin = canJoinChannel(channel, socket); + if (mayJoin !== true) { + return server.reply({ + cmd: 'warn', + text: 'You may not join that channel.', + id: mayJoin, }, socket); } // calling socket already in a channel - // @todo Multichannel update + // @todo multichannel update, will remove if (typeof socket.channel !== 'undefined') { return server.reply({ cmd: 'warn', // @todo Remove this text: 'Joining more than one channel is not currently supported', + id: Errors.Join.ALREADY_JOINED, }, socket); } + // end todo - // check user input - if (typeof payload.channel !== 'string' || typeof payload.nick !== 'string') { - return true; - } - - const channel = payload.channel.trim(); - if (!channel) { - // must join a non-blank channel - return true; - } - - const userInfo = this.parseNickname(core, payload); - if (typeof userInfo === 'string') { + // validates the user input for `nick` + const validName = verifyNickname(nick, socket); + if (validName !== true) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id - text: userInfo, + cmd: 'warn', + text: 'Nickname must consist of up to 24 letters, numbers, and underscores', + id: Errors.Join.INVALID_NICK, }, socket); } + // get trip and level + const { trip, level } = getUserPerms(pass, core.config, channel); + // store the user values + const userInfo = { + nick, + trip, + uType: legacyLevelToLabel(level), + hash: socket.hash, + level, + userid: socket.userid, + channel, + }; + + // prevent admin impersonation + if (nick.toLowerCase() === core.config.adminName.toLowerCase()) { + if (userInfo.trip !== 'Admin') { + userInfo.nick = `Fake${userInfo.nick}`; + } + } + // check if the nickname already exists in the channel const userExists = server.findSockets({ - channel: payload.channel, + channel, nick: (targetNick) => targetNick.toLowerCase() === userInfo.nick.toLowerCase(), }); if (userExists.length > 0) { // that nickname is already in that channel return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', text: 'Nickname taken', + id: Errors.Join.NAME_TAKEN, }, socket); } - // populate final userinfo fields - // @todo this could be move into parseNickname, changing the function name to match - userInfo.hash = server.getSocketHash(socket); - userInfo.userid = socket.userid; - - // @todo place this within it's own function allowing import // prepare to notify channel peers - const newPeerList = server.findSockets({ channel: payload.channel }); + const newPeerList = server.findSockets({ channel }); const nicks = []; /* @legacy */ const users = []; + const joinAnnouncement = { ...{ cmd: 'onlineAdd' }, ...userInfo }; - const joinAnnouncement = { - cmd: 'onlineAdd', - nick: userInfo.nick, - trip: userInfo.trip || 'null', - utype: userInfo.uType, /* @legacy */ - hash: userInfo.hash, - level: userInfo.level, - userid: userInfo.userid, - channel: payload.channel, - }; - - // send join announcement and prep online set + // send join announcement and prep online set reply for (let i = 0, l = newPeerList.length; i < l; i += 1) { server.reply(joinAnnouncement, newPeerList[i]); nicks.push(newPeerList[i].nick); /* @legacy */ @@ -141,34 +120,26 @@ export async function run({ users.push({ nick: newPeerList[i].nick, trip: newPeerList[i].trip, - utype: newPeerList[i].uType, /* @legacy */ + uType: newPeerList[i].uType, /* @legacy */ hash: newPeerList[i].hash, level: newPeerList[i].level, userid: newPeerList[i].userid, - channel: payload.channel, + channel, isme: false, }); } // store user info - socket.uType = userInfo.uType; /* @legacy */ socket.nick = userInfo.nick; socket.trip = userInfo.trip; - socket.channel = payload.channel; /* @legacy */ - socket.hash = userInfo.hash; socket.level = userInfo.level; + socket.uType = userInfo.uType; /* @legacy */ + socket.channel = channel; /* @legacy */ + // @todo multi-channel patch + // socket.channels.push(channel); - nicks.push(socket.nick); /* @legacy */ - users.push({ - nick: socket.nick, - trip: socket.trip, - utype: socket.uType, - hash: socket.hash, - level: socket.level, - userid: socket.userid, - channel: payload.channel, - isme: true, - }); + nicks.push(userInfo.nick); /* @legacy */ + users.push({ ...{ isme: true }, ...userInfo }); // reply with channel peer list server.reply({ @@ -186,7 +157,7 @@ export async function run({ export const requiredData = []; // ['channel', 'nick']; export const info = { name: 'join', - description: 'Place calling socket into target channel with target nick & broadcast event to channel', + description: 'Join the target channel using the supplied nick and password', usage: ` API: { cmd: 'join', nick: '', pass: '', channel: '' }`, }; diff --git a/server/src/commands/core/move.js b/server/src/commands/core/move.js index e27445c..a0ff8e1 100644 --- a/server/src/commands/core/move.js +++ b/server/src/commands/core/move.js @@ -8,7 +8,7 @@ export async function run({ server, socket, payload }) { // check for spam if (server.police.frisk(socket.address, 6)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing channels too fast. Wait a moment before trying again.', }, socket); } @@ -20,7 +20,7 @@ export async function run({ server, socket, payload }) { if (payload.channel === '') { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Cannot move to an empty channel.', }, socket); } @@ -109,7 +109,7 @@ export function moveCheck({ // If there is no channel target parameter if (input[1] === undefined) { server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help move` for instructions on how to use this command.', }, socket); diff --git a/server/src/commands/core/session.js b/server/src/commands/core/session.js index 4a4c9b4..1012400 100644 --- a/server/src/commands/core/session.js +++ b/server/src/commands/core/session.js @@ -53,6 +53,7 @@ export async function run({ server, socket }) { socket.sessionID = createSessionID(); socket.hcProtocol = 2; socket.userid = Math.floor(Math.random() * 9999999999999); + socket.hash = server.getSocketHash(socket); // dispatch info server.reply({ diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index 5ed7d8f..fe9ead6 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -38,7 +38,7 @@ export async function run({ server, socket, payload }) { const score = text.length / 83 / 4; if (server.police.frisk(socket.address, score)) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', }, socket); } @@ -53,7 +53,7 @@ export async function run({ server, socket, payload }) { if (targetClient.length === 0) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Could not find user in channel', }, socket); } @@ -98,7 +98,7 @@ export function whisperCheck({ // If there is no nickname target parameter if (input[1] === undefined) { server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help whisper` for instructions on how to use this command.', }, socket); @@ -126,7 +126,7 @@ export function whisperCheck({ if (payload.text.startsWith('/r ')) { if (typeof socket.whisperReply === 'undefined') { server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Cannot reply to nobody', }, socket); diff --git a/server/src/commands/internal/legacylayer.js b/server/src/commands/internal/legacylayer.js deleted file mode 100644 index f4775b0..0000000 --- a/server/src/commands/internal/legacylayer.js +++ /dev/null @@ -1,166 +0,0 @@ -/* eslint no-param-reassign: 0 */ - -/* - Description: This module adjusts outgoing data, making it compatible with legacy clients - Dear god this module is horrifying -*/ - -// import * as UAC from '../utility/UAC/_info'; - -// module main -export async function run({ server, socket }) { - return server.police.frisk(socket.address, 20); -} - -// module hook functions -export function initHooks(server) { - server.registerHook('in', 'join', this.joinCheck.bind(this), 10); - server.registerHook('in', 'invite', this.inviteInCheck.bind(this), 10); - server.registerHook('out', 'invite', this.inviteOutCheck.bind(this), 10); - server.registerHook('in', 'ban', this.banCheck.bind(this), 10); - server.registerHook('in', 'dumb', this.dumbCheck.bind(this), 10); - server.registerHook('in', 'kick', this.kickCheck.bind(this), 10); -} - -// hook incoming join events, if session was not invoked, default proto to 1 -export function joinCheck({ socket, payload }) { - if (typeof socket.hcProtocol === 'undefined') { - socket.hcProtocol = 1; - - const nickArray = payload.nick.split('#', 2); - payload.nick = nickArray[0].trim(); - if (nickArray[1] && typeof payload.pass === 'undefined') { - payload.pass = nickArray[1]; // eslint-disable-line prefer-destructuring - } - - // dunno how this happened on the legacy version - if (typeof payload.password !== 'undefined') { - payload.pass = payload.password; - } - - if (typeof socket.userid === 'undefined') { - socket.userid = Math.floor(Math.random() * 9999999999999); - } - } - - return payload; -} - -// if legacy client sent an invite, downgrade request -export function inviteInCheck({ server, socket, payload }) { - if (socket.hcProtocol === 1) { - let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick }); - - if (targetClient.length === 0) { - server.reply({ - cmd: 'warn', - text: 'Could not find user in that channel', - }, socket); - - return false; - } - - [targetClient] = targetClient; - - payload.userid = targetClient.userid; - payload.channel = socket.channel; - } - - return payload; -} - -// -export function inviteOutCheck({ server, socket, payload }) { - if (socket.hcProtocol === 1) { - payload.cmd = 'info'; - if (socket.userid === payload.from) { - let toClient = server.findSockets({ channel: socket.channel, userid: payload.from }); - [toClient] = toClient; - payload.type = 'invite'; - payload.from = toClient.nick; - payload.text = `You invited ${toClient.nick} to ?${payload.inviteChannel}`; - } else if (socket.userid === payload.to) { - let fromClient = server.findSockets({ channel: socket.channel, userid: payload.from }); - [fromClient] = fromClient; - payload.type = 'invite'; - payload.from = fromClient.nick; - payload.text = `${fromClient.nick} invited you to ?${payload.inviteChannel}`; - } - } - - return payload; -} - -export function banCheck({ server, socket, payload }) { - if (socket.hcProtocol === 1) { - let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick }); - - if (targetClient.length === 0) { - server.reply({ - cmd: 'warn', - text: 'Could not find user in that channel', - }, socket); - - return false; - } - - [targetClient] = targetClient; - - payload.userid = targetClient.userid; - payload.channel = socket.channel; - } - - return payload; -} - -export function dumbCheck({ server, socket, payload }) { - if (socket.hcProtocol === 1) { - let targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick }); - - if (targetClient.length === 0) { - server.reply({ - cmd: 'warn', - text: 'Could not find user in that channel', - }, socket); - - return false; - } - - [targetClient] = targetClient; - - payload.userid = targetClient.userid; - payload.channel = socket.channel; - } - - return payload; -} - -export function kickCheck({ server, socket, payload }) { - if (socket.hcProtocol === 1) { - if (typeof payload.nick !== 'number') { - if (typeof payload.nick !== 'object' && !Array.isArray(payload.nick)) { - return true; - } - } - - const targetClient = server.findSockets({ channel: socket.channel, nick: payload.nick }); - - if (targetClient.length === 0) { - return false; - } - - payload.userid = []; - for (let i = 0, j = targetClient.length; i < j; i += 1) { - payload.userid.push(targetClient[i].userid); - } - - payload.channel = socket.channel; - } - - return payload; -} - -export const info = { - name: 'legacylayer', - description: 'This module adjusts outgoing data, making it compatible with legacy clients', -}; diff --git a/server/src/commands/internal/socketreply.js b/server/src/commands/internal/socketreply.js index 4221a76..9c7ddc8 100644 --- a/server/src/commands/internal/socketreply.js +++ b/server/src/commands/internal/socketreply.js @@ -11,7 +11,7 @@ export async function run({ server, socket, payload }) { // send warning to target socket server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: payload.text, }, socket); diff --git a/server/src/commands/mod/ban.js b/server/src/commands/mod/ban.js index ff601e8..8d6721d 100644 --- a/server/src/commands/mod/ban.js +++ b/server/src/commands/mod/ban.js @@ -4,6 +4,12 @@ */ import * as UAC from '../utility/UAC/_info'; +import { + Errors, +} from '../utility/_Constants'; +import { + findUser, +} from '../utility/_Channels'; // module main export async function run({ @@ -15,33 +21,38 @@ export async function run({ } // check user input - if (typeof payload.userid !== 'number') { + if (socket.hcProtocol === 1) { + if (typeof payload.nick !== 'string') { + return true; + } + + payload.channel = socket.channel; // eslint-disable-line no-param-reassign + } else if (typeof payload.userid !== 'number') { return true; } // find target user - let badClient = server.findSockets({ channel: socket.channel, userid: payload.userid }); - - if (badClient.length === 0) { + const targetUser = findUser(server, payload); + if (!targetUser) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id - text: 'Could not find user in channel', + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, }, socket); } - - [badClient] = badClient; - const targetNick = badClient.nick; + const targetNick = targetUser.nick; // i guess banning mods or admins isn't the best idea? - if (badClient.level >= socket.level) { + if (targetUser.level >= socket.level) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', text: 'Cannot ban other users of the same level, how rude', + id: Errors.Global.PERMISSION, }, socket); } // commit arrest record - server.police.arrest(badClient.address, badClient.hash); + server.police.arrest(targetUser.address, targetUser.hash); console.log(`${socket.nick} [${socket.trip}] banned ${targetNick} in ${socket.channel}`); @@ -49,20 +60,20 @@ export async function run({ server.broadcast({ cmd: 'info', text: `Banned ${targetNick}`, - user: UAC.getUserDetails(badClient), + user: UAC.getUserDetails(targetUser), }, { channel: socket.channel, level: (level) => level < UAC.levels.moderator }); // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${badClient.hash}`, + text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${targetUser.hash}`, channel: payload.channel, - user: UAC.getUserDetails(badClient), + user: UAC.getUserDetails(targetUser), banner: UAC.getUserDetails(socket), }, { level: UAC.isModerator }); // force connection closed - badClient.terminate(); + targetUser.terminate(); // stats are fun core.stats.increment('users-banned'); diff --git a/server/src/commands/mod/dumb.js b/server/src/commands/mod/dumb.js index 3f8723f..a10d1cb 100644 --- a/server/src/commands/mod/dumb.js +++ b/server/src/commands/mod/dumb.js @@ -7,6 +7,12 @@ */ import * as UAC from '../utility/UAC/_info'; +import { + Errors, +} from '../utility/_Constants'; +import { + findUser, +} from '../utility/_Channels'; // module constructor export function init(core) { @@ -25,32 +31,37 @@ export async function run({ } // check user input - if (typeof payload.userid !== 'number') { + if (socket.hcProtocol === 1) { + if (typeof payload.nick !== 'string') { + return true; + } + + payload.channel = socket.channel; + } else if (typeof payload.userid !== 'number') { return true; } // find target user - let badClient = server.findSockets({ channel: payload.channel, userid: payload.userid }); - - if (badClient.length === 0) { + const targetUser = findUser(server, payload); + if (!targetUser) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id - text: 'Could not find user in channel', + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, }, socket); } - [badClient] = badClient; - // likely dont need this, muting mods and admins is fine - if (badClient.level >= socket.level) { + if (targetUser.level >= socket.level) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', text: 'This trick wont work on users of the same level', + id: Errors.Global.PERMISSION, }, socket); } // store hash in mute list - const record = core.muzzledHashes[badClient.hash] = { + const record = core.muzzledHashes[targetUser.hash] = { dumb: true, }; @@ -62,7 +73,7 @@ export async function run({ // notify mods server.broadcast({ cmd: 'info', - text: `${socket.nick}#${socket.trip} muzzled ${badClient.nick} in ${payload.channel}, userhash: ${badClient.hash}`, + text: `${socket.nick}#${socket.trip} muzzled ${targetUser.nick} in ${payload.channel}, userhash: ${targetUser.hash}`, }, { level: UAC.isModerator }); return true; @@ -129,7 +140,7 @@ export function inviteCheck({ core, socket, payload }) { /* const nickValid = Invite.checkNickname(payload.nick); if (nickValid !== null) { server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: nickValid, }, socket); return false; diff --git a/server/src/commands/mod/kick.js b/server/src/commands/mod/kick.js index 0c73e2a..3f93cd6 100644 --- a/server/src/commands/mod/kick.js +++ b/server/src/commands/mod/kick.js @@ -5,6 +5,12 @@ */ import * as UAC from '../utility/UAC/_info'; +import { + Errors, +} from '../utility/_Constants'; +import { + findUsers, +} from '../utility/_Channels'; // module main export async function run({ @@ -16,27 +22,28 @@ export async function run({ } // check user input - if (typeof payload.userid !== 'number') { + if (socket.hcProtocol === 1) { + if (typeof payload.nick !== 'string') { + if (typeof payload.nick !== 'object' && !Array.isArray(payload.nick)) { + return true; + } + } + + payload.channel = socket.channel; // eslint-disable-line no-param-reassign + } else if (typeof payload.userid !== 'number') { // @todo create multi-ban ui if (typeof payload.userid !== 'object' && !Array.isArray(payload.userid)) { return true; } } - let destChannel; - if (typeof payload.to === 'string' && !!payload.to.trim()) { - destChannel = payload.to; - } else { - destChannel = Math.random().toString(36).substr(2, 8); - } - // find target user(s) - const badClients = server.findSockets({ channel: payload.channel, userid: payload.userid }); - + const badClients = findUsers(server, payload); if (badClients.length === 0) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id - text: 'Could not find user(s) in channel', + cmd: 'warn', + text: 'Could not find user(s) in that channel', + id: Errors.Global.UNKNOWN_USER, }, socket); } @@ -45,8 +52,9 @@ export async function run({ for (let i = 0, j = badClients.length; i < j; i += 1) { if (badClients[i].level >= socket.level) { server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', text: 'Cannot kick other users with the same level, how rude', + id: Errors.Global.PERMISSION, }, socket); } else { kicked.push(badClients[i]); @@ -57,6 +65,13 @@ export async function run({ return true; } + let destChannel; + if (typeof payload.to === 'string' && !!payload.to.trim()) { + destChannel = payload.to; + } else { + destChannel = Math.random().toString(36).substr(2, 8); + } + // Announce the kicked clients arrival in destChannel and that they were kicked // Before they arrive, so they don't see they got moved for (let i = 0; i < kicked.length; i += 1) { @@ -64,12 +79,17 @@ export async function run({ cmd: 'onlineAdd', nick: kicked[i].nick, trip: kicked[i].trip || 'null', + uType: 'user', hash: kicked[i].hash, + level: UAC.levels.default, + userid: kicked[i].userid, + channel: destChannel, }, { channel: destChannel }); } // Move all kicked clients to the new channel for (let i = 0; i < kicked.length; i += 1) { + // @todo multi-channel update kicked[i].channel = destChannel; server.broadcast({ @@ -84,6 +104,7 @@ export async function run({ for (let i = 0, j = kicked.length; i < j; i += 1) { server.broadcast({ cmd: 'onlineRemove', + userid: kicked[i].userid, nick: kicked[i].nick, }, { channel: socket.channel }); } diff --git a/server/src/commands/mod/moveuser.js b/server/src/commands/mod/moveuser.js index 331dcae..7c248b6 100644 --- a/server/src/commands/mod/moveuser.js +++ b/server/src/commands/mod/moveuser.js @@ -1,5 +1,6 @@ /* Description: Removes the target socket from the current channel and forces a join event in another + @deprecated This module will be removed or replaced */ import * as UAC from '../utility/UAC/_info'; @@ -25,7 +26,7 @@ export async function run({ server, socket, payload }) { if (badClients.length === 0) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Could not find user in channel', }, socket); } @@ -34,7 +35,7 @@ export async function run({ server, socket, payload }) { if (badClient.level >= socket.level) { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: 'Cannot move other users of the same level, how rude', }, socket); } diff --git a/server/src/commands/mod/speak.js b/server/src/commands/mod/speak.js index 19774cc..35dcde3 100644 --- a/server/src/commands/mod/speak.js +++ b/server/src/commands/mod/speak.js @@ -26,7 +26,7 @@ export async function run({ // check user input if (typeof payload.ip !== 'string' && typeof payload.hash !== 'string') { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: "hash:'targethash' or ip:'1.2.3.4' is required", }, socket); } diff --git a/server/src/commands/mod/unban.js b/server/src/commands/mod/unban.js index 0c5cb50..e8dc042 100644 --- a/server/src/commands/mod/unban.js +++ b/server/src/commands/mod/unban.js @@ -18,7 +18,7 @@ export async function run({ // check user input if (typeof payload.ip !== 'string' && typeof payload.hash !== 'string') { return server.reply({ - cmd: 'warn', // @todo Remove english and change to numeric id + cmd: 'warn', // @todo Add numeric error code as `id` text: "hash:'targethash' or ip:'1.2.3.4' is required", }, socket); } diff --git a/server/src/commands/utility/UAC/_info.js b/server/src/commands/utility/UAC/_info.js index 7981afc..a43f0e6 100644 --- a/server/src/commands/utility/UAC/_info.js +++ b/server/src/commands/utility/UAC/_info.js @@ -1,3 +1,4 @@ +// NOTE: this has been moved into /utility/ as _UAC.js /** * User Account Control information containing level constants * and simple helper functions related to users diff --git a/server/src/commands/utility/_Channels.js b/server/src/commands/utility/_Channels.js new file mode 100644 index 0000000..15ba3f4 --- /dev/null +++ b/server/src/commands/utility/_Channels.js @@ -0,0 +1,85 @@ +import { + Errors, +} from './_Constants'; + +/** + * Checks if a client can join `channel`, returns numeric error code or true if + * able to join + * @public + * @param {string} channel Target channel + * @param {object} socket Target client to evaluate + * @return {boolean||error id} + */ +// eslint-disable-next-line no-unused-vars +export function canJoinChannel(channel, socket) { + if (typeof channel !== 'string') return Errors.Channel.INVALID_NAME; + if (channel === '') return Errors.Channel.INVALID_NAME; + if (channel.length > 120) return Errors.Channel.INVALID_LENGTH; + + return true; +} + +/** + * Returns an object containing info about the specified channel, + * including if it is owned, mods, permissions + * @public + * @param {string} config Server config object + * @param {string} channel Target channel + * @return {object} + */ +export function getChannelSettings(config, channel) { + if (typeof config.channels !== 'undefined') { + if (typeof config.channels[channel] !== 'undefined') { + return config.channels[channel]; + } + } + + return { + owned: false, + }; +} + +/** + * Returns an object containing info about the specified channel, + * including if it is owned, mods, permissions + * @public + * @param {MainServer} server Main server reference + * @param {object} payload Object containing `userid` or `nick` + * @param {number} limit Optional return limit + * @return {array} + */ +export function findUsers(server, payload, limit = 0) { + let targetClients; + + if (typeof payload.userid !== 'undefined') { + targetClients = server.findSockets({ + channel: payload.channel, + userid: payload.userid, + }); + } else if (typeof payload.nick !== 'undefined') { + targetClients = server.findSockets({ + channel: payload.channel, + nick: payload.nick, + }); + } else { + return []; + } + + if (limit !== 0 && targetClients.length > limit) { + return targetClients.splice(0, limit); + } + + return targetClients; +} + +/** + * Overload for `findUsers` when only 1 user is expected + * @public + * @param {MainServer} server Main server reference + * @param {object} payload Object containing `userid` or `nick` + * @param {number} limit Optional return limit + * @return {boolean||object} + */ +export function findUser(server, payload) { + return findUsers(server, payload, 1)[0] || false; +} diff --git a/server/src/commands/utility/_Constants.js b/server/src/commands/utility/_Constants.js new file mode 100644 index 0000000..1f18aa1 --- /dev/null +++ b/server/src/commands/utility/_Constants.js @@ -0,0 +1,34 @@ +/* Base error ranges */ +const GlobalErrors = 10; +const JoinErrors = 20; +const ChannelErrors = 30; +const InviteErrors = 40; + +/** + * Holds the numeric id values for each error type + * @typedef {object} Errors + */ +exports.Errors = { + Global: { + RATELIMIT: GlobalErrors + 1, + UNKNOWN_USER: GlobalErrors + 2, + PERMISSION: GlobalErrors + 3, + }, + + Join: { + RATELIMIT: JoinErrors + 1, + INVALID_NICK: JoinErrors + 2, + ALREADY_JOINED: JoinErrors + 3, + NAME_TAKEN: JoinErrors + 4, + }, + + Channel: { + INVALID_NAME: ChannelErrors + 1, + INVALID_LENGTH: ChannelErrors + 2, + }, + + Invite: { + RATELIMIT: InviteErrors + 1, + INVALID_LENGTH: InviteErrors + 2, + }, +}; diff --git a/server/src/commands/utility/_LegacyFunctions.js b/server/src/commands/utility/_LegacyFunctions.js new file mode 100644 index 0000000..a55987f --- /dev/null +++ b/server/src/commands/utility/_LegacyFunctions.js @@ -0,0 +1,90 @@ +/* eslint no-param-reassign: 0 */ + +import { + isAdmin, + isModerator, +} from './_UAC'; + +/** + * Marks the socket as using the legacy protocol and + * applies the missing `pass` property to the payload + * @param {MainServer} server Main server reference + * @param {WebSocket} socket Target client socket + * @param {object} payload The original `join` payload + * @returns {object} + */ +export function upgradeLegacyJoin(server, socket, payload) { + const newPayload = payload; + + // `join` is the legacy entry point, so apply protocol version + socket.hcProtocol = 1; + + // this would have been applied in the `session` module, apply it now + socket.hash = server.getSocketHash(socket); + + // pull the password from the nick + const nickArray = payload.nick.split('#', 2); + newPayload.nick = nickArray[0].trim(); + if (nickArray[1] && typeof payload.pass === 'undefined') { + newPayload.pass = nickArray[1]; // eslint-disable-line prefer-destructuring + } + + // dunno how this happened on the legacy version + if (typeof payload.password !== 'undefined') { + newPayload.pass = payload.password; + } + + // apply the missing `userid` prop + if (typeof socket.userid === 'undefined') { + socket.userid = Math.floor(Math.random() * 9999999999999); + } + + return newPayload; +} + +/** + * Return the correct `uType` label for the specific level + * @param {number} level Numeric level to find the label for + */ +export function legacyLevelToLabel(level) { + if (isAdmin(level)) return 'admin'; + if (isModerator(level)) return 'mod'; + + return 'user'; +} + +/** + * Alter the outgoing payload to an `info` cmd and add/change missing props + * @param {object} payload Numeric level to find the label for + * @param {string} nick Numeric level to find the label for + * @return {object} + */ +export function legacyInviteOut(payload, nick) { + return { + ...payload, + ...{ + cmd: 'info', + type: 'invite', + from: nick, + text: `${nick} invited you to ?${payload.inviteChannel}`, + }, + }; +} + +/** + * Alter the outgoing payload to an `info` cmd and add/change missing props + * @param {object} payload Numeric level to find the label for + * @param {string} nick Numeric level to find the label for + * @return {object} + */ +export function legacyInviteReply(payload, nick) { + return { + ...payload, + ...{ + cmd: 'info', + type: 'invite', + from: '', + text: `You invited ${nick} to ?${payload.inviteChannel}`, + }, + }; +} diff --git a/server/src/commands/utility/_UAC.js b/server/src/commands/utility/_UAC.js new file mode 100644 index 0000000..aee98d2 --- /dev/null +++ b/server/src/commands/utility/_UAC.js @@ -0,0 +1,186 @@ +/** + * User Account Control information containing level constants + * and simple helper functions related to users + * @property {Object} levels - Defines labels for default permission ranges + * @author MinusGix ( https://github.com/MinusGix ) + * @version v1.0.0 + * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) + */ + +import { + getChannelSettings, +} from './_Channels'; + +const crypto = require('crypto'); + +/** + * Object defining labels for default permission ranges + * @typedef {Object} levels + * @property {number} admin Global administrator range + * @property {number} moderator Global moderator range + * @property {number} channelOwner Local administrator range + * @property {number} channelModerator Local moderator range + * @property {number} channelTrusted Local (non-public) channel trusted + * @property {number} trustedUser Public channel trusted + * @property {number} default Default user level + */ +export const levels = { + admin: 9999999, + moderator: 999999, + + channelOwner: 99999, + channelModerator: 9999, + channelTrusted: 8999, + + trustedUser: 500, + default: 100, +}; + +/** + * Returns true if target level is equal or greater than the global admin level + * @public + * @param {number} level Level to verify + * @return {boolean} + */ +export function isAdmin(level) { + return level >= levels.admin; +} + +/** + * Returns true if target level is equal or greater than the global moderator level + * @public + * @param {number} level Level to verify + * @return {boolean} + */ +export function isModerator(level) { + return level >= levels.moderator; +} + +/** + * Returns true if target level is equal or greater than the channel owner level + * @public + * @param {number} level Level to verify + * @return {boolean} + */ +export function isChannelOwner(level) { + return level >= levels.channelOwner; +} + +/** + * Returns true if target level is equal or greater than the channel moderator level + * @public + * @param {number} level Level to verify + * @return {boolean} + */ +export function isChannelModerator(level) { + return level >= levels.channelModerator; +} + +/** + * Returns true if target level is equal or greater than the channel trust level + * @public + * @param {number} level Level to verify + * @return {boolean} + */ +export function isChannelTrusted(level) { + return level >= levels.channelTrusted; +} + +/** + * Returns true if target level is equal or greater than a trusted user + * @public + * @param {number} level Level to verify + * @return {boolean} + */ +export function isTrustedUser(level) { + return level >= levels.trustedUser; +} + +/** + * Return an object containing public information about the socket + * @public + * @param {WebSocket} socket Target client + * @return {Object} + */ +export function getUserDetails(socket) { + return { + uType: socket.uType, + nick: socket.nick, + trip: socket.trip || 'null', + hash: socket.hash, + level: socket.level, + userid: socket.userid, + }; +} + +/** + * Returns true if the nickname is valid + * @public + * @param {string} nick Nickname to verify + * @return {boolean} + */ +export function verifyNickname(nick) { + if (typeof nick === 'undefined') return false; + + return /^[a-zA-Z0-9_]{1,24}$/.test(nick); +} + +/** + * Hashes a user's password, returning a trip code + * or a blank string + * @public + * @param {string} pass User's password + * @param {string} config Server config object + * @param {string} channel Channel-level permissions check + * @return {string} + */ +export function getUserPerms(pass, config, channel) { + if (!pass) { + return { + trip: '', + level: levels.default, + }; + } + + const sha = crypto.createHash('sha256'); + sha.update(pass + config.tripSalt); + const trip = sha.digest('base64').substr(0, 6); + + // check if user is global admin + if (trip === config.adminTrip) { + return { + trip: 'Admin', + level: levels.admin, + }; + } + + // check if user is global mod + config.mods.forEach((mod) => { // eslint-disable-line consistent-return + if (trip === mod.trip) { + return { + trip, + level: levels.moderator, + }; + } + }); + + const channelSettings = getChannelSettings(config, channel); + if (channelSettings.owned) { + // check if user is channel owner + // @todo channel ownership patch + + // check if user is channel mod + // @todo channel ownership patch + + // check if user is channel trusted + // @todo channel ownership patch + } + + // check if user is global trusted + // @todo channel ownership patch + + return { + trip, + level: levels.default, + }; +} From 96eacd92b1e823220b397bead7817800bf1ccc85 Mon Sep 17 00:00:00 2001 From: marzavec Date: Tue, 22 Sep 2020 00:41:45 -0500 Subject: [PATCH 04/37] Comment fix --- server/src/commands/utility/_LegacyFunctions.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/commands/utility/_LegacyFunctions.js b/server/src/commands/utility/_LegacyFunctions.js index a55987f..2b436ca 100644 --- a/server/src/commands/utility/_LegacyFunctions.js +++ b/server/src/commands/utility/_LegacyFunctions.js @@ -55,8 +55,8 @@ export function legacyLevelToLabel(level) { /** * Alter the outgoing payload to an `info` cmd and add/change missing props - * @param {object} payload Numeric level to find the label for - * @param {string} nick Numeric level to find the label for + * @param {object} payload Original payload + * @param {string} nick Sender nick * @return {object} */ export function legacyInviteOut(payload, nick) { @@ -73,8 +73,8 @@ export function legacyInviteOut(payload, nick) { /** * Alter the outgoing payload to an `info` cmd and add/change missing props - * @param {object} payload Numeric level to find the label for - * @param {string} nick Numeric level to find the label for + * @param {object} payload Original payload + * @param {string} nick Receiver nick * @return {object} */ export function legacyInviteReply(payload, nick) { From 6a1a9df0960d9518f9db32ef0b39ec2bedf58020 Mon Sep 17 00:00:00 2001 From: marzavec Date: Mon, 28 Sep 2020 00:52:49 -0500 Subject: [PATCH 05/37] Gave emote its own event --- server/src/commands/core/emote.js | 6 +++--- server/src/commands/utility/_Constants.js | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/server/src/commands/core/emote.js b/server/src/commands/core/emote.js index 1939e6f..3e5b781 100644 --- a/server/src/commands/core/emote.js +++ b/server/src/commands/core/emote.js @@ -42,13 +42,13 @@ export async function run({ server, socket, payload }) { text = ` ${text}`; } - // @todo Change `cmd` from `info` to it's own `emote` event const newPayload = { - cmd: 'info', - type: 'emote', + cmd: 'emote', nick: socket.nick, + userid: socket.userid, text: `@${socket.nick}${text}`, }; + if (socket.trip) { newPayload.trip = socket.trip; } diff --git a/server/src/commands/utility/_Constants.js b/server/src/commands/utility/_Constants.js index 1f18aa1..bac25fd 100644 --- a/server/src/commands/utility/_Constants.js +++ b/server/src/commands/utility/_Constants.js @@ -29,6 +29,5 @@ exports.Errors = { Invite: { RATELIMIT: InviteErrors + 1, - INVALID_LENGTH: InviteErrors + 2, }, }; From 866fa9bcfff8f42e5b423db960d47153aa9c1bdf Mon Sep 17 00:00:00 2001 From: marzavec Date: Sat, 10 Oct 2020 00:34:59 -0500 Subject: [PATCH 06/37] Added event channel --- client/client.js | 5 +++++ server/src/commands/admin/addmod.js | 3 +++ server/src/commands/admin/listusers.js | 1 + server/src/commands/admin/reload.js | 1 + server/src/commands/admin/removemod.js | 3 +++ server/src/commands/admin/saveconfig.js | 2 ++ server/src/commands/admin/shout.js | 1 + server/src/commands/core/changenick.js | 9 +++++++++ server/src/commands/core/chat.js | 3 +++ server/src/commands/core/emote.js | 3 +++ server/src/commands/core/help.js | 2 ++ server/src/commands/core/invite.js | 2 ++ server/src/commands/core/join.js | 6 ++++++ server/src/commands/core/morestats.js | 1 + server/src/commands/core/move.js | 6 ++++++ server/src/commands/core/stats.js | 1 + server/src/commands/core/whisper.js | 6 ++++++ server/src/commands/internal/disconnect.js | 1 + server/src/commands/internal/socketreply.js | 1 + server/src/commands/mod/ban.js | 6 +++++- server/src/commands/mod/dumb.js | 6 ++++++ server/src/commands/mod/kick.js | 5 +++++ server/src/commands/mod/moveuser.js | 6 ++++++ server/src/commands/mod/speak.js | 4 ++++ server/src/commands/mod/unban.js | 3 +++ server/src/commands/mod/unbanall.js | 2 ++ server/src/commands/utility/_LegacyFunctions.js | 2 ++ 27 files changed, 90 insertions(+), 1 deletion(-) diff --git a/client/client.js b/client/client.js index 1238e56..682a28e 100644 --- a/client/client.js +++ b/client/client.js @@ -368,6 +368,11 @@ var COMMANDS = { info: function (args) { args.nick = '*'; pushMessage(args); + }, + + emote: function (args) { + args.nick = '*'; + pushMessage(args); }, warn: function (args) { diff --git a/server/src/commands/admin/addmod.js b/server/src/commands/admin/addmod.js index db645fe..0f443eb 100644 --- a/server/src/commands/admin/addmod.js +++ b/server/src/commands/admin/addmod.js @@ -28,6 +28,7 @@ export async function run({ server.send({ cmd: 'info', text: 'You are now a mod.', + channel: newMod[i].channel, // @todo Multichannel }, newMod[i]); } } @@ -36,12 +37,14 @@ export async function run({ server.reply({ cmd: 'info', text: `Added mod trip: ${payload.trip}, remember to run 'saveconfig' to make it permanent`, + channel: socket.channel, // @todo Multichannel }, socket); // notify all mods server.broadcast({ cmd: 'info', text: `Added mod: ${payload.trip}`, + channel: false, // @todo Multichannel, false for global info }, { level: UAC.isModerator }); return true; diff --git a/server/src/commands/admin/listusers.js b/server/src/commands/admin/listusers.js index b7f8d7c..ba5908a 100644 --- a/server/src/commands/admin/listusers.js +++ b/server/src/commands/admin/listusers.js @@ -42,6 +42,7 @@ export async function run({ server, socket }) { server.reply({ cmd: 'info', text: lines.join('\n'), + channel: socket.channel, // @todo Multichannel }, socket); return true; diff --git a/server/src/commands/admin/reload.js b/server/src/commands/admin/reload.js index e39fe6f..83488e5 100644 --- a/server/src/commands/admin/reload.js +++ b/server/src/commands/admin/reload.js @@ -36,6 +36,7 @@ export async function run({ server.broadcast({ cmd: 'info', text: loadResult, + channel: false, // @todo Multichannel, false for global }, { level: UAC.isModerator }); return true; diff --git a/server/src/commands/admin/removemod.js b/server/src/commands/admin/removemod.js index 1fff3b0..96ae439 100644 --- a/server/src/commands/admin/removemod.js +++ b/server/src/commands/admin/removemod.js @@ -29,6 +29,7 @@ export async function run({ server.send({ cmd: 'info', text: 'You are now a user.', + channel: targetMod[i].channel, // @todo Multichannel }, targetMod[i]); } } @@ -39,12 +40,14 @@ export async function run({ text: `Removed mod trip: ${ payload.trip }, remember to run 'saveconfig' to make it permanent`, + channel: socket.channel, // @todo Multichannel }, socket); // notify all mods server.broadcast({ cmd: 'info', text: `Removed mod: ${payload.trip}`, + channel: false, // @todo Multichannel, false for global }, { level: UAC.isModerator }); return true; diff --git a/server/src/commands/admin/saveconfig.js b/server/src/commands/admin/saveconfig.js index bc01270..2ad8a6e 100644 --- a/server/src/commands/admin/saveconfig.js +++ b/server/src/commands/admin/saveconfig.js @@ -16,6 +16,7 @@ export async function run({ core, server, socket }) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Failed to save config, check logs.', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -23,6 +24,7 @@ export async function run({ core, server, socket }) { server.broadcast({ cmd: 'info', text: 'Config saved!', + channel: false, // @todo Multichannel }, { level: UAC.isModerator }); return true; diff --git a/server/src/commands/admin/shout.js b/server/src/commands/admin/shout.js index 27002fc..bd3b10d 100644 --- a/server/src/commands/admin/shout.js +++ b/server/src/commands/admin/shout.js @@ -15,6 +15,7 @@ export async function run({ server, socket, payload }) { server.broadcast({ cmd: 'info', text: `Server Notice: ${payload.text}`, + channel: false, // @todo Multichannel, false for global }, {}); return true; diff --git a/server/src/commands/core/changenick.js b/server/src/commands/core/changenick.js index e520aba..2dc55bd 100644 --- a/server/src/commands/core/changenick.js +++ b/server/src/commands/core/changenick.js @@ -14,6 +14,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing nicknames too fast. Wait a moment before trying again.', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -30,6 +31,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Nickname must consist of up to 24 letters, numbers, and underscores', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -41,6 +43,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are not the admin, liar!', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -48,6 +51,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You already have that name', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -65,6 +69,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Nickname taken', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -74,6 +79,7 @@ export async function run({ const leaveNotice = { cmd: 'onlineRemove', nick: socket.nick, + channel: socket.channel, // @todo Multichannel }; const joinNotice = { @@ -81,6 +87,7 @@ export async function run({ nick: newNick, trip: socket.trip || 'null', hash: socket.hash, + channel: socket.channel, // @todo Multichannel }; // broadcast remove event and join event with new name, this is to support legacy clients and bots @@ -91,6 +98,7 @@ export async function run({ server.broadcast({ cmd: 'info', text: `${socket.nick} is now ${newNick}`, + channel: socket.channel, // @todo Multichannel }, { channel: socket.channel }); // commit change to nickname @@ -120,6 +128,7 @@ export function nickCheck({ server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help nick` for instructions on how to use this command.', + channel: socket.channel, // @todo Multichannel }, socket); return false; diff --git a/server/src/commands/core/chat.js b/server/src/commands/core/chat.js index f8998a5..579d7d5 100644 --- a/server/src/commands/core/chat.js +++ b/server/src/commands/core/chat.js @@ -39,6 +39,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -88,6 +89,7 @@ export function commandCheckIn({ server, socket, payload }) { server.reply({ cmd: 'info', text: `Your hash: ${socket.hash}`, + channel: socket.channel, // @todo Multichannel }, socket); return false; @@ -114,6 +116,7 @@ export function finalCmdCheck({ server, socket, payload }) { server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: `Unknown command: ${payload.text}`, + channel: socket.channel, // @todo Multichannel }, socket); return false; diff --git a/server/src/commands/core/emote.js b/server/src/commands/core/emote.js index 3e5b781..da64596 100644 --- a/server/src/commands/core/emote.js +++ b/server/src/commands/core/emote.js @@ -35,6 +35,7 @@ export async function run({ server, socket, payload }) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -47,6 +48,7 @@ export async function run({ server, socket, payload }) { nick: socket.nick, userid: socket.userid, text: `@${socket.nick}${text}`, + channel: socket.channel, // @todo Multichannel }; if (socket.trip) { @@ -80,6 +82,7 @@ export function emoteCheck({ server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help emote` for instructions on how to use this command.', + channel: socket.channel, // @todo Multichannel }, socket); return false; diff --git a/server/src/commands/core/help.js b/server/src/commands/core/help.js index faebd14..ad03ff3 100644 --- a/server/src/commands/core/help.js +++ b/server/src/commands/core/help.js @@ -11,6 +11,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -54,6 +55,7 @@ export async function run({ server.reply({ cmd: 'info', text: reply, + channel: socket.channel, // @todo Multichannel }, socket); return true; diff --git a/server/src/commands/core/invite.js b/server/src/commands/core/invite.js index 14fcb74..9fab2ed 100644 --- a/server/src/commands/core/invite.js +++ b/server/src/commands/core/invite.js @@ -36,6 +36,7 @@ export async function run({ cmd: 'warn', text: 'You are sending invites too fast. Wait a moment before trying again.', id: Errors.Invite.RATELIMIT, + channel: socket.channel, // @todo Multichannel }, socket); } @@ -59,6 +60,7 @@ export async function run({ cmd: 'warn', text: 'Could not find user in that channel', id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel }, socket); } diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index 037eb6c..8174a67 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -29,6 +29,7 @@ export async function run({ cmd: 'warn', text: 'You are joining channels too fast. Wait a moment and try again.', id: Errors.Join.RATELIMIT, + channel: false, // @todo Multichannel, false for global event }, socket); } @@ -47,6 +48,7 @@ export async function run({ cmd: 'warn', text: 'You may not join that channel.', id: mayJoin, + channel: false, // @todo Multichannel, false for global event }, socket); } @@ -57,6 +59,7 @@ export async function run({ cmd: 'warn', // @todo Remove this text: 'Joining more than one channel is not currently supported', id: Errors.Join.ALREADY_JOINED, + channel: false, // @todo Multichannel, false for global event }, socket); } // end todo @@ -68,6 +71,7 @@ export async function run({ cmd: 'warn', text: 'Nickname must consist of up to 24 letters, numbers, and underscores', id: Errors.Join.INVALID_NICK, + channel: false, // @todo Multichannel, false for global event }, socket); } @@ -103,6 +107,7 @@ export async function run({ cmd: 'warn', text: 'Nickname taken', id: Errors.Join.NAME_TAKEN, + channel: false, // @todo Multichannel, false for global event }, socket); } @@ -146,6 +151,7 @@ export async function run({ cmd: 'onlineSet', nicks, /* @legacy */ users, + channel, // @todo Multichannel (?) }, socket); // stats are fun diff --git a/server/src/commands/core/morestats.js b/server/src/commands/core/morestats.js index e84a309..f2a9612 100644 --- a/server/src/commands/core/morestats.js +++ b/server/src/commands/core/morestats.js @@ -51,6 +51,7 @@ export async function run({ core, server, socket }) { users-kicked: ${(core.stats.get('users-kicked') || 0)} stats-requested: ${(core.stats.get('stats-requested') || 0)} server-uptime: ${formatTime(process.hrtime(core.stats.get('start-time')))}`, + channel: socket.channel, // @todo Multichannel }, socket); // stats are fun diff --git a/server/src/commands/core/move.js b/server/src/commands/core/move.js index a0ff8e1..8de0a71 100644 --- a/server/src/commands/core/move.js +++ b/server/src/commands/core/move.js @@ -10,6 +10,7 @@ export async function run({ server, socket, payload }) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing channels too fast. Wait a moment before trying again.', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -22,6 +23,7 @@ export async function run({ server, socket, payload }) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Cannot move to an empty channel.', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -50,12 +52,14 @@ export async function run({ server, socket, payload }) { server.reply({ cmd: 'onlineRemove', nick: peerList[i].nick, + channel: socket.channel, // @todo Multichannel }, socket); if (socket.nick !== peerList[i].nick) { server.reply({ cmd: 'onlineRemove', nick: socket.nick, + channel: socket.channel, // @todo Multichannel }, peerList[i]); } } @@ -83,6 +87,7 @@ export async function run({ server, socket, payload }) { server.reply({ cmd: 'onlineSet', nicks, + channel: socket.channel, // @todo Multichannel (!) }, socket); // commit change @@ -111,6 +116,7 @@ export function moveCheck({ server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help move` for instructions on how to use this command.', + channel: socket.channel, // @todo Multichannel }, socket); return false; diff --git a/server/src/commands/core/stats.js b/server/src/commands/core/stats.js index 76bbc98..e3e58fa 100644 --- a/server/src/commands/core/stats.js +++ b/server/src/commands/core/stats.js @@ -25,6 +25,7 @@ export async function run({ core, server, socket }) { server.reply({ cmd: 'info', text: `${uniqueClientCount} unique IPs in ${uniqueChannels} channels`, + channel: socket.channel, // @todo Multichannel }, socket); // stats are fun diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index fe9ead6..6105ede 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -40,6 +40,7 @@ export async function run({ server, socket, payload }) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -55,6 +56,7 @@ export async function run({ server, socket, payload }) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Could not find user in channel', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -66,6 +68,7 @@ export async function run({ server, socket, payload }) { from: socket.nick, trip: socket.trip || 'null', text: `${socket.nick} whispered: ${text}`, + channel: socket.channel, // @todo Multichannel }, targetClient); targetClient.whisperReply = socket.nick; @@ -74,6 +77,7 @@ export async function run({ server, socket, payload }) { cmd: 'info', type: 'whisper', text: `You whispered to @${targetNick}: ${text}`, + channel: socket.channel, // @todo Multichannel }, socket); return true; @@ -100,6 +104,7 @@ export function whisperCheck({ server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help whisper` for instructions on how to use this command.', + channel: socket.channel, // @todo Multichannel }, socket); return false; @@ -128,6 +133,7 @@ export function whisperCheck({ server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Cannot reply to nobody', + channel: socket.channel, // @todo Multichannel }, socket); return false; diff --git a/server/src/commands/internal/disconnect.js b/server/src/commands/internal/disconnect.js index 27280da..69bb061 100644 --- a/server/src/commands/internal/disconnect.js +++ b/server/src/commands/internal/disconnect.js @@ -16,6 +16,7 @@ export async function run({ server, socket, payload }) { cmd: 'onlineRemove', userid: socket.userid, nick: socket.nick, /* @legacy */ + channel: socket.channel, // @todo Multichannel }, { channel: socket.channel }); } diff --git a/server/src/commands/internal/socketreply.js b/server/src/commands/internal/socketreply.js index 9c7ddc8..22fa5ba 100644 --- a/server/src/commands/internal/socketreply.js +++ b/server/src/commands/internal/socketreply.js @@ -13,6 +13,7 @@ export async function run({ server, socket, payload }) { server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: payload.text, + channel: socket.channel || false, // @todo Multichannel }, socket); return true; diff --git a/server/src/commands/mod/ban.js b/server/src/commands/mod/ban.js index 8d6721d..2db87cd 100644 --- a/server/src/commands/mod/ban.js +++ b/server/src/commands/mod/ban.js @@ -38,6 +38,7 @@ export async function run({ cmd: 'warn', text: 'Could not find user in that channel', id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel }, socket); } const targetNick = targetUser.nick; @@ -48,6 +49,7 @@ export async function run({ cmd: 'warn', text: 'Cannot ban other users of the same level, how rude', id: Errors.Global.PERMISSION, + channel: socket.channel, // @todo Multichannel }, socket); } @@ -61,13 +63,15 @@ export async function run({ cmd: 'info', text: `Banned ${targetNick}`, user: UAC.getUserDetails(targetUser), + channel: socket.channel, // @todo Multichannel }, { channel: socket.channel, level: (level) => level < UAC.levels.moderator }); // notify mods server.broadcast({ cmd: 'info', text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${targetUser.hash}`, - channel: payload.channel, + channel: socket.channel, // @todo Multichannel + inChannel: payload.channel, user: UAC.getUserDetails(targetUser), banner: UAC.getUserDetails(socket), }, { level: UAC.isModerator }); diff --git a/server/src/commands/mod/dumb.js b/server/src/commands/mod/dumb.js index a10d1cb..558f02e 100644 --- a/server/src/commands/mod/dumb.js +++ b/server/src/commands/mod/dumb.js @@ -48,6 +48,7 @@ export async function run({ cmd: 'warn', text: 'Could not find user in that channel', id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel }, socket); } @@ -57,6 +58,7 @@ export async function run({ cmd: 'warn', text: 'This trick wont work on users of the same level', id: Errors.Global.PERMISSION, + channel: socket.channel, // @todo Multichannel }, socket); } @@ -74,6 +76,7 @@ export async function run({ server.broadcast({ cmd: 'info', text: `${socket.nick}#${socket.trip} muzzled ${targetUser.nick} in ${payload.channel}, userhash: ${targetUser.hash}`, + channel: false, // @todo Multichannel, false for global }, { level: UAC.isModerator }); return true; @@ -100,6 +103,7 @@ export function chatCheck({ cmd: 'chat', nick: socket.nick, text: payload.text, + channel: socket.channel, // @todo Multichannel }; if (socket.trip) { @@ -142,6 +146,7 @@ export function inviteCheck({ core, socket, payload }) { server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: nickValid, + channel: socket.channel, // @todo Multichannel }, socket); return false; } @@ -177,6 +182,7 @@ export function whisperCheck({ cmd: 'info', type: 'whisper', text: `You whispered to @${targetNick}: ${payload.text}`, + channel: socket.channel, // @todo Multichannel }, socket); // blanket "spam" protection, may expose the ratelimiting lines from diff --git a/server/src/commands/mod/kick.js b/server/src/commands/mod/kick.js index 3f93cd6..6dc58ea 100644 --- a/server/src/commands/mod/kick.js +++ b/server/src/commands/mod/kick.js @@ -44,6 +44,7 @@ export async function run({ cmd: 'warn', text: 'Could not find user(s) in that channel', id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel }, socket); } @@ -55,6 +56,7 @@ export async function run({ cmd: 'warn', text: 'Cannot kick other users with the same level, how rude', id: Errors.Global.PERMISSION, + channel: socket.channel, // @todo Multichannel }, socket); } else { kicked.push(badClients[i]); @@ -95,6 +97,7 @@ export async function run({ server.broadcast({ cmd: 'info', text: `${kicked[i].nick} was banished to ?${destChannel}`, + channel: socket.channel, // @todo Multichannel }, { channel: socket.channel, level: UAC.isModerator }); console.log(`${socket.nick} [${socket.trip}] kicked ${kicked[i].nick} in ${socket.channel} to ${destChannel} `); @@ -106,6 +109,7 @@ export async function run({ cmd: 'onlineRemove', userid: kicked[i].userid, nick: kicked[i].nick, + channel: socket.channel, // @todo Multichannel }, { channel: socket.channel }); } @@ -113,6 +117,7 @@ export async function run({ server.broadcast({ cmd: 'info', text: `Kicked ${kicked.map((k) => k.nick).join(', ')}`, + channel: socket.channel, // @todo Multichannel }, { channel: socket.channel, level: (level) => level < UAC.levels.moderator }); // stats are fun diff --git a/server/src/commands/mod/moveuser.js b/server/src/commands/mod/moveuser.js index 7c248b6..eb17cf8 100644 --- a/server/src/commands/mod/moveuser.js +++ b/server/src/commands/mod/moveuser.js @@ -28,6 +28,7 @@ export async function run({ server, socket, payload }) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Could not find user in channel', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -37,6 +38,7 @@ export async function run({ server, socket, payload }) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Cannot move other users of the same level, how rude', + channel: socket.channel, // @todo Multichannel }, socket); } @@ -58,12 +60,14 @@ export async function run({ server, socket, payload }) { server.reply({ cmd: 'onlineRemove', nick: peerList[i].nick, + channel: socket.channel, // @todo Multichannel }, badClient); if (badClient.nick !== peerList[i].nick) { server.reply({ cmd: 'onlineRemove', nick: badClient.nick, + channel: socket.channel, // @todo Multichannel }, peerList[i]); } } @@ -89,6 +93,7 @@ export async function run({ server, socket, payload }) { server.reply({ cmd: 'onlineSet', nicks, + channel: socket.channel, // @todo Multichannel (!) }, badClient); badClient.channel = payload.channel; @@ -96,6 +101,7 @@ export async function run({ server, socket, payload }) { server.broadcast({ cmd: 'info', text: `${badClient.nick} was moved into ?${payload.channel}`, + channel: socket.channel, // @todo Multichannel }, { channel: payload.channel }); return true; diff --git a/server/src/commands/mod/speak.js b/server/src/commands/mod/speak.js index 35dcde3..a197d01 100644 --- a/server/src/commands/mod/speak.js +++ b/server/src/commands/mod/speak.js @@ -28,6 +28,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: "hash:'targethash' or ip:'1.2.3.4' is required", + channel: socket.channel, // @todo Multichannel }, socket); } @@ -38,6 +39,7 @@ export async function run({ return server.broadcast({ cmd: 'info', text: `${socket.nick} unmuzzled all users`, + channel: false, // @todo Multichannel, false for global }, { level: UAC.isModerator }); } } else if (payload.hash === '*') { @@ -46,6 +48,7 @@ export async function run({ return server.broadcast({ cmd: 'info', text: `${socket.nick} unmuzzled all users`, + channel: false, // @todo Multichannel, false for global }, { level: UAC.isModerator }); } @@ -63,6 +66,7 @@ export async function run({ server.broadcast({ cmd: 'info', text: `${socket.nick}#${socket.trip} unmuzzled : ${target}`, + channel: false, // @todo Multichannel, false for global }, { level: UAC.isModerator }); return true; diff --git a/server/src/commands/mod/unban.js b/server/src/commands/mod/unban.js index e8dc042..a13dea3 100644 --- a/server/src/commands/mod/unban.js +++ b/server/src/commands/mod/unban.js @@ -20,6 +20,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: "hash:'targethash' or ip:'1.2.3.4' is required", + channel: socket.channel, // @todo Multichannel }, socket); } @@ -47,12 +48,14 @@ export async function run({ server.reply({ cmd: 'info', text: `Unbanned ${target}`, + channel: socket.channel, // @todo Multichannel }, socket); // notify mods server.broadcast({ cmd: 'info', text: `${socket.nick}#${socket.trip} unbanned: ${target}`, + channel: false, // @todo Multichannel, false for global }, { level: UAC.isModerator }); // stats are fun diff --git a/server/src/commands/mod/unbanall.js b/server/src/commands/mod/unbanall.js index b43685a..3d37efd 100644 --- a/server/src/commands/mod/unbanall.js +++ b/server/src/commands/mod/unbanall.js @@ -24,12 +24,14 @@ export async function run({ core, server, socket }) { server.reply({ cmd: 'info', text: 'Unbanned all ip addresses', + channel: socket.channel, // @todo Multichannel }, socket); // notify mods server.broadcast({ cmd: 'info', text: `${socket.nick}#${socket.trip} unbanned all ip addresses`, + channel: false, // @todo Multichannel, false for global }, { level: UAC.isModerator }); return true; diff --git a/server/src/commands/utility/_LegacyFunctions.js b/server/src/commands/utility/_LegacyFunctions.js index 2b436ca..4553a48 100644 --- a/server/src/commands/utility/_LegacyFunctions.js +++ b/server/src/commands/utility/_LegacyFunctions.js @@ -67,6 +67,7 @@ export function legacyInviteOut(payload, nick) { type: 'invite', from: nick, text: `${nick} invited you to ?${payload.inviteChannel}`, + channel: payload.channel, // @todo Multichannel }, }; } @@ -85,6 +86,7 @@ export function legacyInviteReply(payload, nick) { type: 'invite', from: '', text: `You invited ${nick} to ?${payload.inviteChannel}`, + channel: payload.channel, // @todo Multichannel }, }; } From 308130e2b0509dd7105ce84eac5e824c9958bdda Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 14 Oct 2020 23:17:11 -0500 Subject: [PATCH 07/37] Updated Whisper --- server/src/commands/core/invite.js | 2 +- server/src/commands/core/whisper.js | 69 +++++++++++-------- .../src/commands/utility/_LegacyFunctions.js | 38 +++++++++- 3 files changed, 78 insertions(+), 31 deletions(-) diff --git a/server/src/commands/core/invite.js b/server/src/commands/core/invite.js index 9fab2ed..092a30f 100644 --- a/server/src/commands/core/invite.js +++ b/server/src/commands/core/invite.js @@ -70,7 +70,7 @@ export async function run({ // build invite const outgoingPayload = { cmd: 'invite', - channel: socket.channel, + channel: socket.channel, // @todo Multichannel from: socket.userid, to: targetUser.userid, inviteChannel: channel, diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index 6105ede..a2d85dd 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -4,7 +4,16 @@ and accept a `userid` rather than `nick` */ -import * as UAC from '../utility/UAC/_info'; +import { + findUser, +} from '../utility/_Channels'; +import { + Errors, +} from '../utility/_Constants'; +import { + legacyWhisperOut, + legacyWhisperReply, +} from '../utility/_LegacyFunctions'; // module support functions @@ -26,7 +35,12 @@ const parseText = (text) => { // module main export async function run({ server, socket, payload }) { - // check user input + // if this is a legacy client add missing params to payload + if (socket.hcProtocol === 1) { + payload.channel = socket.channel; // eslint-disable-line no-param-reassign + } + + // verify user input const text = parseText(payload.text); if (!text) { @@ -44,41 +58,37 @@ export async function run({ server, socket, payload }) { }, socket); } - const targetNick = payload.nick; - if (!UAC.verifyNickname(targetNick)) { - return true; - } - - // find target user - let targetClient = server.findSockets({ channel: socket.channel, nick: targetNick }); - - if (targetClient.length === 0) { + const targetUser = findUser(server, payload); + if (!targetUser) { return server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: 'Could not find user in channel', + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, channel: socket.channel, // @todo Multichannel }, socket); } - [targetClient] = targetClient; - - server.reply({ - cmd: 'info', - type: 'whisper', - from: socket.nick, - trip: socket.trip || 'null', - text: `${socket.nick} whispered: ${text}`, + const outgoingPayload = { + cmd: 'whisper', channel: socket.channel, // @todo Multichannel - }, targetClient); + from: socket.userid, + to: targetUser.userid, + text, + }; - targetClient.whisperReply = socket.nick; + // send invite notice to target client + if (targetUser.hcProtocol === 1) { + server.reply(legacyWhisperOut(outgoingPayload, socket), targetUser); + } else { + server.reply(outgoingPayload, targetUser); + } - server.reply({ - cmd: 'info', - type: 'whisper', - text: `You whispered to @${targetNick}: ${text}`, - channel: socket.channel, // @todo Multichannel - }, socket); + // send invite notice to this client + if (socket.hcProtocol === 1) { + server.reply(legacyWhisperReply(outgoingPayload, targetUser.nick), socket); + } else { + server.reply(outgoingPayload, socket); + } return true; } @@ -120,6 +130,7 @@ export function whisperCheck({ socket, payload: { cmd: 'whisper', + channel: socket.channel, // @todo Multichannel nick: target, text: whisperText, }, diff --git a/server/src/commands/utility/_LegacyFunctions.js b/server/src/commands/utility/_LegacyFunctions.js index 4553a48..5568da8 100644 --- a/server/src/commands/utility/_LegacyFunctions.js +++ b/server/src/commands/utility/_LegacyFunctions.js @@ -59,7 +59,7 @@ export function legacyLevelToLabel(level) { * @param {string} nick Sender nick * @return {object} */ -export function legacyInviteOut(payload, nick) { + export function legacyInviteOut(payload, nick) { return { ...payload, ...{ @@ -90,3 +90,39 @@ export function legacyInviteReply(payload, nick) { }, }; } + +/** + * Alter the outgoing payload to a `whisper` cmd and add/change missing props + * @param {object} payload Original payload + * @param {string} nick Sender nick + * @return {object} + */ + export function legacyWhisperOut(payload, from) { + return { + ...payload, + ...{ + cmd: 'info', + type: 'whisper', + from: from.nick, + trip: from.trip || 'null', + text: `${from.nick} whispered: ${payload.text}`, + }, + }; +} + +/** + * Alter the outgoing payload to a `whisper` cmd and add/change missing props + * @param {object} payload Original payload + * @param {string} nick Receiver nick + * @return {object} + */ +export function legacyWhisperReply(payload, nick) { + return { + ...payload, + ...{ + cmd: 'info', + type: 'whisper', + text: `You whispered to @${nick}: ${payload.text}`, + }, + }; +} From d227bcc4f60965622066f44d1bc4de7ba3dded11 Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 14 Oct 2020 23:43:38 -0500 Subject: [PATCH 08/37] Added bot declarations --- server/src/commands/core/join.js | 3 ++- server/src/commands/core/session.js | 3 ++- server/src/commands/utility/_LegacyFunctions.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index 8174a67..d832104 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -131,6 +131,7 @@ export async function run({ userid: newPeerList[i].userid, channel, isme: false, + isBot: newPeerList[i].isBot, }); } @@ -144,7 +145,7 @@ export async function run({ // socket.channels.push(channel); nicks.push(userInfo.nick); /* @legacy */ - users.push({ ...{ isme: true }, ...userInfo }); + users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo }); // reply with channel peer list server.reply({ diff --git a/server/src/commands/core/session.js b/server/src/commands/core/session.js index 1012400..2d02810 100644 --- a/server/src/commands/core/session.js +++ b/server/src/commands/core/session.js @@ -14,7 +14,7 @@ const createSessionID = () => { }; // module main -export async function run({ server, socket }) { +export async function run({ server, socket, payload }) { // gather connection and channel count let ips = {}; let channels = {}; @@ -54,6 +54,7 @@ export async function run({ server, socket }) { socket.hcProtocol = 2; socket.userid = Math.floor(Math.random() * 9999999999999); socket.hash = server.getSocketHash(socket); + socket.isBot = payload.isBot || false; // dispatch info server.reply({ diff --git a/server/src/commands/utility/_LegacyFunctions.js b/server/src/commands/utility/_LegacyFunctions.js index 5568da8..6662267 100644 --- a/server/src/commands/utility/_LegacyFunctions.js +++ b/server/src/commands/utility/_LegacyFunctions.js @@ -19,8 +19,9 @@ export function upgradeLegacyJoin(server, socket, payload) { // `join` is the legacy entry point, so apply protocol version socket.hcProtocol = 1; - // this would have been applied in the `session` module, apply it now + // these would have been applied in the `session` module, apply it now socket.hash = server.getSocketHash(socket); + socket.isBot = false; // pull the password from the nick const nickArray = payload.nick.split('#', 2); From 76b30c8553370bc41b6d190b84d6d48526d50e49 Mon Sep 17 00:00:00 2001 From: marzavec Date: Fri, 16 Oct 2020 23:36:28 -0500 Subject: [PATCH 09/37] Update join.js --- server/src/commands/core/join.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index d832104..60250d0 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -65,8 +65,7 @@ export async function run({ // end todo // validates the user input for `nick` - const validName = verifyNickname(nick, socket); - if (validName !== true) { + if (verifyNickname(nick, socket) !== true) { return server.reply({ cmd: 'warn', text: 'Nickname must consist of up to 24 letters, numbers, and underscores', From b4553511f0b0e56fec7ba324107e5286fbaa2adc Mon Sep 17 00:00:00 2001 From: marzavec Date: Fri, 6 Nov 2020 13:16:43 -0800 Subject: [PATCH 10/37] dev sync --- server/package-lock.json | 5 + server/package.json | 1 + server/src/commands/admin/addmod.js | 33 ++++- server/src/commands/admin/listusers.js | 6 +- server/src/commands/admin/reload.js | 9 +- server/src/commands/admin/removemod.js | 12 +- server/src/commands/admin/saveconfig.js | 9 +- server/src/commands/admin/shout.js | 6 +- server/src/commands/core/changecolor.js | 111 ++++++++++++++++ server/src/commands/core/changenick.js | 69 ++++++---- server/src/commands/core/chat.js | 13 +- server/src/commands/core/join.js | 21 ++-- server/src/commands/core/move.js | 43 +++++-- server/src/commands/core/session.js | 1 + server/src/commands/core/whisper.js | 3 + server/src/commands/mod/ban.js | 18 +-- server/src/commands/mod/dumb.js | 8 +- server/src/commands/mod/kick.js | 30 ++--- server/src/commands/mod/moveuser.js | 47 +++++-- server/src/commands/mod/speak.js | 12 +- server/src/commands/mod/unban.js | 8 +- server/src/commands/mod/unbanall.js | 8 +- server/src/commands/utility/UAC/_info.js | 119 ------------------ .../src/commands/utility/_LegacyFunctions.js | 1 + server/src/commands/utility/_UAC.js | 15 +-- 25 files changed, 370 insertions(+), 238 deletions(-) create mode 100644 server/src/commands/core/changecolor.js delete mode 100644 server/src/commands/utility/UAC/_info.js diff --git a/server/package-lock.json b/server/package-lock.json index 8f42463..8049c6c 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -18,6 +18,11 @@ "color-convert": "^2.0.1" } }, + "ascii-captcha": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/ascii-captcha/-/ascii-captcha-0.0.3.tgz", + "integrity": "sha1-NAtO1oVYOHEHsJVzBC/kc4v0mPk=" + }, "async": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", diff --git a/server/package.json b/server/package.json index f6a9a90..a6459d7 100644 --- a/server/package.json +++ b/server/package.json @@ -18,6 +18,7 @@ "author": "Marzavec", "license": "WTFPL", "dependencies": { + "ascii-captcha": "0.0.3", "chalk": "^3.0.0", "common-tags": "^1.8.0", "dateformat": "^3.0.3", diff --git a/server/src/commands/admin/addmod.js b/server/src/commands/admin/addmod.js index 0f443eb..3a6b140 100644 --- a/server/src/commands/admin/addmod.js +++ b/server/src/commands/admin/addmod.js @@ -2,14 +2,19 @@ Description: Adds the target trip to the mod list then elevates the uType */ -import * as UAC from '../utility/UAC/_info'; +import { + isAdmin, + isModerator, + levels, + getUserDetails, +} from '../utility/_UAC'; // module main export async function run({ core, server, socket, payload, }) { // increase rate limit chance and ignore if not admin - if (!UAC.isAdmin(socket.level)) { + if (!isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); } @@ -19,10 +24,20 @@ export async function run({ // find targets current connections const newMod = server.findSockets({ trip: payload.trip }); if (newMod.length !== 0) { + // build update notice with new privileges + const updateNotice = { + ...getUserDetails(newMod[0]), + ...{ + cmd: 'updateUser', + uType: 'mod', // @todo use legacyLevelToLabel from _LegacyFunctions.js + level: levels.moderator, + }, + }; + for (let i = 0, l = newMod.length; i < l; i += 1) { // upgrade privilages - newMod[i].uType = 'mod'; - newMod[i].level = UAC.levels.moderator; + newMod[i].uType = 'mod'; // @todo use legacyLevelToLabel from _LegacyFunctions.js + newMod[i].level = levels.moderator; // inform new mod server.send({ @@ -30,6 +45,14 @@ export async function run({ text: 'You are now a mod.', channel: newMod[i].channel, // @todo Multichannel }, newMod[i]); + + // notify channel + server.broadcast({ + ...updateNotice, + ...{ + channel: newMod[i].channel, + }, + }, { channel: newMod[i].channel }); } } @@ -45,7 +68,7 @@ export async function run({ cmd: 'info', text: `Added mod: ${payload.trip}`, channel: false, // @todo Multichannel, false for global info - }, { level: UAC.isModerator }); + }, { level: isModerator }); return true; } diff --git a/server/src/commands/admin/listusers.js b/server/src/commands/admin/listusers.js index ba5908a..850ae75 100644 --- a/server/src/commands/admin/listusers.js +++ b/server/src/commands/admin/listusers.js @@ -6,12 +6,14 @@ Description: Outputs all current channels and their user nicks */ -import * as UAC from '../utility/UAC/_info'; +import { + isAdmin, +} from '../utility/_UAC'; // module main export async function run({ server, socket }) { // increase rate limit chance and ignore if not admin - if (!UAC.isAdmin(socket.level)) { + if (!isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); } diff --git a/server/src/commands/admin/reload.js b/server/src/commands/admin/reload.js index 83488e5..32ca04f 100644 --- a/server/src/commands/admin/reload.js +++ b/server/src/commands/admin/reload.js @@ -2,14 +2,17 @@ Description: Clears and resets the command modules, outputting any errors */ -import * as UAC from '../utility/UAC/_info'; +import { + isAdmin, + isModerator, +} from '../utility/_UAC'; // module main export async function run({ core, server, socket, payload, }) { // increase rate limit chance and ignore if not admin - if (!UAC.isAdmin(socket.level)) { + if (!isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); } @@ -37,7 +40,7 @@ export async function run({ cmd: 'info', text: loadResult, channel: false, // @todo Multichannel, false for global - }, { level: UAC.isModerator }); + }, { level: isModerator }); return true; } diff --git a/server/src/commands/admin/removemod.js b/server/src/commands/admin/removemod.js index 96ae439..85d5fd6 100644 --- a/server/src/commands/admin/removemod.js +++ b/server/src/commands/admin/removemod.js @@ -2,14 +2,18 @@ Description: Removes target trip from the config as a mod and downgrades the socket type */ -import * as UAC from '../utility/UAC/_info'; +import { + isAdmin, + isModerator, + levels, +} from '../utility/_UAC'; // module main export async function run({ core, server, socket, payload, }) { // increase rate limit chance and ignore if not admin - if (!UAC.isAdmin(socket.level)) { + if (!isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); } @@ -23,7 +27,7 @@ export async function run({ for (let i = 0, l = targetMod.length; i < l; i += 1) { // downgrade privilages targetMod[i].uType = 'user'; - targetMod[i].level = UAC.levels.default; + targetMod[i].level = levels.default; // inform ex-mod server.send({ @@ -48,7 +52,7 @@ export async function run({ cmd: 'info', text: `Removed mod: ${payload.trip}`, channel: false, // @todo Multichannel, false for global - }, { level: UAC.isModerator }); + }, { level: isModerator }); return true; } diff --git a/server/src/commands/admin/saveconfig.js b/server/src/commands/admin/saveconfig.js index 2ad8a6e..a24f422 100644 --- a/server/src/commands/admin/saveconfig.js +++ b/server/src/commands/admin/saveconfig.js @@ -2,12 +2,15 @@ Description: Writes the current config to disk */ -import * as UAC from '../utility/UAC/_info'; +import { + isAdmin, + isModerator, +} from '../utility/_UAC'; // module main export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin - if (!UAC.isAdmin(socket.level)) { + if (!isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); } @@ -25,7 +28,7 @@ export async function run({ core, server, socket }) { cmd: 'info', text: 'Config saved!', channel: false, // @todo Multichannel - }, { level: UAC.isModerator }); + }, { level: isModerator }); return true; } diff --git a/server/src/commands/admin/shout.js b/server/src/commands/admin/shout.js index bd3b10d..fa75058 100644 --- a/server/src/commands/admin/shout.js +++ b/server/src/commands/admin/shout.js @@ -2,12 +2,14 @@ Description: Emmits a server-wide message as `info` */ -import * as UAC from '../utility/UAC/_info'; +import { + isAdmin, +} from '../utility/_UAC'; // module main export async function run({ server, socket, payload }) { // increase rate limit chance and ignore if not admin - if (!UAC.isAdmin(socket.level)) { + if (!isAdmin(socket.level)) { return server.police.frisk(socket.address, 20); } diff --git a/server/src/commands/core/changecolor.js b/server/src/commands/core/changecolor.js new file mode 100644 index 0000000..afbb8f7 --- /dev/null +++ b/server/src/commands/core/changecolor.js @@ -0,0 +1,111 @@ +/* + Description: Allows calling client to change their nickname color +*/ + +// module support functions +const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); + +// module main +export async function run({ + core, server, socket, payload, +}) { + const channel = socket.channel; + + if (server.police.frisk(socket.address, 6)) { + return server.reply({ + cmd: 'warn', // @todo Add numeric error code as `id` + text: 'You are changing colors too fast. Wait a moment before trying again.', + channel, // @todo Multichannel + }, socket); + } + + // verify user data is string + if (typeof payload.color !== 'string') { + return true; + } + + // make sure requested nickname meets standards + const newColor = payload.color.trim().toUpperCase().replace(/#/g, ''); + if (newColor !== 'RESET' && !verifyColor(newColor)) { + return server.reply({ + cmd: 'warn', + text: 'Invalid color! Color must be in hex value', + channel, // @todo Multichannel + }, socket); + } + + if (newColor === 'RESET') { + socket.color = false; + } else { + socket.color = newColor; + } + + // build update notice with new color + const updateNotice = { + ...getUserDetails(socket), + ...{ + cmd: 'updateUser', + channel: socket.channel, // @todo Multichannel + } + }; + + // notify channel that the user has changed their name + // @todo this should be sent to every channel the user is in (multichannel) + server.broadcast(updateNotice, { channel: socket.channel }); + + return true; +} + +// module hook functions +export function initHooks(server) { + server.registerHook('in', 'chat', this.colorCheck.bind(this), 29); +} + +// hooks chat commands checking for /color +export function colorCheck({ + core, server, socket, payload, +}) { + if (typeof payload.text !== 'string') { + return false; + } + + if (payload.text.startsWith('/color ')) { + const input = payload.text.split(' '); + + // If there is no color target parameter + if (input[1] === undefined) { + server.reply({ + cmd: 'warn', + text: 'Refer to `/help changecolor` for instructions on how to use this command.', + channel: socket.channel, // @todo Multichannel + }, socket); + + return false; + } + + this.run({ + core, + server, + socket, + payload: { + cmd: 'changecolor', + color: input[1], + }, + }); + + return false; + } + + return payload; +} + +// module meta +export const requiredData = ['color']; +export const info = { + name: 'changecolor', + description: 'This will change your nickname color', + usage: ` + API: { cmd: 'changecolor', color: '' } + Text: /color + Removal: /color reset`, +}; diff --git a/server/src/commands/core/changenick.js b/server/src/commands/core/changenick.js index 2dc55bd..558a1b8 100644 --- a/server/src/commands/core/changenick.js +++ b/server/src/commands/core/changenick.js @@ -4,17 +4,22 @@ Description: Allows calling client to change their current nickname */ -import * as UAC from '../utility/UAC/_info'; +import { + verifyNickname, + getUserDetails, +} from '../utility/_UAC'; // module main export async function run({ core, server, socket, payload, }) { + const channel = socket.channel; + if (server.police.frisk(socket.address, 6)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing nicknames too fast. Wait a moment before trying again.', - channel: socket.channel, // @todo Multichannel + channel, // @todo Multichannel }, socket); } @@ -27,11 +32,11 @@ export async function run({ // make sure requested nickname meets standards const newNick = payload.nick.trim(); - if (!UAC.verifyNickname(newNick)) { + if (!verifyNickname(newNick)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Nickname must consist of up to 24 letters, numbers, and underscores', - channel: socket.channel, // @todo Multichannel + channel, // @todo Multichannel }, socket); } @@ -43,7 +48,7 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are not the admin, liar!', - channel: socket.channel, // @todo Multichannel + channel, // @todo Multichannel }, socket); } @@ -51,13 +56,13 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You already have that name', - channel: socket.channel, // @todo Multichannel + channel, // @todo Multichannel }, socket); } // find any sockets that have the same nickname const userExists = server.findSockets({ - channel: socket.channel, + channel, nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase() // Allow them to rename themselves to a different case && targetNick != previousNick, @@ -69,37 +74,57 @@ export async function run({ return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Nickname taken', - channel: socket.channel, // @todo Multichannel + channel, // @todo Multichannel }, socket); } - // build join and leave notices - // @todo this is a legacy client holdover, name changes in the future will - // have thieir own event + // build update notice with new nickname + const updateNotice = { + ...getUserDetails(socket), + ...{ + cmd: 'updateUser', + nick: newNick, + channel, // @todo Multichannel + } + }; + + // build join and leave notices for legacy clients const leaveNotice = { cmd: 'onlineRemove', + userid: socket.userid, nick: socket.nick, - channel: socket.channel, // @todo Multichannel + channel, // @todo Multichannel }; const joinNotice = { - cmd: 'onlineAdd', - nick: newNick, - trip: socket.trip || 'null', - hash: socket.hash, - channel: socket.channel, // @todo Multichannel + ...getUserDetails(socket), + ...{ + cmd: 'onlineAdd', + nick: newNick, + channel, // @todo Multichannel + }, }; - // broadcast remove event and join event with new name, this is to support legacy clients and bots - server.broadcast(leaveNotice, { channel: socket.channel }); - server.broadcast(joinNotice, { channel: socket.channel }); + // gather channel peers + const peerList = server.findSockets({ channel }); + for (let i = 0, l = peerList.length; i < l; i += 1) { + if (peerList[i].hcProtocol === 1) { + // send join/leave to legacy clients + server.send(leaveNotice, peerList[i]); + server.send(joinNotice, peerList[i]); + } else { + // send update info + // @todo this should be sent to every channel the client is in + server.send(updateNotice, peerList[i]); + } + } // notify channel that the user has changed their name server.broadcast({ cmd: 'info', text: `${socket.nick} is now ${newNick}`, - channel: socket.channel, // @todo Multichannel - }, { channel: socket.channel }); + channel, // @todo Multichannel + }, { channel }); // commit change to nickname socket.nick = newNick; // eslint-disable-line no-param-reassign diff --git a/server/src/commands/core/chat.js b/server/src/commands/core/chat.js index 579d7d5..65e26c4 100644 --- a/server/src/commands/core/chat.js +++ b/server/src/commands/core/chat.js @@ -2,7 +2,10 @@ Description: Rebroadcasts any `text` to all clients in a `channel` */ -import * as UAC from '../utility/UAC/_info'; +import { + isAdmin, + isModerator, +} from '../utility/_UAC'; // module support functions const parseText = (text) => { @@ -54,9 +57,9 @@ export async function run({ level: socket.level, }; - if (UAC.isAdmin(socket.level)) { + if (isAdmin(socket.level)) { outgoingPayload.admin = true; - } else if (UAC.isModerator(socket.level)) { + } else if (isModerator(socket.level)) { outgoingPayload.mod = true; } @@ -64,6 +67,10 @@ export async function run({ outgoingPayload.trip = socket.trip; /* @legacy */ } + if (socket.color) { + outgoingPayload.color = socket.color; + } + // broadcast to channel peers server.broadcast(outgoingPayload, { channel: socket.channel }); diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index 60250d0..9332c8c 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -4,7 +4,6 @@ Description: Adds requested channel into the calling clients "subscribed channels" */ -// import * as UAC from '../utility/UAC/_info'; import { canJoinChannel, } from '../utility/_Channels'; @@ -18,6 +17,7 @@ import { import { verifyNickname, getUserPerms, + getUserDetails, } from '../utility/_UAC'; // module main @@ -76,6 +76,7 @@ export async function run({ // get trip and level const { trip, level } = getUserPerms(pass, core.config, channel); + // store the user values const userInfo = { nick, @@ -84,6 +85,8 @@ export async function run({ hash: socket.hash, level, userid: socket.userid, + isBot: socket.isBot, + color: socket.color, channel, }; @@ -119,18 +122,14 @@ export async function run({ // send join announcement and prep online set reply for (let i = 0, l = newPeerList.length; i < l; i += 1) { server.reply(joinAnnouncement, newPeerList[i]); + nicks.push(newPeerList[i].nick); /* @legacy */ - users.push({ - nick: newPeerList[i].nick, - trip: newPeerList[i].trip, - uType: newPeerList[i].uType, /* @legacy */ - hash: newPeerList[i].hash, - level: newPeerList[i].level, - userid: newPeerList[i].userid, - channel, - isme: false, - isBot: newPeerList[i].isBot, + ...{ + channel, + isme: false, + }, + ...getUserDetails(newPeerList[i]), }); } diff --git a/server/src/commands/core/move.js b/server/src/commands/core/move.js index 8de0a71..d6537c5 100644 --- a/server/src/commands/core/move.js +++ b/server/src/commands/core/move.js @@ -2,6 +2,11 @@ Description: Changes the current channel of the calling socket @deprecated This module will be removed or replaced */ +import { + verifyNickname, + getUserPerms, + getUserDetails, +} from '../utility/_UAC'; // module main export async function run({ server, socket, payload }) { @@ -27,7 +32,7 @@ export async function run({ server, socket, payload }) { }, socket); } - if (payload.channel === socket.channel) { + if (payload.channel === socket.channel) { // @todo Multichannel update // they are trying to rejoin the channel return true; } @@ -52,41 +57,61 @@ export async function run({ server, socket, payload }) { server.reply({ cmd: 'onlineRemove', nick: peerList[i].nick, + userid: peerList[i].userid, channel: socket.channel, // @todo Multichannel }, socket); - if (socket.nick !== peerList[i].nick) { + if (socket.userid !== peerList[i].userid) { server.reply({ cmd: 'onlineRemove', nick: socket.nick, + userid: socket.userid, channel: socket.channel, // @todo Multichannel }, peerList[i]); } } } - // @todo import function from join module // broadcast join notice to new peers const newPeerList = server.findSockets({ channel: payload.channel }); const moveAnnouncement = { - cmd: 'onlineAdd', - nick: socket.nick, - trip: socket.trip || 'null', - hash: socket.hash, + ...{ + cmd: 'onlineAdd', + channel: payload.channel, // @todo Multichannel + }, + ...getUserDetails(socket), }; + const nicks = []; + const users = []; for (let i = 0, l = newPeerList.length; i < l; i += 1) { server.reply(moveAnnouncement, newPeerList[i]); - nicks.push(newPeerList[i].nick); + + nicks.push(newPeerList[i].nick); /* @legacy */ + users.push({ + ...{ + channel: payload.channel, + isme: false, + }, + ...getUserDetails(newPeerList[i]), + }); } - nicks.push(socket.nick); + nicks.push(socket.nick); /* @legacy */ + users.push({ + ...{ + channel: payload.channel, + isme: true, + }, + ...getUserDetails(socket) + }); // reply with new user list server.reply({ cmd: 'onlineSet', nicks, + users, channel: socket.channel, // @todo Multichannel (!) }, socket); diff --git a/server/src/commands/core/session.js b/server/src/commands/core/session.js index 2d02810..1e4249b 100644 --- a/server/src/commands/core/session.js +++ b/server/src/commands/core/session.js @@ -55,6 +55,7 @@ export async function run({ server, socket, payload }) { socket.userid = Math.floor(Math.random() * 9999999999999); socket.hash = server.getSocketHash(socket); socket.isBot = payload.isBot || false; + socket.color = false; // dispatch info server.reply({ diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index a2d85dd..6705cb7 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -90,6 +90,8 @@ export async function run({ server, socket, payload }) { server.reply(outgoingPayload, socket); } + targetUser.whisperReply = socket.nick; + return true; } @@ -161,6 +163,7 @@ export function whisperCheck({ payload: { cmd: 'whisper', nick: socket.whisperReply, + channel: socket.channel, // @todo Multichannel text: whisperText, }, }); diff --git a/server/src/commands/mod/ban.js b/server/src/commands/mod/ban.js index 2db87cd..2529633 100644 --- a/server/src/commands/mod/ban.js +++ b/server/src/commands/mod/ban.js @@ -3,7 +3,11 @@ Description: Adds the target socket's ip to the ratelimiter */ -import * as UAC from '../utility/UAC/_info'; +import { + isModerator, + getUserDetails, + levels, +} from '../utility/_UAC'; import { Errors, } from '../utility/_Constants'; @@ -16,7 +20,7 @@ export async function run({ core, server, socket, payload, }) { // increase rate limit chance and ignore if not admin or mod - if (!UAC.isModerator(socket.level)) { + if (!isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } @@ -62,9 +66,9 @@ export async function run({ server.broadcast({ cmd: 'info', text: `Banned ${targetNick}`, - user: UAC.getUserDetails(targetUser), + user: getUserDetails(targetUser), channel: socket.channel, // @todo Multichannel - }, { channel: socket.channel, level: (level) => level < UAC.levels.moderator }); + }, { channel: socket.channel, level: (level) => level < levels.moderator }); // notify mods server.broadcast({ @@ -72,9 +76,9 @@ export async function run({ text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${targetUser.hash}`, channel: socket.channel, // @todo Multichannel inChannel: payload.channel, - user: UAC.getUserDetails(targetUser), - banner: UAC.getUserDetails(socket), - }, { level: UAC.isModerator }); + user: getUserDetails(targetUser), + banner: getUserDetails(socket), + }, { level: isModerator }); // force connection closed targetUser.terminate(); diff --git a/server/src/commands/mod/dumb.js b/server/src/commands/mod/dumb.js index 558f02e..5b66684 100644 --- a/server/src/commands/mod/dumb.js +++ b/server/src/commands/mod/dumb.js @@ -6,7 +6,9 @@ * Author: simple */ -import * as UAC from '../utility/UAC/_info'; +import { + isModerator, +} from '../utility/_UAC'; import { Errors, } from '../utility/_Constants'; @@ -26,7 +28,7 @@ export async function run({ core, server, socket, payload, }) { // increase rate limit chance and ignore if not admin or mod - if (!UAC.isModerator(socket.level)) { + if (!isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } @@ -77,7 +79,7 @@ export async function run({ cmd: 'info', text: `${socket.nick}#${socket.trip} muzzled ${targetUser.nick} in ${payload.channel}, userhash: ${targetUser.hash}`, channel: false, // @todo Multichannel, false for global - }, { level: UAC.isModerator }); + }, { level: isModerator }); return true; } diff --git a/server/src/commands/mod/kick.js b/server/src/commands/mod/kick.js index 6dc58ea..c476e57 100644 --- a/server/src/commands/mod/kick.js +++ b/server/src/commands/mod/kick.js @@ -4,7 +4,11 @@ Description: Forces a change on the target(s) socket's channel, then broadcasts event */ -import * as UAC from '../utility/UAC/_info'; +import { + isModerator, + levels, + getUserDetails, +} from '../utility/_UAC'; import { Errors, } from '../utility/_Constants'; @@ -17,7 +21,7 @@ export async function run({ core, server, socket, payload, }) { // increase rate limit chance and ignore if not admin or mod - if (!UAC.isModerator(socket.level)) { + if (!isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } @@ -76,17 +80,15 @@ export async function run({ // Announce the kicked clients arrival in destChannel and that they were kicked // Before they arrive, so they don't see they got moved - for (let i = 0; i < kicked.length; i += 1) { - server.broadcast({ + const moveAnnouncement = { + ...getUserDetails(socket), + ...{ cmd: 'onlineAdd', - nick: kicked[i].nick, - trip: kicked[i].trip || 'null', - uType: 'user', - hash: kicked[i].hash, - level: UAC.levels.default, - userid: kicked[i].userid, - channel: destChannel, - }, { channel: destChannel }); + channel: destChannel, // @todo Multichannel + }, + }; + for (let i = 0; i < kicked.length; i += 1) { + server.broadcast(moveAnnouncement, { channel: destChannel }); } // Move all kicked clients to the new channel @@ -98,7 +100,7 @@ export async function run({ cmd: 'info', text: `${kicked[i].nick} was banished to ?${destChannel}`, channel: socket.channel, // @todo Multichannel - }, { channel: socket.channel, level: UAC.isModerator }); + }, { channel: socket.channel, level: isModerator }); console.log(`${socket.nick} [${socket.trip}] kicked ${kicked[i].nick} in ${socket.channel} to ${destChannel} `); } @@ -118,7 +120,7 @@ export async function run({ cmd: 'info', text: `Kicked ${kicked.map((k) => k.nick).join(', ')}`, channel: socket.channel, // @todo Multichannel - }, { channel: socket.channel, level: (level) => level < UAC.levels.moderator }); + }, { channel: socket.channel, level: (level) => level < levels.moderator }); // stats are fun core.stats.increment('users-kicked', kicked.length); diff --git a/server/src/commands/mod/moveuser.js b/server/src/commands/mod/moveuser.js index eb17cf8..a616620 100644 --- a/server/src/commands/mod/moveuser.js +++ b/server/src/commands/mod/moveuser.js @@ -3,12 +3,15 @@ @deprecated This module will be removed or replaced */ -import * as UAC from '../utility/UAC/_info'; +import { + isModerator, + getUserDetails, +} from '../utility/_UAC'; // module main export async function run({ server, socket, payload }) { // increase rate limit chance and ignore if not admin or mod - if (!UAC.isModerator(socket.level)) { + if (!isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } @@ -59,6 +62,7 @@ export async function run({ server, socket, payload }) { for (let i = 0, l = peerList.length; i < l; i += 1) { server.reply({ cmd: 'onlineRemove', + userid: peerList[i].userid, nick: peerList[i].nick, channel: socket.channel, // @todo Multichannel }, badClient); @@ -66,6 +70,7 @@ export async function run({ server, socket, payload }) { if (badClient.nick !== peerList[i].nick) { server.reply({ cmd: 'onlineRemove', + userid: badClient.userid, nick: badClient.nick, channel: socket.channel, // @todo Multichannel }, peerList[i]); @@ -73,27 +78,43 @@ export async function run({ server, socket, payload }) { } } - // @todo import from join module + const newPeerList = server.findSockets({ channel: payload.channel }); const moveAnnouncement = { - cmd: 'onlineAdd', - nick: badClient.nick, - trip: badClient.trip || 'null', - hash: server.getSocketHash(badClient), + ...getUserDetails(badClient), + ...{ + cmd: 'onlineAdd', + channel: payload.channel, // @todo Multichannel + }, }; const nicks = []; - + const users = []; for (let i = 0, l = newPeerList.length; i < l; i += 1) { server.reply(moveAnnouncement, newPeerList[i]); - nicks.push(newPeerList[i].nick); + + nicks.push(newPeerList[i].nick); /* @legacy */ + users.push({ + ...{ + channel, + isme: false, + }, + ...getUserDetails(newPeerList[i]), + }); } - nicks.push(badClient.nick); + nicks.push(badClient.nick); /* @legacy */ + users.push({ + ...{ + isme: true, + }, + ...getUserDetails(badClient), + }); server.reply({ cmd: 'onlineSet', - nicks, - channel: socket.channel, // @todo Multichannel (!) + nicks, /* @legacy */ + users, + channel, // @todo Multichannel (?) }, badClient); badClient.channel = payload.channel; @@ -101,7 +122,7 @@ export async function run({ server, socket, payload }) { server.broadcast({ cmd: 'info', text: `${badClient.nick} was moved into ?${payload.channel}`, - channel: socket.channel, // @todo Multichannel + channel: payload.channel, // @todo Multichannel }, { channel: payload.channel }); return true; diff --git a/server/src/commands/mod/speak.js b/server/src/commands/mod/speak.js index a197d01..15b3c10 100644 --- a/server/src/commands/mod/speak.js +++ b/server/src/commands/mod/speak.js @@ -5,7 +5,9 @@ * Author: simple */ -import * as UAC from '../utility/UAC/_info'; +import { + isModerator, +} from '../utility/_UAC'; // module constructor export function init(core) { @@ -19,7 +21,7 @@ export async function run({ core, server, socket, payload, }) { // increase rate limit chance and ignore if not admin or mod - if (!UAC.isModerator(socket.level)) { + if (!isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } @@ -40,7 +42,7 @@ export async function run({ cmd: 'info', text: `${socket.nick} unmuzzled all users`, channel: false, // @todo Multichannel, false for global - }, { level: UAC.isModerator }); + }, { level: isModerator }); } } else if (payload.hash === '*') { core.muzzledHashes = {}; @@ -49,7 +51,7 @@ export async function run({ cmd: 'info', text: `${socket.nick} unmuzzled all users`, channel: false, // @todo Multichannel, false for global - }, { level: UAC.isModerator }); + }, { level: isModerator }); } // find target & remove mute status @@ -67,7 +69,7 @@ export async function run({ cmd: 'info', text: `${socket.nick}#${socket.trip} unmuzzled : ${target}`, channel: false, // @todo Multichannel, false for global - }, { level: UAC.isModerator }); + }, { level: isModerator }); return true; } diff --git a/server/src/commands/mod/unban.js b/server/src/commands/mod/unban.js index a13dea3..5554585 100644 --- a/server/src/commands/mod/unban.js +++ b/server/src/commands/mod/unban.js @@ -4,14 +4,16 @@ Description: Removes a target ip from the ratelimiter */ -import * as UAC from '../utility/UAC/_info'; +import { + isModerator, +} from '../utility/_UAC'; // module main export async function run({ core, server, socket, payload, }) { // increase rate limit chance and ignore if not admin or mod - if (!UAC.isModerator(socket.level)) { + if (!isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } @@ -56,7 +58,7 @@ export async function run({ cmd: 'info', text: `${socket.nick}#${socket.trip} unbanned: ${target}`, channel: false, // @todo Multichannel, false for global - }, { level: UAC.isModerator }); + }, { level: isModerator }); // stats are fun core.stats.decrement('users-banned'); diff --git a/server/src/commands/mod/unbanall.js b/server/src/commands/mod/unbanall.js index 3d37efd..5705704 100644 --- a/server/src/commands/mod/unbanall.js +++ b/server/src/commands/mod/unbanall.js @@ -4,12 +4,14 @@ Description: Clears all bans and ratelimits */ -import * as UAC from '../utility/UAC/_info'; +import { + isModerator, +} from '../utility/_UAC'; // module main export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin or mod - if (!UAC.isModerator(socket.level)) { + if (!isModerator(socket.level)) { return server.police.frisk(socket.address, 10); } @@ -32,7 +34,7 @@ export async function run({ core, server, socket }) { cmd: 'info', text: `${socket.nick}#${socket.trip} unbanned all ip addresses`, channel: false, // @todo Multichannel, false for global - }, { level: UAC.isModerator }); + }, { level: isModerator }); return true; } diff --git a/server/src/commands/utility/UAC/_info.js b/server/src/commands/utility/UAC/_info.js deleted file mode 100644 index a43f0e6..0000000 --- a/server/src/commands/utility/UAC/_info.js +++ /dev/null @@ -1,119 +0,0 @@ -// NOTE: this has been moved into /utility/ as _UAC.js -/** - * User Account Control information containing level constants - * and simple helper functions related to users - * @property {Object} levels - Defines labels for default permission ranges - * @author MinusGix ( https://github.com/MinusGix ) - * @version v1.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ - -/** - * Object defining labels for default permission ranges - * @typedef {Object} levels - * @property {number} admin Global administrator range - * @property {number} moderator Global moderator range - * @property {number} channelOwner Local administrator range - * @property {number} channelModerator Local moderator range - * @property {number} channelTrusted Local (non-public) channel trusted - * @property {number} trustedUser Public channel trusted - * @property {number} default Default user level - */ -export const levels = { - admin: 9999999, - moderator: 999999, - - channelOwner: 99999, - channelModerator: 9999, - channelTrusted: 8999, - - trustedUser: 500, - default: 100, -}; - -/** - * Returns true if target level is equal or greater than the global admin level - * @public - * @param {number} level Level to verify - * @return {boolean} - */ -export function isAdmin(level) { - return level >= levels.admin; -} - -/** - * Returns true if target level is equal or greater than the global moderator level - * @public - * @param {number} level Level to verify - * @return {boolean} - */ -export function isModerator(level) { - return level >= levels.moderator; -} - -/** - * Returns true if target level is equal or greater than the channel owner level - * @public - * @param {number} level Level to verify - * @return {boolean} - */ -export function isChannelOwner(level) { - return level >= levels.channelOwner; -} - -/** - * Returns true if target level is equal or greater than the channel moderator level - * @public - * @param {number} level Level to verify - * @return {boolean} - */ -export function isChannelModerator(level) { - return level >= levels.channelModerator; -} - -/** - * Returns true if target level is equal or greater than the channel trust level - * @public - * @param {number} level Level to verify - * @return {boolean} - */ -export function isChannelTrusted(level) { - return level >= levels.channelTrusted; -} - -/** - * Returns true if target level is equal or greater than a trusted user - * @public - * @param {number} level Level to verify - * @return {boolean} - */ -export function isTrustedUser(level) { - return level >= levels.trustedUser; -} - -/** - * Return an object containing public information about the socket - * @public - * @param {WebSocket} socket Target client - * @return {Object} - */ -export function getUserDetails(socket) { - return { - uType: socket.uType, - nick: socket.nick, - trip: socket.trip || 'null', - hash: socket.hash, - level: socket.level, - userid: socket.userid, - }; -} - -/** - * Returns true if the nickname is valid - * @public - * @param {string} nick Nickname to verify - * @return {boolean} - */ -export function verifyNickname(nick) { - return /^[a-zA-Z0-9_]{1,24}$/.test(nick); -} diff --git a/server/src/commands/utility/_LegacyFunctions.js b/server/src/commands/utility/_LegacyFunctions.js index 6662267..7c27b7b 100644 --- a/server/src/commands/utility/_LegacyFunctions.js +++ b/server/src/commands/utility/_LegacyFunctions.js @@ -22,6 +22,7 @@ export function upgradeLegacyJoin(server, socket, payload) { // these would have been applied in the `session` module, apply it now socket.hash = server.getSocketHash(socket); socket.isBot = false; + socket.color = false; // pull the password from the nick const nickArray = payload.nick.split('#', 2); diff --git a/server/src/commands/utility/_UAC.js b/server/src/commands/utility/_UAC.js index aee98d2..52e5e7a 100644 --- a/server/src/commands/utility/_UAC.js +++ b/server/src/commands/utility/_UAC.js @@ -104,12 +104,14 @@ export function isTrustedUser(level) { */ export function getUserDetails(socket) { return { - uType: socket.uType, nick: socket.nick, - trip: socket.trip || 'null', + trip: socket.trip || '', + uType: socket.uType, hash: socket.hash, level: socket.level, userid: socket.userid, + isBot: socket.isBot, + color: socket.color, }; } @@ -154,13 +156,12 @@ export function getUserPerms(pass, config, channel) { }; } + let level = levels.default; + // check if user is global mod config.mods.forEach((mod) => { // eslint-disable-line consistent-return if (trip === mod.trip) { - return { - trip, - level: levels.moderator, - }; + level = levels.moderator; } }); @@ -181,6 +182,6 @@ export function getUserPerms(pass, config, channel) { return { trip, - level: levels.default, + level, }; } From 22772fa90cfdf2c4cbe15d9ab7dff748238f9442 Mon Sep 17 00:00:00 2001 From: marzavec Date: Fri, 6 Nov 2020 13:22:50 -0800 Subject: [PATCH 11/37] minimized command penalty Can't wait to see the flashing rainbow nicks! :D --- server/src/commands/core/changecolor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/commands/core/changecolor.js b/server/src/commands/core/changecolor.js index afbb8f7..2801fcf 100644 --- a/server/src/commands/core/changecolor.js +++ b/server/src/commands/core/changecolor.js @@ -11,7 +11,7 @@ export async function run({ }) { const channel = socket.channel; - if (server.police.frisk(socket.address, 6)) { + if (server.police.frisk(socket.address, 1)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing colors too fast. Wait a moment before trying again.', From 85b9ad08bb49f660949131a8399c6543bb4e98bc Mon Sep 17 00:00:00 2001 From: marzavec Date: Fri, 6 Nov 2020 14:12:36 -0800 Subject: [PATCH 12/37] Bug fix --- server/src/commands/mod/kick.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/server/src/commands/mod/kick.js b/server/src/commands/mod/kick.js index c476e57..183c05f 100644 --- a/server/src/commands/mod/kick.js +++ b/server/src/commands/mod/kick.js @@ -80,15 +80,14 @@ export async function run({ // Announce the kicked clients arrival in destChannel and that they were kicked // Before they arrive, so they don't see they got moved - const moveAnnouncement = { - ...getUserDetails(socket), - ...{ - cmd: 'onlineAdd', - channel: destChannel, // @todo Multichannel - }, - }; for (let i = 0; i < kicked.length; i += 1) { - server.broadcast(moveAnnouncement, { channel: destChannel }); + server.broadcast({ + ...getUserDetails(kicked[i]), + ...{ + cmd: 'onlineAdd', + channel: destChannel, // @todo Multichannel + }, + }, { channel: destChannel }); } // Move all kicked clients to the new channel From 7b7a511b8ddffc5110be583157da11eef768854b Mon Sep 17 00:00:00 2001 From: marzavec Date: Mon, 9 Nov 2020 11:55:54 -0800 Subject: [PATCH 13/37] syncing dev changes --- client/client.js | 44 ++++- server/src/commands/admin/removemod.js | 19 ++ server/src/commands/core/changecolor.js | 12 +- server/src/commands/core/changenick.js | 4 +- server/src/commands/core/join.js | 4 +- server/src/commands/core/move.js | 4 +- server/src/commands/core/whisper.js | 1 - server/src/commands/mod/dumb.js | 179 ++++++++++++++---- server/src/commands/mod/forcecolor.js | 162 ++++++++++++++++ server/src/commands/mod/moveuser.js | 5 +- .../src/commands/utility/_LegacyFunctions.js | 4 +- 11 files changed, 381 insertions(+), 57 deletions(-) create mode 100644 server/src/commands/mod/forcecolor.js diff --git a/client/client.js b/client/client.js index 682a28e..5b902bc 100644 --- a/client/client.js +++ b/client/client.js @@ -353,7 +353,9 @@ function join(channel) { var args = JSON.parse(message.data); var cmd = args.cmd; var command = COMMANDS[cmd]; - command.call(null, args); + if (command) { + command.call(null, args); + } } } @@ -368,9 +370,9 @@ var COMMANDS = { info: function (args) { args.nick = '*'; pushMessage(args); - }, + }, - emote: function (args) { + emote: function (args) { args.nick = '*'; pushMessage(args); }, @@ -410,6 +412,30 @@ var COMMANDS = { if ($('#joined-left').checked) { pushMessage({ nick: '*', text: nick + " left" }); } + }, + + captcha: function (args) { + var messageEl = document.createElement('div'); + messageEl.classList.add('info'); + + + var nickSpanEl = document.createElement('span'); + nickSpanEl.classList.add('nick'); + messageEl.appendChild(nickSpanEl); + + var nickLinkEl = document.createElement('a'); + nickLinkEl.textContent = '#'; + nickSpanEl.appendChild(nickLinkEl); + + var textEl = document.createElement('pre'); + textEl.style.fontSize = '4px'; + textEl.classList.add('text'); + textEl.innerHTML = args.text; + + messageEl.appendChild(textEl); + $('#messages').appendChild(messageEl); + + window.scrollTo(0, document.body.scrollHeight); } } @@ -447,7 +473,13 @@ function pushMessage(args) { if (args.trip) { var tripEl = document.createElement('span'); - tripEl.textContent = args.trip + " "; + + if (args.mod) { + tripEl.textContent = String.fromCodePoint(11088) + " " + args.trip + " "; + } else { + tripEl.textContent = args.trip + " "; + } + tripEl.classList.add('trip'); nickSpanEl.appendChild(tripEl); } @@ -456,6 +488,10 @@ function pushMessage(args) { var nickLinkEl = document.createElement('a'); nickLinkEl.textContent = args.nick; + if (args.color && /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(args.color)) { + nickLinkEl.setAttribute('style', 'color:#' + args.color + ' !important'); + } + nickLinkEl.onclick = function () { insertAtCursor("@" + args.nick + " "); $('#chatinput').focus(); diff --git a/server/src/commands/admin/removemod.js b/server/src/commands/admin/removemod.js index 85d5fd6..e1ab7af 100644 --- a/server/src/commands/admin/removemod.js +++ b/server/src/commands/admin/removemod.js @@ -6,6 +6,7 @@ import { isAdmin, isModerator, levels, + getUserDetails, } from '../utility/_UAC'; // module main @@ -24,6 +25,16 @@ export async function run({ // find targets current connections const targetMod = server.findSockets({ trip: payload.trip }); if (targetMod.length !== 0) { + // build update notice with new privileges + const updateNotice = { + ...getUserDetails(targetMod[0]), + ...{ + cmd: 'updateUser', + uType: 'user', // @todo use legacyLevelToLabel from _LegacyFunctions.js + level: levels.default, + }, + }; + for (let i = 0, l = targetMod.length; i < l; i += 1) { // downgrade privilages targetMod[i].uType = 'user'; @@ -35,6 +46,14 @@ export async function run({ text: 'You are now a user.', channel: targetMod[i].channel, // @todo Multichannel }, targetMod[i]); + + // notify channel + server.broadcast({ + ...updateNotice, + ...{ + channel: targetMod[i].channel, + }, + }, { channel: targetMod[i].channel }); } } diff --git a/server/src/commands/core/changecolor.js b/server/src/commands/core/changecolor.js index 2801fcf..0eecdcd 100644 --- a/server/src/commands/core/changecolor.js +++ b/server/src/commands/core/changecolor.js @@ -2,12 +2,16 @@ Description: Allows calling client to change their nickname color */ +import { + getUserDetails, +} from '../utility/_UAC'; + // module support functions const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); // module main export async function run({ - core, server, socket, payload, + server, socket, payload, }) { const channel = socket.channel; @@ -35,9 +39,9 @@ export async function run({ } if (newColor === 'RESET') { - socket.color = false; + socket.color = false; // eslint-disable-line no-param-reassign } else { - socket.color = newColor; + socket.color = newColor; // eslint-disable-line no-param-reassign } // build update notice with new color @@ -46,7 +50,7 @@ export async function run({ ...{ cmd: 'updateUser', channel: socket.channel, // @todo Multichannel - } + }, }; // notify channel that the user has changed their name diff --git a/server/src/commands/core/changenick.js b/server/src/commands/core/changenick.js index 558a1b8..8bc3b6d 100644 --- a/server/src/commands/core/changenick.js +++ b/server/src/commands/core/changenick.js @@ -85,7 +85,7 @@ export async function run({ cmd: 'updateUser', nick: newNick, channel, // @todo Multichannel - } + }, }; // build join and leave notices for legacy clients @@ -114,7 +114,7 @@ export async function run({ server.send(joinNotice, peerList[i]); } else { // send update info - // @todo this should be sent to every channel the client is in + // @todo this should be sent to every channel the client is in (multichannel) server.send(updateNotice, peerList[i]); } } diff --git a/server/src/commands/core/join.js b/server/src/commands/core/join.js index 9332c8c..45e6446 100644 --- a/server/src/commands/core/join.js +++ b/server/src/commands/core/join.js @@ -76,7 +76,7 @@ export async function run({ // get trip and level const { trip, level } = getUserPerms(pass, core.config, channel); - + // store the user values const userInfo = { nick, @@ -122,7 +122,7 @@ export async function run({ // send join announcement and prep online set reply for (let i = 0, l = newPeerList.length; i < l; i += 1) { server.reply(joinAnnouncement, newPeerList[i]); - + nicks.push(newPeerList[i].nick); /* @legacy */ users.push({ ...{ diff --git a/server/src/commands/core/move.js b/server/src/commands/core/move.js index d6537c5..de6a4fb 100644 --- a/server/src/commands/core/move.js +++ b/server/src/commands/core/move.js @@ -3,8 +3,6 @@ @deprecated This module will be removed or replaced */ import { - verifyNickname, - getUserPerms, getUserDetails, } from '../utility/_UAC'; @@ -104,7 +102,7 @@ export async function run({ server, socket, payload }) { channel: payload.channel, isme: true, }, - ...getUserDetails(socket) + ...getUserDetails(socket), }); // reply with new user list diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index 6705cb7..25bc1b6 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -16,7 +16,6 @@ import { } from '../utility/_LegacyFunctions'; // module support functions - const parseText = (text) => { // verifies user input is text if (typeof text !== 'string') { diff --git a/server/src/commands/mod/dumb.js b/server/src/commands/mod/dumb.js index 5b66684..4625b58 100644 --- a/server/src/commands/mod/dumb.js +++ b/server/src/commands/mod/dumb.js @@ -9,12 +9,45 @@ import { isModerator, } from '../utility/_UAC'; +import { + findUser, +} from '../utility/_Channels'; import { Errors, } from '../utility/_Constants'; import { - findUser, -} from '../utility/_Channels'; + legacyInviteReply, + legacyWhisperReply, +} from '../utility/_LegacyFunctions'; + +// module support functions +/** + * Returns the channel that should be invited to. + * @param {any} channel + * @return {string} + */ +export function getChannel(channel = undefined) { + if (typeof channel === 'string') { + return channel; + } + return Math.random().toString(36).substr(2, 8); +} + +const parseText = (text) => { + // verifies user input is text + if (typeof text !== 'string') { + return false; + } + + let sanitizedText = text; + + // strip newlines from beginning and end + sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); + // replace 3+ newlines with just 2 newlines + sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n'); + + return sanitizedText; +}; // module constructor export function init(core) { @@ -101,24 +134,31 @@ export function chatCheck({ if (core.muzzledHashes[socket.hash]) { // build fake chat payload - const mutedPayload = { + const outgoingPayload = { cmd: 'chat', - nick: socket.nick, + nick: socket.nick, /* @legacy */ + uType: socket.uType, /* @legacy */ + userid: socket.userid, + channel: socket.channel, text: payload.text, - channel: socket.channel, // @todo Multichannel + level: socket.level, }; if (socket.trip) { - mutedPayload.trip = socket.trip; + outgoingPayload.trip = socket.trip; + } + + if (socket.color) { + outgoingPayload.color = socket.color; } // broadcast to any duplicate connections in channel - server.broadcast(mutedPayload, { channel: socket.channel, hash: socket.hash }); + server.broadcast(outgoingPayload, { channel: socket.channel, hash: socket.hash }); // broadcast to allies, if any if (core.muzzledHashes[socket.hash].allies) { server.broadcast( - mutedPayload, + outgoingPayload, { channel: socket.channel, nick: core.muzzledHashes[socket.hash].allies, @@ -140,24 +180,62 @@ export function chatCheck({ } // shadow-prevent all invites from muzzled users -export function inviteCheck({ core, socket, payload }) { +export function inviteCheck({ + core, server, socket, payload, +}) { if (core.muzzledHashes[socket.hash]) { - // @todo convert to protocol 2 - /* const nickValid = Invite.checkNickname(payload.nick); - if (nickValid !== null) { - server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: nickValid, + // check for spam + if (server.police.frisk(socket.address, 2)) { + return server.reply({ + cmd: 'warn', + text: 'You are sending invites too fast. Wait a moment before trying again.', + id: Errors.Invite.RATELIMIT, + channel: socket.channel, // @todo Multichannel + }, socket); + } + + // verify user input + // if this is a legacy client add missing params to payload + if (socket.hcProtocol === 1) { + if (typeof socket.channel === 'undefined' || typeof payload.nick !== 'string') { + return true; + } + + payload.channel = socket.channel; // eslint-disable-line no-param-reassign + } else if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') { + return true; + } + + // @todo Verify this socket is part of payload.channel - multichannel patch + // find target user + const targetUser = findUser(server, payload); + if (!targetUser) { + return server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, channel: socket.channel, // @todo Multichannel }, socket); - return false; } // generate common channel - const channel = Invite.getChannel(); + const channel = getChannel(payload.to); - // send fake reply - server.reply(Invite.createSuccessPayload(payload.nick, channel), socket); */ + // build invite + const outgoingPayload = { + cmd: 'invite', + channel: socket.channel, // @todo Multichannel + from: socket.userid, + to: targetUser.userid, + inviteChannel: channel, + }; + + // send invite notice to this client + if (socket.hcProtocol === 1) { + server.reply(legacyInviteReply(outgoingPayload, targetUser.nick), socket); + } else { + server.reply(outgoingPayload, socket); + } return false; } @@ -169,27 +247,56 @@ export function inviteCheck({ core, socket, payload }) { export function whisperCheck({ core, server, socket, payload, }) { - if (typeof payload.nick !== 'string') { - return false; - } - - if (typeof payload.text !== 'string') { - return false; - } - if (core.muzzledHashes[socket.hash]) { - const targetNick = payload.nick; + // if this is a legacy client add missing params to payload + if (socket.hcProtocol === 1) { + payload.channel = socket.channel; // eslint-disable-line no-param-reassign + } - server.reply({ - cmd: 'info', - type: 'whisper', - text: `You whispered to @${targetNick}: ${payload.text}`, + // verify user input + const text = parseText(payload.text); + + if (!text) { + // lets not send objects or empty text, yea? + return server.police.frisk(socket.address, 13); + } + + // check for spam + const score = text.length / 83 / 4; + if (server.police.frisk(socket.address, score)) { + return server.reply({ + cmd: 'warn', // @todo Add numeric error code as `id` + text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', + channel: socket.channel, // @todo Multichannel + }, socket); + } + + const targetUser = findUser(server, payload); + if (!targetUser) { + return server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel + }, socket); + } + + const outgoingPayload = { + cmd: 'whisper', channel: socket.channel, // @todo Multichannel - }, socket); + from: socket.userid, + to: targetUser.userid, + text, + }; - // blanket "spam" protection, may expose the ratelimiting lines from - // `chat` and use that, @todo one day #lazydev - server.police.frisk(socket.address, 9); + // send invite notice to this client + if (socket.hcProtocol === 1) { + server.reply(legacyWhisperReply(outgoingPayload, targetUser.nick), socket); + } else { + server.reply(outgoingPayload, socket); + } + + targetUser.whisperReply = socket.nick; return false; } diff --git a/server/src/commands/mod/forcecolor.js b/server/src/commands/mod/forcecolor.js new file mode 100644 index 0000000..42eb2b8 --- /dev/null +++ b/server/src/commands/mod/forcecolor.js @@ -0,0 +1,162 @@ +/* + Description: Forces a change on the target socket's nick color +*/ + +import { + isModerator, + getUserDetails, +} from '../utility/_UAC'; +import { + Errors, +} from '../utility/_Constants'; +import { + findUser, +} from '../utility/_Channels'; + +const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); + +// module main +export async function run({ + server, socket, payload, +}) { + // increase rate limit chance and ignore if not admin or mod + if (!isModerator(socket.level)) { + return server.police.frisk(socket.address, 10); + } + + const channel = socket.channel; + if (typeof payload.channel === 'undefined') { + payload.channel = channel; + } + + // check user input + if (typeof payload.nick !== 'string') { + return true; + } + + if (typeof payload.color !== 'string') { + return true; + } + + // make sure requested nickname meets standards + const newColor = payload.color.trim().toUpperCase().replace(/#/g, ''); + if (newColor !== 'RESET' && !verifyColor(newColor)) { + return server.reply({ + cmd: 'warn', + text: 'Invalid color! Color must be in hex value', + channel, // @todo Multichannel + }, socket); + } + + // find target user + const targetUser = findUser(server, payload); + if (!targetUser) { + return server.reply({ + cmd: 'warn', + text: 'Could not find user in that channel', + id: Errors.Global.UNKNOWN_USER, + channel: socket.channel, // @todo Multichannel + }, socket); + } + + // TODO: Change this uType to use level / uac + // i guess coloring mods or admins isn't the best idea? + if (targetUser.uType !== 'user') { + return true; + } + + if (newColor === 'RESET') { + targetUser.color = false; + } else { + targetUser.color = newColor; + } + + // build update notice with new color + const updateNotice = { + ...getUserDetails(targetUser), + ...{ + cmd: 'updateUser', + channel: socket.channel, // @todo Multichannel + }, + }; + + // notify channel that the user has changed their name + // @todo this should be sent to every channel the user is in (multichannel) + server.broadcast(updateNotice, { channel: socket.channel }); + + // mod perks + // TODO: Change this uType to use level / uac + if (socket.uType !== 'user') { + if (typeof server.police.records[socket.address] !== 'undefined') { + server.police.records[socket.address].score = -50; + } + } + + return true; +} + +// module hook functions +export function initHooks(server) { + server.registerHook('in', 'chat', this.colorCheck.bind(this), 20); +} + +// hooks chat commands checking for /whisper +export function colorCheck({ + core, server, socket, payload, +}) { + if (typeof payload.text !== 'string') { + return false; + } + + if (payload.text.startsWith('/forcecolor ')) { + const input = payload.text.split(' '); + + // If there is no nickname target parameter + if (input[1] === undefined) { + server.reply({ + cmd: 'warn', + text: 'Refer to `/help forcecolor` for instructions on how to use this command.', + channel: socket.channel, // @todo Multichannel + }, socket); + + return false; + } + + if (input[2] === undefined) { + server.reply({ + cmd: 'warn', + text: 'Refer to `/help forcecolor` for instructions on how to use this command.', + channel: socket.channel, // @todo Multichannel + }, socket); + + return false; + } + + const target = input[1].replace(/@/g, ''); + + this.run({ + core, + server, + socket, + payload: { + cmd: 'forcecolor', + nick: target, + color: input[2], + }, + }); + + return false; + } + + return payload; +} + +// module meta +export const requiredData = ['nick', 'color']; +export const info = { + name: 'forcecolor', + description: 'Forces a user nick to become a certain color', + usage: ` + API: { cmd: 'forcecolor', nick: '', color: '' } +Text: /forcecolor `, +}; diff --git a/server/src/commands/mod/moveuser.js b/server/src/commands/mod/moveuser.js index a616620..edae2aa 100644 --- a/server/src/commands/mod/moveuser.js +++ b/server/src/commands/mod/moveuser.js @@ -78,7 +78,6 @@ export async function run({ server, socket, payload }) { } } - const newPeerList = server.findSockets({ channel: payload.channel }); const moveAnnouncement = { ...getUserDetails(badClient), @@ -95,7 +94,7 @@ export async function run({ server, socket, payload }) { nicks.push(newPeerList[i].nick); /* @legacy */ users.push({ ...{ - channel, + channel: payload.channel, isme: false, }, ...getUserDetails(newPeerList[i]), @@ -114,7 +113,7 @@ export async function run({ server, socket, payload }) { cmd: 'onlineSet', nicks, /* @legacy */ users, - channel, // @todo Multichannel (?) + channel: payload.channel, // @todo Multichannel (?) }, badClient); badClient.channel = payload.channel; diff --git a/server/src/commands/utility/_LegacyFunctions.js b/server/src/commands/utility/_LegacyFunctions.js index 7c27b7b..4fa9891 100644 --- a/server/src/commands/utility/_LegacyFunctions.js +++ b/server/src/commands/utility/_LegacyFunctions.js @@ -61,7 +61,7 @@ export function legacyLevelToLabel(level) { * @param {string} nick Sender nick * @return {object} */ - export function legacyInviteOut(payload, nick) { +export function legacyInviteOut(payload, nick) { return { ...payload, ...{ @@ -99,7 +99,7 @@ export function legacyInviteReply(payload, nick) { * @param {string} nick Sender nick * @return {object} */ - export function legacyWhisperOut(payload, from) { +export function legacyWhisperOut(payload, from) { return { ...payload, ...{ From 28ba8282fc6f40117fcbfb6150f3e9116373039d Mon Sep 17 00:00:00 2001 From: marzavec Date: Mon, 9 Nov 2020 11:56:48 -0800 Subject: [PATCH 14/37] Update forcecolor.js --- server/src/commands/mod/forcecolor.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/server/src/commands/mod/forcecolor.js b/server/src/commands/mod/forcecolor.js index 42eb2b8..9f24d41 100644 --- a/server/src/commands/mod/forcecolor.js +++ b/server/src/commands/mod/forcecolor.js @@ -84,14 +84,6 @@ export async function run({ // @todo this should be sent to every channel the user is in (multichannel) server.broadcast(updateNotice, { channel: socket.channel }); - // mod perks - // TODO: Change this uType to use level / uac - if (socket.uType !== 'user') { - if (typeof server.police.records[socket.address] !== 'undefined') { - server.police.records[socket.address].score = -50; - } - } - return true; } From af59db11e0fec94c73aeded477be98fde519028d Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 11 Nov 2020 09:31:57 -0800 Subject: [PATCH 15/37] Update whisper.js --- server/src/commands/core/whisper.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index 25bc1b6..9ab1433 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -107,7 +107,7 @@ export function whisperCheck({ return false; } - if (payload.text.startsWith('/whisper') || payload.text.startsWith('/w ')) { + if (payload.text.startsWith('/whisper ') || payload.text.startsWith('/w ')) { const input = payload.text.split(' '); // If there is no nickname target parameter @@ -140,7 +140,7 @@ export function whisperCheck({ return false; } - if (payload.text.startsWith('/r ')) { + if (payload.text.startsWith('/reply ') || payload.text.startsWith('/r ')) { if (typeof socket.whisperReply === 'undefined') { server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` From d293cc1236392a0693955c2502a6295af0a33b5f Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 11 Nov 2020 09:36:06 -0800 Subject: [PATCH 16/37] Update whisper.js --- server/src/commands/core/whisper.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/commands/core/whisper.js b/server/src/commands/core/whisper.js index 9ab1433..3c0b18b 100644 --- a/server/src/commands/core/whisper.js +++ b/server/src/commands/core/whisper.js @@ -181,5 +181,6 @@ export const info = { API: { cmd: 'whisper', nick: '', text: '' } Text: /whisper Text: /w + Alt Text: /reply Alt Text: /r `, }; From 2f6372b0fded6183acb90dc092e48d6cd633c59f Mon Sep 17 00:00:00 2001 From: Arteom Balanuta Date: Sun, 11 Jul 2021 13:44:42 +0300 Subject: [PATCH 17/37] * console.error() added to a empty `catch` block. * typo fixes --- client/client.js | 4 ++-- documentation/templateCommand.js | 6 +++--- server/src/serverLib/MainServer.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/client.js b/client/client.js index 5b902bc..d333178 100644 --- a/client/client.js +++ b/client/client.js @@ -169,7 +169,7 @@ var notifySwitch = document.getElementById("notify-switch") var notifySetting = localStorageGet("notify-api") var notifyPermissionExplained = 0; // 1 = granted msg shown, -1 = denied message shown -// Inital request for notifications permission +// Initial request for notifications permission function RequestNotifyPermission() { try { var notifyPromise = Notification.requestPermission(); @@ -916,7 +916,7 @@ $('#highlight-selector').onchange = function (e) { setHighlight(e.target.value); } -// Load sidebar configaration values from local storage if available +// Load sidebar configuration values from local storage if available if (localStorageGet('scheme')) { setScheme(localStorageGet('scheme')); } diff --git a/documentation/templateCommand.js b/documentation/templateCommand.js index c9f3604..4971528 100644 --- a/documentation/templateCommand.js +++ b/documentation/templateCommand.js @@ -1,6 +1,6 @@ /* Description: This is a template module that should not be user in a production - enviroment + environment */ // you can require() modules here @@ -56,7 +56,7 @@ exports.initHooks = (server) => { `in`: a hook function registered as `in` will be called before the client request is passed to the module they are attempting to call. Note: socket in this context is the client that sent the data - `out`: a hook function registerd as `out` will be called before the data is + `out`: a hook function registered as `out` will be called before the data is sent to any clients. Note: `socket` in this context is the socket that will be sent the data. @@ -89,6 +89,6 @@ exports.requiredData = ['echo']; exports.info = { name: 'showcase', // actual command name aliases: ['templateModule'], // optional, an array of other names this module can be executed by - usage: 'showcase {echo}', // used for help output, can be ommited if no parameters are required + usage: 'showcase {echo}', // used for help output, can be omitted if no parameters are required description: 'Simple command module template & info' // used for help output }; diff --git a/server/src/serverLib/MainServer.js b/server/src/serverLib/MainServer.js index 41af7e5..745507d 100644 --- a/server/src/serverLib/MainServer.js +++ b/server/src/serverLib/MainServer.js @@ -289,7 +289,7 @@ class MainServer extends WsServer { if (socket.readyState === SocketReady) { socket.send(JSON.stringify(outgoingPayload)); } - } catch (e) { /* yolo */ } + } catch (e) { console.error(e); } } /** From 39b47554b84dbd2129720883d2f19de5e614b6d3 Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 22 Jun 2022 10:31:28 -0500 Subject: [PATCH 18/37] Moved all command modules to their new home --- {server/src/commands => commands}/admin/addmod.js | 0 {server/src/commands => commands}/admin/listusers.js | 0 {server/src/commands => commands}/admin/reload.js | 0 {server/src/commands => commands}/admin/removemod.js | 0 {server/src/commands => commands}/admin/saveconfig.js | 0 {server/src/commands => commands}/admin/shout.js | 0 {server/src/commands => commands}/core/changecolor.js | 0 {server/src/commands => commands}/core/changenick.js | 0 {server/src/commands => commands}/core/chat.js | 0 {server/src/commands => commands}/core/emote.js | 0 {server/src/commands => commands}/core/help.js | 0 {server/src/commands => commands}/core/invite.js | 0 {server/src/commands => commands}/core/join.js | 0 {server/src/commands => commands}/core/morestats.js | 0 {server/src/commands => commands}/core/move.js | 0 {server/src/commands => commands}/core/ping.js | 0 {server/src/commands => commands}/core/session.js | 0 {server/src/commands => commands}/core/stats.js | 0 {server/src/commands => commands}/core/whisper.js | 0 {server/src/commands => commands}/internal/disconnect.js | 0 {server/src/commands => commands}/internal/socketreply.js | 0 {server/src/commands => commands}/mod/ban.js | 0 {server/src/commands => commands}/mod/dumb.js | 0 {server/src/commands => commands}/mod/forcecolor.js | 0 {server/src/commands => commands}/mod/kick.js | 0 {server/src/commands => commands}/mod/moveuser.js | 0 {server/src/commands => commands}/mod/speak.js | 0 {server/src/commands => commands}/mod/unban.js | 0 {server/src/commands => commands}/mod/unbanall.js | 0 {server/src/commands => commands}/utility/_Channels.js | 0 {server/src/commands => commands}/utility/_Constants.js | 0 {server/src/commands => commands}/utility/_LegacyFunctions.js | 0 {server/src/commands => commands}/utility/_UAC.js | 0 33 files changed, 0 insertions(+), 0 deletions(-) rename {server/src/commands => commands}/admin/addmod.js (100%) rename {server/src/commands => commands}/admin/listusers.js (100%) rename {server/src/commands => commands}/admin/reload.js (100%) rename {server/src/commands => commands}/admin/removemod.js (100%) rename {server/src/commands => commands}/admin/saveconfig.js (100%) rename {server/src/commands => commands}/admin/shout.js (100%) rename {server/src/commands => commands}/core/changecolor.js (100%) rename {server/src/commands => commands}/core/changenick.js (100%) rename {server/src/commands => commands}/core/chat.js (100%) rename {server/src/commands => commands}/core/emote.js (100%) rename {server/src/commands => commands}/core/help.js (100%) rename {server/src/commands => commands}/core/invite.js (100%) rename {server/src/commands => commands}/core/join.js (100%) rename {server/src/commands => commands}/core/morestats.js (100%) rename {server/src/commands => commands}/core/move.js (100%) rename {server/src/commands => commands}/core/ping.js (100%) rename {server/src/commands => commands}/core/session.js (100%) rename {server/src/commands => commands}/core/stats.js (100%) rename {server/src/commands => commands}/core/whisper.js (100%) rename {server/src/commands => commands}/internal/disconnect.js (100%) rename {server/src/commands => commands}/internal/socketreply.js (100%) rename {server/src/commands => commands}/mod/ban.js (100%) rename {server/src/commands => commands}/mod/dumb.js (100%) rename {server/src/commands => commands}/mod/forcecolor.js (100%) rename {server/src/commands => commands}/mod/kick.js (100%) rename {server/src/commands => commands}/mod/moveuser.js (100%) rename {server/src/commands => commands}/mod/speak.js (100%) rename {server/src/commands => commands}/mod/unban.js (100%) rename {server/src/commands => commands}/mod/unbanall.js (100%) rename {server/src/commands => commands}/utility/_Channels.js (100%) rename {server/src/commands => commands}/utility/_Constants.js (100%) rename {server/src/commands => commands}/utility/_LegacyFunctions.js (100%) rename {server/src/commands => commands}/utility/_UAC.js (100%) diff --git a/server/src/commands/admin/addmod.js b/commands/admin/addmod.js similarity index 100% rename from server/src/commands/admin/addmod.js rename to commands/admin/addmod.js diff --git a/server/src/commands/admin/listusers.js b/commands/admin/listusers.js similarity index 100% rename from server/src/commands/admin/listusers.js rename to commands/admin/listusers.js diff --git a/server/src/commands/admin/reload.js b/commands/admin/reload.js similarity index 100% rename from server/src/commands/admin/reload.js rename to commands/admin/reload.js diff --git a/server/src/commands/admin/removemod.js b/commands/admin/removemod.js similarity index 100% rename from server/src/commands/admin/removemod.js rename to commands/admin/removemod.js diff --git a/server/src/commands/admin/saveconfig.js b/commands/admin/saveconfig.js similarity index 100% rename from server/src/commands/admin/saveconfig.js rename to commands/admin/saveconfig.js diff --git a/server/src/commands/admin/shout.js b/commands/admin/shout.js similarity index 100% rename from server/src/commands/admin/shout.js rename to commands/admin/shout.js diff --git a/server/src/commands/core/changecolor.js b/commands/core/changecolor.js similarity index 100% rename from server/src/commands/core/changecolor.js rename to commands/core/changecolor.js diff --git a/server/src/commands/core/changenick.js b/commands/core/changenick.js similarity index 100% rename from server/src/commands/core/changenick.js rename to commands/core/changenick.js diff --git a/server/src/commands/core/chat.js b/commands/core/chat.js similarity index 100% rename from server/src/commands/core/chat.js rename to commands/core/chat.js diff --git a/server/src/commands/core/emote.js b/commands/core/emote.js similarity index 100% rename from server/src/commands/core/emote.js rename to commands/core/emote.js diff --git a/server/src/commands/core/help.js b/commands/core/help.js similarity index 100% rename from server/src/commands/core/help.js rename to commands/core/help.js diff --git a/server/src/commands/core/invite.js b/commands/core/invite.js similarity index 100% rename from server/src/commands/core/invite.js rename to commands/core/invite.js diff --git a/server/src/commands/core/join.js b/commands/core/join.js similarity index 100% rename from server/src/commands/core/join.js rename to commands/core/join.js diff --git a/server/src/commands/core/morestats.js b/commands/core/morestats.js similarity index 100% rename from server/src/commands/core/morestats.js rename to commands/core/morestats.js diff --git a/server/src/commands/core/move.js b/commands/core/move.js similarity index 100% rename from server/src/commands/core/move.js rename to commands/core/move.js diff --git a/server/src/commands/core/ping.js b/commands/core/ping.js similarity index 100% rename from server/src/commands/core/ping.js rename to commands/core/ping.js diff --git a/server/src/commands/core/session.js b/commands/core/session.js similarity index 100% rename from server/src/commands/core/session.js rename to commands/core/session.js diff --git a/server/src/commands/core/stats.js b/commands/core/stats.js similarity index 100% rename from server/src/commands/core/stats.js rename to commands/core/stats.js diff --git a/server/src/commands/core/whisper.js b/commands/core/whisper.js similarity index 100% rename from server/src/commands/core/whisper.js rename to commands/core/whisper.js diff --git a/server/src/commands/internal/disconnect.js b/commands/internal/disconnect.js similarity index 100% rename from server/src/commands/internal/disconnect.js rename to commands/internal/disconnect.js diff --git a/server/src/commands/internal/socketreply.js b/commands/internal/socketreply.js similarity index 100% rename from server/src/commands/internal/socketreply.js rename to commands/internal/socketreply.js diff --git a/server/src/commands/mod/ban.js b/commands/mod/ban.js similarity index 100% rename from server/src/commands/mod/ban.js rename to commands/mod/ban.js diff --git a/server/src/commands/mod/dumb.js b/commands/mod/dumb.js similarity index 100% rename from server/src/commands/mod/dumb.js rename to commands/mod/dumb.js diff --git a/server/src/commands/mod/forcecolor.js b/commands/mod/forcecolor.js similarity index 100% rename from server/src/commands/mod/forcecolor.js rename to commands/mod/forcecolor.js diff --git a/server/src/commands/mod/kick.js b/commands/mod/kick.js similarity index 100% rename from server/src/commands/mod/kick.js rename to commands/mod/kick.js diff --git a/server/src/commands/mod/moveuser.js b/commands/mod/moveuser.js similarity index 100% rename from server/src/commands/mod/moveuser.js rename to commands/mod/moveuser.js diff --git a/server/src/commands/mod/speak.js b/commands/mod/speak.js similarity index 100% rename from server/src/commands/mod/speak.js rename to commands/mod/speak.js diff --git a/server/src/commands/mod/unban.js b/commands/mod/unban.js similarity index 100% rename from server/src/commands/mod/unban.js rename to commands/mod/unban.js diff --git a/server/src/commands/mod/unbanall.js b/commands/mod/unbanall.js similarity index 100% rename from server/src/commands/mod/unbanall.js rename to commands/mod/unbanall.js diff --git a/server/src/commands/utility/_Channels.js b/commands/utility/_Channels.js similarity index 100% rename from server/src/commands/utility/_Channels.js rename to commands/utility/_Channels.js diff --git a/server/src/commands/utility/_Constants.js b/commands/utility/_Constants.js similarity index 100% rename from server/src/commands/utility/_Constants.js rename to commands/utility/_Constants.js diff --git a/server/src/commands/utility/_LegacyFunctions.js b/commands/utility/_LegacyFunctions.js similarity index 100% rename from server/src/commands/utility/_LegacyFunctions.js rename to commands/utility/_LegacyFunctions.js diff --git a/server/src/commands/utility/_UAC.js b/commands/utility/_UAC.js similarity index 100% rename from server/src/commands/utility/_UAC.js rename to commands/utility/_UAC.js From 2bbb507f01adfe5a8a4071c0834dc4cf5c971a9a Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 22 Jun 2022 11:32:51 -0500 Subject: [PATCH 19/37] Latest dev sync --- .editorconfig | 9 +- .eslintignore | 3 + .eslintrc.cjs | 33 + .eslintrc.js | 15 - .gitignore | 85 +- .hcserver.json | 1 + .nycrc | 29 + CHANGELOG.md | 147 - LICENSE | 26 +- README.md | 19 +- commands/admin/addmod.js | 40 +- commands/admin/listusers.js | 29 +- commands/admin/reload.js | 34 +- commands/admin/removemod.js | 44 +- commands/admin/saveconfig.js | 33 +- commands/admin/shout.js | 36 +- commands/core/changecolor.js | 67 +- commands/core/changenick.js | 72 +- commands/core/chat.js | 70 +- commands/core/emote.js | 61 +- commands/core/help.js | 44 +- commands/core/invite.js | 36 +- commands/core/join.js | 140 +- commands/core/morestats.js | 116 +- commands/core/move.js | 171 - commands/core/ping.js | 30 +- commands/core/session.js | 249 +- commands/core/stats.js | 27 +- commands/core/whisper.js | 71 +- commands/internal/disconnect.js | 56 +- commands/internal/socketreply.js | 44 +- commands/mod/ban.js | 41 +- commands/mod/dumb.js | 93 +- commands/mod/forcecolor.js | 67 +- commands/mod/kick.js | 36 +- commands/mod/moveuser.js | 136 - commands/mod/speak.js | 39 +- commands/mod/unban.js | 33 +- commands/mod/unbanall.js | 31 +- commands/utility/_Channels.js | 33 +- commands/utility/_Constants.js | 18 +- commands/utility/_LegacyFunctions.js | 10 +- commands/utility/_UAC.js | 20 +- documentation/DOCUMENTATION.md | 48 - documentation/admin_addmod.js.html | 159 + documentation/admin_listusers.js.html | 128 + documentation/admin_reload.js.html | 122 + documentation/admin_removemod.js.html | 164 + documentation/admin_saveconfig.js.html | 113 + documentation/admin_shout.js.html | 109 + documentation/core_changecolor.js.html | 209 + documentation/core_changenick.js.html | 264 + documentation/core_chat.js.html | 246 + documentation/core_emote.js.html | 213 + documentation/core_help.js.html | 185 + documentation/core_invite.js.html | 174 + documentation/core_join.js.html | 323 + documentation/core_morestats.js.html | 215 + documentation/core_ping.js.html | 83 + documentation/core_session.js.html | 244 + documentation/core_stats.js.html | 110 + documentation/core_whisper.js.html | 282 + documentation/fonts/OpenSans-Bold-webfont.eot | Bin 0 -> 19544 bytes documentation/fonts/OpenSans-Bold-webfont.svg | 1830 +++ .../fonts/OpenSans-Bold-webfont.woff | Bin 0 -> 22432 bytes .../fonts/OpenSans-BoldItalic-webfont.eot | Bin 0 -> 20133 bytes .../fonts/OpenSans-BoldItalic-webfont.svg | 1830 +++ .../fonts/OpenSans-BoldItalic-webfont.woff | Bin 0 -> 23048 bytes .../fonts/OpenSans-Italic-webfont.eot | Bin 0 -> 20265 bytes .../fonts/OpenSans-Italic-webfont.svg | 1830 +++ .../fonts/OpenSans-Italic-webfont.woff | Bin 0 -> 23188 bytes .../fonts/OpenSans-Light-webfont.eot | Bin 0 -> 19514 bytes .../fonts/OpenSans-Light-webfont.svg | 1831 +++ .../fonts/OpenSans-Light-webfont.woff | Bin 0 -> 22248 bytes .../fonts/OpenSans-LightItalic-webfont.eot | Bin 0 -> 20535 bytes .../fonts/OpenSans-LightItalic-webfont.svg | 1835 +++ .../fonts/OpenSans-LightItalic-webfont.woff | Bin 0 -> 23400 bytes .../fonts/OpenSans-Regular-webfont.eot | Bin 0 -> 19836 bytes .../fonts/OpenSans-Regular-webfont.svg | 1831 +++ .../fonts/OpenSans-Regular-webfont.woff | Bin 0 -> 22660 bytes documentation/index.html | 105 + documentation/internal_disconnect.js.html | 117 + documentation/internal_socketreply.js.html | 102 + documentation/mod_ban.js.html | 166 + documentation/mod_dumb.js.html | 424 + documentation/mod_forcecolor.js.html | 250 + documentation/mod_kick.js.html | 203 + documentation/mod_speak.js.html | 157 + documentation/mod_unban.js.html | 142 + documentation/mod_unbanall.js.html | 115 + documentation/module-addmod.html | 604 + documentation/module-ban.html | 531 + documentation/module-changecolor.html | 902 ++ documentation/module-changenick.html | 902 ++ documentation/module-chat.html | 1047 ++ documentation/module-disconnect.html | 604 + documentation/module-dumb.html | 1273 ++ documentation/module-emote.html | 903 ++ documentation/module-forcecolor.html | 903 ++ documentation/module-help.html | 830 ++ documentation/module-invite.html | 531 + documentation/module-join.html | 531 + documentation/module-kick.html | 531 + documentation/module-listusers.html | 531 + documentation/module-morestats.html | 830 ++ documentation/module-ping.html | 482 + documentation/module-reload.html | 531 + documentation/module-removemod.html | 604 + documentation/module-saveconfig.html | 531 + documentation/module-session.html | 1034 ++ documentation/module-shout.html | 604 + documentation/module-socketreply.html | 605 + documentation/module-speak.html | 686 ++ documentation/module-stats.html | 531 + documentation/module-unban.html | 531 + documentation/module-unbanall.html | 531 + documentation/module-whisper.html | 911 ++ documentation/scripts/linenumber.js | 25 + .../scripts/prettify/Apache-License-2.0.txt | 202 + documentation/scripts/prettify/lang-css.js | 2 + documentation/scripts/prettify/prettify.js | 28 + documentation/styles/jsdoc-default.css | 358 + documentation/styles/prettify-jsdoc.css | 111 + documentation/styles/prettify-tomorrow.css | 132 + documentation/templateCommand.js | 94 - index.js | 1 - jsdoc.json | 23 + main.mjs | 45 + package-lock.json | 10287 ++++++++++++++-- package.json | 43 +- pm2.config.js => pm2.config.cjs | 8 +- scripts/config.js | 191 + server/main.js | 12 - server/package-lock.json | 357 - server/package.json | 32 - server/src/scripts/configLib/SetupWizard.js | 115 - server/src/scripts/configure.js | 17 - server/src/scripts/setupSchema/Banner.js | 30 - server/src/scripts/setupSchema/Footer.js | 11 - server/src/scripts/setupSchema/Questions.js | 58 - server/src/serverLib/CommandManager.js | 313 - server/src/serverLib/ConfigManager.js | 105 - server/src/serverLib/CoreApp.js | 95 - server/src/serverLib/ImportsManager.js | 124 - server/src/serverLib/MainServer.js | 548 - server/src/serverLib/RateLimiter.js | 139 - server/src/serverLib/StatsManager.js | 80 - server/src/serverLib/index.js | 8 - server/src/utility/Constants.js | 19 - test/addmod.test.js | 78 + test/ban.test.js | 145 + test/changecolor.test.js | 126 + test/changenick.test.js | 253 + test/channels.test.js | 65 + test/chat.test.js | 198 + test/disconnect.test.js | 80 + test/dumb.test.js | 366 + test/emote.test.js | 113 + test/forcecolor.test.js | 194 + test/help.test.js | 182 + test/invite.test.js | 230 + test/join.test.js | 288 + test/kick.test.js | 171 + test/legacyFunctions.test.js | 52 + test/listusers.test.js | 68 + test/mockImports.js | 115 + test/morestats.test.js | 95 + test/ping.test.js | 50 + test/reload.test.js | 89 + test/removemod.test.js | 76 + test/saveconfig.test.js | 92 + test/session.test.js | 250 + test/shout.test.js | 65 + test/socketreply.test.js | 61 + test/speak.test.js | 71 + test/stats.test.js | 48 + test/uac.test.js | 67 + test/unban.test.js | 64 + test/unbanall.test.js | 50 + test/whisper.test.js | 269 + 180 files changed, 50855 insertions(+), 4416 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.cjs delete mode 100644 .eslintrc.js create mode 100644 .hcserver.json create mode 100644 .nycrc delete mode 100644 CHANGELOG.md delete mode 100644 commands/core/move.js delete mode 100644 commands/mod/moveuser.js delete mode 100644 documentation/DOCUMENTATION.md create mode 100644 documentation/admin_addmod.js.html create mode 100644 documentation/admin_listusers.js.html create mode 100644 documentation/admin_reload.js.html create mode 100644 documentation/admin_removemod.js.html create mode 100644 documentation/admin_saveconfig.js.html create mode 100644 documentation/admin_shout.js.html create mode 100644 documentation/core_changecolor.js.html create mode 100644 documentation/core_changenick.js.html create mode 100644 documentation/core_chat.js.html create mode 100644 documentation/core_emote.js.html create mode 100644 documentation/core_help.js.html create mode 100644 documentation/core_invite.js.html create mode 100644 documentation/core_join.js.html create mode 100644 documentation/core_morestats.js.html create mode 100644 documentation/core_ping.js.html create mode 100644 documentation/core_session.js.html create mode 100644 documentation/core_stats.js.html create mode 100644 documentation/core_whisper.js.html create mode 100644 documentation/fonts/OpenSans-Bold-webfont.eot create mode 100644 documentation/fonts/OpenSans-Bold-webfont.svg create mode 100644 documentation/fonts/OpenSans-Bold-webfont.woff create mode 100644 documentation/fonts/OpenSans-BoldItalic-webfont.eot create mode 100644 documentation/fonts/OpenSans-BoldItalic-webfont.svg create mode 100644 documentation/fonts/OpenSans-BoldItalic-webfont.woff create mode 100644 documentation/fonts/OpenSans-Italic-webfont.eot create mode 100644 documentation/fonts/OpenSans-Italic-webfont.svg create mode 100644 documentation/fonts/OpenSans-Italic-webfont.woff create mode 100644 documentation/fonts/OpenSans-Light-webfont.eot create mode 100644 documentation/fonts/OpenSans-Light-webfont.svg create mode 100644 documentation/fonts/OpenSans-Light-webfont.woff create mode 100644 documentation/fonts/OpenSans-LightItalic-webfont.eot create mode 100644 documentation/fonts/OpenSans-LightItalic-webfont.svg create mode 100644 documentation/fonts/OpenSans-LightItalic-webfont.woff create mode 100644 documentation/fonts/OpenSans-Regular-webfont.eot create mode 100644 documentation/fonts/OpenSans-Regular-webfont.svg create mode 100644 documentation/fonts/OpenSans-Regular-webfont.woff create mode 100644 documentation/index.html create mode 100644 documentation/internal_disconnect.js.html create mode 100644 documentation/internal_socketreply.js.html create mode 100644 documentation/mod_ban.js.html create mode 100644 documentation/mod_dumb.js.html create mode 100644 documentation/mod_forcecolor.js.html create mode 100644 documentation/mod_kick.js.html create mode 100644 documentation/mod_speak.js.html create mode 100644 documentation/mod_unban.js.html create mode 100644 documentation/mod_unbanall.js.html create mode 100644 documentation/module-addmod.html create mode 100644 documentation/module-ban.html create mode 100644 documentation/module-changecolor.html create mode 100644 documentation/module-changenick.html create mode 100644 documentation/module-chat.html create mode 100644 documentation/module-disconnect.html create mode 100644 documentation/module-dumb.html create mode 100644 documentation/module-emote.html create mode 100644 documentation/module-forcecolor.html create mode 100644 documentation/module-help.html create mode 100644 documentation/module-invite.html create mode 100644 documentation/module-join.html create mode 100644 documentation/module-kick.html create mode 100644 documentation/module-listusers.html create mode 100644 documentation/module-morestats.html create mode 100644 documentation/module-ping.html create mode 100644 documentation/module-reload.html create mode 100644 documentation/module-removemod.html create mode 100644 documentation/module-saveconfig.html create mode 100644 documentation/module-session.html create mode 100644 documentation/module-shout.html create mode 100644 documentation/module-socketreply.html create mode 100644 documentation/module-speak.html create mode 100644 documentation/module-stats.html create mode 100644 documentation/module-unban.html create mode 100644 documentation/module-unbanall.html create mode 100644 documentation/module-whisper.html create mode 100644 documentation/scripts/linenumber.js create mode 100644 documentation/scripts/prettify/Apache-License-2.0.txt create mode 100644 documentation/scripts/prettify/lang-css.js create mode 100644 documentation/scripts/prettify/prettify.js create mode 100644 documentation/styles/jsdoc-default.css create mode 100644 documentation/styles/prettify-jsdoc.css create mode 100644 documentation/styles/prettify-tomorrow.css delete mode 100644 documentation/templateCommand.js delete mode 100644 index.js create mode 100644 jsdoc.json create mode 100644 main.mjs rename pm2.config.js => pm2.config.cjs (79%) create mode 100644 scripts/config.js delete mode 100644 server/main.js delete mode 100644 server/package-lock.json delete mode 100644 server/package.json delete mode 100644 server/src/scripts/configLib/SetupWizard.js delete mode 100644 server/src/scripts/configure.js delete mode 100644 server/src/scripts/setupSchema/Banner.js delete mode 100644 server/src/scripts/setupSchema/Footer.js delete mode 100644 server/src/scripts/setupSchema/Questions.js delete mode 100644 server/src/serverLib/CommandManager.js delete mode 100644 server/src/serverLib/ConfigManager.js delete mode 100644 server/src/serverLib/CoreApp.js delete mode 100644 server/src/serverLib/ImportsManager.js delete mode 100644 server/src/serverLib/MainServer.js delete mode 100644 server/src/serverLib/RateLimiter.js delete mode 100644 server/src/serverLib/StatsManager.js delete mode 100644 server/src/serverLib/index.js delete mode 100644 server/src/utility/Constants.js create mode 100644 test/addmod.test.js create mode 100644 test/ban.test.js create mode 100644 test/changecolor.test.js create mode 100644 test/changenick.test.js create mode 100644 test/channels.test.js create mode 100644 test/chat.test.js create mode 100644 test/disconnect.test.js create mode 100644 test/dumb.test.js create mode 100644 test/emote.test.js create mode 100644 test/forcecolor.test.js create mode 100644 test/help.test.js create mode 100644 test/invite.test.js create mode 100644 test/join.test.js create mode 100644 test/kick.test.js create mode 100644 test/legacyFunctions.test.js create mode 100644 test/listusers.test.js create mode 100644 test/mockImports.js create mode 100644 test/morestats.test.js create mode 100644 test/ping.test.js create mode 100644 test/reload.test.js create mode 100644 test/removemod.test.js create mode 100644 test/saveconfig.test.js create mode 100644 test/session.test.js create mode 100644 test/shout.test.js create mode 100644 test/socketreply.test.js create mode 100644 test/speak.test.js create mode 100644 test/stats.test.js create mode 100644 test/uac.test.js create mode 100644 test/unban.test.js create mode 100644 test/unbanall.test.js create mode 100644 test/whisper.test.js diff --git a/.editorconfig b/.editorconfig index 5370727..9d08a1a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,14 +1,9 @@ -# editorconfig.org - root = true [*] charset = utf-8 -end_of_line = lf -insert_final_newline = true indent_style = space indent_size = 2 +end_of_line = lf +insert_final_newline = true trim_trailing_whitespace = true - -[*.md] -trim_trailing_whitespace = false diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..ebc367f --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +/test/*.js +/client/* +/documentation/* diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..24182a1 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,33 @@ +module.exports = { + env: { + es2021: true, + node: true, + }, + extends: [ + 'airbnb-base', + ], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, + rules: { + "no-console": 0, + "no-param-reassign": [ + "error", + { + "props": false, + } + ], + "import/extensions": [ + "error", + "ignorePackages", + { + js: "always", + jsx: "always", + ts: "always", + tsx: "always", + mjs: "always", + } + ] + }, +}; diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index a55639c..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - env: { - browser: true, - commonjs: true, - es2021: true, - }, - extends: [ - 'airbnb-base', - ], - parserOptions: { - ecmaVersion: 12, - }, - rules: { - }, -}; diff --git a/.gitignore b/.gitignore index 4bf93f7..a93c6d0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,11 @@ logs npm-debug.log* yarn-debug.log* yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids @@ -15,12 +20,13 @@ pids lib-cov # Coverage directory used by tools like istanbul -coverage +.coverage +*.lcov # nyc test coverage .nyc_output -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) @@ -36,8 +42,11 @@ build/Release node_modules/ jspm_packages/ -# Typescript v1 declaration files -typings/ +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo # Optional npm cache directory .npm @@ -45,6 +54,15 @@ typings/ # Optional eslint cache .eslintcache +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + # Optional REPL history .node_repl_history @@ -54,10 +72,63 @@ typings/ # Yarn Integrity file .yarn-integrity -# dotenv environment variables file +# dotenv environment variable files .env +.env.development.local +.env.test.local +.env.production.local +.env.local -# next.js build output +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output .next +out -server/config/ \ No newline at end of file +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +session.key +salt.key +config.json diff --git a/.hcserver.json b/.hcserver.json new file mode 100644 index 0000000..eb59264 --- /dev/null +++ b/.hcserver.json @@ -0,0 +1 @@ +{"modulesPath":"./commands","websocketPort":"6060","rateLimit":{"halflife":"30000","threshold":"25"},"pulseSpeed":"16000"} diff --git a/.nycrc b/.nycrc new file mode 100644 index 0000000..9328f12 --- /dev/null +++ b/.nycrc @@ -0,0 +1,29 @@ +{ + "check-coverage": true, + "per-file": true, + "lines": 80, + "statements": 80, + "functions": 80, + "branches": 80, + "include": [ + "commands/**/*.js" + ], + "exclude": [ + "commands/**/*.spec.js" + ], + "ignore-class-method": "methodToIgnore", + "reporter": [ + "html", + "lcov", + "text", + "text-summary" + ], + "require": [ + "dotenv/config" + ], + "extension": [], + "cache": true, + "all": true, + "temp-dir": "", + "report-dir": "./.coverage" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index f52afd7..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,147 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -## [Unreleased] - -## [2.1.93 pre 2.2] - 2020-03-12 -### Added -- (Source) `./pm2.config.js` PM2 ecosystem config handling both http-server and the websocket -- (Source) NPM new commands: -- "start": Starts or reloads the dev environment -- "stop": Stops and clears the dev environment -- "logs": Show / watch http & websocket logs for errors and events -- "clear": Clear all logged data -- "status": Show status of http and websocket -- "refresh": Clears logged data and stops http and websocket -- (Server) Numeric user levels / UAC, related to issue #86 -- (Server) `join` module password property, related to V2 protocol update -- (Server) `users` array to `onlineSet` structure, related to V2 protocol update -- (Server) `session` module, related to V2 protocol update -- (Server) `/move` chat hook to `move` module - -### Removed -- (Source) `./clientSource/` directory - -### Changed -- (Server) Minor bug fixes -- (Server) Increased module abstraction to remove duplicate code (thanks @MinusGix) - -## [2.1.92 pre 2.2] - 2019-11-06 -### Added -- (Server) `./server/src/utility/` directory -- (Server) `Constants.js` class in `utility` -- (Server) `esm` module to transpile ES6 - -### Changed -- (Server) Changed ES5 styling to ES6 -- (Server) And improved source comments -- (Server) Minor code format changes -- (Server) Updated all dependencies (be sure to update your local copy with the new packages) - -## [2.1.91 pre 2.2] - 2019-08-17 -### Added -- (Client) Markdown engine -- (Client) Imgur based image posting (through markdown) - -### Changed -- (Client) Removed cloudflare references making hack.chat self-hosted again -- (Client) The way messages are pushed, closing an xss vuln in PRs 985dd6f and 9fcb235 -- (Client) Side bar layout -- (Client) Fixed some options not storing -- (Client) Fixed firefox drop down menu bug -- (Client) Updated Katex lib - -### Stretched -- The term "minimal" - -## [2.1.9 pre 2.2] - 2019-03-18 -### Changed -- Configuration script setup, making it more portable/sane -- Refactored naming scheme and entry point - -### Removed -- Configuration setup from `./serverLib/ConfigManager` -- Unused feature allowing command modules to add to the configuration/setup process -- `deasync` dependency - -## [2.1.9] - 2019-02-21 -### Added -- `./server/src/commands/core/emote.js` module to provide action text -- `./server/src/core/server.js` priorities to command hooking -- Priority levels to all command modules -- `./server/src/commands/core/chat.js` Unknown '/' commands will now return a warning -- `./server/src/commands/internal/legacylayer.js` to provide compatibility to legacy connections - -### Changed -- Updated all libraries to latest -- `./server/src/core/server.js` Removed unneeded function bindings -- `./server/src/core/server.js` Hook function layout -- `./server/src/managers/config.js` Documentation wording - -## [2.1.0] - 2018-09-29 -### Added -- Module hook framework, isolating modules and making them truly drop-to-install -- `./server/src/commands/core/whisper.js` module to send in-channel private messages, `/whisper` hook -- `muzzle` and `mute` aliases to `./server/src/commands/mod/dumb.js` -- `unmuzzle` and `unmute` aliases to `./server/src/commands/mod/speak.js` -- `./server/src/commands/admin/removemod.js` module to remove mods -- `./server/src/commands/mod/unbanall.js` module to clear all bans and ratelimiting - -### Changed -- Further code cleanup on all modules -- Adjusted `ipSalt` entropy -- `./server/src/commands/core/help.js` output is now helpful, added `/help` hook -- `./server/src/commands/core/chat.js` added `/myhash` and `/me` hooks -- `./server/src/commands/core/morestats.js` added `/stats` hook - -## [2.0.3] - 2018-06-03 -### Added -- `./server/src/commands/mod/dumb.js` module for server-wide shadow muting -- `./server/src/commands/mod/speak.js` module unmuting -- `./server/src/commands/internal/socketreply.js` module to route warning to clients -- `./server/src/commands/core/ping.js` module to prevent `didYouMean` errors on legacy sources - -### Changed -- Moved `disconnect.js` into servers internal modules directory -- Restructured `server.js` and `commands.js`, removing hardcoded protocol use - -## [2.0.2] - 2018-05-19 -### Added -- `./documentation/DOCUMENTATION.md` document which gives overview of the applications protocol -- `./documentation/DEPLOY.md` document which gives overview of deploying the server live -- `./LICENSE` License file -- Code highlighting, triggered with # - -### Changed -- `README.md` wording and layout - -### Removed -- Unneeded `use strict` - -## [2.0.1] - 2018-04-18 -### Added -- `users-kicked` tracking to `morestats` command -- Server-side ping interval -- `move` command to change channels without reconnecting -- `disconnect` command module to free core server from protocol dependency -- `changenick` command to change client nick without reconnecting - -### Changed -- Filter object of the `findSockets` function now accepts more complex parameters, including functions and arrays -- `kick` command now accepts an array as the `nick` argument allowing multiple simultaneous kicks -- `join` command now takes advantage of the new filter object -- Core server disconnect handler now calls the `disconnect` module instead of broadcasting hard coded `onlineRemove` - -### Removed -- Client-side ping interval - -## [2.0.0] - 2018-04-12 -### Added -- CHANGELOG.md -- `index.html` files to `katex` directories - -### Changed -- Updated client html KaTeX libraries to v0.9.0 - -### Removed -- Uneeded files under `katex` directories diff --git a/LICENSE b/LICENSE index 5c93f45..f0e18e1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,21 @@ - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 +MIT License - Copyright (C) 2004 Sam Hocevar +Copyright (c) 2022 marzavec - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - 0. You just DO WHAT THE FUCK YOU WANT TO. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 2208ea6..d3a2cb4 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,14 @@ A list of software developed for the hack.chat framework can be found at the [3rd party software list](https://github.com/hack-chat/3rd-party-software-list) repository. This includes bots, clients, docker containers, etc. -This is a backwards compatible continuation of the [work by Andrew Belt](https://github.com/AndrewBelt/hack.chat). The server code has been updated to ES6 along with several new features including new commands and hot-reload of the commands/protocol. There is also [documentation](documentation/DOCUMENTATION.md) and a [changelog](CHANGELOG.md). +This is a backwards compatible continuation of the [work by Andrew Belt](https://github.com/AndrewBelt/hack.chat). The server code has been updated to ES6 along with several new features including new commands and hot-reload of the commands/protocol. There is also [documentation](documentation/index.html). # Installation ## Prerequisites -- [node.js 8.10.0](https://nodejs.org/en/download/package-manager/#windows) or higher -- [npm 5.7.1](https://nodejs.org/en/download/package-manager/#windows) or higher +- [node.js v16.14.0](https://nodejs.org/) or higher +- [npm 8.5.4](https://nodejs.org/) or higher ## Developer Installation @@ -20,19 +20,14 @@ This is a backwards compatible continuation of the [work by Andrew Belt](https:/ 1. Install the dependencies: `npm install` 1. Launch: `npm start` - If you change the `websocketPort` option during the config setup then these changes will need to be reflected on [line 60 of client.js](https://github.com/hack-chat/main/blob/master/client/client.js#L60). - ## Live Deployment Installation See [DEPLOY.md](documentation/DEPLOY.md) # Contributing -- If you are modifying commands, make sure it is backwards compatible with the legacy client and you update the documentation accordingly. -- Use [the template](documentation/templateCommand.js) to learn how to create new commands. - Use two space indents. - Name files in camelCase. -- Scripts that do not default to strict mode (such as modules) must use the `'use strict'` directive. # Credits @@ -41,10 +36,10 @@ See [DEPLOY.md](documentation/DEPLOY.md) * [**Neel Kamath**](https://github.com/neelkamath) - *Base Documentation* * [**Carlos Villavicencio**](https://github.com/po5i) - *Syntax Highlighting Integration* * [**OpSimple**](https://github.com/OpSimple) - *Modules Added: dumb.js & speak.js* -* Andrew Belt, https://github.com/AndrewBelt, for original base work -* [wwandrew](https://github.com/wwandrew), for finding server flaws (including attack vectors) and submitting ~~___incredibly detailed___~~ bug reports -* [Everyone else](https://github.com/hack-chat/main/graphs/contributors) who participated in this project. +* [**Andrew Belt**](https://github.com/AndrewBelt), for original base work +* [**wwandrew**](https://github.com/wwandrew), for finding server flaws (including attack vectors) and submitting ~~___incredibly detailed___~~ bug reports +* [**Everyone else**](https://github.com/hack-chat/main/graphs/contributors) who participated in this project. # License -This project is licensed under the [WTFPL License](LICENSE). +This project is licensed under the [MIT License](LICENSE). diff --git a/commands/admin/addmod.js b/commands/admin/addmod.js index 3a6b140..204c38f 100644 --- a/commands/admin/addmod.js +++ b/commands/admin/addmod.js @@ -1,15 +1,24 @@ -/* - Description: Adds the target trip to the mod list then elevates the uType -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Create a new mod trip + * @version 1.0.0 + * @description Adds target trip to the config as a mod and upgrades the socket type + * @module addmod + */ import { isAdmin, isModerator, levels, getUserDetails, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -19,7 +28,7 @@ export async function run({ } // add new trip to config - core.config.mods.push({ trip: payload.trip }); + core.appConfig.data.globalMods.push({ trip: payload.trip }); // find targets current connections const newMod = server.findSockets({ trip: payload.trip }); @@ -35,7 +44,7 @@ export async function run({ }; for (let i = 0, l = newMod.length; i < l; i += 1) { - // upgrade privilages + // upgrade privileges newMod[i].uType = 'mod'; // @todo use legacyLevelToLabel from _LegacyFunctions.js newMod[i].level = levels.moderator; @@ -73,9 +82,26 @@ export async function run({ return true; } +/** + * The following payload properties are required to invoke this module: + * "trip" + * @public + * @typedef {Array} addmod/requiredData + */ export const requiredData = ['trip']; + +/** + * Module meta information + * @public + * @typedef {Object} addmod/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'addmod', + category: 'admin', description: 'Adds target trip to the config as a mod and upgrades the socket type', usage: ` API: { cmd: 'addmod', trip: '' }`, diff --git a/commands/admin/listusers.js b/commands/admin/listusers.js index 850ae75..f5081f0 100644 --- a/commands/admin/listusers.js +++ b/commands/admin/listusers.js @@ -2,15 +2,24 @@ /* eslint no-restricted-syntax: 0 */ /* eslint guard-for-in: 0 */ -/* - Description: Outputs all current channels and their user nicks -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Show users and channels + * @version 1.0.0 + * @description Outputs all current channels and sockets in those channels + * @module listusers + */ import { isAdmin, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ server, socket }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { @@ -50,8 +59,18 @@ export async function run({ server, socket }) { return true; } +/** + * Module meta information + * @public + * @typedef {Object} listusers/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'listusers', + category: 'admin', description: 'Outputs all current channels and sockets in those channels', usage: ` API: { cmd: 'listusers' }`, diff --git a/commands/admin/reload.js b/commands/admin/reload.js index 32ca04f..aa4d212 100644 --- a/commands/admin/reload.js +++ b/commands/admin/reload.js @@ -1,13 +1,22 @@ -/* - Description: Clears and resets the command modules, outputting any errors -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Refresh modules + * @version 1.0.0 + * @description Allows a remote user to clear and re-import the server command modules + * @module reload + */ import { isAdmin, isModerator, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -17,8 +26,7 @@ export async function run({ } // do command reload and store results - let loadResult = core.dynamicImports.reloadDirCache(); - loadResult += core.commands.loadCommands(); + let loadResult = await core.commands.reloadCommands(); // clear and rebuild all module hooks server.loadHooks(); @@ -45,9 +53,19 @@ export async function run({ return true; } +/** + * Module meta information + * @public + * @typedef {Object} reload/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'reload', - description: '(Re)loads any new commands into memory, outputs errors if any', + category: 'admin', + description: 'Allows a remote user to clear and re-import the server command modules', usage: ` API: { cmd: 'reload', reason: '' }`, }; diff --git a/commands/admin/removemod.js b/commands/admin/removemod.js index e1ab7af..fe7c28c 100644 --- a/commands/admin/removemod.js +++ b/commands/admin/removemod.js @@ -1,15 +1,24 @@ -/* - Description: Removes target trip from the config as a mod and downgrades the socket type -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Removes a mod + * @version 1.0.0 + * @description Removes target trip from the config as a mod and downgrades the socket type + * @module removemod + */ import { isAdmin, isModerator, levels, getUserDetails, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -20,7 +29,9 @@ export async function run({ // remove trip from config // eslint-disable-next-line no-param-reassign - core.config.mods = core.config.mods.filter((mod) => mod.trip !== payload.trip); + core.appConfig.data.globalMods = core.appConfig.data.globalMods.filter( + (mod) => mod.trip !== payload.trip, + ); // find targets current connections const targetMod = server.findSockets({ trip: payload.trip }); @@ -36,8 +47,8 @@ export async function run({ }; for (let i = 0, l = targetMod.length; i < l; i += 1) { - // downgrade privilages - targetMod[i].uType = 'user'; + // downgrade privileges + targetMod[i].uType = 'user'; /* @legacy */ targetMod[i].level = levels.default; // inform ex-mod @@ -76,9 +87,26 @@ export async function run({ return true; } +/** + * The following payload properties are required to invoke this module: + * "trip" + * @public + * @typedef {Array} removemod/requiredData + */ export const requiredData = ['trip']; + +/** + * Module meta information + * @public + * @typedef {Object} removemod/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'removemod', + category: 'admin', description: 'Removes target trip from the config as a mod and downgrades the socket type', usage: ` API: { cmd: 'removemod', trip: '' }`, diff --git a/commands/admin/saveconfig.js b/commands/admin/saveconfig.js index a24f422..1407c94 100644 --- a/commands/admin/saveconfig.js +++ b/commands/admin/saveconfig.js @@ -1,13 +1,22 @@ -/* - Description: Writes the current config to disk -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Saves the config + * @version 1.0.0 + * @description Writes the current config to disk + * @module saveconfig + */ import { isAdmin, isModerator, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { @@ -15,7 +24,9 @@ export async function run({ core, server, socket }) { } // attempt save, notify of failure - if (!core.configManager.save()) { + try { + await core.appConfig.write(); + } catch (err) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Failed to save config, check logs.', @@ -33,8 +44,18 @@ export async function run({ core, server, socket }) { return true; } +/** + * Module meta information + * @public + * @typedef {Object} saveconfig/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'saveconfig', + category: 'admin', description: 'Writes the current config to disk', usage: ` API: { cmd: 'saveconfig' }`, diff --git a/commands/admin/shout.js b/commands/admin/shout.js index fa75058..3e5914a 100644 --- a/commands/admin/shout.js +++ b/commands/admin/shout.js @@ -1,12 +1,21 @@ -/* - Description: Emmits a server-wide message as `info` -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Emit text everywhere + * @version 1.0.0 + * @description Displays passed text to every client connected + * @module shout + */ import { isAdmin, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ server, socket, payload }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { @@ -23,9 +32,26 @@ export async function run({ server, socket, payload }) { return true; } +/** + * The following payload properties are required to invoke this module: + * "text" + * @public + * @typedef {Array} shout/requiredData + */ export const requiredData = ['text']; + +/** + * Module meta information + * @public + * @typedef {Object} shout/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'shout', + category: 'admin', description: 'Displays passed text to every client connected', usage: ` API: { cmd: 'shout', text: '' }`, diff --git a/commands/core/changecolor.js b/commands/core/changecolor.js index 0eecdcd..5143c7b 100644 --- a/commands/core/changecolor.js +++ b/commands/core/changecolor.js @@ -1,19 +1,34 @@ -/* - Description: Allows calling client to change their nickname color -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Update name color + * @version 1.0.0 + * @description Allows calling client to change their nickname color + * @module changecolor + */ import { getUserDetails, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module support functions +/** + * Validate a string as a valid hex color string + * @param {string} color - Color string to validate + * @private + * @todo Move into utility module + * @return {boolean} + */ const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ server, socket, payload, }) { - const channel = socket.channel; + const { channel } = socket; if (server.police.frisk(socket.address, 1)) { return server.reply({ @@ -25,7 +40,7 @@ export async function run({ // verify user data is string if (typeof payload.color !== 'string') { - return true; + return false; } // make sure requested nickname meets standards @@ -60,12 +75,24 @@ export async function run({ return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.colorCheck.bind(this), 29); } -// hooks chat commands checking for /color +/** + * Executes every time an incoming chat command is invoked + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function colorCheck({ core, server, socket, payload, }) { @@ -103,11 +130,27 @@ export function colorCheck({ return payload; } -// module meta +/** + * The following payload properties are required to invoke this module: + * "color" + * @public + * @typedef {Array} changecolor/requiredData + */ export const requiredData = ['color']; + +/** + * Module meta information + * @public + * @typedef {Object} changecolor/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'changecolor', - description: 'This will change your nickname color', + category: 'core', + description: 'Allows calling client to change their nickname color', usage: ` API: { cmd: 'changecolor', color: '' } Text: /color diff --git a/commands/core/changenick.js b/commands/core/changenick.js index 8bc3b6d..664561e 100644 --- a/commands/core/changenick.js +++ b/commands/core/changenick.js @@ -1,19 +1,28 @@ /* eslint eqeqeq: 0 */ -/* - Description: Allows calling client to change their current nickname -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Update nickname + * @version 1.0.0 + * @description Allows calling client to change their current nickname + * @module changenick + */ import { verifyNickname, getUserDetails, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ - core, server, socket, payload, + server, socket, payload, }) { - const channel = socket.channel; + const { channel } = socket; if (server.police.frisk(socket.address, 6)) { return server.reply({ @@ -40,18 +49,6 @@ export async function run({ }, socket); } - // prevent admin impersonation - // @todo prevent mod impersonation - if (newNick.toLowerCase() === core.config.adminName.toLowerCase()) { - server.police.frisk(socket.address, 4); - - return server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: 'You are not the admin, liar!', - channel, // @todo Multichannel - }, socket); - } - if (newNick == previousNick) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` @@ -132,12 +129,24 @@ export async function run({ return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.nickCheck.bind(this), 29); } -// hooks chat commands checking for /nick +/** + * Executes every time an incoming chat command is invoked + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function nickCheck({ core, server, socket, payload, }) { @@ -149,7 +158,7 @@ export function nickCheck({ const input = payload.text.split(' '); // If there is no nickname target parameter - if (input[1] === undefined) { + if (!input[1]) { server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help nick` for instructions on how to use this command.', @@ -177,10 +186,27 @@ export function nickCheck({ return payload; } +/** + * The following payload properties are required to invoke this module: + * "nick" + * @public + * @typedef {Array} changenick/requiredData + */ export const requiredData = ['nick']; + +/** + * Module meta information + * @public + * @typedef {Object} changenick/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'changenick', - description: 'This will change your current connections nickname', + category: 'core', + description: 'Allows calling client to change their current nickname', usage: ` API: { cmd: 'changenick', nick: '' } Text: /nick `, diff --git a/commands/core/chat.js b/commands/core/chat.js index 65e26c4..fdd8eb9 100644 --- a/commands/core/chat.js +++ b/commands/core/chat.js @@ -1,13 +1,23 @@ -/* - Description: Rebroadcasts any `text` to all clients in a `channel` -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Send chat messages + * @version 1.0.0 + * @description Broadcasts passed `text` field to the calling users channel + * @module chat + */ import { isAdmin, isModerator, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module support functions +/** + * Check and trim string provided by remote client + * @param {string} text - Subject string + * @private + * @todo Move into utility module + * @return {string|boolean} + */ const parseText = (text) => { // verifies user input is text if (typeof text !== 'string') { @@ -24,7 +34,12 @@ const parseText = (text) => { return sanitizedText; }; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -80,13 +95,26 @@ export async function run({ return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.commandCheckIn.bind(this), 20); server.registerHook('in', 'chat', this.finalCmdCheck.bind(this), 254); } -// checks for miscellaneous '/' based commands +/** + * Executes every time an incoming chat command is invoked; + * checks for miscellaneous '/' based commands + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function commandCheckIn({ server, socket, payload }) { if (typeof payload.text !== 'string') { return false; @@ -105,6 +133,15 @@ export function commandCheckIn({ server, socket, payload }) { return payload; } +/** + * Executes every time an incoming chat command is invoked; + * assumes a failed chat command invocation and will reject with notice + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function finalCmdCheck({ server, socket, payload }) { if (typeof payload.text !== 'string') { return false; @@ -129,9 +166,26 @@ export function finalCmdCheck({ server, socket, payload }) { return false; } +/** + * The following payload properties are required to invoke this module: + * "text" + * @public + * @typedef {Array} chat/requiredData + */ export const requiredData = ['text']; + +/** + * Module meta information + * @public + * @typedef {Object} chat/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'chat', + category: 'core', description: 'Broadcasts passed `text` field to the calling users channel', usage: ` API: { cmd: 'chat', text: '' } diff --git a/commands/core/emote.js b/commands/core/emote.js index da64596..e080504 100644 --- a/commands/core/emote.js +++ b/commands/core/emote.js @@ -1,8 +1,18 @@ -/* - Description: Broadcasts an emote to the current channel -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Emote / action text + * @version 1.0.0 + * @description Broadcasts an emote to the current channel + * @module emote + */ -// module support functions +/** + * Check and trim string provided by remote client + * @param {string} text - Subject string + * @private + * @todo Move into utility module + * @return {string|boolean} + */ const parseText = (text) => { // verifies user input is text if (typeof text !== 'string') { @@ -19,7 +29,12 @@ const parseText = (text) => { return sanitizedText; }; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ server, socket, payload }) { // check user input let text = parseText(payload.text); @@ -61,12 +76,25 @@ export async function run({ server, socket, payload }) { return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.emoteCheck.bind(this), 30); } -// hooks chat commands checking for /me +/** + * Executes every time an incoming chat command is invoked; + * hooks chat commands checking for /me + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function emoteCheck({ core, server, socket, payload, }) { @@ -107,10 +135,27 @@ export function emoteCheck({ return payload; } +/** + * The following payload properties are required to invoke this module: + * "text" + * @public + * @typedef {Array} emote/requiredData + */ export const requiredData = ['text']; + +/** + * Module meta information + * @public + * @typedef {Object} emote/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'emote', - description: 'Typical emote / action text', + category: 'core', + description: 'Broadcasts an emote to the current channel', usage: ` API: { cmd: 'emote', text: '' } Text: /me `, diff --git a/commands/core/help.js b/commands/core/help.js index ad03ff3..b8e70b2 100644 --- a/commands/core/help.js +++ b/commands/core/help.js @@ -1,8 +1,17 @@ -/* - Description: Outputs the current command module list or command categories -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Get help + * @version 1.0.0 + * @description Outputs information about the servers current protocol + * @module help + */ -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -61,12 +70,25 @@ export async function run({ return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.helpCheck.bind(this), 28); } -// hooks chat commands checking for /whisper +/** + * Executes every time an incoming chat command is invoked; + * hooks chat commands checking for /help + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function helpCheck({ core, server, socket, payload, }) { @@ -93,8 +115,18 @@ export function helpCheck({ return payload; } +/** + * Module meta information + * @public + * @typedef {Object} help/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'help', + category: 'core', description: 'Outputs information about the servers current protocol', usage: ` API: { cmd: 'help', command: '' } diff --git a/commands/core/invite.js b/commands/core/invite.js index 092a30f..09b2670 100644 --- a/commands/core/invite.js +++ b/commands/core/invite.js @@ -1,22 +1,26 @@ -/* - Description: Generates a semi-unique channel name then broadcasts it to each client -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Send an invite + * @version 1.0.0 + * @description Sends an invite to the target client with the provided channel, or a random channel + * @module invite + */ import { findUser, -} from '../utility/_Channels'; +} from '../utility/_Channels.js'; import { Errors, -} from '../utility/_Constants'; +} from '../utility/_Constants.js'; import { legacyInviteOut, legacyInviteReply, -} from '../utility/_LegacyFunctions'; +} from '../utility/_LegacyFunctions.js'; -// module support functions /** * Returns the channel that should be invited to. * @param {any} channel + * @private * @return {string} */ export function getChannel(channel = undefined) { @@ -26,7 +30,12 @@ export function getChannel(channel = undefined) { return Math.random().toString(36).substr(2, 8); } -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -96,9 +105,18 @@ export async function run({ return true; } -export const requiredData = []; // ['nick']; +/** + * Module meta information + * @public + * @typedef {Object} invite/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'invite', + category: 'core', description: 'Sends an invite to the target client with the provided channel, or a random channel.', usage: ` API: { cmd: 'invite', nick: '', to: '' }`, diff --git a/commands/core/join.js b/commands/core/join.js index 45e6446..8956376 100644 --- a/commands/core/join.js +++ b/commands/core/join.js @@ -1,29 +1,44 @@ /* eslint no-param-reassign: 0 */ +/* eslint import/no-cycle: [0, { ignoreExternal: true }] */ -/* - Description: Adds requested channel into the calling clients "subscribed channels" -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Join target channel + * @version 1.0.0 + * @description Join the target channel using the supplied nick and password + * @module join + */ +import { + getSession, +} from './session.js'; import { canJoinChannel, -} from '../utility/_Channels'; + socketInChannel, +} from '../utility/_Channels.js'; import { Errors, -} from '../utility/_Constants'; +} from '../utility/_Constants.js'; import { upgradeLegacyJoin, legacyLevelToLabel, -} from '../utility/_LegacyFunctions'; +} from '../utility/_LegacyFunctions.js'; import { verifyNickname, getUserPerms, getUserDetails, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, -}) { // check for spam +}) { + // check for spam if (server.police.frisk(socket.address, 3)) { return server.reply({ cmd: 'warn', @@ -75,7 +90,7 @@ export async function run({ } // get trip and level - const { trip, level } = getUserPerms(pass, core.config, channel); + const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel); // store the user values const userInfo = { @@ -90,13 +105,6 @@ export async function run({ channel, }; - // prevent admin impersonation - if (nick.toLowerCase() === core.config.adminName.toLowerCase()) { - if (userInfo.trip !== 'Admin') { - userInfo.nick = `Fake${userInfo.nick}`; - } - } - // check if the nickname already exists in the channel const userExists = server.findSockets({ channel, @@ -141,6 +149,7 @@ export async function run({ socket.channel = channel; /* @legacy */ // @todo multi-channel patch // socket.channels.push(channel); + socket.channels = [channel]; nicks.push(userInfo.nick); /* @legacy */ users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo }); @@ -153,15 +162,110 @@ export async function run({ channel, // @todo Multichannel (?) }, socket); + // update client with new session info + server.reply({ + cmd: 'session', + restored: false, + token: getSession(socket, core), + channels: socket.channels, + }, socket); + // stats are fun core.stats.increment('users-joined'); return true; } -export const requiredData = []; // ['channel', 'nick']; +export function restoreJoin({ + server, socket, channel, +}) { + // check if a client is able to join target channel + const mayJoin = canJoinChannel(channel, socket); + if (mayJoin !== true) { + return server.reply({ + cmd: 'warn', + text: 'You may not join that channel.', + id: mayJoin, + channel: false, // @todo Multichannel, false for global event + }, socket); + } + + // store the user values + const userInfo = { + nick: socket.nick, + trip: socket.trip, + uType: legacyLevelToLabel(socket.level), + hash: socket.hash, + level: socket.level, + userid: socket.userid, + isBot: socket.isBot, + color: socket.color, + channel, + }; + + // prepare to notify channel peers + const newPeerList = server.findSockets({ channel }); + const nicks = []; /* @legacy */ + const users = []; + const joinAnnouncement = { ...{ cmd: 'onlineAdd' }, ...userInfo }; + // build update notice with new privileges + const updateAnnouncement = { + ...getUserDetails(socket), + ...{ + cmd: 'updateUser', + online: true, + }, + }; + + const isDuplicate = socketInChannel(server, channel, socket); + + // send join announcement and prep online set reply + for (let i = 0, l = newPeerList.length; i < l; i += 1) { + if (isDuplicate) { + server.reply(updateAnnouncement, newPeerList[i]); + } else { + server.reply(joinAnnouncement, newPeerList[i]); + } + + nicks.push(newPeerList[i].nick); /* @legacy */ + users.push({ + ...{ + channel, + isme: false, + }, + ...getUserDetails(newPeerList[i]), + }); + } + + nicks.push(userInfo.nick); /* @legacy */ + users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo }); + + // reply with channel peer list + server.reply({ + cmd: 'onlineSet', + nicks, /* @legacy */ + users, + channel, // @todo Multichannel (?) + }, socket); + + socket.channel = channel; /* @legacy */ + socket.channels.push(channel); + + return true; +} + +/** + * Module meta information + * @public + * @typedef {Object} join/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'join', + category: 'core', description: 'Join the target channel using the supplied nick and password', usage: ` API: { cmd: 'join', nick: '', pass: '', channel: '' }`, diff --git a/commands/core/morestats.js b/commands/core/morestats.js index f2a9612..93cdc5c 100644 --- a/commands/core/morestats.js +++ b/commands/core/morestats.js @@ -1,10 +1,17 @@ -/* - Description: Outputs more info than the legacy stats command -*/ - -// module support functions -const { stripIndents } = require('common-tags'); +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Get stats + * @version 1.0.0 + * @description Sends back current server stats to the calling client + * @module morestats + */ +/** + * Format input time into string + * @param {Date} time - Subject date + * @private + * @return {string} + */ const formatTime = (time) => { let seconds = time[0] + time[1] / 1e9; @@ -20,50 +27,101 @@ const formatTime = (time) => { return `${days.toFixed(0)}d ${hours.toFixed(0)}h ${minutes.toFixed(0)}m ${seconds.toFixed(0)}s`; }; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket }) { // gather connection and channel count - let ips = {}; - let channels = {}; - // for (const client of server.clients) { + const ips = {}; + const channels = {}; + // @todo use public channels from core.appConfig.data + const publicChanCounts = { + lounge: 0, + meta: 0, + math: 0, + physics: 0, + chemistry: 0, + technology: 0, + programming: 0, + games: 0, + banana: 0, + chinese: 0, + }; + + // @todo code resuage between here and `session`; should share exported function server.clients.forEach((client) => { if (client.channel) { channels[client.channel] = true; ips[client.address] = true; + if (typeof publicChanCounts[client.channel] !== 'undefined') { + publicChanCounts[client.channel] += 1; + } } }); const uniqueClientCount = Object.keys(ips).length; const uniqueChannels = Object.keys(channels).length; - - ips = null; - channels = null; + const joins = core.stats.get('users-joined') || 0; + const invites = core.stats.get('invites-sent') || 0; + const messages = core.stats.get('messages-sent') || 0; + const banned = core.stats.get('users-banned') || 0; + const kicked = core.stats.get('users-kicked') || 0; + const stats = core.stats.get('stats-requested') || 0; + const uptime = formatTime(process.hrtime(core.stats.get('start-time'))); // dispatch info server.reply({ cmd: 'info', - text: stripIndents`current-connections: ${uniqueClientCount} - current-channels: ${uniqueChannels} - users-joined: ${(core.stats.get('users-joined') || 0)} - invites-sent: ${(core.stats.get('invites-sent') || 0)} - messages-sent: ${(core.stats.get('messages-sent') || 0)} - users-banned: ${(core.stats.get('users-banned') || 0)} - users-kicked: ${(core.stats.get('users-kicked') || 0)} - stats-requested: ${(core.stats.get('stats-requested') || 0)} - server-uptime: ${formatTime(process.hrtime(core.stats.get('start-time')))}`, + users: uniqueClientCount, + chans: uniqueChannels, + joins, + invites, + messages, + banned, + kicked, + stats, + uptime, + public: publicChanCounts, + text: `current-connections: ${uniqueClientCount} +current-channels: ${uniqueChannels} +users-joined: ${joins} +invites-sent: ${invites} +messages-sent: ${messages} +users-banned: ${banned} +users-kicked: ${kicked} +stats-requested: ${stats} +server-uptime: ${uptime}`, channel: socket.channel, // @todo Multichannel }, socket); // stats are fun core.stats.increment('stats-requested'); + + return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.statsCheck.bind(this), 26); } -// hooks chat commands checking for /stats +/** + * Executes every time an incoming chat command is invoked; + * hooks chat commands checking for /stats + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function statsCheck({ core, server, socket, payload, }) { @@ -87,8 +145,18 @@ export function statsCheck({ return payload; } +/** + * Module meta information + * @public + * @typedef {Object} morestats/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'morestats', + category: 'core', description: 'Sends back current server stats to the calling client', usage: ` API: { cmd: 'morestats' } diff --git a/commands/core/move.js b/commands/core/move.js deleted file mode 100644 index de6a4fb..0000000 --- a/commands/core/move.js +++ /dev/null @@ -1,171 +0,0 @@ -/* - Description: Changes the current channel of the calling socket - @deprecated This module will be removed or replaced -*/ -import { - getUserDetails, -} from '../utility/_UAC'; - -// module main -export async function run({ server, socket, payload }) { - // check for spam - if (server.police.frisk(socket.address, 6)) { - return server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: 'You are changing channels too fast. Wait a moment before trying again.', - channel: socket.channel, // @todo Multichannel - }, socket); - } - - // check user input - if (typeof payload.channel !== 'string') { - return true; - } - - if (payload.channel === '') { - return server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: 'Cannot move to an empty channel.', - channel: socket.channel, // @todo Multichannel - }, socket); - } - - if (payload.channel === socket.channel) { // @todo Multichannel update - // they are trying to rejoin the channel - return true; - } - - // check that the nickname isn't already in target channel - const currentNick = socket.nick.toLowerCase(); - const userExists = server.findSockets({ - channel: payload.channel, - nick: (targetNick) => targetNick.toLowerCase() === currentNick, - }); - - if (userExists.length > 0) { - // That nickname is already in that channel - return true; - } - - // broadcast leave notice to peers - const peerList = server.findSockets({ channel: socket.channel }); - - if (peerList.length > 1) { - for (let i = 0, l = peerList.length; i < l; i += 1) { - server.reply({ - cmd: 'onlineRemove', - nick: peerList[i].nick, - userid: peerList[i].userid, - channel: socket.channel, // @todo Multichannel - }, socket); - - if (socket.userid !== peerList[i].userid) { - server.reply({ - cmd: 'onlineRemove', - nick: socket.nick, - userid: socket.userid, - channel: socket.channel, // @todo Multichannel - }, peerList[i]); - } - } - } - - // broadcast join notice to new peers - const newPeerList = server.findSockets({ channel: payload.channel }); - const moveAnnouncement = { - ...{ - cmd: 'onlineAdd', - channel: payload.channel, // @todo Multichannel - }, - ...getUserDetails(socket), - }; - - const nicks = []; - const users = []; - - for (let i = 0, l = newPeerList.length; i < l; i += 1) { - server.reply(moveAnnouncement, newPeerList[i]); - - nicks.push(newPeerList[i].nick); /* @legacy */ - users.push({ - ...{ - channel: payload.channel, - isme: false, - }, - ...getUserDetails(newPeerList[i]), - }); - } - - nicks.push(socket.nick); /* @legacy */ - users.push({ - ...{ - channel: payload.channel, - isme: true, - }, - ...getUserDetails(socket), - }); - - // reply with new user list - server.reply({ - cmd: 'onlineSet', - nicks, - users, - channel: socket.channel, // @todo Multichannel (!) - }, socket); - - // commit change - socket.channel = payload.channel; // eslint-disable-line no-param-reassign - - return true; -} - -// module hook functions -export function initHooks(server) { - server.registerHook('in', 'chat', this.moveCheck.bind(this), 29); -} - -export function moveCheck({ - core, server, socket, payload, -}) { - if (typeof payload.text !== 'string') { - return false; - } - - if (payload.text.startsWith('/move ')) { - const input = payload.text.split(' '); - - // If there is no channel target parameter - if (input[1] === undefined) { - server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: 'Refer to `/help move` for instructions on how to use this command.', - channel: socket.channel, // @todo Multichannel - }, socket); - - return false; - } - - this.run({ - core, - server, - socket, - payload: { - cmd: 'move', - channel: input[1], - }, - }); - - return false; - } - - return payload; -} - -export const requiredData = ['channel']; -export const info = { - name: 'move', - description: 'This will change your current channel to the new one provided', - usage: ` - API: { cmd: 'move', channel: '' } - Text: /move `, -}; diff --git a/commands/core/ping.js b/commands/core/ping.js index 642a526..f387bb7 100644 --- a/commands/core/ping.js +++ b/commands/core/ping.js @@ -1,12 +1,32 @@ /* eslint no-empty-function: 0 */ -/* - Description: This module is only in place to supress error notices legacy sources may get -*/ -// module main +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Legacy support module + * @version 1.0.0 + * @description This module is only in place to supress error notices legacy clients may get + * @module ping + */ + +/** + * Executes when invoked by a remote client + * @public + * @return {void} + */ export async function run() { } +/** + * Module meta information + * @public + * @typedef {Object} ping/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'ping', - description: 'This module is only in place to supress error notices legacy sources may get', + category: 'core', + description: 'This module is only in place to supress error notices legacy clients may get', + usage: 'none', }; diff --git a/commands/core/session.js b/commands/core/session.js index 1e4249b..eebed57 100644 --- a/commands/core/session.js +++ b/commands/core/session.js @@ -1,76 +1,193 @@ -/* eslint no-param-reassign: 0 */ +/* eslint import/no-cycle: [0, { ignoreExternal: true }] */ -/* - Description: Create a new socket session or restore previous session -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Restore session + * @version 1.0.0 + * @description Restore previous state by session + * @module session + */ -// module support functions -const createSessionID = () => { - let sessionID = ''; - for (let i = 0, j = 32; i < j; i += 1) { - sessionID += Math.random().toString(36).substr(2, 9); - } - return sessionID; -}; +import fs from 'fs'; +import jsonwebtoken from 'jsonwebtoken'; -// module main -export async function run({ server, socket, payload }) { - // gather connection and channel count - let ips = {}; - let channels = {}; - // @todo use public channel flag - const publicChanCounts = { - lounge: 0, - meta: 0, - math: 0, - physics: 0, - chemistry: 0, - technology: 0, - programming: 0, - games: 0, - banana: 0, - chinese: 0, - }; +import { + verifyNickname, +} from '../utility/_UAC.js'; +import { + Errors, +} from '../utility/_Constants.js'; +import { + restoreJoin, +} from './join.js'; - // todo code resuage between here and `morestats`, export function - server.clients.forEach((client) => { - if (client.channel) { - channels[client.channel] = true; - ips[client.address] = true; - if (typeof publicChanCounts[client.channel] !== 'undefined') { - publicChanCounts[client.channel] += 1; - } - } +const SessionLocation = './session.key'; + +/** + * Get a fresh session string for target socket + * @param {Object} socket + * @param {Object} core + * @returns {object} + */ +export function getSession(socket, core) { + return jsonwebtoken.sign({ + channel: socket.channel, + channels: socket.channels, + color: socket.color, + isBot: socket.isBot, + level: socket.level, + nick: socket.nick, + trip: socket.trip, + userid: socket.userid, + uType: socket.uType, /* @legacy */ + muzzled: socket.muzzled || false, + banned: socket.banned || false, + }, core.sessionKey, { + expiresIn: '7 days', }); - - const uniqueClientCount = Object.keys(ips).length; - const uniqueChannels = Object.keys(channels).length; - - ips = null; - channels = null; - - // @todo restore session - socket.sessionID = createSessionID(); - socket.hcProtocol = 2; - socket.userid = Math.floor(Math.random() * 9999999999999); - socket.hash = server.getSocketHash(socket); - socket.isBot = payload.isBot || false; - socket.color = false; - - // dispatch info - server.reply({ - cmd: 'session', - users: uniqueClientCount, - chans: uniqueChannels, - public: publicChanCounts, - sessionID: socket.sessionID, - restored: false, - }, socket); } +/** + * Reply to target socket with session failure notice + * @param {Object} server + * @param {Object} socket + * @returns {boolean} + */ +function notifyFailure(server, socket) { + server.reply({ + cmd: 'error', + id: Errors.Session.BAD_SESSION, + text: 'Invalid session', + }, socket); + + return false; +} + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + core, server, socket, payload, +}) { + if (typeof payload.token === 'undefined') { + return notifyFailure(server, socket); + } + + let session = false; + try { + session = jsonwebtoken.verify(payload.token, core.sessionKey); + } catch (err) { + return notifyFailure(server, socket); + } + + // validate session + if (typeof session.channel !== 'string') { + return notifyFailure(server, socket); + } + + if (Array.isArray(session.channels) === false) { + return notifyFailure(server, socket); + } + + if (typeof session.color !== 'string' && typeof session.color !== 'boolean') { + return notifyFailure(server, socket); + } + + if (typeof session.isBot !== 'boolean') { + return notifyFailure(server, socket); + } + + if (typeof session.level !== 'number') { + return notifyFailure(server, socket); + } + + if (verifyNickname(session.nick) === false) { + return notifyFailure(server, socket); + } + + if (typeof session.trip !== 'string') { + return notifyFailure(server, socket); + } + + if (typeof session.userid !== 'number') { + return notifyFailure(server, socket); + } + + if (typeof session.uType !== 'string') { + return notifyFailure(server, socket); + } + + if (typeof session.muzzled !== 'boolean') { + return notifyFailure(server, socket); + } + + if (typeof session.banned !== 'boolean') { + return notifyFailure(server, socket); + } + + // populate socket info with validated session + socket.channels = []; + socket.color = session.color; + socket.isBot = session.isBot; + socket.level = session.level; + socket.nick = session.nick; + socket.trip = session.trip; + socket.userid = session.userid; + socket.uType = session.uType; /* @legacy */ + socket.muzzled = session.muzzled; + socket.banned = session.banned; + + socket.hash = server.getSocketHash(socket); + socket.hcProtocol = 2; + + for (let i = 0, j = session.channels.length; i < j; i += 1) { + restoreJoin({ + core, + server, + socket, + channel: session.channels[i], + }, true); + } + + // dispatch updated session + server.reply({ + cmd: 'session', + restored: true, + token: getSession(socket, core), + channels: socket.channels, + }, socket); + + return true; +} + +/** + * Automatically executes once after server is ready + * @param {Object} core - Reference to core enviroment object + * @public + * @return {void} + */ +export function init(core) { + // load the encryption key if required + if (typeof core.sessionKey === 'undefined') { + core.sessionKey = fs.readFileSync(SessionLocation); + } +} + +/** + * Module meta information + * @public + * @typedef {Object} session/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'session', - description: 'Restore previous state by session id or return new session id (currently unavailable)', - usage: ` - API: { cmd: 'session', id: '' }`, + category: 'core', + description: 'Restore previous state by session or create new session', + usage: "API: { cmd: 'session', id: '' }", }; diff --git a/commands/core/stats.js b/commands/core/stats.js index e3e58fa..69f5a07 100644 --- a/commands/core/stats.js +++ b/commands/core/stats.js @@ -1,8 +1,17 @@ -/* - Description: Legacy stats output, kept for compatibility, outputs user and channel count -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Simple stats + * @version 1.0.0 + * @description Sends back legacy server stats to the calling client + * @module stats + */ -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket }) { // gather connection and channel count let ips = {}; @@ -32,8 +41,18 @@ export async function run({ core, server, socket }) { core.stats.increment('stats-requested'); } +/** + * Module meta information + * @public + * @typedef {Object} stats/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'stats', + category: 'core', description: 'Sends back legacy server stats to the calling client', usage: ` API: { cmd: 'stats' }`, diff --git a/commands/core/whisper.js b/commands/core/whisper.js index 3c0b18b..317c756 100644 --- a/commands/core/whisper.js +++ b/commands/core/whisper.js @@ -1,21 +1,31 @@ -/* - Description: Display text on targets screen that only they can see - @todo This should be changed to it's own event type, instead of `info` +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Send whisper + * @version 1.0.0 + * @description Display text on target users screen that only they can see + * @module whisper + * @todo This should be changed to it's own event type, instead of `info` and accept a `userid` rather than `nick` -*/ + */ import { findUser, -} from '../utility/_Channels'; +} from '../utility/_Channels.js'; import { Errors, -} from '../utility/_Constants'; +} from '../utility/_Constants.js'; import { legacyWhisperOut, legacyWhisperReply, -} from '../utility/_LegacyFunctions'; +} from '../utility/_LegacyFunctions.js'; -// module support functions +/** + * Check and trim string provided by remote client + * @param {string} text - Subject string + * @private + * @todo Move into utility module + * @return {string|boolean} + */ const parseText = (text) => { // verifies user input is text if (typeof text !== 'string') { @@ -32,7 +42,12 @@ const parseText = (text) => { return sanitizedText; }; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ server, socket, payload }) { // if this is a legacy client add missing params to payload if (socket.hcProtocol === 1) { @@ -94,12 +109,25 @@ export async function run({ server, socket, payload }) { return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.whisperCheck.bind(this), 20); } -// hooks chat commands checking for /whisper +/** + * Executes every time an incoming chat command is invoked; + * hooks chat commands checking for /whisper + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function whisperCheck({ core, server, socket, payload, }) { @@ -111,7 +139,7 @@ export function whisperCheck({ const input = payload.text.split(' '); // If there is no nickname target parameter - if (input[1] === undefined) { + if (!input[1]) { server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Refer to `/help whisper` for instructions on how to use this command.', @@ -173,10 +201,27 @@ export function whisperCheck({ return payload; } +/** + * The following payload properties are required to invoke this module: + * "nick", "text" + * @public + * @typedef {Array} whisper/requiredData + */ export const requiredData = ['nick', 'text']; + +/** + * Module meta information + * @public + * @typedef {Object} whisper/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'whisper', - description: 'Display text on targets screen that only they can see', + category: 'core', + description: 'Display text on target users screen that only they can see', usage: ` API: { cmd: 'whisper', nick: '', text: '' } Text: /whisper diff --git a/commands/internal/disconnect.js b/commands/internal/disconnect.js index 69bb061..cef5913 100644 --- a/commands/internal/disconnect.js +++ b/commands/internal/disconnect.js @@ -1,9 +1,21 @@ -/* - Description: This module will be directly called by the server event handler - when a socket connection is closed or lost. -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Disconnection handler + * @version 1.0.0 + * @description The server invokes this module each time a websocket connection is disconnected + * @module disconnect + */ -// module main +import { + socketInChannel, +} from '../utility/_Channels.js'; + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ server, socket, payload }) { if (payload.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore @@ -11,13 +23,16 @@ export async function run({ server, socket, payload }) { } // send leave notice to client peers + // @todo Multichannel update if (socket.channel) { - server.broadcast({ - cmd: 'onlineRemove', - userid: socket.userid, - nick: socket.nick, /* @legacy */ - channel: socket.channel, // @todo Multichannel - }, { channel: socket.channel }); + const isDuplicate = socketInChannel(server, socket.channel, socket); + + if (isDuplicate === false) { + server.broadcast({ + cmd: 'onlineRemove', + nick: socket.nick, + }, { channel: socket.channel }); + } } // commit close just in case @@ -26,9 +41,26 @@ export async function run({ server, socket, payload }) { return true; } +/** + * The following payload properties are required to invoke this module: + * "cmdKey" + * @public + * @typedef {Array} disconnect/requiredData + */ export const requiredData = ['cmdKey']; + +/** + * Module meta information + * @public + * @typedef {Object} disconnect/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'disconnect', + category: 'internal', + description: 'Internally used to relay disconnect events to clients', usage: 'Internal Use Only', - description: 'Internally used to relay `onlineRemove` event to clients', }; diff --git a/commands/internal/socketreply.js b/commands/internal/socketreply.js index 22fa5ba..3c4405c 100644 --- a/commands/internal/socketreply.js +++ b/commands/internal/socketreply.js @@ -1,8 +1,18 @@ -/* - Description: Used to relay warnings to clients internally -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Bridge warning events to a user + * @version 1.0.0 + * @description If a warning occurs within the server, this module will relay the warning to the + * client + * @module socketreply + */ -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ server, socket, payload }) { if (payload.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore @@ -10,18 +20,32 @@ export async function run({ server, socket, payload }) { } // send warning to target socket - server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` + return server.reply({ + cmd: 'warn', text: payload.text, - channel: socket.channel || false, // @todo Multichannel }, socket); - - return true; } +/** + * The following payload properties are required to invoke this module: + * "cmdKey", "text" + * @public + * @typedef {Array} socketreply/requiredData + */ export const requiredData = ['cmdKey', 'text']; + +/** + * Module meta information + * @public + * @typedef {Object} socketreply/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'socketreply', - usage: 'Internal Use Only', + category: 'internal', description: 'Internally used to relay warnings to clients', + usage: 'Internal Use Only', }; diff --git a/commands/mod/ban.js b/commands/mod/ban.js index 2529633..a791ec9 100644 --- a/commands/mod/ban.js +++ b/commands/mod/ban.js @@ -1,21 +1,29 @@ -/* eslint no-console: 0 */ -/* - Description: Adds the target socket's ip to the ratelimiter -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Ban a user + * @version 1.0.0 + * @description Bans target user by name + * @module ban + */ import { isModerator, getUserDetails, levels, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; import { Errors, -} from '../utility/_Constants'; +} from '../utility/_Constants.js'; import { findUser, -} from '../utility/_Channels'; +} from '../utility/_Channels.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -27,12 +35,12 @@ export async function run({ // check user input if (socket.hcProtocol === 1) { if (typeof payload.nick !== 'string') { - return true; + return false; } payload.channel = socket.channel; // eslint-disable-line no-param-reassign } else if (typeof payload.userid !== 'number') { - return true; + return false; } // find target user @@ -89,10 +97,19 @@ export async function run({ return true; } -// export const requiredData = ['nick']; +/** + * Module meta information + * @public + * @typedef {Object} ban/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'ban', - description: 'Disconnects the target nickname in the same channel as calling socket & adds to ratelimiter', + category: 'moderators', + description: 'Bans target user by name', usage: ` API: { cmd: 'ban', nick: '' }`, }; diff --git a/commands/mod/dumb.js b/commands/mod/dumb.js index 4625b58..e50df7f 100644 --- a/commands/mod/dumb.js +++ b/commands/mod/dumb.js @@ -1,29 +1,32 @@ /* eslint no-param-reassign: 0 */ /* eslint no-multi-assign: 0 */ -/* - * Description: Make a user (spammer) dumb (mute) - * Author: simple - */ +/** + * @author OpSimple ( https://github.com/OpSimple ) + * @summary Muzzle a user + * @version 1.0.0 + * @description Globally shadow mute a connection. Optional allies array will see muted messages. + * @module dumb + */ import { isModerator, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; import { findUser, -} from '../utility/_Channels'; +} from '../utility/_Channels.js'; import { Errors, -} from '../utility/_Constants'; +} from '../utility/_Constants.js'; import { legacyInviteReply, legacyWhisperReply, -} from '../utility/_LegacyFunctions'; +} from '../utility/_LegacyFunctions.js'; -// module support functions /** * Returns the channel that should be invited to. * @param {any} channel + * @private * @return {string} */ export function getChannel(channel = undefined) { @@ -33,6 +36,13 @@ export function getChannel(channel = undefined) { return Math.random().toString(36).substr(2, 8); } +/** + * Check and trim string provided by remote client + * @param {string} text - Subject string + * @private + * @todo Move into utility module + * @return {string|boolean} + */ const parseText = (text) => { // verifies user input is text if (typeof text !== 'string') { @@ -49,14 +59,24 @@ const parseText = (text) => { return sanitizedText; }; -// module constructor +/** + * Automatically executes once after server is ready + * @param {Object} core - Reference to core enviroment object + * @public + * @return {void} + */ export function init(core) { if (typeof core.muzzledHashes === 'undefined') { core.muzzledHashes = {}; } } -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -78,6 +98,7 @@ export async function run({ // find target user const targetUser = findUser(server, payload); + if (!targetUser) { return server.reply({ cmd: 'warn', @@ -117,14 +138,27 @@ export async function run({ return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.chatCheck.bind(this), 10); server.registerHook('in', 'invite', this.inviteCheck.bind(this), 10); server.registerHook('in', 'whisper', this.whisperCheck.bind(this), 10); } -// hook incoming chat commands, shadow-prevent chat if they are muzzled +/** + * Executes every time an incoming chat command is invoked; + * hook incoming chat commands, shadow-prevent chat if they are muzzled + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function chatCheck({ core, server, socket, payload, }) { @@ -179,7 +213,15 @@ export function chatCheck({ return payload; } -// shadow-prevent all invites from muzzled users +/** + * Executes every time an incoming chat command is invoked; + * shadow-prevent all invites from muzzled users + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function inviteCheck({ core, server, socket, payload, }) { @@ -243,7 +285,15 @@ export function inviteCheck({ return payload; } -// shadow-prevent all whispers from muzzled users +/** + * Executes every time an incoming chat command is invoked; + * shadow-prevent all whispers from muzzled users + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function whisperCheck({ core, server, socket, payload, }) { @@ -304,11 +354,20 @@ export function whisperCheck({ return payload; } -// export const requiredData = ['nick']; +/** + * Module meta information + * @public + * @typedef {Object} dumb/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'dumb', + category: 'moderators', description: 'Globally shadow mute a connection. Optional allies array will see muted messages.', + aliases: ['muzzle', 'mute'], usage: ` API: { cmd: 'dumb', nick: '', allies: ['', ...] }`, }; -info.aliases = ['muzzle', 'mute']; diff --git a/commands/mod/forcecolor.js b/commands/mod/forcecolor.js index 9f24d41..c5be5bd 100644 --- a/commands/mod/forcecolor.js +++ b/commands/mod/forcecolor.js @@ -1,21 +1,37 @@ -/* - Description: Forces a change on the target socket's nick color -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Color a user + * @version 1.0.0 + * @description Forces a user nick to become a certain color + * @module forcecolor + */ import { isModerator, getUserDetails, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; import { Errors, -} from '../utility/_Constants'; +} from '../utility/_Constants.js'; import { findUser, -} from '../utility/_Channels'; +} from '../utility/_Channels.js'; +/** + * Validate a string as a valid hex color string + * @param {string} color - Color string to validate + * @private + * @todo Move into utility module + * @return {boolean} + */ const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ server, socket, payload, }) { @@ -24,7 +40,7 @@ export async function run({ return server.police.frisk(socket.address, 10); } - const channel = socket.channel; + const { channel } = socket; if (typeof payload.channel === 'undefined') { payload.channel = channel; } @@ -87,12 +103,25 @@ export async function run({ return true; } -// module hook functions +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ export function initHooks(server) { server.registerHook('in', 'chat', this.colorCheck.bind(this), 20); } -// hooks chat commands checking for /whisper +/** + * Executes every time an incoming chat command is invoked; + * hooks chat commands checking for /forcecolor + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ export function colorCheck({ core, server, socket, payload, }) { @@ -143,10 +172,26 @@ export function colorCheck({ return payload; } -// module meta +/** + * The following payload properties are required to invoke this module: + * "nick", "color" + * @public + * @typedef {Array} forcecolor/requiredData + */ export const requiredData = ['nick', 'color']; + +/** + * Module meta information + * @public + * @typedef {Object} forcecolor/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'forcecolor', + category: 'moderators', description: 'Forces a user nick to become a certain color', usage: ` API: { cmd: 'forcecolor', nick: '', color: '' } diff --git a/commands/mod/kick.js b/commands/mod/kick.js index 183c05f..7520c86 100644 --- a/commands/mod/kick.js +++ b/commands/mod/kick.js @@ -1,22 +1,29 @@ -/* eslint no-console: 0 */ - -/* - Description: Forces a change on the target(s) socket's channel, then broadcasts event -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Give da boot + * @version 1.0.0 + * @description Silently forces target client(s) into another channel + * @module kick + */ import { isModerator, levels, getUserDetails, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; import { Errors, -} from '../utility/_Constants'; +} from '../utility/_Constants.js'; import { findUsers, -} from '../utility/_Channels'; +} from '../utility/_Channels.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -127,9 +134,18 @@ export async function run({ return true; } -// export const requiredData = ['nick']; +/** + * Module meta information + * @public + * @typedef {Object} kick/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'kick', + category: 'moderators', description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings', usage: ` API: { cmd: 'kick', nick: '', to: '' }`, diff --git a/commands/mod/moveuser.js b/commands/mod/moveuser.js deleted file mode 100644 index edae2aa..0000000 --- a/commands/mod/moveuser.js +++ /dev/null @@ -1,136 +0,0 @@ -/* - Description: Removes the target socket from the current channel and forces a join event in another - @deprecated This module will be removed or replaced -*/ - -import { - isModerator, - getUserDetails, -} from '../utility/_UAC'; - -// module main -export async function run({ server, socket, payload }) { - // increase rate limit chance and ignore if not admin or mod - if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); - } - - // check user input - if (typeof payload.nick !== 'string' || typeof payload.channel !== 'string') { - return true; - } - - if (payload.channel === socket.channel) { - // moving them into the same channel? y u do this? - return true; - } - - const badClients = server.findSockets({ channel: socket.channel, nick: payload.nick }); - - if (badClients.length === 0) { - return server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: 'Could not find user in channel', - channel: socket.channel, // @todo Multichannel - }, socket); - } - - const badClient = badClients[0]; - - if (badClient.level >= socket.level) { - return server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: 'Cannot move other users of the same level, how rude', - channel: socket.channel, // @todo Multichannel - }, socket); - } - - const currentNick = badClient.nick.toLowerCase(); - const userExists = server.findSockets({ - channel: payload.channel, - nick: (targetNick) => targetNick.toLowerCase() === currentNick, - }); - - if (userExists.length > 0) { - // That nickname is already in that channel - return true; - } - - const peerList = server.findSockets({ channel: socket.channel }); - - if (peerList.length > 1) { - for (let i = 0, l = peerList.length; i < l; i += 1) { - server.reply({ - cmd: 'onlineRemove', - userid: peerList[i].userid, - nick: peerList[i].nick, - channel: socket.channel, // @todo Multichannel - }, badClient); - - if (badClient.nick !== peerList[i].nick) { - server.reply({ - cmd: 'onlineRemove', - userid: badClient.userid, - nick: badClient.nick, - channel: socket.channel, // @todo Multichannel - }, peerList[i]); - } - } - } - - const newPeerList = server.findSockets({ channel: payload.channel }); - const moveAnnouncement = { - ...getUserDetails(badClient), - ...{ - cmd: 'onlineAdd', - channel: payload.channel, // @todo Multichannel - }, - }; - const nicks = []; - const users = []; - for (let i = 0, l = newPeerList.length; i < l; i += 1) { - server.reply(moveAnnouncement, newPeerList[i]); - - nicks.push(newPeerList[i].nick); /* @legacy */ - users.push({ - ...{ - channel: payload.channel, - isme: false, - }, - ...getUserDetails(newPeerList[i]), - }); - } - - nicks.push(badClient.nick); /* @legacy */ - users.push({ - ...{ - isme: true, - }, - ...getUserDetails(badClient), - }); - - server.reply({ - cmd: 'onlineSet', - nicks, /* @legacy */ - users, - channel: payload.channel, // @todo Multichannel (?) - }, badClient); - - badClient.channel = payload.channel; - - server.broadcast({ - cmd: 'info', - text: `${badClient.nick} was moved into ?${payload.channel}`, - channel: payload.channel, // @todo Multichannel - }, { channel: payload.channel }); - - return true; -} - -export const requiredData = ['nick', 'channel']; -export const info = { - name: 'moveuser', - description: 'This will move the target user nick into another channel', - usage: ` - API: { cmd: 'moveuser', nick: '', channel: '' }`, -}; diff --git a/commands/mod/speak.js b/commands/mod/speak.js index 15b3c10..69330ad 100644 --- a/commands/mod/speak.js +++ b/commands/mod/speak.js @@ -1,22 +1,35 @@ /* eslint no-param-reassign: 0 */ -/* - * Description: Pardon a dumb user to be able to speak again - * Author: simple - */ +/** + * @author OpSimple ( https://github.com/OpSimple ) + * @summary Unmuzzle a user + * @version 1.0.0 + * @description Pardon a dumb user to be able to speak again + * @module speak + */ import { isModerator, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module constructor +/** + * Automatically executes once after server is ready + * @param {Object} core - Reference to core enviroment object + * @public + * @return {void} + */ export function init(core) { if (typeof core.muzzledHashes === 'undefined') { core.muzzledHashes = {}; } } -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket, payload, }) { @@ -74,10 +87,20 @@ export async function run({ return true; } +/** + * Module meta information + * @public + * @typedef {Object} speak/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'speak', + category: 'moderators', description: 'Pardon a dumb user to be able to speak again', + aliases: ['unmuzzle', 'unmute'], usage: ` API: { cmd: 'speak', ip/hash: '' }`, }; diff --git a/commands/mod/unbanall.js b/commands/mod/unbanall.js index 5705704..83f5afc 100644 --- a/commands/mod/unbanall.js +++ b/commands/mod/unbanall.js @@ -1,14 +1,21 @@ -/* eslint no-console: 0 */ - -/* - Description: Clears all bans and ratelimits -*/ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Released them from the void + * @version 1.0.0 + * @description Clears all banned ip addresses + * @module unbanall + */ import { isModerator, -} from '../utility/_UAC'; +} from '../utility/_UAC.js'; -// module main +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { @@ -39,8 +46,18 @@ export async function run({ core, server, socket }) { return true; } +/** + * Module meta information + * @public + * @typedef {Object} unbanall/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ export const info = { name: 'unbanall', + category: 'moderators', description: 'Clears all banned ip addresses', usage: ` API: { cmd: 'unbanall' }`, diff --git a/commands/utility/_Channels.js b/commands/utility/_Channels.js index 15ba3f4..bf8074a 100644 --- a/commands/utility/_Channels.js +++ b/commands/utility/_Channels.js @@ -1,6 +1,14 @@ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Channel helper + * @version 1.0.0 + * @description Functions to assist with channel manipulation + * @module Channels + */ + import { Errors, -} from './_Constants'; +} from './_Constants.js'; /** * Checks if a client can join `channel`, returns numeric error code or true if @@ -10,12 +18,13 @@ import { * @param {object} socket Target client to evaluate * @return {boolean||error id} */ -// eslint-disable-next-line no-unused-vars export function canJoinChannel(channel, socket) { if (typeof channel !== 'string') return Errors.Channel.INVALID_NAME; if (channel === '') return Errors.Channel.INVALID_NAME; if (channel.length > 120) return Errors.Channel.INVALID_LENGTH; + if (typeof socket.banned !== 'undefined' && socket.banned) return Errors.Channel.DEY_BANNED; + return true; } @@ -28,9 +37,9 @@ export function canJoinChannel(channel, socket) { * @return {object} */ export function getChannelSettings(config, channel) { - if (typeof config.channels !== 'undefined') { - if (typeof config.channels[channel] !== 'undefined') { - return config.channels[channel]; + if (typeof config.permissions !== 'undefined') { + if (typeof config.permissions[channel] !== 'undefined') { + return config.permissions[channel]; } } @@ -83,3 +92,17 @@ export function findUsers(server, payload, limit = 0) { export function findUser(server, payload) { return findUsers(server, payload, 1)[0] || false; } + +/** + * Check if the target socket's userid is already in target channel + * @param {MainServer} server Main server reference + * @param {string} channel Target channel + * @param {object} socket Target client to evaluate + * @return {boolean||object} + */ +export function socketInChannel(server, channel, socket) { + return findUser(server, { + channel, + userid: socket.userid, + }); +} diff --git a/commands/utility/_Constants.js b/commands/utility/_Constants.js index bac25fd..7f567ef 100644 --- a/commands/utility/_Constants.js +++ b/commands/utility/_Constants.js @@ -1,14 +1,23 @@ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Error ID list + * @version 1.0.0 + * @description Exports an object that hold common global error IDs + * @module Constants + */ + /* Base error ranges */ const GlobalErrors = 10; const JoinErrors = 20; const ChannelErrors = 30; const InviteErrors = 40; +const SessionErrors = 50; /** * Holds the numeric id values for each error type * @typedef {object} Errors */ -exports.Errors = { +export const Errors = { Global: { RATELIMIT: GlobalErrors + 1, UNKNOWN_USER: GlobalErrors + 2, @@ -25,9 +34,16 @@ exports.Errors = { Channel: { INVALID_NAME: ChannelErrors + 1, INVALID_LENGTH: ChannelErrors + 2, + DEY_BANNED: ChannelErrors + 3, }, Invite: { RATELIMIT: InviteErrors + 1, }, + + Session: { + BAD_SESSION: SessionErrors + 1, + }, }; + +export default Errors; diff --git a/commands/utility/_LegacyFunctions.js b/commands/utility/_LegacyFunctions.js index 4fa9891..bb9f518 100644 --- a/commands/utility/_LegacyFunctions.js +++ b/commands/utility/_LegacyFunctions.js @@ -1,9 +1,17 @@ /* eslint no-param-reassign: 0 */ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Support functions for old clients + * @version 1.0.0 + * @description Functions to bridge the older v1 clients with the latest protocol + * @module LegacyFunctions + */ + import { isAdmin, isModerator, -} from './_UAC'; +} from './_UAC.js'; /** * Marks the socket as using the legacy protocol and diff --git a/commands/utility/_UAC.js b/commands/utility/_UAC.js index 52e5e7a..f003288 100644 --- a/commands/utility/_UAC.js +++ b/commands/utility/_UAC.js @@ -4,14 +4,16 @@ * @property {Object} levels - Defines labels for default permission ranges * @author MinusGix ( https://github.com/MinusGix ) * @version v1.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) + * @module UAC */ import { getChannelSettings, -} from './_Channels'; +} from './_Channels.js'; -const crypto = require('crypto'); +const { + createHash, +} = await import('crypto'); /** * Object defining labels for default permission ranges @@ -106,12 +108,13 @@ export function getUserDetails(socket) { return { nick: socket.nick, trip: socket.trip || '', - uType: socket.uType, + uType: socket.uType, /* @legacy */ hash: socket.hash, level: socket.level, userid: socket.userid, isBot: socket.isBot, color: socket.color, + online: true, }; } @@ -132,11 +135,12 @@ export function verifyNickname(nick) { * or a blank string * @public * @param {string} pass User's password + * @param {buffer} salt Server salt data * @param {string} config Server config object * @param {string} channel Channel-level permissions check * @return {string} */ -export function getUserPerms(pass, config, channel) { +export function getUserPerms(pass, salt, config, channel) { if (!pass) { return { trip: '', @@ -144,8 +148,8 @@ export function getUserPerms(pass, config, channel) { }; } - const sha = crypto.createHash('sha256'); - sha.update(pass + config.tripSalt); + const sha = createHash('sha256'); + sha.update(pass + salt); const trip = sha.digest('base64').substr(0, 6); // check if user is global admin @@ -159,7 +163,7 @@ export function getUserPerms(pass, config, channel) { let level = levels.default; // check if user is global mod - config.mods.forEach((mod) => { // eslint-disable-line consistent-return + config.globalMods.forEach((mod) => { // eslint-disable-line consistent-return if (trip === mod.trip) { level = levels.moderator; } diff --git a/documentation/DOCUMENTATION.md b/documentation/DOCUMENTATION.md deleted file mode 100644 index c535cd7..0000000 --- a/documentation/DOCUMENTATION.md +++ /dev/null @@ -1,48 +0,0 @@ -You can programmatically access hack.chat using the following commands via a websocket. A list of wrappers written for accessing hack.chat can be found [here](https://github.com/hack-chat/3rd-party-software-list#libraries). - -The commands are to be sent through a websocket to the URL `wss://hack.chat/chat-ws` (everything sent and received are JSON). If you are sending messages locally or to another domain, replace 'hack.chat' with the respective domain. If you're running your own instance of hack.chat, you can retain backwards-compatibility in order to ensure that software created for the main server will work on yours too. - -All commands sent must be JSON objects with the command specified in the `"cmd"` key. For example: -```json -{ - "cmd": "join", - "channel": "programming", - "nick": "john#doe" -} -``` - -hack.chat has three permission levels. When you access a command, hack.chat automatically knows your permission level from your trip code. The lowest permission level is `user`. `mod` is above `user`, so it can access `user` commands in addition to `mod` commands. `admin` is similarly above `mod`. - -# `user` - -|Command|Parameters|Explanation| -|-------|----------|-----------| -|`changenick`|`nick`|Changes the current connection's nickname.| -|`chat`|`text`|This broadcasts `text` to the channel the user is connected to.| -|`disconnect`||An event handler or forced disconnect.| -|`invite`|`nick`|Generates a pseudo-unique channel name and passes it to both the calling user and `nick`.| -|`join`|`channel`, `nick`|Places the calling socket into the target channel with the target nick and broadcasts the event to the channel.| -|`morestats`||Sends back the current server's stats to the calling client.| -|`move`|`channel`|This will change the current channel to `channel`.| -|`stats`||Sends back legacy server stats to the calling client. Use `morestats` when possible.| -|`help`|`category` or `command`|Gives documentation programmatically. If `category` (the permission level, such as `mod`) is sent, a list of commands available to that permission level will be sent back (as a `string` and not an `array`). This list only includes what is unique to that category and not every command a user with that permission level could perform. If `command` (e.g., `chat`) is sent, a description of the command will be sent back.| - -# `mod` - -|Command|Parameters|Explanation| -|-------|----------|-----------| -|`ban`|`nick`|Disconnects the target nickname in the same channel as the calling socket and adds it to the rate limiter.| -|`kick`|`nick`|Silently forces target client(s) into another channel. `nick` may be `string` or `array` of `string`s.| -|`unban`|`ip` or `hash`|Removes the target ip from the rate limiter.| -|`dumb`|`nick`|Mutes a user's (spammer's) texts such that it is displayable to the user only.| -|`speak`|`ip` or `hash`|Unmutes the user's (spammer's) texts and makes it displayable to everyone again.| - -# `admin` - -|Command|Parameters|Explanation| -|-------|----------|-----------| -|`addmod`|`nick`|Adds the target trip to the config as a mod and upgrades the socket type.| -|`listusers`||Outputs all current channels and sockets in those channels.| -|`reload`||(Re)loads any new commands into memory and outputs errors, if any.| -|`saveconfig`||Saves the current config.| -|`shout`|`text`|Displays the passed text to each client connected.| diff --git a/documentation/admin_addmod.js.html b/documentation/admin_addmod.js.html new file mode 100644 index 0000000..eacf973 --- /dev/null +++ b/documentation/admin_addmod.js.html @@ -0,0 +1,159 @@ + + + + + JSDoc: Source: admin/addmod.js + + + + + + + + + + +
+ +

Source: admin/addmod.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Create a new mod trip
+  * @version 1.0.0
+  * @description Adds target trip to the config as a mod and upgrades the socket type
+  * @module addmod
+  */
+
+import {
+  isAdmin,
+  isModerator,
+  levels,
+  getUserDetails,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin
+  if (!isAdmin(socket.level)) {
+    return server.police.frisk(socket.address, 20);
+  }
+
+  // add new trip to config
+  core.appConfig.data.globalMods.push({ trip: payload.trip });
+
+  // find targets current connections
+  const newMod = server.findSockets({ trip: payload.trip });
+  if (newMod.length !== 0) {
+    // build update notice with new privileges
+    const updateNotice = {
+      ...getUserDetails(newMod[0]),
+      ...{
+        cmd: 'updateUser',
+        uType: 'mod', // @todo use legacyLevelToLabel from _LegacyFunctions.js
+        level: levels.moderator,
+      },
+    };
+
+    for (let i = 0, l = newMod.length; i < l; i += 1) {
+      // upgrade privileges
+      newMod[i].uType = 'mod'; // @todo use legacyLevelToLabel from _LegacyFunctions.js
+      newMod[i].level = levels.moderator;
+
+      // inform new mod
+      server.send({
+        cmd: 'info',
+        text: 'You are now a mod.',
+        channel: newMod[i].channel, // @todo Multichannel
+      }, newMod[i]);
+
+      // notify channel
+      server.broadcast({
+        ...updateNotice,
+        ...{
+          channel: newMod[i].channel,
+        },
+      }, { channel: newMod[i].channel });
+    }
+  }
+
+  // return success message
+  server.reply({
+    cmd: 'info',
+    text: `Added mod trip: ${payload.trip}, remember to run 'saveconfig' to make it permanent`,
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  // notify all mods
+  server.broadcast({
+    cmd: 'info',
+    text: `Added mod: ${payload.trip}`,
+    channel: false, // @todo Multichannel, false for global info
+  }, { level: isModerator });
+
+  return true;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "trip"
+  * @public
+  * @typedef {Array} addmod/requiredData
+  */
+export const requiredData = ['trip'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} addmod/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'addmod',
+  category: 'admin',
+  description: 'Adds target trip to the config as a mod and upgrades the socket type',
+  usage: `
+    API: { cmd: 'addmod', trip: '<target trip>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/admin_listusers.js.html b/documentation/admin_listusers.js.html new file mode 100644 index 0000000..fa199b7 --- /dev/null +++ b/documentation/admin_listusers.js.html @@ -0,0 +1,128 @@ + + + + + JSDoc: Source: admin/listusers.js + + + + + + + + + + +
+ +

Source: admin/listusers.js

+ + + + + + +
+
+
/* eslint no-unused-vars: 0 */
+/* eslint no-restricted-syntax: 0 */
+/* eslint guard-for-in: 0 */
+
+/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Show users and channels
+  * @version 1.0.0
+  * @description Outputs all current channels and sockets in those channels
+  * @module listusers
+  */
+
+import {
+  isAdmin,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ server, socket }) {
+  // increase rate limit chance and ignore if not admin
+  if (!isAdmin(socket.level)) {
+    return server.police.frisk(socket.address, 20);
+  }
+
+  // find all users currently in a channel
+  const currentUsers = server.findSockets({
+    channel: (channel) => true,
+  });
+
+  // compile channel and user list
+  const channels = {};
+  for (let i = 0, j = currentUsers.length; i < j; i += 1) {
+    if (typeof channels[currentUsers[i].channel] === 'undefined') {
+      channels[currentUsers[i].channel] = [];
+    }
+
+    channels[currentUsers[i].channel].push(
+      `[${currentUsers[i].trip || 'null'}]${currentUsers[i].nick}`,
+    );
+  }
+
+  // build output
+  const lines = [];
+  for (const channel in channels) {
+    lines.push(`?${channel} ${channels[channel].join(', ')}`);
+  }
+
+  // send reply
+  server.reply({
+    cmd: 'info',
+    text: lines.join('\n'),
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} listusers/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'listusers',
+  category: 'admin',
+  description: 'Outputs all current channels and sockets in those channels',
+  usage: `
+    API: { cmd: 'listusers' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/admin_reload.js.html b/documentation/admin_reload.js.html new file mode 100644 index 0000000..f3831f5 --- /dev/null +++ b/documentation/admin_reload.js.html @@ -0,0 +1,122 @@ + + + + + JSDoc: Source: admin/reload.js + + + + + + + + + + +
+ +

Source: admin/reload.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Refresh modules
+  * @version 1.0.0
+  * @description Allows a remote user to clear and re-import the server command modules
+  * @module reload
+  */
+
+import {
+  isAdmin,
+  isModerator,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin
+  if (!isAdmin(socket.level)) {
+    return server.police.frisk(socket.address, 20);
+  }
+
+  // do command reload and store results
+  let loadResult = await core.commands.reloadCommands();
+
+  // clear and rebuild all module hooks
+  server.loadHooks();
+
+  // build reply based on reload results
+  if (loadResult === '') {
+    loadResult = `Reloaded ${core.commands.commands.length} commands, 0 errors`;
+  } else {
+    loadResult = `Reloaded ${core.commands.commands.length} commands, error(s):
+      ${loadResult}`;
+  }
+
+  if (typeof payload.reason !== 'undefined') {
+    loadResult += `\nReason: ${payload.reason}`;
+  }
+
+  // send results to moderators (which the user using this command is higher than)
+  server.broadcast({
+    cmd: 'info',
+    text: loadResult,
+    channel: false, // @todo Multichannel, false for global
+  }, { level: isModerator });
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} reload/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'reload',
+  category: 'admin',
+  description: 'Allows a remote user to clear and re-import the server command modules',
+  usage: `
+    API: { cmd: 'reload', reason: '<optional reason append>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/admin_removemod.js.html b/documentation/admin_removemod.js.html new file mode 100644 index 0000000..5d40cd2 --- /dev/null +++ b/documentation/admin_removemod.js.html @@ -0,0 +1,164 @@ + + + + + JSDoc: Source: admin/removemod.js + + + + + + + + + + +
+ +

Source: admin/removemod.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Removes a mod
+  * @version 1.0.0
+  * @description Removes target trip from the config as a mod and downgrades the socket type
+  * @module removemod
+  */
+
+import {
+  isAdmin,
+  isModerator,
+  levels,
+  getUserDetails,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin
+  if (!isAdmin(socket.level)) {
+    return server.police.frisk(socket.address, 20);
+  }
+
+  // remove trip from config
+  // eslint-disable-next-line no-param-reassign
+  core.appConfig.data.globalMods = core.appConfig.data.globalMods.filter(
+    (mod) => mod.trip !== payload.trip,
+  );
+
+  // find targets current connections
+  const targetMod = server.findSockets({ trip: payload.trip });
+  if (targetMod.length !== 0) {
+    // build update notice with new privileges
+    const updateNotice = {
+      ...getUserDetails(targetMod[0]),
+      ...{
+        cmd: 'updateUser',
+        uType: 'user', // @todo use legacyLevelToLabel from _LegacyFunctions.js
+        level: levels.default,
+      },
+    };
+
+    for (let i = 0, l = targetMod.length; i < l; i += 1) {
+      // downgrade privileges
+      targetMod[i].uType = 'user'; /* @legacy */
+      targetMod[i].level = levels.default;
+
+      // inform ex-mod
+      server.send({
+        cmd: 'info',
+        text: 'You are now a user.',
+        channel: targetMod[i].channel, // @todo Multichannel
+      }, targetMod[i]);
+
+      // notify channel
+      server.broadcast({
+        ...updateNotice,
+        ...{
+          channel: targetMod[i].channel,
+        },
+      }, { channel: targetMod[i].channel });
+    }
+  }
+
+  // return success message
+  server.reply({
+    cmd: 'info',
+    text: `Removed mod trip: ${
+      payload.trip
+    }, remember to run 'saveconfig' to make it permanent`,
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  // notify all mods
+  server.broadcast({
+    cmd: 'info',
+    text: `Removed mod: ${payload.trip}`,
+    channel: false, // @todo Multichannel, false for global
+  }, { level: isModerator });
+
+  return true;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "trip"
+  * @public
+  * @typedef {Array} removemod/requiredData
+  */
+export const requiredData = ['trip'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} removemod/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'removemod',
+  category: 'admin',
+  description: 'Removes target trip from the config as a mod and downgrades the socket type',
+  usage: `
+    API: { cmd: 'removemod', trip: '<target trip>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/admin_saveconfig.js.html b/documentation/admin_saveconfig.js.html new file mode 100644 index 0000000..a3af560 --- /dev/null +++ b/documentation/admin_saveconfig.js.html @@ -0,0 +1,113 @@ + + + + + JSDoc: Source: admin/saveconfig.js + + + + + + + + + + +
+ +

Source: admin/saveconfig.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Saves the config
+  * @version 1.0.0
+  * @description Writes the current config to disk
+  * @module saveconfig
+  */
+
+import {
+  isAdmin,
+  isModerator,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ core, server, socket }) {
+  // increase rate limit chance and ignore if not admin
+  if (!isAdmin(socket.level)) {
+    return server.police.frisk(socket.address, 20);
+  }
+
+  // attempt save, notify of failure
+  try {
+    await core.appConfig.write();
+  } catch (err) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'Failed to save config, check logs.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // return success message to moderators and admins
+  server.broadcast({
+    cmd: 'info',
+    text: 'Config saved!',
+    channel: false, // @todo Multichannel
+  }, { level: isModerator });
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} saveconfig/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'saveconfig',
+  category: 'admin',
+  description: 'Writes the current config to disk',
+  usage: `
+    API: { cmd: 'saveconfig' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/admin_shout.js.html b/documentation/admin_shout.js.html new file mode 100644 index 0000000..40b6367 --- /dev/null +++ b/documentation/admin_shout.js.html @@ -0,0 +1,109 @@ + + + + + JSDoc: Source: admin/shout.js + + + + + + + + + + +
+ +

Source: admin/shout.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Emit text everywhere
+  * @version 1.0.0
+  * @description Displays passed text to every client connected
+  * @module shout
+  */
+
+import {
+  isAdmin,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ server, socket, payload }) {
+  // increase rate limit chance and ignore if not admin
+  if (!isAdmin(socket.level)) {
+    return server.police.frisk(socket.address, 20);
+  }
+
+  // send text to all channels
+  server.broadcast({
+    cmd: 'info',
+    text: `Server Notice: ${payload.text}`,
+    channel: false, // @todo Multichannel, false for global
+  }, {});
+
+  return true;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "text"
+  * @public
+  * @typedef {Array} shout/requiredData
+  */
+export const requiredData = ['text'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} shout/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'shout',
+  category: 'admin',
+  description: 'Displays passed text to every client connected',
+  usage: `
+    API: { cmd: 'shout', text: '<shout text>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_changecolor.js.html b/documentation/core_changecolor.js.html new file mode 100644 index 0000000..5241ad8 --- /dev/null +++ b/documentation/core_changecolor.js.html @@ -0,0 +1,209 @@ + + + + + JSDoc: Source: core/changecolor.js + + + + + + + + + + +
+ +

Source: core/changecolor.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Update name color
+  * @version 1.0.0
+  * @description Allows calling client to change their nickname color
+  * @module changecolor
+  */
+
+import {
+  getUserDetails,
+} from '../utility/_UAC.js';
+
+/**
+  * Validate a string as a valid hex color string
+  * @param {string} color - Color string to validate
+  * @private
+  * @todo Move into utility module
+  * @return {boolean}
+  */
+const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color);
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  server, socket, payload,
+}) {
+  const { channel } = socket;
+
+  if (server.police.frisk(socket.address, 1)) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'You are changing colors too fast. Wait a moment before trying again.',
+      channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // verify user data is string
+  if (typeof payload.color !== 'string') {
+    return false;
+  }
+
+  // make sure requested nickname meets standards
+  const newColor = payload.color.trim().toUpperCase().replace(/#/g, '');
+  if (newColor !== 'RESET' && !verifyColor(newColor)) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Invalid color! Color must be in hex value',
+      channel, // @todo Multichannel
+    }, socket);
+  }
+
+  if (newColor === 'RESET') {
+    socket.color = false; // eslint-disable-line no-param-reassign
+  } else {
+    socket.color = newColor; // eslint-disable-line no-param-reassign
+  }
+
+  // build update notice with new color
+  const updateNotice = {
+    ...getUserDetails(socket),
+    ...{
+      cmd: 'updateUser',
+      channel: socket.channel, // @todo Multichannel
+    },
+  };
+
+  // notify channel that the user has changed their name
+  // @todo this should be sent to every channel the user is in (multichannel)
+  server.broadcast(updateNotice, { channel: socket.channel });
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.colorCheck.bind(this), 29);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function colorCheck({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (payload.text.startsWith('/color ')) {
+    const input = payload.text.split(' ');
+
+    // If there is no color target parameter
+    if (input[1] === undefined) {
+      server.reply({
+        cmd: 'warn',
+        text: 'Refer to `/help changecolor` for instructions on how to use this command.',
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+
+      return false;
+    }
+
+    this.run({
+      core,
+      server,
+      socket,
+      payload: {
+        cmd: 'changecolor',
+        color: input[1],
+      },
+    });
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "color"
+  * @public
+  * @typedef {Array} changecolor/requiredData
+  */
+export const requiredData = ['color'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} changecolor/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'changecolor',
+  category: 'core',
+  description: 'Allows calling client to change their nickname color',
+  usage: `
+    API: { cmd: 'changecolor', color: '<new color as hex>' }
+    Text: /color <new color as hex>
+    Removal: /color reset`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_changenick.js.html b/documentation/core_changenick.js.html new file mode 100644 index 0000000..f666107 --- /dev/null +++ b/documentation/core_changenick.js.html @@ -0,0 +1,264 @@ + + + + + JSDoc: Source: core/changenick.js + + + + + + + + + + +
+ +

Source: core/changenick.js

+ + + + + + +
+
+
/* eslint eqeqeq: 0 */
+
+/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Update nickname
+  * @version 1.0.0
+  * @description Allows calling client to change their current nickname
+  * @module changenick
+  */
+
+import {
+  verifyNickname,
+  getUserDetails,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  server, socket, payload,
+}) {
+  const { channel } = socket;
+
+  if (server.police.frisk(socket.address, 6)) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'You are changing nicknames too fast. Wait a moment before trying again.',
+      channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // verify user data is string
+  if (typeof payload.nick !== 'string') {
+    return true;
+  }
+
+  const previousNick = socket.nick;
+
+  // make sure requested nickname meets standards
+  const newNick = payload.nick.trim();
+  if (!verifyNickname(newNick)) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'Nickname must consist of up to 24 letters, numbers, and underscores',
+      channel, // @todo Multichannel
+    }, socket);
+  }
+
+  if (newNick == previousNick) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'You already have that name',
+      channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // find any sockets that have the same nickname
+  const userExists = server.findSockets({
+    channel,
+    nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase()
+      // Allow them to rename themselves to a different case
+      && targetNick != previousNick,
+  });
+
+  // return error if found
+  if (userExists.length > 0) {
+    // That nickname is already in that channel
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'Nickname taken',
+      channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // build update notice with new nickname
+  const updateNotice = {
+    ...getUserDetails(socket),
+    ...{
+      cmd: 'updateUser',
+      nick: newNick,
+      channel, // @todo Multichannel
+    },
+  };
+
+  // build join and leave notices for legacy clients
+  const leaveNotice = {
+    cmd: 'onlineRemove',
+    userid: socket.userid,
+    nick: socket.nick,
+    channel, // @todo Multichannel
+  };
+
+  const joinNotice = {
+    ...getUserDetails(socket),
+    ...{
+      cmd: 'onlineAdd',
+      nick: newNick,
+      channel, // @todo Multichannel
+    },
+  };
+
+  // gather channel peers
+  const peerList = server.findSockets({ channel });
+  for (let i = 0, l = peerList.length; i < l; i += 1) {
+    if (peerList[i].hcProtocol === 1) {
+      // send join/leave to legacy clients
+      server.send(leaveNotice, peerList[i]);
+      server.send(joinNotice, peerList[i]);
+    } else {
+      // send update info
+      // @todo this should be sent to every channel the client is in (multichannel)
+      server.send(updateNotice, peerList[i]);
+    }
+  }
+
+  // notify channel that the user has changed their name
+  server.broadcast({
+    cmd: 'info',
+    text: `${socket.nick} is now ${newNick}`,
+    channel, // @todo Multichannel
+  }, { channel });
+
+  // commit change to nickname
+  socket.nick = newNick; // eslint-disable-line no-param-reassign
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.nickCheck.bind(this), 29);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function nickCheck({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (payload.text.startsWith('/nick')) {
+    const input = payload.text.split(' ');
+
+    // If there is no nickname target parameter
+    if (!input[1]) {
+      server.reply({
+        cmd: 'warn', // @todo Add numeric error code as `id`
+        text: 'Refer to `/help nick` for instructions on how to use this command.',
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+
+      return false;
+    }
+
+    const newNick = input[1].replace(/@/g, '');
+
+    this.run({
+      core,
+      server,
+      socket,
+      payload: {
+        cmd: 'changenick',
+        nick: newNick,
+      },
+    });
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "nick"
+  * @public
+  * @typedef {Array} changenick/requiredData
+  */
+export const requiredData = ['nick'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} changenick/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'changenick',
+  category: 'core',
+  description: 'Allows calling client to change their current nickname',
+  usage: `
+    API: { cmd: 'changenick', nick: '<new nickname>' }
+    Text: /nick <new nickname>`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_chat.js.html b/documentation/core_chat.js.html new file mode 100644 index 0000000..0243531 --- /dev/null +++ b/documentation/core_chat.js.html @@ -0,0 +1,246 @@ + + + + + JSDoc: Source: core/chat.js + + + + + + + + + + +
+ +

Source: core/chat.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Send chat messages
+  * @version 1.0.0
+  * @description Broadcasts passed `text` field to the calling users channel
+  * @module chat
+  */
+
+import {
+  isAdmin,
+  isModerator,
+} from '../utility/_UAC.js';
+
+/**
+  * Check and trim string provided by remote client
+  * @param {string} text - Subject string
+  * @private
+  * @todo Move into utility module
+  * @return {string|boolean}
+  */
+const parseText = (text) => {
+  // verifies user input is text
+  if (typeof text !== 'string') {
+    return false;
+  }
+
+  let sanitizedText = text;
+
+  // strip newlines from beginning and end
+  sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, '');
+  // replace 3+ newlines with just 2 newlines
+  sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n');
+
+  return sanitizedText;
+};
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // check user input
+  const text = parseText(payload.text);
+
+  if (!text) {
+    // lets not send objects or empty text, yea?
+    return server.police.frisk(socket.address, 13);
+  }
+
+  // check for spam
+  const score = text.length / 83 / 4;
+  if (server.police.frisk(socket.address, score)) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // build chat payload
+  const outgoingPayload = {
+    cmd: 'chat',
+    nick: socket.nick, /* @legacy */
+    uType: socket.uType, /* @legacy */
+    userid: socket.userid,
+    channel: socket.channel,
+    text,
+    level: socket.level,
+  };
+
+  if (isAdmin(socket.level)) {
+    outgoingPayload.admin = true;
+  } else if (isModerator(socket.level)) {
+    outgoingPayload.mod = true;
+  }
+
+  if (socket.trip) {
+    outgoingPayload.trip = socket.trip; /* @legacy */
+  }
+
+  if (socket.color) {
+    outgoingPayload.color = socket.color;
+  }
+
+  // broadcast to channel peers
+  server.broadcast(outgoingPayload, { channel: socket.channel });
+
+  // stats are fun
+  core.stats.increment('messages-sent');
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.commandCheckIn.bind(this), 20);
+  server.registerHook('in', 'chat', this.finalCmdCheck.bind(this), 254);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * checks for miscellaneous '/' based commands
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function commandCheckIn({ server, socket, payload }) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (payload.text.startsWith('/myhash')) {
+    server.reply({
+      cmd: 'info',
+      text: `Your hash: ${socket.hash}`,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * assumes a failed chat command invocation and will reject with notice
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function finalCmdCheck({ server, socket, payload }) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (!payload.text.startsWith('/')) {
+    return payload;
+  }
+
+  if (payload.text.startsWith('//')) {
+    payload.text = payload.text.substr(1); // eslint-disable-line no-param-reassign
+
+    return payload;
+  }
+
+  server.reply({
+    cmd: 'warn', // @todo Add numeric error code as `id`
+    text: `Unknown command: ${payload.text}`,
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  return false;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "text"
+  * @public
+  * @typedef {Array} chat/requiredData
+  */
+export const requiredData = ['text'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} chat/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'chat',
+  category: 'core',
+  description: 'Broadcasts passed `text` field to the calling users channel',
+  usage: `
+    API: { cmd: 'chat', text: '<text to send>' }
+    Text: Uuuuhm. Just kind type in that little box at the bottom and hit enter.\n
+    Bonus super secret hidden commands:
+    /myhash`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_emote.js.html b/documentation/core_emote.js.html new file mode 100644 index 0000000..e81a524 --- /dev/null +++ b/documentation/core_emote.js.html @@ -0,0 +1,213 @@ + + + + + JSDoc: Source: core/emote.js + + + + + + + + + + +
+ +

Source: core/emote.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Emote / action text
+  * @version 1.0.0
+  * @description Broadcasts an emote to the current channel
+  * @module emote
+  */
+
+/**
+  * Check and trim string provided by remote client
+  * @param {string} text - Subject string
+  * @private
+  * @todo Move into utility module
+  * @return {string|boolean}
+  */
+const parseText = (text) => {
+  // verifies user input is text
+  if (typeof text !== 'string') {
+    return false;
+  }
+
+  let sanitizedText = text;
+
+  // strip newlines from beginning and end
+  sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, '');
+  // replace 3+ newlines with just 2 newlines
+  sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n');
+
+  return sanitizedText;
+};
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ server, socket, payload }) {
+  // check user input
+  let text = parseText(payload.text);
+
+  if (!text) {
+    // lets not send objects or empty text, yea?
+    return server.police.frisk(socket.address, 8);
+  }
+
+  // check for spam
+  const score = text.length / 83 / 4;
+  if (server.police.frisk(socket.address, score)) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  if (!text.startsWith("'")) {
+    text = ` ${text}`;
+  }
+
+  const newPayload = {
+    cmd: 'emote',
+    nick: socket.nick,
+    userid: socket.userid,
+    text: `@${socket.nick}${text}`,
+    channel: socket.channel, // @todo Multichannel
+  };
+
+  if (socket.trip) {
+    newPayload.trip = socket.trip;
+  }
+
+  // broadcast to channel peers
+  server.broadcast(newPayload, { channel: socket.channel });
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.emoteCheck.bind(this), 30);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * hooks chat commands checking for /me
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function emoteCheck({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (payload.text.startsWith('/me ')) {
+    const input = payload.text.split(' ');
+
+    // If there is no emote target parameter
+    if (input[1] === undefined) {
+      server.reply({
+        cmd: 'warn', // @todo Add numeric error code as `id`
+        text: 'Refer to `/help emote` for instructions on how to use this command.',
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+
+      return false;
+    }
+
+    input.splice(0, 1);
+    const actionText = input.join(' ');
+
+    this.run({
+      core,
+      server,
+      socket,
+      payload: {
+        cmd: 'emote',
+        text: actionText,
+      },
+    });
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "text"
+  * @public
+  * @typedef {Array} emote/requiredData
+  */
+export const requiredData = ['text'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} emote/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'emote',
+  category: 'core',
+  description: 'Broadcasts an emote to the current channel',
+  usage: `
+    API: { cmd: 'emote', text: '<emote/action text>' }
+    Text: /me <emote/action text>`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_help.js.html b/documentation/core_help.js.html new file mode 100644 index 0000000..7a3eaae --- /dev/null +++ b/documentation/core_help.js.html @@ -0,0 +1,185 @@ + + + + + JSDoc: Source: core/help.js + + + + + + + + + + +
+ +

Source: core/help.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Get help
+  * @version 1.0.0
+  * @description Outputs information about the servers current protocol
+  * @module help
+  */
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // check for spam
+  if (server.police.frisk(socket.address, 2)) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // verify user input
+  if (typeof payload.command !== 'undefined' && typeof payload.command !== 'string') {
+    return true;
+  }
+
+  let reply = '';
+  if (typeof payload.command === 'undefined') {
+    reply += '# All commands:\n|Category:|Name:|\n|---:|---|\n';
+
+    const categories = core.commands.categoriesList.sort();
+    for (let i = 0, j = categories.length; i < j; i += 1) {
+      reply += `|${categories[i].replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())}:|`;
+      const catCommands = core.commands.all(categories[i]).sort(
+        (a, b) => a.info.name.localeCompare(b.info.name),
+      );
+      reply += `${catCommands.map((c) => `${c.info.name}`).join(', ')}|\n`;
+    }
+
+    reply += '---\nFor specific help on certain commands, use either:\nText: `/help <command name>`\nAPI: `{cmd: \'help\', command: \'<command name>\'}`';
+  } else {
+    const command = core.commands.get(payload.command);
+
+    if (typeof command === 'undefined') {
+      reply += 'Unknown command';
+    } else {
+      reply += `# ${command.info.name} command:\n| | |\n|---:|---|\n`;
+      reply += `|**Name:**|${command.info.name}|\n`;
+      reply += `|**Aliases:**|${typeof command.info.aliases !== 'undefined' ? command.info.aliases.join(', ') : 'None'}|\n`;
+      reply += `|**Category:**|${command.info.category.replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())}|\n`;
+      reply += `|**Required Parameters:**|${command.requiredData || 'None'}|\n`;
+      // eslint-disable-next-line no-useless-escape
+      reply += `|**Description:**|${command.info.description || '¯\_(ツ)_/¯'}|\n\n`;
+      reply += `**Usage:** ${command.info.usage || command.info.name}`;
+    }
+  }
+
+  // output reply
+  server.reply({
+    cmd: 'info',
+    text: reply,
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.helpCheck.bind(this), 28);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * hooks chat commands checking for /help
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function helpCheck({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (payload.text.startsWith('/help')) {
+    const input = payload.text.substr(1).split(' ', 2);
+
+    this.run({
+      core,
+      server,
+      socket,
+      payload: {
+        cmd: input[0],
+        command: input[1],
+      },
+    });
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} help/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'help',
+  category: 'core',
+  description: 'Outputs information about the servers current protocol',
+  usage: `
+    API: { cmd: 'help', command: '<optional command name>' }
+    Text: /help <optional command name>`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_invite.js.html b/documentation/core_invite.js.html new file mode 100644 index 0000000..7920f80 --- /dev/null +++ b/documentation/core_invite.js.html @@ -0,0 +1,174 @@ + + + + + JSDoc: Source: core/invite.js + + + + + + + + + + +
+ +

Source: core/invite.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Send an invite
+  * @version 1.0.0
+  * @description Sends an invite to the target client with the provided channel, or a random channel
+  * @module invite
+  */
+
+import {
+  findUser,
+} from '../utility/_Channels.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  legacyInviteOut,
+  legacyInviteReply,
+} from '../utility/_LegacyFunctions.js';
+
+/**
+  * Returns the channel that should be invited to.
+  * @param {any} channel
+  * @private
+  * @return {string}
+  */
+export function getChannel(channel = undefined) {
+  if (typeof channel === 'string') {
+    return channel;
+  }
+  return Math.random().toString(36).substr(2, 8);
+}
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // check for spam
+  if (server.police.frisk(socket.address, 2)) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'You are sending invites too fast. Wait a moment before trying again.',
+      id: Errors.Invite.RATELIMIT,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // verify user input
+  // if this is a legacy client add missing params to payload
+  if (socket.hcProtocol === 1) {
+    if (typeof socket.channel === 'undefined' || typeof payload.nick !== 'string') {
+      return true;
+    }
+
+    payload.channel = socket.channel; // eslint-disable-line no-param-reassign
+  } else if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') {
+    return true;
+  }
+
+  // @todo Verify this socket is part of payload.channel - multichannel patch
+  // find target user
+  const targetUser = findUser(server, payload);
+  if (!targetUser) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Could not find user in that channel',
+      id: Errors.Global.UNKNOWN_USER,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // generate common channel
+  const channel = getChannel(payload.to);
+
+  // build invite
+  const outgoingPayload = {
+    cmd: 'invite',
+    channel: socket.channel, // @todo Multichannel
+    from: socket.userid,
+    to: targetUser.userid,
+    inviteChannel: channel,
+  };
+
+  // send invite notice to target client
+  if (targetUser.hcProtocol === 1) {
+    server.reply(legacyInviteOut(outgoingPayload, socket.nick), targetUser);
+  } else {
+    server.reply(outgoingPayload, targetUser);
+  }
+
+  // send invite notice to this client
+  if (socket.hcProtocol === 1) {
+    server.reply(legacyInviteReply(outgoingPayload, targetUser.nick), socket);
+  } else {
+    server.reply(outgoingPayload, socket);
+  }
+
+  // stats are fun
+  core.stats.increment('invites-sent');
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} invite/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'invite',
+  category: 'core',
+  description: 'Sends an invite to the target client with the provided channel, or a random channel.',
+  usage: `
+    API: { cmd: 'invite', nick: '<target nickname>', to: '<optional destination channel>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_join.js.html b/documentation/core_join.js.html new file mode 100644 index 0000000..bba3e25 --- /dev/null +++ b/documentation/core_join.js.html @@ -0,0 +1,323 @@ + + + + + JSDoc: Source: core/join.js + + + + + + + + + + +
+ +

Source: core/join.js

+ + + + + + +
+
+
/* eslint no-param-reassign: 0 */
+/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
+
+/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Join target channel
+  * @version 1.0.0
+  * @description Join the target channel using the supplied nick and password
+  * @module join
+  */
+
+import {
+  getSession,
+} from './session.js';
+import {
+  canJoinChannel,
+  socketInChannel,
+} from '../utility/_Channels.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  upgradeLegacyJoin,
+  legacyLevelToLabel,
+} from '../utility/_LegacyFunctions.js';
+import {
+  verifyNickname,
+  getUserPerms,
+  getUserDetails,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // check for spam
+  if (server.police.frisk(socket.address, 3)) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'You are joining channels too fast. Wait a moment and try again.',
+      id: Errors.Join.RATELIMIT,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // `join` is the legacy entry point, check if it needs to be upgraded
+  if (typeof socket.hcProtocol === 'undefined') {
+    payload = upgradeLegacyJoin(server, socket, payload);
+  }
+
+  // store payload values
+  const { channel, nick, pass } = payload;
+
+  // check if a client is able to join target channel
+  const mayJoin = canJoinChannel(channel, socket);
+  if (mayJoin !== true) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'You may not join that channel.',
+      id: mayJoin,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // calling socket already in a channel
+  // @todo multichannel update, will remove
+  if (typeof socket.channel !== 'undefined') {
+    return server.reply({
+      cmd: 'warn', // @todo Remove this
+      text: 'Joining more than one channel is not currently supported',
+      id: Errors.Join.ALREADY_JOINED,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+  // end todo
+
+  // validates the user input for `nick`
+  if (verifyNickname(nick, socket) !== true) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Nickname must consist of up to 24 letters, numbers, and underscores',
+      id: Errors.Join.INVALID_NICK,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // get trip and level
+  const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel);
+
+  // store the user values
+  const userInfo = {
+    nick,
+    trip,
+    uType: legacyLevelToLabel(level),
+    hash: socket.hash,
+    level,
+    userid: socket.userid,
+    isBot: socket.isBot,
+    color: socket.color,
+    channel,
+  };
+
+  // check if the nickname already exists in the channel
+  const userExists = server.findSockets({
+    channel,
+    nick: (targetNick) => targetNick.toLowerCase() === userInfo.nick.toLowerCase(),
+  });
+
+  if (userExists.length > 0) {
+    // that nickname is already in that channel
+    return server.reply({
+      cmd: 'warn',
+      text: 'Nickname taken',
+      id: Errors.Join.NAME_TAKEN,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // prepare to notify channel peers
+  const newPeerList = server.findSockets({ channel });
+  const nicks = []; /* @legacy */
+  const users = [];
+  const joinAnnouncement = { ...{ cmd: 'onlineAdd' }, ...userInfo };
+
+  // send join announcement and prep online set reply
+  for (let i = 0, l = newPeerList.length; i < l; i += 1) {
+    server.reply(joinAnnouncement, newPeerList[i]);
+
+    nicks.push(newPeerList[i].nick); /* @legacy */
+    users.push({
+      ...{
+        channel,
+        isme: false,
+      },
+      ...getUserDetails(newPeerList[i]),
+    });
+  }
+
+  // store user info
+  socket.nick = userInfo.nick;
+  socket.trip = userInfo.trip;
+  socket.level = userInfo.level;
+  socket.uType = userInfo.uType; /* @legacy */
+  socket.channel = channel; /* @legacy */
+  // @todo multi-channel patch
+  // socket.channels.push(channel);
+  socket.channels = [channel];
+
+  nicks.push(userInfo.nick); /* @legacy */
+  users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo });
+
+  // reply with channel peer list
+  server.reply({
+    cmd: 'onlineSet',
+    nicks, /* @legacy */
+    users,
+    channel, // @todo Multichannel (?)
+  }, socket);
+
+  // update client with new session info
+  server.reply({
+    cmd: 'session',
+    restored: false,
+    token: getSession(socket, core),
+    channels: socket.channels,
+  }, socket);
+
+  // stats are fun
+  core.stats.increment('users-joined');
+
+  return true;
+}
+
+export function restoreJoin({
+  server, socket, channel,
+}) {
+  // check if a client is able to join target channel
+  const mayJoin = canJoinChannel(channel, socket);
+  if (mayJoin !== true) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'You may not join that channel.',
+      id: mayJoin,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // store the user values
+  const userInfo = {
+    nick: socket.nick,
+    trip: socket.trip,
+    uType: legacyLevelToLabel(socket.level),
+    hash: socket.hash,
+    level: socket.level,
+    userid: socket.userid,
+    isBot: socket.isBot,
+    color: socket.color,
+    channel,
+  };
+
+  // prepare to notify channel peers
+  const newPeerList = server.findSockets({ channel });
+  const nicks = []; /* @legacy */
+  const users = [];
+  const joinAnnouncement = { ...{ cmd: 'onlineAdd' }, ...userInfo };
+  // build update notice with new privileges
+  const updateAnnouncement = {
+    ...getUserDetails(socket),
+    ...{
+      cmd: 'updateUser',
+      online: true,
+    },
+  };
+
+  const isDuplicate = socketInChannel(server, channel, socket);
+
+  // send join announcement and prep online set reply
+  for (let i = 0, l = newPeerList.length; i < l; i += 1) {
+    if (isDuplicate) {
+      server.reply(updateAnnouncement, newPeerList[i]);
+    } else {
+      server.reply(joinAnnouncement, newPeerList[i]);
+    }
+
+    nicks.push(newPeerList[i].nick); /* @legacy */
+    users.push({
+      ...{
+        channel,
+        isme: false,
+      },
+      ...getUserDetails(newPeerList[i]),
+    });
+  }
+
+  nicks.push(userInfo.nick); /* @legacy */
+  users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo });
+
+  // reply with channel peer list
+  server.reply({
+    cmd: 'onlineSet',
+    nicks, /* @legacy */
+    users,
+    channel, // @todo Multichannel (?)
+  }, socket);
+
+  socket.channel = channel; /* @legacy */
+  socket.channels.push(channel);
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} join/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'join',
+  category: 'core',
+  description: 'Join the target channel using the supplied nick and password',
+  usage: `
+    API: { cmd: 'join', nick: '<your nickname>', pass: '<optional password>', channel: '<target channel>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_morestats.js.html b/documentation/core_morestats.js.html new file mode 100644 index 0000000..07b3fad --- /dev/null +++ b/documentation/core_morestats.js.html @@ -0,0 +1,215 @@ + + + + + JSDoc: Source: core/morestats.js + + + + + + + + + + +
+ +

Source: core/morestats.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Get stats
+  * @version 1.0.0
+  * @description Sends back current server stats to the calling client
+  * @module morestats
+  */
+
+/**
+  * Format input time into string
+  * @param {Date} time - Subject date
+  * @private
+  * @return {string}
+  */
+const formatTime = (time) => {
+  let seconds = time[0] + time[1] / 1e9;
+
+  let minutes = Math.floor(seconds / 60);
+  seconds %= 60;
+
+  let hours = Math.floor(minutes / 60);
+  minutes %= 60;
+
+  const days = Math.floor(hours / 24);
+  hours %= 24;
+
+  return `${days.toFixed(0)}d ${hours.toFixed(0)}h ${minutes.toFixed(0)}m ${seconds.toFixed(0)}s`;
+};
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ core, server, socket }) {
+  // gather connection and channel count
+  const ips = {};
+  const channels = {};
+  // @todo use public channel flag
+  const publicChanCounts = {
+    lounge: 0,
+    meta: 0,
+    math: 0,
+    physics: 0,
+    chemistry: 0,
+    technology: 0,
+    programming: 0,
+    games: 0,
+    banana: 0,
+    chinese: 0,
+  };
+
+  // @todo code resuage between here and `session`; should share exported function
+  server.clients.forEach((client) => {
+    if (client.channel) {
+      channels[client.channel] = true;
+      ips[client.address] = true;
+      if (typeof publicChanCounts[client.channel] !== 'undefined') {
+        publicChanCounts[client.channel] += 1;
+      }
+    }
+  });
+
+  const uniqueClientCount = Object.keys(ips).length;
+  const uniqueChannels = Object.keys(channels).length;
+  const joins = core.stats.get('users-joined') || 0;
+  const invites = core.stats.get('invites-sent') || 0;
+  const messages = core.stats.get('messages-sent') || 0;
+  const banned = core.stats.get('users-banned') || 0;
+  const kicked = core.stats.get('users-kicked') || 0;
+  const stats = core.stats.get('stats-requested') || 0;
+  const uptime = formatTime(process.hrtime(core.stats.get('start-time')));
+
+  // dispatch info
+  server.reply({
+    cmd: 'info',
+    users: uniqueClientCount,
+    chans: uniqueChannels,
+    joins,
+    invites,
+    messages,
+    banned,
+    kicked,
+    stats,
+    uptime,
+    public: publicChanCounts,
+    text: `current-connections: ${uniqueClientCount}
+current-channels: ${uniqueChannels}
+users-joined: ${joins}
+invites-sent: ${invites}
+messages-sent: ${messages}
+users-banned: ${banned}
+users-kicked: ${kicked}
+stats-requested: ${stats}
+server-uptime: ${uptime}`,
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  // stats are fun
+  core.stats.increment('stats-requested');
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.statsCheck.bind(this), 26);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * hooks chat commands checking for /stats
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function statsCheck({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (payload.text.startsWith('/stats')) {
+    this.run({
+      core,
+      server,
+      socket,
+      payload: {
+        cmd: 'morestats',
+      },
+    });
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} morestats/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'morestats',
+  category: 'core',
+  description: 'Sends back current server stats to the calling client',
+  usage: `
+    API: { cmd: 'morestats' }
+    Text: /stats`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_ping.js.html b/documentation/core_ping.js.html new file mode 100644 index 0000000..9285bc0 --- /dev/null +++ b/documentation/core_ping.js.html @@ -0,0 +1,83 @@ + + + + + JSDoc: Source: core/ping.js + + + + + + + + + + +
+ +

Source: core/ping.js

+ + + + + + +
+
+
/* eslint no-empty-function: 0 */
+
+/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Legacy support module
+  * @version 1.0.0
+  * @description This module is only in place to supress error notices legacy clients may get
+  * @module ping
+  */
+
+/**
+  * Executes when invoked by a remote client
+  * @public
+  * @return {void}
+  */
+export async function run() { }
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} ping/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'ping',
+  category: 'core',
+  description: 'This module is only in place to supress error notices legacy clients may get',
+  usage: 'none',
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_session.js.html b/documentation/core_session.js.html new file mode 100644 index 0000000..4d37721 --- /dev/null +++ b/documentation/core_session.js.html @@ -0,0 +1,244 @@ + + + + + JSDoc: Source: core/session.js + + + + + + + + + + +
+ +

Source: core/session.js

+ + + + + + +
+
+
/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
+
+/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Create or restore session
+  * @version 1.0.0
+  * @description Restore previous state by session or create new session
+  * @module session
+  */
+
+import fs from 'fs';
+import jsonwebtoken from 'jsonwebtoken';
+
+import {
+  verifyNickname,
+} from '../utility/_UAC.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  restoreJoin,
+} from './join.js';
+
+const SessionLocation = './session.key';
+
+/**
+  *
+  * @param {*} socket
+  * @param {*} core
+  * @returns {object}
+  */
+export function getSession(socket, core) {
+  return jsonwebtoken.sign({
+    channel: socket.channel,
+    channels: socket.channels,
+    color: socket.color,
+    isBot: socket.isBot,
+    level: socket.level,
+    nick: socket.nick,
+    trip: socket.trip,
+    userid: socket.userid,
+    uType: socket.uType, /* @legacy */
+    muzzled: socket.muzzled || false,
+    banned: socket.banned || false,
+  }, core.sessionKey, {
+    expiresIn: '7 days',
+  });
+}
+
+/**
+  *
+  * @param {*} server
+  * @param {*} socket
+  * @returns {boolean}
+  */
+function notifyFailure(server, socket) {
+  server.reply({
+    cmd: 'error',
+    id: Errors.Session.BAD_SESSION,
+    text: 'Invalid session',
+  }, socket);
+
+  return false;
+}
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.token === 'undefined') {
+    return notifyFailure(server, socket);
+  }
+
+  let session = false;
+  try {
+    session = jsonwebtoken.verify(payload.token, core.sessionKey);
+  } catch (err) {
+    return notifyFailure(server, socket);
+  }
+
+  // validate session
+  if (typeof session.channel !== 'string') {
+    return notifyFailure(server, socket);
+  }
+
+  if (Array.isArray(session.channels) === false) {
+    return notifyFailure(server, socket);
+  }
+
+  if (typeof session.color !== 'string' && typeof session.color !== 'boolean') {
+    return notifyFailure(server, socket);
+  }
+
+  if (typeof session.isBot !== 'boolean') {
+    return notifyFailure(server, socket);
+  }
+
+  if (typeof session.level !== 'number') {
+    return notifyFailure(server, socket);
+  }
+
+  if (verifyNickname(session.nick) === false) {
+    return notifyFailure(server, socket);
+  }
+
+  if (typeof session.trip !== 'string') {
+    return notifyFailure(server, socket);
+  }
+
+  if (typeof session.userid !== 'number') {
+    return notifyFailure(server, socket);
+  }
+
+  if (typeof session.uType !== 'string') {
+    return notifyFailure(server, socket);
+  }
+
+  if (typeof session.muzzled !== 'boolean') {
+    return notifyFailure(server, socket);
+  }
+
+  if (typeof session.banned !== 'boolean') {
+    return notifyFailure(server, socket);
+  }
+
+  // populate socket info with validated session
+  socket.channels = [];
+  socket.color = session.color;
+  socket.isBot = session.isBot;
+  socket.level = session.level;
+  socket.nick = session.nick;
+  socket.trip = session.trip;
+  socket.userid = session.userid;
+  socket.uType = session.uType; /* @legacy */
+  socket.muzzled = session.muzzled;
+  socket.banned = session.banned;
+
+  socket.hash = server.getSocketHash(socket);
+  socket.hcProtocol = 2;
+
+  // dispatch info
+  server.reply({
+    cmd: 'session',
+    restored: true,
+    token: getSession(socket, core),
+    channels: socket.channels,
+  }, socket);
+
+  for (let i = 0, j = session.channels.length; i < j; i += 1) {
+    restoreJoin({
+      core,
+      server,
+      socket,
+      channel: session.channels[i],
+    }, true);
+  }
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready
+  * @param {Object} core - Reference to core enviroment object
+  * @public
+  * @return {void}
+  */
+export function init(core) {
+  // load the encryption key if required
+  if (typeof core.sessionKey === 'undefined') {
+    core.sessionKey = fs.readFileSync(SessionLocation);
+  }
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} session/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'session',
+  category: 'core',
+  description: 'Restore previous state by session or create new session',
+  usage: "API: { cmd: 'session', id: '<previous session>' }",
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_stats.js.html b/documentation/core_stats.js.html new file mode 100644 index 0000000..1b25125 --- /dev/null +++ b/documentation/core_stats.js.html @@ -0,0 +1,110 @@ + + + + + JSDoc: Source: core/stats.js + + + + + + + + + + +
+ +

Source: core/stats.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Simple stats
+  * @version 1.0.0
+  * @description Sends back legacy server stats to the calling client
+  * @module stats
+  */
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ core, server, socket }) {
+  // gather connection and channel count
+  let ips = {};
+  let channels = {};
+  // for (const client of server.clients) {
+  server.clients.forEach((client) => {
+    if (client.channel) {
+      channels[client.channel] = true;
+      ips[client.address] = true;
+    }
+  });
+
+  const uniqueClientCount = Object.keys(ips).length;
+  const uniqueChannels = Object.keys(channels).length;
+
+  ips = null;
+  channels = null;
+
+  // dispatch info
+  server.reply({
+    cmd: 'info',
+    text: `${uniqueClientCount} unique IPs in ${uniqueChannels} channels`,
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  // stats are fun
+  core.stats.increment('stats-requested');
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} stats/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'stats',
+  category: 'core',
+  description: 'Sends back legacy server stats to the calling client',
+  usage: `
+    API: { cmd: 'stats' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/core_whisper.js.html b/documentation/core_whisper.js.html new file mode 100644 index 0000000..f82308d --- /dev/null +++ b/documentation/core_whisper.js.html @@ -0,0 +1,282 @@ + + + + + JSDoc: Source: core/whisper.js + + + + + + + + + + +
+ +

Source: core/whisper.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Send whisper
+  * @version 1.0.0
+  * @description Display text on target users screen that only they can see
+  * @module whisper
+  * @todo This should be changed to it's own event type, instead of `info`
+        and accept a `userid` rather than `nick`
+  */
+
+import {
+  findUser,
+} from '../utility/_Channels.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  legacyWhisperOut,
+  legacyWhisperReply,
+} from '../utility/_LegacyFunctions.js';
+
+/**
+  * Check and trim string provided by remote client
+  * @param {string} text - Subject string
+  * @private
+  * @todo Move into utility module
+  * @return {string|boolean}
+  */
+const parseText = (text) => {
+  // verifies user input is text
+  if (typeof text !== 'string') {
+    return false;
+  }
+
+  let sanitizedText = text;
+
+  // strip newlines from beginning and end
+  sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, '');
+  // replace 3+ newlines with just 2 newlines
+  sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n');
+
+  return sanitizedText;
+};
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ server, socket, payload }) {
+  // if this is a legacy client add missing params to payload
+  if (socket.hcProtocol === 1) {
+    payload.channel = socket.channel; // eslint-disable-line no-param-reassign
+  }
+
+  // verify user input
+  const text = parseText(payload.text);
+
+  if (!text) {
+    // lets not send objects or empty text, yea?
+    return server.police.frisk(socket.address, 13);
+  }
+
+  // check for spam
+  const score = text.length / 83 / 4;
+  if (server.police.frisk(socket.address, score)) {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  const targetUser = findUser(server, payload);
+  if (!targetUser) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Could not find user in that channel',
+      id: Errors.Global.UNKNOWN_USER,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  const outgoingPayload = {
+    cmd: 'whisper',
+    channel: socket.channel, // @todo Multichannel
+    from: socket.userid,
+    to: targetUser.userid,
+    text,
+  };
+
+  // send invite notice to target client
+  if (targetUser.hcProtocol === 1) {
+    server.reply(legacyWhisperOut(outgoingPayload, socket), targetUser);
+  } else {
+    server.reply(outgoingPayload, targetUser);
+  }
+
+  // send invite notice to this client
+  if (socket.hcProtocol === 1) {
+    server.reply(legacyWhisperReply(outgoingPayload, targetUser.nick), socket);
+  } else {
+    server.reply(outgoingPayload, socket);
+  }
+
+  targetUser.whisperReply = socket.nick;
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.whisperCheck.bind(this), 20);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * hooks chat commands checking for /whisper
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function whisperCheck({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (payload.text.startsWith('/whisper ') || payload.text.startsWith('/w ')) {
+    const input = payload.text.split(' ');
+
+    // If there is no nickname target parameter
+    if (!input[1]) {
+      server.reply({
+        cmd: 'warn', // @todo Add numeric error code as `id`
+        text: 'Refer to `/help whisper` for instructions on how to use this command.',
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+
+      return false;
+    }
+
+    const target = input[1].replace(/@/g, '');
+    input.splice(0, 2);
+    const whisperText = input.join(' ');
+
+    this.run({
+      core,
+      server,
+      socket,
+      payload: {
+        cmd: 'whisper',
+        channel: socket.channel, // @todo Multichannel
+        nick: target,
+        text: whisperText,
+      },
+    });
+
+    return false;
+  }
+
+  if (payload.text.startsWith('/reply ') || payload.text.startsWith('/r ')) {
+    if (typeof socket.whisperReply === 'undefined') {
+      server.reply({
+        cmd: 'warn', // @todo Add numeric error code as `id`
+        text: 'Cannot reply to nobody',
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+
+      return false;
+    }
+
+    const input = payload.text.split(' ');
+    input.splice(0, 1);
+    const whisperText = input.join(' ');
+
+    this.run({
+      core,
+      server,
+      socket,
+      payload: {
+        cmd: 'whisper',
+        nick: socket.whisperReply,
+        channel: socket.channel, // @todo Multichannel
+        text: whisperText,
+      },
+    });
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "nick", "text"
+  * @public
+  * @typedef {Array} whisper/requiredData
+  */
+export const requiredData = ['nick', 'text'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} whisper/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'whisper',
+  category: 'core',
+  description: 'Display text on target users screen that only they can see',
+  usage: `
+    API: { cmd: 'whisper', nick: '<target name>', text: '<text to whisper>' }
+    Text: /whisper <target name> <text to whisper>
+    Text: /w <target name> <text to whisper>
+    Alt Text: /reply <text to whisper, this will auto reply to the last person who whispered to you>
+    Alt Text: /r <text to whisper, this will auto reply to the last person who whispered to you>`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/fonts/OpenSans-Bold-webfont.eot b/documentation/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..5d20d916338a5890a033952e2e07ba7380f5a7d3 GIT binary patch literal 19544 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 literal 0 HcmV?d00001 diff --git a/documentation/fonts/OpenSans-Bold-webfont.svg b/documentation/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..3ed7be4 --- /dev/null +++ b/documentation/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/fonts/OpenSans-Bold-webfont.woff b/documentation/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..1205787b0ed50db71ebd4f8a7f85d106721ff258 GIT binary patch literal 22432 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 ig3W + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/fonts/OpenSans-BoldItalic-webfont.woff b/documentation/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..ed760c0628b6a0026041f5b8bba466a0471fd2e0 GIT binary patch literal 23048 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/fonts/OpenSans-Italic-webfont.woff b/documentation/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..ff652e64356b538c001423b6aedefcf1ee66cd17 GIT binary patch literal 23188 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 literal 0 HcmV?d00001 diff --git a/documentation/fonts/OpenSans-Light-webfont.svg b/documentation/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..11a472c --- /dev/null +++ b/documentation/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/fonts/OpenSans-Light-webfont.woff b/documentation/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..e786074813a27d0a7a249047832988d5bf0fe756 GIT binary patch literal 22248 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 literal 0 HcmV?d00001 diff --git a/documentation/fonts/OpenSans-LightItalic-webfont.eot b/documentation/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..8f445929ffb03b50e98c2a2f7d831a0cb1b276a2 GIT binary patch literal 20535 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 Z%0#`NexefPFV?Xj51H#Y#AC7WXn+Jg($4?@ literal 0 HcmV?d00001 diff --git a/documentation/fonts/OpenSans-LightItalic-webfont.svg b/documentation/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..431d7e3 --- /dev/null +++ b/documentation/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/fonts/OpenSans-LightItalic-webfont.woff b/documentation/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..43e8b9e6cc061ff17fd2903075cbde12715512b3 GIT binary patch literal 23400 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
+ +

Home

+ + + + + + + + +

+ + + + + + + + + + + + + + + +
+

hack.chat

+

hack.chat is a minimal, distraction-free, accountless, logless, disappearing chat service which is easily deployable as your own service. The current client comes bundled with LaTeX rendering provided by KaTeX and code syntax highlighting provided by highlight.js.

+

A list of software developed for the hack.chat framework can be found at the 3rd party software list repository. This includes bots, clients, docker containers, etc.

+

This is a backwards compatible continuation of the work by Andrew Belt. The server code has been updated to ES6 along with several new features including new commands and hot-reload of the commands/protocol. There is also documentation.

+

Installation

+

Prerequisites

+ +

Developer Installation

+
    +
  1. Clone the repository: git clone https://github.com/hack-chat/main.git
  2. +
  3. Change the directory: cd main
  4. +
  5. Install the dependencies: npm install
  6. +
  7. Launch: npm start
  8. +
+

Live Deployment Installation

+

See DEPLOY.md

+

Contributing

+
    +
  • Use two space indents.
  • +
  • Name files in camelCase.
  • +
+

Credits

+ +

License

+

This project is licensed under the MIT License.

+
+ + + + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/internal_disconnect.js.html b/documentation/internal_disconnect.js.html new file mode 100644 index 0000000..35dd4b8 --- /dev/null +++ b/documentation/internal_disconnect.js.html @@ -0,0 +1,117 @@ + + + + + JSDoc: Source: internal/disconnect.js + + + + + + + + + + +
+ +

Source: internal/disconnect.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Disconnection handler
+  * @version 1.0.0
+  * @description The server invokes this module each time a websocket connection is disconnected
+  * @module disconnect
+  */
+
+import {
+  socketInChannel,
+} from '../utility/_Channels.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ server, socket, payload }) {
+  if (payload.cmdKey !== server.cmdKey) {
+    // internal command attempt by client, increase rate limit chance and ignore
+    return server.police.frisk(socket.address, 20);
+  }
+
+  // send leave notice to client peers
+  // @todo Multichannel update
+  if (socket.channel) {
+    const isDuplicate = socketInChannel(server, socket.channel, socket);
+
+    if (isDuplicate === false) {
+      server.broadcast({
+        cmd: 'onlineRemove',
+        nick: socket.nick,
+      }, { channel: socket.channel });
+    }
+  }
+
+  // commit close just in case
+  socket.terminate();
+
+  return true;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "cmdKey"
+  * @public
+  * @typedef {Array} disconnect/requiredData
+  */
+export const requiredData = ['cmdKey'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} disconnect/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'disconnect',
+  category: 'internal',
+  description: 'Internally used to relay disconnect events to clients',
+  usage: 'Internal Use Only',
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/internal_socketreply.js.html b/documentation/internal_socketreply.js.html new file mode 100644 index 0000000..f1f6455 --- /dev/null +++ b/documentation/internal_socketreply.js.html @@ -0,0 +1,102 @@ + + + + + JSDoc: Source: internal/socketreply.js + + + + + + + + + + +
+ +

Source: internal/socketreply.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Bridge warning events to a user
+  * @version 1.0.0
+  * @description If a warning occurs within the server, this module will relay the warning to the
+  *   client
+  * @module socketreply
+  */
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ server, socket, payload }) {
+  if (payload.cmdKey !== server.cmdKey) {
+    // internal command attempt by client, increase rate limit chance and ignore
+    return server.police.frisk(socket.address, 20);
+  }
+
+  // send warning to target socket
+  return server.reply({
+    cmd: 'warn',
+    text: payload.text,
+  }, socket);
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "cmdKey", "text"
+  * @public
+  * @typedef {Array} socketreply/requiredData
+  */
+export const requiredData = ['cmdKey', 'text'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} socketreply/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'socketreply',
+  category: 'internal',
+  description: 'Internally used to relay warnings to clients',
+  usage: 'Internal Use Only',
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/mod_ban.js.html b/documentation/mod_ban.js.html new file mode 100644 index 0000000..9471b5e --- /dev/null +++ b/documentation/mod_ban.js.html @@ -0,0 +1,166 @@ + + + + + JSDoc: Source: mod/ban.js + + + + + + + + + + +
+ +

Source: mod/ban.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Ban a user
+  * @version 1.0.0
+  * @description Bans target user by name
+  * @module ban
+  */
+
+import {
+  isModerator,
+  getUserDetails,
+  levels,
+} from '../utility/_UAC.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  findUser,
+} from '../utility/_Channels.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket.address, 10);
+  }
+
+  // check user input
+  if (socket.hcProtocol === 1) {
+    if (typeof payload.nick !== 'string') {
+      return false;
+    }
+
+    payload.channel = socket.channel; // eslint-disable-line no-param-reassign
+  } else if (typeof payload.userid !== 'number') {
+    return false;
+  }
+
+  // find target user
+  const targetUser = findUser(server, payload);
+  if (!targetUser) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Could not find user in that channel',
+      id: Errors.Global.UNKNOWN_USER,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+  const targetNick = targetUser.nick;
+
+  // i guess banning mods or admins isn't the best idea?
+  if (targetUser.level >= socket.level) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Cannot ban other users of the same level, how rude',
+      id: Errors.Global.PERMISSION,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // commit arrest record
+  server.police.arrest(targetUser.address, targetUser.hash);
+
+  console.log(`${socket.nick} [${socket.trip}] banned ${targetNick} in ${socket.channel}`);
+
+  // notify normal users
+  server.broadcast({
+    cmd: 'info',
+    text: `Banned ${targetNick}`,
+    user: getUserDetails(targetUser),
+    channel: socket.channel, // @todo Multichannel
+  }, { channel: socket.channel, level: (level) => level < levels.moderator });
+
+  // notify mods
+  server.broadcast({
+    cmd: 'info',
+    text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${targetUser.hash}`,
+    channel: socket.channel, // @todo Multichannel
+    inChannel: payload.channel,
+    user: getUserDetails(targetUser),
+    banner: getUserDetails(socket),
+  }, { level: isModerator });
+
+  // force connection closed
+  targetUser.terminate();
+
+  // stats are fun
+  core.stats.increment('users-banned');
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} ban/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'ban',
+  category: 'moderators',
+  description: 'Bans target user by name',
+  usage: `
+    API: { cmd: 'ban', nick: '<target nickname>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/mod_dumb.js.html b/documentation/mod_dumb.js.html new file mode 100644 index 0000000..f197c42 --- /dev/null +++ b/documentation/mod_dumb.js.html @@ -0,0 +1,424 @@ + + + + + JSDoc: Source: mod/dumb.js + + + + + + + + + + +
+ +

Source: mod/dumb.js

+ + + + + + +
+
+
/* eslint no-param-reassign: 0 */
+/* eslint no-multi-assign: 0 */
+
+/**
+  * @author OpSimple ( https://github.com/OpSimple )
+  * @summary Muzzle a user
+  * @version 1.0.0
+  * @description Globally shadow mute a connection. Optional allies array will see muted messages.
+  * @module dumb
+  */
+
+import {
+  isModerator,
+} from '../utility/_UAC.js';
+import {
+  findUser,
+} from '../utility/_Channels.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  legacyInviteReply,
+  legacyWhisperReply,
+} from '../utility/_LegacyFunctions.js';
+
+/**
+  * Returns the channel that should be invited to.
+  * @param {any} channel
+  * @private
+  * @return {string}
+  */
+export function getChannel(channel = undefined) {
+  if (typeof channel === 'string') {
+    return channel;
+  }
+  return Math.random().toString(36).substr(2, 8);
+}
+
+/**
+  * Check and trim string provided by remote client
+  * @param {string} text - Subject string
+  * @private
+  * @todo Move into utility module
+  * @return {string|boolean}
+  */
+const parseText = (text) => {
+  // verifies user input is text
+  if (typeof text !== 'string') {
+    return false;
+  }
+
+  let sanitizedText = text;
+
+  // strip newlines from beginning and end
+  sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, '');
+  // replace 3+ newlines with just 2 newlines
+  sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n');
+
+  return sanitizedText;
+};
+
+/**
+  * Automatically executes once after server is ready
+  * @param {Object} core - Reference to core enviroment object
+  * @public
+  * @return {void}
+  */
+export function init(core) {
+  if (typeof core.muzzledHashes === 'undefined') {
+    core.muzzledHashes = {};
+  }
+}
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket.address, 10);
+  }
+
+  // check user input
+  if (socket.hcProtocol === 1) {
+    if (typeof payload.nick !== 'string') {
+      return true;
+    }
+
+    payload.channel = socket.channel;
+  } else if (typeof payload.userid !== 'number') {
+    return true;
+  }
+
+  // find target user
+  const targetUser = findUser(server, payload);
+
+  if (!targetUser) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Could not find user in that channel',
+      id: Errors.Global.UNKNOWN_USER,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // likely dont need this, muting mods and admins is fine
+  if (targetUser.level >= socket.level) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'This trick wont work on users of the same level',
+      id: Errors.Global.PERMISSION,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // store hash in mute list
+  const record = core.muzzledHashes[targetUser.hash] = {
+    dumb: true,
+  };
+
+  // store allies if needed
+  if (payload.allies && Array.isArray(payload.allies)) {
+    record.allies = payload.allies;
+  }
+
+  // notify mods
+  server.broadcast({
+    cmd: 'info',
+    text: `${socket.nick}#${socket.trip} muzzled ${targetUser.nick} in ${payload.channel}, userhash: ${targetUser.hash}`,
+    channel: false, // @todo Multichannel, false for global
+  }, { level: isModerator });
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.chatCheck.bind(this), 10);
+  server.registerHook('in', 'invite', this.inviteCheck.bind(this), 10);
+  server.registerHook('in', 'whisper', this.whisperCheck.bind(this), 10);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * hook incoming chat commands, shadow-prevent chat if they are muzzled
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function chatCheck({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (core.muzzledHashes[socket.hash]) {
+    // build fake chat payload
+    const outgoingPayload = {
+      cmd: 'chat',
+      nick: socket.nick, /* @legacy */
+      uType: socket.uType, /* @legacy */
+      userid: socket.userid,
+      channel: socket.channel,
+      text: payload.text,
+      level: socket.level,
+    };
+
+    if (socket.trip) {
+      outgoingPayload.trip = socket.trip;
+    }
+
+    if (socket.color) {
+      outgoingPayload.color = socket.color;
+    }
+
+    // broadcast to any duplicate connections in channel
+    server.broadcast(outgoingPayload, { channel: socket.channel, hash: socket.hash });
+
+    // broadcast to allies, if any
+    if (core.muzzledHashes[socket.hash].allies) {
+      server.broadcast(
+        outgoingPayload,
+        {
+          channel: socket.channel,
+          nick: core.muzzledHashes[socket.hash].allies,
+        },
+      );
+    }
+
+    /**
+      * Blanket "spam" protection.
+      * May expose the ratelimiting lines from `chat` and use that
+      * @todo one day #lazydev
+      */
+    server.police.frisk(socket.address, 9);
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * shadow-prevent all invites from muzzled users
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function inviteCheck({
+  core, server, socket, payload,
+}) {
+  if (core.muzzledHashes[socket.hash]) {
+    // check for spam
+    if (server.police.frisk(socket.address, 2)) {
+      return server.reply({
+        cmd: 'warn',
+        text: 'You are sending invites too fast. Wait a moment before trying again.',
+        id: Errors.Invite.RATELIMIT,
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+    }
+
+    // verify user input
+    // if this is a legacy client add missing params to payload
+    if (socket.hcProtocol === 1) {
+      if (typeof socket.channel === 'undefined' || typeof payload.nick !== 'string') {
+        return true;
+      }
+
+      payload.channel = socket.channel; // eslint-disable-line no-param-reassign
+    } else if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') {
+      return true;
+    }
+
+    // @todo Verify this socket is part of payload.channel - multichannel patch
+    // find target user
+    const targetUser = findUser(server, payload);
+    if (!targetUser) {
+      return server.reply({
+        cmd: 'warn',
+        text: 'Could not find user in that channel',
+        id: Errors.Global.UNKNOWN_USER,
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+    }
+
+    // generate common channel
+    const channel = getChannel(payload.to);
+
+    // build invite
+    const outgoingPayload = {
+      cmd: 'invite',
+      channel: socket.channel, // @todo Multichannel
+      from: socket.userid,
+      to: targetUser.userid,
+      inviteChannel: channel,
+    };
+
+    // send invite notice to this client
+    if (socket.hcProtocol === 1) {
+      server.reply(legacyInviteReply(outgoingPayload, targetUser.nick), socket);
+    } else {
+      server.reply(outgoingPayload, socket);
+    }
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * shadow-prevent all whispers from muzzled users
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function whisperCheck({
+  core, server, socket, payload,
+}) {
+  if (core.muzzledHashes[socket.hash]) {
+    // if this is a legacy client add missing params to payload
+    if (socket.hcProtocol === 1) {
+      payload.channel = socket.channel; // eslint-disable-line no-param-reassign
+    }
+
+    // verify user input
+    const text = parseText(payload.text);
+
+    if (!text) {
+      // lets not send objects or empty text, yea?
+      return server.police.frisk(socket.address, 13);
+    }
+
+    // check for spam
+    const score = text.length / 83 / 4;
+    if (server.police.frisk(socket.address, score)) {
+      return server.reply({
+        cmd: 'warn', // @todo Add numeric error code as `id`
+        text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+    }
+
+    const targetUser = findUser(server, payload);
+    if (!targetUser) {
+      return server.reply({
+        cmd: 'warn',
+        text: 'Could not find user in that channel',
+        id: Errors.Global.UNKNOWN_USER,
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+    }
+
+    const outgoingPayload = {
+      cmd: 'whisper',
+      channel: socket.channel, // @todo Multichannel
+      from: socket.userid,
+      to: targetUser.userid,
+      text,
+    };
+
+    // send invite notice to this client
+    if (socket.hcProtocol === 1) {
+      server.reply(legacyWhisperReply(outgoingPayload, targetUser.nick), socket);
+    } else {
+      server.reply(outgoingPayload, socket);
+    }
+
+    targetUser.whisperReply = socket.nick;
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} dumb/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'dumb',
+  category: 'moderators',
+  description: 'Globally shadow mute a connection. Optional allies array will see muted messages.',
+  aliases: ['muzzle', 'mute'],
+  usage: `
+    API: { cmd: 'dumb', nick: '<target nick>', allies: ['<optional nick array>', ...] }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/mod_forcecolor.js.html b/documentation/mod_forcecolor.js.html new file mode 100644 index 0000000..232b4e5 --- /dev/null +++ b/documentation/mod_forcecolor.js.html @@ -0,0 +1,250 @@ + + + + + JSDoc: Source: mod/forcecolor.js + + + + + + + + + + +
+ +

Source: mod/forcecolor.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Color a user
+  * @version 1.0.0
+  * @description Forces a user nick to become a certain color
+  * @module forcecolor
+  */
+
+import {
+  isModerator,
+  getUserDetails,
+} from '../utility/_UAC.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  findUser,
+} from '../utility/_Channels.js';
+
+/**
+  * Validate a string as a valid hex color string
+  * @param {string} color - Color string to validate
+  * @private
+  * @todo Move into utility module
+  * @return {boolean}
+  */
+const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color);
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket.address, 10);
+  }
+
+  const { channel } = socket;
+  if (typeof payload.channel === 'undefined') {
+    payload.channel = channel;
+  }
+
+  // check user input
+  if (typeof payload.nick !== 'string') {
+    return true;
+  }
+
+  if (typeof payload.color !== 'string') {
+    return true;
+  }
+
+  // make sure requested nickname meets standards
+  const newColor = payload.color.trim().toUpperCase().replace(/#/g, '');
+  if (newColor !== 'RESET' && !verifyColor(newColor)) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Invalid color! Color must be in hex value',
+      channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // find target user
+  const targetUser = findUser(server, payload);
+  if (!targetUser) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Could not find user in that channel',
+      id: Errors.Global.UNKNOWN_USER,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // TODO: Change this uType to use level / uac
+  // i guess coloring mods or admins isn't the best idea?
+  if (targetUser.uType !== 'user') {
+    return true;
+  }
+
+  if (newColor === 'RESET') {
+    targetUser.color = false;
+  } else {
+    targetUser.color = newColor;
+  }
+
+  // build update notice with new color
+  const updateNotice = {
+    ...getUserDetails(targetUser),
+    ...{
+      cmd: 'updateUser',
+      channel: socket.channel, // @todo Multichannel
+    },
+  };
+
+  // notify channel that the user has changed their name
+  // @todo this should be sent to every channel the user is in (multichannel)
+  server.broadcast(updateNotice, { channel: socket.channel });
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.colorCheck.bind(this), 20);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * hooks chat commands checking for /forcecolor
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {{Object|boolean|string}} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function colorCheck({
+  core, server, socket, payload,
+}) {
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (payload.text.startsWith('/forcecolor ')) {
+    const input = payload.text.split(' ');
+
+    // If there is no nickname target parameter
+    if (input[1] === undefined) {
+      server.reply({
+        cmd: 'warn',
+        text: 'Refer to `/help forcecolor` for instructions on how to use this command.',
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+
+      return false;
+    }
+
+    if (input[2] === undefined) {
+      server.reply({
+        cmd: 'warn',
+        text: 'Refer to `/help forcecolor` for instructions on how to use this command.',
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+
+      return false;
+    }
+
+    const target = input[1].replace(/@/g, '');
+
+    this.run({
+      core,
+      server,
+      socket,
+      payload: {
+        cmd: 'forcecolor',
+        nick: target,
+        color: input[2],
+      },
+    });
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "nick", "color"
+  * @public
+  * @typedef {Array} forcecolor/requiredData
+  */
+export const requiredData = ['nick', 'color'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} forcecolor/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'forcecolor',
+  category: 'moderators',
+  description: 'Forces a user nick to become a certain color',
+  usage: `
+    API: { cmd: 'forcecolor', nick: '<target nick>', color: '<color as hex>' }
+Text: /forcecolor <target nick> <color as hex>`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/mod_kick.js.html b/documentation/mod_kick.js.html new file mode 100644 index 0000000..650b684 --- /dev/null +++ b/documentation/mod_kick.js.html @@ -0,0 +1,203 @@ + + + + + JSDoc: Source: mod/kick.js + + + + + + + + + + +
+ +

Source: mod/kick.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Give da boot
+  * @version 1.0.0
+  * @description Silently forces target client(s) into another channel
+  * @module kick
+  */
+
+import {
+  isModerator,
+  levels,
+  getUserDetails,
+} from '../utility/_UAC.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  findUsers,
+} from '../utility/_Channels.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket.address, 10);
+  }
+
+  // check user input
+  if (socket.hcProtocol === 1) {
+    if (typeof payload.nick !== 'string') {
+      if (typeof payload.nick !== 'object' && !Array.isArray(payload.nick)) {
+        return true;
+      }
+    }
+
+    payload.channel = socket.channel; // eslint-disable-line no-param-reassign
+  } else if (typeof payload.userid !== 'number') {
+    // @todo create multi-ban ui
+    if (typeof payload.userid !== 'object' && !Array.isArray(payload.userid)) {
+      return true;
+    }
+  }
+
+  // find target user(s)
+  const badClients = findUsers(server, payload);
+  if (badClients.length === 0) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Could not find user(s) in that channel',
+      id: Errors.Global.UNKNOWN_USER,
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // check if found targets are kickable, add them to the list if they are
+  const kicked = [];
+  for (let i = 0, j = badClients.length; i < j; i += 1) {
+    if (badClients[i].level >= socket.level) {
+      server.reply({
+        cmd: 'warn',
+        text: 'Cannot kick other users with the same level, how rude',
+        id: Errors.Global.PERMISSION,
+        channel: socket.channel, // @todo Multichannel
+      }, socket);
+    } else {
+      kicked.push(badClients[i]);
+    }
+  }
+
+  if (kicked.length === 0) {
+    return true;
+  }
+
+  let destChannel;
+  if (typeof payload.to === 'string' && !!payload.to.trim()) {
+    destChannel = payload.to;
+  } else {
+    destChannel = Math.random().toString(36).substr(2, 8);
+  }
+
+  // Announce the kicked clients arrival in destChannel and that they were kicked
+  // Before they arrive, so they don't see they got moved
+  for (let i = 0; i < kicked.length; i += 1) {
+    server.broadcast({
+      ...getUserDetails(kicked[i]),
+      ...{
+        cmd: 'onlineAdd',
+        channel: destChannel, // @todo Multichannel
+      },
+    }, { channel: destChannel });
+  }
+
+  // Move all kicked clients to the new channel
+  for (let i = 0; i < kicked.length; i += 1) {
+    // @todo multi-channel update
+    kicked[i].channel = destChannel;
+
+    server.broadcast({
+      cmd: 'info',
+      text: `${kicked[i].nick} was banished to ?${destChannel}`,
+      channel: socket.channel, // @todo Multichannel
+    }, { channel: socket.channel, level: isModerator });
+
+    console.log(`${socket.nick} [${socket.trip}] kicked ${kicked[i].nick} in ${socket.channel} to ${destChannel} `);
+  }
+
+  // broadcast client leave event
+  for (let i = 0, j = kicked.length; i < j; i += 1) {
+    server.broadcast({
+      cmd: 'onlineRemove',
+      userid: kicked[i].userid,
+      nick: kicked[i].nick,
+      channel: socket.channel, // @todo Multichannel
+    }, { channel: socket.channel });
+  }
+
+  // publicly broadcast kick event
+  server.broadcast({
+    cmd: 'info',
+    text: `Kicked ${kicked.map((k) => k.nick).join(', ')}`,
+    channel: socket.channel, // @todo Multichannel
+  }, { channel: socket.channel, level: (level) => level < levels.moderator });
+
+  // stats are fun
+  core.stats.increment('users-kicked', kicked.length);
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} kick/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'kick',
+  category: 'moderators',
+  description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings',
+  usage: `
+    API: { cmd: 'kick', nick: '<target nick>', to: '<optional target channel>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/mod_speak.js.html b/documentation/mod_speak.js.html new file mode 100644 index 0000000..c9566c7 --- /dev/null +++ b/documentation/mod_speak.js.html @@ -0,0 +1,157 @@ + + + + + JSDoc: Source: mod/speak.js + + + + + + + + + + +
+ +

Source: mod/speak.js

+ + + + + + +
+
+
/* eslint no-param-reassign: 0 */
+
+/**
+  * @author OpSimple ( https://github.com/OpSimple )
+  * @summary Unmuzzle a user
+  * @version 1.0.0
+  * @description Pardon a dumb user to be able to speak again
+  * @module speak
+  */
+
+import {
+  isModerator,
+} from '../utility/_UAC.js';
+
+/**
+  * Automatically executes once after server is ready
+  * @param {Object} core - Reference to core enviroment object
+  * @public
+  * @return {void}
+  */
+export function init(core) {
+  if (typeof core.muzzledHashes === 'undefined') {
+    core.muzzledHashes = {};
+  }
+}
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket.address, 10);
+  }
+
+  // check user input
+  if (typeof payload.ip !== 'string' && typeof payload.hash !== 'string') {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: "hash:'targethash' or ip:'1.2.3.4' is required",
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  if (typeof payload.ip === 'string') {
+    if (payload.ip === '*') {
+      core.muzzledHashes = {};
+
+      return server.broadcast({
+        cmd: 'info',
+        text: `${socket.nick} unmuzzled all users`,
+        channel: false, // @todo Multichannel, false for global
+      }, { level: isModerator });
+    }
+  } else if (payload.hash === '*') {
+    core.muzzledHashes = {};
+
+    return server.broadcast({
+      cmd: 'info',
+      text: `${socket.nick} unmuzzled all users`,
+      channel: false, // @todo Multichannel, false for global
+    }, { level: isModerator });
+  }
+
+  // find target & remove mute status
+  let target;
+  if (typeof payload.ip === 'string') {
+    target = server.getSocketHash(payload.ip);
+  } else {
+    target = payload.hash;
+  }
+
+  delete core.muzzledHashes[target];
+
+  // notify mods
+  server.broadcast({
+    cmd: 'info',
+    text: `${socket.nick}#${socket.trip} unmuzzled : ${target}`,
+    channel: false, // @todo Multichannel, false for global
+  }, { level: isModerator });
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} speak/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'speak',
+  category: 'moderators',
+  description: 'Pardon a dumb user to be able to speak again',
+  aliases: ['unmuzzle', 'unmute'],
+  usage: `
+    API: { cmd: 'speak', ip/hash: '<target ip or hash' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/mod_unban.js.html b/documentation/mod_unban.js.html new file mode 100644 index 0000000..1ed956a --- /dev/null +++ b/documentation/mod_unban.js.html @@ -0,0 +1,142 @@ + + + + + JSDoc: Source: mod/unban.js + + + + + + + + + + +
+ +

Source: mod/unban.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Unban a user
+  * @version 1.0.0
+  * @description Un-bans target user by ip or hash
+  * @module unban
+  */
+
+import {
+  isModerator,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket.address, 10);
+  }
+
+  // check user input
+  if (typeof payload.ip !== 'string' && typeof payload.hash !== 'string') {
+    return server.reply({
+      cmd: 'warn', // @todo Add numeric error code as `id`
+      text: "hash:'targethash' or ip:'1.2.3.4' is required",
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // find target
+  let mode;
+  let target;
+  if (typeof payload.ip === 'string') {
+    mode = 'ip';
+    target = payload.ip;
+  } else {
+    mode = 'hash';
+    target = payload.hash;
+  }
+
+  // remove arrest record
+  server.police.pardon(target);
+
+  // mask ip if used
+  if (mode === 'ip') {
+    target = server.getSocketHash(target);
+  }
+  console.log(`${socket.nick} [${socket.trip}] unbanned ${target} in ${socket.channel}`);
+
+  // reply with success
+  server.reply({
+    cmd: 'info',
+    text: `Unbanned ${target}`,
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  // notify mods
+  server.broadcast({
+    cmd: 'info',
+    text: `${socket.nick}#${socket.trip} unbanned: ${target}`,
+    channel: false, // @todo Multichannel, false for global
+  }, { level: isModerator });
+
+  // stats are fun
+  core.stats.decrement('users-banned');
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} unban/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'unban',
+  category: 'moderators',
+  description: 'Un-bans target user by ip or hash',
+  usage: `
+    API: { cmd: 'unban', ip/hash: '<target ip or hash>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/mod_unbanall.js.html b/documentation/mod_unbanall.js.html new file mode 100644 index 0000000..8e4c416 --- /dev/null +++ b/documentation/mod_unbanall.js.html @@ -0,0 +1,115 @@ + + + + + JSDoc: Source: mod/unbanall.js + + + + + + + + + + +
+ +

Source: mod/unbanall.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Released them from the void
+  * @version 1.0.0
+  * @description Clears all banned ip addresses
+  * @module unbanall
+  */
+
+import {
+  isModerator,
+} from '../utility/_UAC.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({ core, server, socket }) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket.address, 10);
+  }
+
+  // remove arrest records
+  server.police.clear();
+
+  core.stats.set('users-banned', 0);
+
+  console.log(`${socket.nick} [${socket.trip}] unbanned all`);
+
+  // reply with success
+  server.reply({
+    cmd: 'info',
+    text: 'Unbanned all ip addresses',
+    channel: socket.channel, // @todo Multichannel
+  }, socket);
+
+  // notify mods
+  server.broadcast({
+    cmd: 'info',
+    text: `${socket.nick}#${socket.trip} unbanned all ip addresses`,
+    channel: false, // @todo Multichannel, false for global
+  }, { level: isModerator });
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} unbanall/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'unbanall',
+  category: 'moderators',
+  description: 'Clears all banned ip addresses',
+  usage: `
+    API: { cmd: 'unbanall' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + diff --git a/documentation/module-addmod.html b/documentation/module-addmod.html new file mode 100644 index 0000000..1e4b182 --- /dev/null +++ b/documentation/module-addmod.html @@ -0,0 +1,604 @@ + + + + + JSDoc: Module: addmod + + + + + + + + + + +
+ +

Module: addmod

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Adds target trip to the config as a mod and upgrades the socket type
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

addmod/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

addmod/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"trip" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-ban.html b/documentation/module-ban.html new file mode 100644 index 0000000..bf7061d --- /dev/null +++ b/documentation/module-ban.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: ban + + + + + + + + + + +
+ +

Module: ban

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Bans target user by name
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

ban/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-changecolor.html b/documentation/module-changecolor.html new file mode 100644 index 0000000..337cb77 --- /dev/null +++ b/documentation/module-changecolor.html @@ -0,0 +1,902 @@ + + + + + JSDoc: Module: changecolor + + + + + + + + + + +
+ +

Module: changecolor

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Allows calling client to change their nickname color
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) colorCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

changecolor/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

changecolor/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"color" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-changenick.html b/documentation/module-changenick.html new file mode 100644 index 0000000..10b4082 --- /dev/null +++ b/documentation/module-changenick.html @@ -0,0 +1,902 @@ + + + + + JSDoc: Module: changenick + + + + + + + + + + +
+ +

Module: changenick

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Allows calling client to change their current nickname
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) nickCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

changenick/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

changenick/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"nick" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-chat.html b/documentation/module-chat.html new file mode 100644 index 0000000..2df83e7 --- /dev/null +++ b/documentation/module-chat.html @@ -0,0 +1,1047 @@ + + + + + JSDoc: Module: chat + + + + + + + + + + +
+ +

Module: chat

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Broadcasts passed `text` field to the calling users channel
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) commandCheckIn(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +checks for miscellaneous '/' based commands +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) finalCmdCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +assumes a failed chat command invocation and will reject with notice +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

chat/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

chat/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"text" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-disconnect.html b/documentation/module-disconnect.html new file mode 100644 index 0000000..46e4209 --- /dev/null +++ b/documentation/module-disconnect.html @@ -0,0 +1,604 @@ + + + + + JSDoc: Module: disconnect + + + + + + + + + + +
+ +

Module: disconnect

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
The server invokes this module each time a websocket connection is disconnected
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

disconnect/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

disconnect/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"cmdKey" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-dumb.html b/documentation/module-dumb.html new file mode 100644 index 0000000..4316c2f --- /dev/null +++ b/documentation/module-dumb.html @@ -0,0 +1,1273 @@ + + + + + JSDoc: Module: dumb + + + + + + + + + + +
+ +

Module: dumb

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Globally shadow mute a connection. Optional allies array will see muted messages.
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • OpSimple ( https://github.com/OpSimple )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) chatCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +hook incoming chat commands, shadow-prevent chat if they are muzzled +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) init(core) → {void}

+ + + + + + +
+ Automatically executes once after server is ready +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
core + + +Object + + + + Reference to core enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) inviteCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +shadow-prevent all invites from muzzled users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) whisperCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +shadow-prevent all whispers from muzzled users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + +

Type Definitions

+ + + +

dumb/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-emote.html b/documentation/module-emote.html new file mode 100644 index 0000000..c1c2541 --- /dev/null +++ b/documentation/module-emote.html @@ -0,0 +1,903 @@ + + + + + JSDoc: Module: emote + + + + + + + + + + +
+ +

Module: emote

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Broadcasts an emote to the current channel
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) emoteCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +hooks chat commands checking for /me +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

emote/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

emote/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"text" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-forcecolor.html b/documentation/module-forcecolor.html new file mode 100644 index 0000000..ca2ecb6 --- /dev/null +++ b/documentation/module-forcecolor.html @@ -0,0 +1,903 @@ + + + + + JSDoc: Module: forcecolor + + + + + + + + + + +
+ +

Module: forcecolor

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Forces a user nick to become a certain color
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) colorCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +hooks chat commands checking for /forcecolor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

forcecolor/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

forcecolor/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"nick", "color" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-help.html b/documentation/module-help.html new file mode 100644 index 0000000..e905547 --- /dev/null +++ b/documentation/module-help.html @@ -0,0 +1,830 @@ + + + + + JSDoc: Module: help + + + + + + + + + + +
+ +

Module: help

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Outputs information about the servers current protocol
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) helpCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +hooks chat commands checking for /help +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

help/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-invite.html b/documentation/module-invite.html new file mode 100644 index 0000000..8e4d552 --- /dev/null +++ b/documentation/module-invite.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: invite + + + + + + + + + + +
+ +

Module: invite

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Sends an invite to the target client with the provided channel, or a random channel
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

invite/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-join.html b/documentation/module-join.html new file mode 100644 index 0000000..4fca6e6 --- /dev/null +++ b/documentation/module-join.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: join + + + + + + + + + + +
+ +

Module: join

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Join the target channel using the supplied nick and password
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

join/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-kick.html b/documentation/module-kick.html new file mode 100644 index 0000000..f522c78 --- /dev/null +++ b/documentation/module-kick.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: kick + + + + + + + + + + +
+ +

Module: kick

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Silently forces target client(s) into another channel
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

kick/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-listusers.html b/documentation/module-listusers.html new file mode 100644 index 0000000..7ecfac1 --- /dev/null +++ b/documentation/module-listusers.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: listusers + + + + + + + + + + +
+ +

Module: listusers

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Outputs all current channels and sockets in those channels
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

listusers/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-morestats.html b/documentation/module-morestats.html new file mode 100644 index 0000000..f6b1b34 --- /dev/null +++ b/documentation/module-morestats.html @@ -0,0 +1,830 @@ + + + + + JSDoc: Module: morestats + + + + + + + + + + +
+ +

Module: morestats

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Sends back current server stats to the calling client
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) statsCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +hooks chat commands checking for /stats +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + +

Type Definitions

+ + + +

morestats/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-ping.html b/documentation/module-ping.html new file mode 100644 index 0000000..087e342 --- /dev/null +++ b/documentation/module-ping.html @@ -0,0 +1,482 @@ + + + + + JSDoc: Module: ping + + + + + + + + + + +
+ +

Module: ping

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
This module is only in place to supress error notices legacy clients may get
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run() → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

ping/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-reload.html b/documentation/module-reload.html new file mode 100644 index 0000000..9b69736 --- /dev/null +++ b/documentation/module-reload.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: reload + + + + + + + + + + +
+ +

Module: reload

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Allows a remote user to clear and re-import the server command modules
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

reload/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-removemod.html b/documentation/module-removemod.html new file mode 100644 index 0000000..89443c9 --- /dev/null +++ b/documentation/module-removemod.html @@ -0,0 +1,604 @@ + + + + + JSDoc: Module: removemod + + + + + + + + + + +
+ +

Module: removemod

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Removes target trip from the config as a mod and downgrades the socket type
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

removemod/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

removemod/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"trip" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-saveconfig.html b/documentation/module-saveconfig.html new file mode 100644 index 0000000..9e7635c --- /dev/null +++ b/documentation/module-saveconfig.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: saveconfig + + + + + + + + + + +
+ +

Module: saveconfig

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Writes the current config to disk
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

saveconfig/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-session.html b/documentation/module-session.html new file mode 100644 index 0000000..b6056eb --- /dev/null +++ b/documentation/module-session.html @@ -0,0 +1,1034 @@ + + + + + JSDoc: Module: session + + + + + + + + + + +
+ +

Module: session

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Restore previous state by session or create new session
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) getSession(socket, core) → {object}

+ + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +* + + + +
core + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

(static) init(core) → {void}

+ + + + + + +
+ Automatically executes once after server is ready +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
core + + +Object + + + + Reference to core enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(inner) notifyFailure(server, socket) → {boolean}

+ + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +* + + + +
socket + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

session/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-shout.html b/documentation/module-shout.html new file mode 100644 index 0000000..b1d7fea --- /dev/null +++ b/documentation/module-shout.html @@ -0,0 +1,604 @@ + + + + + JSDoc: Module: shout + + + + + + + + + + +
+ +

Module: shout

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Displays passed text to every client connected
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

shout/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

shout/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"text" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-socketreply.html b/documentation/module-socketreply.html new file mode 100644 index 0000000..295fb88 --- /dev/null +++ b/documentation/module-socketreply.html @@ -0,0 +1,605 @@ + + + + + JSDoc: Module: socketreply + + + + + + + + + + +
+ +

Module: socketreply

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
If a warning occurs within the server, this module will relay the warning to the + client
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

socketreply/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

socketreply/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"cmdKey", "text" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-speak.html b/documentation/module-speak.html new file mode 100644 index 0000000..8c26b26 --- /dev/null +++ b/documentation/module-speak.html @@ -0,0 +1,686 @@ + + + + + JSDoc: Module: speak + + + + + + + + + + +
+ +

Module: speak

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Pardon a dumb user to be able to speak again
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • OpSimple ( https://github.com/OpSimple )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) init(core) → {void}

+ + + + + + +
+ Automatically executes once after server is ready +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
core + + +Object + + + + Reference to core enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

speak/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-stats.html b/documentation/module-stats.html new file mode 100644 index 0000000..fbe8aef --- /dev/null +++ b/documentation/module-stats.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: stats + + + + + + + + + + +
+ +

Module: stats

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Sends back legacy server stats to the calling client
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

stats/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-unban.html b/documentation/module-unban.html new file mode 100644 index 0000000..91cf840 --- /dev/null +++ b/documentation/module-unban.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: unban + + + + + + + + + + +
+ +

Module: unban

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Un-bans target user by ip or hash
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

unban/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-unbanall.html b/documentation/module-unbanall.html new file mode 100644 index 0000000..917a661 --- /dev/null +++ b/documentation/module-unbanall.html @@ -0,0 +1,531 @@ + + + + + JSDoc: Module: unbanall + + + + + + + + + + +
+ +

Module: unbanall

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Clears all banned ip addresses
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

unbanall/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-whisper.html b/documentation/module-whisper.html new file mode 100644 index 0000000..5d5aea7 --- /dev/null +++ b/documentation/module-whisper.html @@ -0,0 +1,911 @@ + + + + + JSDoc: Module: whisper + + + + + + + + + + +
+ +

Module: whisper

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Display text on target users screen that only they can see
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
To Do:
+
+
    +
  • This should be changed to it's own event type, instead of `info` + and accept a `userid` rather than `nick`
  • +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) whisperCheck(env)

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +hooks chat commands checking for /whisper +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + + + + + + + + + + + +

Type Definitions

+ + + +

whisper/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

whisper/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"nick", "text" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/scripts/linenumber.js b/documentation/scripts/linenumber.js new file mode 100644 index 0000000..4354785 --- /dev/null +++ b/documentation/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +(() => { + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/documentation/scripts/prettify/Apache-License-2.0.txt b/documentation/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/documentation/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/documentation/scripts/prettify/lang-css.js b/documentation/scripts/prettify/lang-css.js new file mode 100644 index 0000000..041e1f5 --- /dev/null +++ b/documentation/scripts/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/documentation/scripts/prettify/prettify.js b/documentation/scripts/prettify/prettify.js new file mode 100644 index 0000000..eef5ad7 --- /dev/null +++ b/documentation/scripts/prettify/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p th:last-child { border-right: 1px solid #ddd; } + +.ancestors, .attribs { color: #999; } +.ancestors a, .attribs a +{ + color: #999 !important; + text-decoration: none; +} + +.clear +{ + clear: both; +} + +.important +{ + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.details { margin-top: 14px; border-left: 2px solid #DDD; } +.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } +.details dd { margin-left: 70px; } +.details ul { margin: 0; } +.details ul { list-style-type: none; } +.details li { margin-left: 30px; padding-top: 6px; } +.details pre.prettyprint { margin: 0 } +.details .object-value { padding-top: 0; } + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption +{ + font-style: italic; + font-size: 107%; + margin: 0; +} + +.source +{ + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.source code +{ + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4D4E53; +} + +.prettyprint code span.line +{ + display: inline-block; +} + +.prettyprint.linenums +{ + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol +{ + padding-left: 0; +} + +.prettyprint.linenums li +{ + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * +{ + background-color: lightyellow; +} + +.prettyprint.linenums li * +{ + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params .name, .props .name, .name code { + color: #4D4E53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; +} + +.params td.description > p:first-child, +.props td.description > p:first-child +{ + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child +{ + margin-bottom: 0; + padding-bottom: 0; +} + +.disabled { + color: #454545; +} diff --git a/documentation/styles/prettify-jsdoc.css b/documentation/styles/prettify-jsdoc.css new file mode 100644 index 0000000..5a2526e --- /dev/null +++ b/documentation/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/documentation/styles/prettify-tomorrow.css b/documentation/styles/prettify-tomorrow.css new file mode 100644 index 0000000..b6f92a7 --- /dev/null +++ b/documentation/styles/prettify-tomorrow.css @@ -0,0 +1,132 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: #718c00; } + + /* a keyword */ + .kwd { + color: #8959a8; } + + /* a comment */ + .com { + color: #8e908c; } + + /* a type name */ + .typ { + color: #4271ae; } + + /* a literal value */ + .lit { + color: #f5871f; } + + /* punctuation */ + .pun { + color: #4d4d4c; } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/documentation/templateCommand.js b/documentation/templateCommand.js deleted file mode 100644 index 4971528..0000000 --- a/documentation/templateCommand.js +++ /dev/null @@ -1,94 +0,0 @@ -/* - Description: This is a template module that should not be user in a production - environment -*/ - -// you can require() modules here - -// this function will only be only in the scope of the module -// module support functions -const createReply = (echoInput) => { - if (echoInput.length > 100) - echoInput = 'HOW ABOUT NO?'; - - return `You want me to echo: ${echoInput}?` -}; - -/* - `exports.init()` is optional, and will only be run when the module is loaded into memory - it will always be passed a reference to the global core class - note: this will fire again if a reload is issued, keep that in mind -*/ -exports.init = (core) => { - if (typeof core.showcase === 'undefined') { - core.showcase = 'init is a handy place to put global data by assigning it to `core`'; - } -} - -/* - `exports.run()` is required and will always be passed (core, server, socket, data) - - be sure it's async too - this is the main function that will run when called -*/ -// module main -exports.run = async (core, server, socket, data) => { - - server.reply({ - cmd: 'info', - text: `SHOWCASE MODULE: ${core.showcase} - ${createReply(data.echo)}` - }, socket); - -}; - -/* - `exports.initHooks` is optional, this will be called when the server is ready - for modules to register their hooking functions - - Hook function may alter the data before it is sent to a module, or before it - is sent to a client. If the function returns `false` then the data will be - dropped without further processing -*/ -// module hook functions -exports.initHooks = (server) => { - /* - First param is hook type. A hook may be registered as either `in` or `out`: - `in`: a hook function registered as `in` will be called before the client - request is passed to the module they are attempting to call. Note: socket - in this context is the client that sent the data - `out`: a hook function registered as `out` will be called before the data is - sent to any clients. Note: `socket` in this context is the socket that - will be sent the data. - - Second param is the `cmd` type to target, any valid module may be targeted - - Third param is the hook function itself, see `exports.hookExample` for an example - */ - server.registerHook('in', 'chat', this.hookExample); -}; - -/* - This hook function example alters the payload before it gets to the `chat` module, - changing the user's input from 'hookexample' to 'WORKING!' -*/ -exports.hookExample = (core, server, socket, payload) => { - // check if we need to alter the payload - if (payload.text === 'hookexample') { - payload.text = 'WORKING!'; - } - - // always return the payload, or false if processing should drop it - return payload; -} - -// optional, if `data.echo` is missing `exports.run()` will never be called & the user will be alerted -// remember; this will only verify that the data is not undefined, not the type of data -exports.requiredData = ['echo']; - -// optional parameters are marked, all others are required -exports.info = { - name: 'showcase', // actual command name - aliases: ['templateModule'], // optional, an array of other names this module can be executed by - usage: 'showcase {echo}', // used for help output, can be omitted if no parameters are required - description: 'Simple command module template & info' // used for help output -}; diff --git a/index.js b/index.js deleted file mode 100644 index 865ee71..0000000 --- a/index.js +++ /dev/null @@ -1 +0,0 @@ -console.log('Use "npm start" instead.') diff --git a/jsdoc.json b/jsdoc.json new file mode 100644 index 0000000..2876057 --- /dev/null +++ b/jsdoc.json @@ -0,0 +1,23 @@ +{ + "plugins": [], + "recurseDepth": 10, + "source": { + "include": ["commands"], + "includePattern": ".+\\.js(doc|x)?$", + "excludePattern": "(^|\\/|\\\\)_" + }, + "sourceType": "module", + "tags": { + "allowUnknownTags": true, + "dictionaries": ["jsdoc","closure"] + }, + "templates": { + "cleverLinks": false, + "monospaceLinks": false + }, + "opts": { + "destination": "documentation", + "recurse": true, + "readme": "README.md" + } +} \ No newline at end of file diff --git a/main.mjs b/main.mjs new file mode 100644 index 0000000..285f160 --- /dev/null +++ b/main.mjs @@ -0,0 +1,45 @@ +import fs from 'fs'; +import { join, dirname } from 'path'; +import { Low, JSONFile } from 'lowdb'; +import { fileURLToPath } from 'url'; +import { CoreApp } from 'hackchat-server'; + +// required file paths +const SessionLocation = './session.key'; +const SaltLocation = './salt.key'; +const AppConfigLocation = './config.json'; + +// verify required files exist +if (fs.existsSync(SessionLocation) === false) { + throw Error('Missing session key, you may need to run: npm run config'); +} + +if (fs.existsSync(SaltLocation) === false) { + throw Error('Missing salt key, you may need to run: npm run config'); +} + +if (fs.existsSync(AppConfigLocation) === false) { + throw Error('Missing config, you may need to run: npm run config'); +} + +// build main hack chat server +const server = new CoreApp({ + configPath: './.hcserver.json', + logErrDetailed: true, + lang: 'en', +}); + +// load sessoin key data +server.sessionKey = fs.readFileSync(SessionLocation); + +// load salt key data +server.saltKey = fs.readFileSync(SaltLocation); + +// load the configuration data +const adapter = new JSONFile(AppConfigLocation); +server.appConfig = new Low(adapter); +await server.appConfig.read(); + +server.init(); + +console.log('Websocket server ready'); diff --git a/package-lock.json b/package-lock.json index 43ea2c8..5d3a2c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,31 +1,6225 @@ { "name": "hack.chat-v2", - "version": "2.1.93", - "lockfileVersion": 1, + "version": "2.2.0", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "hack.chat-v2", + "version": "2.2.0", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "enquirer": "^2.3.6", + "hackchat-server": "^2.2.27", + "http-server": "^14.1.0", + "jsonwebtoken": "^8.5.1", + "lowdb": "^3.0.0", + "pm2": "^5.2.0" + }, + "devDependencies": { + "c8": "^7.11.0", + "chai": "^4.3.6", + "codecov": "^3.8.3", + "eslint": "^8.9.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.25.4", + "mocha": "^9.2.1", + "nyc": "^15.1.0" + }, + "engines": { + "node": ">= 10.15.1", + "npm": ">= 6.7.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.17.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", + "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.3", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", + "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", + "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", + "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", + "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@eslint/eslintrc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.1.0.tgz", + "integrity": "sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@opencensus/core": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz", + "integrity": "sha512-31Q4VWtbzXpVUd2m9JS6HEaPjlKvNMOiF7lWKNmXF84yUcgfAFL5re7/hjDmdyQbOp32oGc+RFV78jXIldVz6Q==", + "dependencies": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^5.5.0", + "shimmer": "^1.2.0", + "uuid": "^3.2.1" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@opencensus/core/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@opencensus/propagation-b3": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@opencensus/propagation-b3/-/propagation-b3-0.0.8.tgz", + "integrity": "sha512-PffXX2AL8Sh0VHQ52jJC4u3T0H6wDK6N/4bg7xh4ngMYOIi13aR1kzVvX1sVDBgfGwDOkMbl4c54Xm3tlPx/+A==", + "dependencies": { + "@opencensus/core": "^0.0.8", + "uuid": "^3.2.1" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@opencensus/propagation-b3/node_modules/@opencensus/core": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.8.tgz", + "integrity": "sha512-yUFT59SFhGMYQgX0PhoTR0LBff2BEhPrD9io1jWfF/VDbakRfs6Pq60rjv0Z7iaTav5gQlttJCX2+VPxFWCuoQ==", + "dependencies": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^5.5.0", + "shimmer": "^1.2.0", + "uuid": "^3.2.1" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@opencensus/propagation-b3/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@pm2/agent": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.1.tgz", + "integrity": "sha512-QKHMm6yexcvdDfcNE7PL9D6uEjoQPGRi+8dh+rc4Hwtbpsbh5IAvZbz3BVGjcd4HaX6pt2xGpOohG7/Y2L4QLw==", + "dependencies": { + "async": "~3.2.0", + "chalk": "~3.0.0", + "dayjs": "~1.8.24", + "debug": "~4.3.1", + "eventemitter2": "~5.0.1", + "fast-json-patch": "^3.0.0-1", + "fclone": "~1.0.11", + "nssocket": "0.6.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.0", + "proxy-agent": "~5.0.0", + "semver": "~7.2.0", + "ws": "~7.4.0" + } + }, + "node_modules/@pm2/agent/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@pm2/agent/node_modules/semver": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz", + "integrity": "sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@pm2/agent/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@pm2/io": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.0.tgz", + "integrity": "sha512-3rToDVJaRoob5Lq8+7Q2TZFruoEkdORxwzFpZaqF4bmH6Bkd7kAbdPrI/z8X6k1Meq5rTtScM7MmDgppH6aLlw==", + "dependencies": { + "@opencensus/core": "0.0.9", + "@opencensus/propagation-b3": "0.0.8", + "async": "~2.6.1", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "require-in-the-middle": "^5.0.0", + "semver": "6.3.0", + "shimmer": "^1.2.0", + "signal-exit": "^3.0.3", + "tslib": "1.9.3" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@pm2/io/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/@pm2/io/node_modules/eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" + }, + "node_modules/@pm2/io/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@pm2/js-api": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.6.7.tgz", + "integrity": "sha512-jiJUhbdsK+5C4zhPZNnyA3wRI01dEc6a2GhcQ9qI38DyIk+S+C8iC3fGjcjUbt/viLYKPjlAaE+hcT2/JMQPXw==", + "dependencies": { + "async": "^2.6.3", + "axios": "^0.21.0", + "debug": "~4.3.1", + "eventemitter2": "^6.3.1", + "ws": "^7.0.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@pm2/js-api/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/@pm2/js-api/node_modules/eventemitter2": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" + }, + "node_modules/@pm2/js-api/node_modules/ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@pm2/pm2-version-check": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz", + "integrity": "sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==", + "dependencies": { + "debug": "^4.3.1" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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/amp": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", + "integrity": "sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0=" + }, + "node_modules/amp-message": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", + "integrity": "sha1-p48cmJlQh602GSpBKY5NtJ49/EU=", + "dependencies": { + "amp": "0.3.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "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", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", + "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", + "dev": true, + "engines": { + "node": ">=0.6.10" + } + }, + "node_modules/array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types/node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, + "node_modules/async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "dependencies": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "engines": { + "node": "<=0.11.8 || >0.11.10" + } + }, + "node_modules/async-listener/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/blessed": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", + "integrity": "sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=", + "bin": { + "blessed": "bin/tput.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/bodec": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", + "integrity": "sha1-vIUVVUMPI8n3ZQp172TGqUw0GMw=" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", + "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001312", + "electron-to-chromium": "^1.4.71", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c8": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.0.tgz", + "integrity": "sha512-XqPyj1uvlHMr+Y1IeRndC2X5P7iJzJlEJwBpCdBbq2JocXOgJfr+JVfJkyNMGROke5LfKrhSFXGFXnwnRJAUJw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.2", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.0.1", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.0.2", + "rimraf": "^3.0.0", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^8.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.7" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/c8/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/c8/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/c8/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/c8/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/c8/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/c8/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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/c8/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "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", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001312", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", + "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/charm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", + "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY=" + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-tableau": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz", + "integrity": "sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==", + "dependencies": { + "chalk": "3.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/cli-tableau/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/codecov": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.8.3.tgz", + "integrity": "sha512-Y8Hw+V3HgR7V71xWH2vQ9lyS358CbGCldWlJFR0JirqoGtOoas3R3/OclRTvgUYFK29mmJICDPauVKmpqbwhOA==", + "deprecated": "https://about.codecov.io/blog/codecov-uploader-deprecation-plan/", + "dev": true, + "dependencies": { + "argv": "0.0.2", + "ignore-walk": "3.0.4", + "js-yaml": "3.14.1", + "teeny-request": "7.1.1", + "urlgrey": "1.0.0" + }, + "bin": { + "codecov": "bin/codecov" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/codecov/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "dependencies": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/croner": { + "version": "4.1.97", + "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", + "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/culvert": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", + "integrity": "sha1-lQL18BVKLVoioCPnn3HMk2+m728=" + }, + "node_modules/data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/dayjs": { + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==" + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-require-extensions/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/degenerator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "dependencies": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/didyoumean2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/didyoumean2/-/didyoumean2-4.2.0.tgz", + "integrity": "sha512-o8KZ9RERbXaPgvXklxuLwD4RotaV5trShsNXaA/y1h5e4u6qmtv5I6enJsst9l8R1b/eqFQFwfPAiTf+FgHAQQ==", + "dependencies": { + "@babel/runtime": "^7.10.2", + "leven": "^3.1.0", + "lodash.deburr": "^4.1.0" + }, + "engines": { + "node": ">=10.13" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.75", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.75.tgz", + "integrity": "sha512-LxgUNeu3BVU7sXaKjUDD9xivocQLxFtq6wgERrutdY/yIOps3ODOZExK1jg8DTEg4U8TUCb5MLGeWFOYuxjF3Q==", + "dev": true + }, + "node_modules/emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "dependencies": { + "shimmer": "^1.2.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "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/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", + "integrity": "sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.1.0", + "@humanwhocodes/config-array": "^0.9.2", + "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.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "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", + "v8-compile-cache": "^2.0.3" + }, + "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", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "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-config-airbnb-base/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.25.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", + "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "dev": true, + "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.2", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.12.0" + }, + "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", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", + "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=" + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-patch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.0.tgz", + "integrity": "sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "node_modules/fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", + "dev": true, + "dependencies": { + "punycode": "^1.3.2" + } + }, + "node_modules/fast-url-parser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "node_modules/fclone": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", + "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "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" + } + ] + }, + "node_modules/fs-extra": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dependencies": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dependencies": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/git-node-fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", + "integrity": "sha1-SbIV4kLr5Dqkx1Ybu6SZUhdSCA8=" + }, + "node_modules/git-sha1": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/git-sha1/-/git-sha1-0.1.2.tgz", + "integrity": "sha1-WZrBkrcYdYJeE6RF86bgURjC90U=" + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "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/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/hackchat-server": { + "version": "2.2.27", + "resolved": "https://registry.npmjs.org/hackchat-server/-/hackchat-server-2.2.27.tgz", + "integrity": "sha512-ojTngxzBO9OYj12510XsoUEddMYbE3qf7AsRkyBfNStyiNKIMWG8/kyZkLsr/f/CIYKJZCQ3/Es6Cu6t/FBHvA==", + "dependencies": { + "didyoumean2": "^4.2.0", + "enquirer": "^2.3.6", + "esm": "^3.2.25", + "fs-extra": "^10.0.0", + "ws": "^8.2.1", + "yargs": "^17.1.1" + }, + "bin": { + "hc-config": "scripts/configure.js", + "hc-generate-cmd": "scripts/generate.js", + "hc-import": "scripts/import.js" + }, + "engines": { + "node": ">= 14.10.0", + "npm": ">= 7.0.0" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-server": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.0.tgz", + "integrity": "sha512-5lYsIcZtf6pdR8tCtzAHTWrAveo4liUlJdWc7YafwK/maPgYHs+VNP6KpCClmUnSorJrARVMXqtT055zBv11Yg==", + "dependencies": { + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "bin": { + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "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.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "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.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-git": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", + "integrity": "sha1-UvplWrYYd9bxB578ZTS1VPMeVEQ=", + "dependencies": { + "bodec": "^0.1.0", + "culvert": "^0.1.2", + "git-sha1": "^0.1.2", + "pako": "^0.2.5" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "optional": true + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=", + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.deburr": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", + "integrity": "sha1-3bG7s+8HRYwBd7oH3hRCLLAz/5s=" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "engines": { + "node": ">=0.8.6" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lowdb": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-3.0.0.tgz", + "integrity": "sha512-9KZRulmIcU8fZuWiaM0d5e2/nPnrFyXkeXVpqT+MJS+vgbgOf1EbtvgQmba8HwUFgDl1oeZR6XqEJnkJmQdKmg==", + "dependencies": { + "steno": "^2.1.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", + "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.2.0", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "node_modules/nanoid": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/needle": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", + "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nssocket": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz", + "integrity": "sha1-Wflvb/MhVm8zxw99vu7N/cBxVPo=", + "dependencies": { + "eventemitter2": "~0.4.14", + "lazy": "~1.0.11" + }, + "engines": { + "node": ">= 0.10.x" + } + }, + "node_modules/nssocket/node_modules/eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "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": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pac-resolver": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", + "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", + "dependencies": { + "degenerator": "^3.0.1", + "ip": "^1.1.5", + "netmask": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidusage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.0.tgz", + "integrity": "sha512-8VJLToXhj+RYZGNVw8oxc7dS54iCQXUJ+MDFHezQ/fwF5B8W4OWodAMboc1wb08S/4LiHwAmkT4ohf/d3YPPsw==", + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pidusage/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pm2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.0.tgz", + "integrity": "sha512-PO5hMVhQ85cTszFM++6v07Me9hPJMkFbHjkFigtMMk+La8ty2wCi2dlBTeZYJDhPUSjK8Ccltpq2buNRcyMOTw==", + "dependencies": { + "@pm2/agent": "~2.0.0", + "@pm2/io": "~5.0.0", + "@pm2/js-api": "~0.6.7", + "@pm2/pm2-version-check": "latest", + "async": "~3.2.0", + "blessed": "0.1.81", + "chalk": "3.0.0", + "chokidar": "^3.5.1", + "cli-tableau": "^2.0.0", + "commander": "2.15.1", + "croner": "~4.1.92", + "dayjs": "~1.8.25", + "debug": "^4.3.1", + "enquirer": "2.3.6", + "eventemitter2": "5.0.1", + "fclone": "1.0.11", + "mkdirp": "1.0.4", + "needle": "2.4.0", + "pidusage": "~3.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.1", + "pm2-deploy": "~1.0.2", + "pm2-multimeter": "^0.1.2", + "promptly": "^2", + "semver": "^7.2", + "source-map-support": "0.5.19", + "sprintf-js": "1.1.2", + "vizion": "~2.2.1", + "yamljs": "0.3.0" + }, + "bin": { + "pm2": "bin/pm2", + "pm2-dev": "bin/pm2-dev", + "pm2-docker": "bin/pm2-docker", + "pm2-runtime": "bin/pm2-runtime" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "pm2-sysmonit": "^1.2.8" + } + }, + "node_modules/pm2-axon": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pm2-axon/-/pm2-axon-4.0.1.tgz", + "integrity": "sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg==", + "dependencies": { + "amp": "~0.3.1", + "amp-message": "~0.1.1", + "debug": "^4.3.1", + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=5" + } + }, + "node_modules/pm2-axon-rpc": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz", + "integrity": "sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw==", + "dependencies": { + "debug": "^4.3.1" + }, + "engines": { + "node": ">=5" + } + }, + "node_modules/pm2-deploy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-1.0.2.tgz", + "integrity": "sha512-YJx6RXKrVrWaphEYf++EdOOx9EH18vM8RSZN/P1Y+NokTKqYAca/ejXwVLyiEpNju4HPZEk3Y2uZouwMqUlcgg==", + "dependencies": { + "run-series": "^1.1.8", + "tv4": "^1.3.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pm2-multimeter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz", + "integrity": "sha1-Gh5VFT1BoFU0zqI8/oYKuqDrSs4=", + "dependencies": { + "charm": "~0.1.1" + } + }, + "node_modules/pm2-sysmonit": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/pm2-sysmonit/-/pm2-sysmonit-1.2.8.tgz", + "integrity": "sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==", + "optional": true, + "dependencies": { + "async": "^3.2.0", + "debug": "^4.3.1", + "pidusage": "^2.0.21", + "systeminformation": "^5.7", + "tx2": "~1.0.4" + } + }, + "node_modules/pm2-sysmonit/node_modules/pidusage": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", + "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "optional": true, + "dependencies": { + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pm2-sysmonit/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/pm2/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pm2/node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/portfinder/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/promptly": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/promptly/-/promptly-2.2.0.tgz", + "integrity": "sha1-KhP6BjaIoqWYOxYf/wEIoH0m/HQ=", + "dependencies": { + "read": "^1.0.4" + } + }, + "node_modules/proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dependencies": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/raw-body": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.0.tgz", + "integrity": "sha512-XpyZ6O7PVu3ItMQl0LslfsRoKxMOxi3SzDkrOtxMES5AqLFpYjQCryxI4LGygUN2jL+RgFsPkMPPlG7cg/47+A==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", + "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "dependencies": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.12.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dependencies": { + "is-core-module": "^2.8.1", + "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", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-series": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "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/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/steno": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/steno/-/steno-2.1.0.tgz", + "integrity": "sha512-mauOsiaqTNGFkWqIfwcm3y/fq+qKKaIWf1vf3ocOuTdco9XoHCO2AGF1gFYXuZFSWuP38Q8LBHBGJv2KnJSXyA==", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "dev": true, + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "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.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", + "dev": true + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/systeminformation": { + "version": "5.11.4", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.11.4.tgz", + "integrity": "sha512-rh7bjpjP5whUaTknim5CiGdAiKZcgWhmbmxjzBRXDWqUc/k67bz2OP+03DdcX6/SN/CDSAi/NeUwM5o2gjHJoA==", + "optional": true, + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, + "node_modules/teeny-request": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.1.1.tgz", + "integrity": "sha512-iwY6rkW5DDGq8hE2YgNQlKbptYpY5Nn2xecjQiNjOXWbKzPGUfmeUBCSQbbr306d7Z7U2N0TPl+/SwYRfua1Dg==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/teeny-request/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "node_modules/tsconfig-paths": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", + "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "node_modules/tv4": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", + "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/tx2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tx2/-/tx2-1.0.5.tgz", + "integrity": "sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==", + "optional": true, + "dependencies": { + "json-stringify-safe": "^5.0.1" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" + }, + "node_modules/urlgrey": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-1.0.0.tgz", + "integrity": "sha512-hJfIzMPJmI9IlLkby8QrsCykQ+SXDeO2W5Q9QTW3QpqZVTx4a/K7p8/5q+/isD8vsbVaFgql/gvAoQCRQ2Cb5w==", + "dev": true, + "dependencies": { + "fast-url-parser": "^1.1.3" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/vizion": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vizion/-/vizion-2.2.1.tgz", + "integrity": "sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==", + "dependencies": { + "async": "^2.6.3", + "git-node-fs": "^1.0.0", + "ini": "^1.3.5", + "js-git": "^0.7.8" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vizion/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/vm2": { + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.8.tgz", + "integrity": "sha512-/1PYg/BwdKzMPo8maOZ0heT7DLI0DAFTm7YQaz/Lim9oIaFZsJs3EdtalvXuBfZwczNwsYhju75NW4d6E+4q+w==", + "dependencies": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + }, + "bin": { + "vm2": "bin/vm2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "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/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "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", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "engines": { + "node": "*" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dependencies": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "bin": { + "json2yaml": "bin/json2yaml", + "yaml2json": "bin/yaml2json" + } + }, + "node_modules/yargs": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "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-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@jridgewell/trace-mapping": "^0.3.0" + } + }, + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/compat-data": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "dev": true + }, + "@babel/core": { + "version": "7.17.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", + "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.17.2", + "@babel/parser": "^7.17.3", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + }, + "dependencies": { + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", + "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", + "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/helpers": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", + "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" + } + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -65,6 +6259,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -82,35 +6282,223 @@ } } }, + "@babel/parser": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", + "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "dev": true + }, + "@babel/runtime": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", + "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "@eslint/eslintrc": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", - "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.1.0.tgz", + "integrity": "sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "lodash": "^4.17.19", + "js-yaml": "^4.1.0", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { - "ms": "^2.1.1" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true } } }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@opencensus/core": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.9.tgz", @@ -159,75 +6547,56 @@ } }, "@pm2/agent": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-1.0.4.tgz", - "integrity": "sha512-cZLwaoLa45FRuetKCcoI3kHnnQ7VMLpZnmVom04MoK0cpY/RxcSarkCHSCu9V+pdARwxx96QrWdrtAJdw97dng==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.1.tgz", + "integrity": "sha512-QKHMm6yexcvdDfcNE7PL9D6uEjoQPGRi+8dh+rc4Hwtbpsbh5IAvZbz3BVGjcd4HaX6pt2xGpOohG7/Y2L4QLw==", "requires": { "async": "~3.2.0", "chalk": "~3.0.0", "dayjs": "~1.8.24", - "debug": "~4.1.1", + "debug": "~4.3.1", "eventemitter2": "~5.0.1", + "fast-json-patch": "^3.0.0-1", "fclone": "~1.0.11", "nssocket": "0.6.0", - "pm2-axon": "^3.2.0", - "pm2-axon-rpc": "^0.5.0", - "proxy-agent": "~3.1.1", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.0", + "proxy-agent": "~5.0.0", "semver": "~7.2.0", - "ws": "~7.2.0" + "ws": "~7.4.0" }, "dependencies": { - "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "requires": { - "ms": "^2.1.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "semver": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz", "integrity": "sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig==" - } - } - }, - "@pm2/agent-node": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@pm2/agent-node/-/agent-node-1.1.10.tgz", - "integrity": "sha512-xRcrk7OEwhS3d/227/kKGvxgmbIi6Yyp27FzGlFNermEKhgddmFaRnmd7GRLIsBM/KB28NrwflBZulzk/mma6g==", - "requires": { - "debug": "^3.1.0", - "eventemitter2": "^5.0.1", - "proxy-agent": "^3.0.3", - "ws": "^6.0.0" - }, - "dependencies": { + }, "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "requires": { - "async-limiter": "~1.0.0" - } + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "requires": {} } } }, "@pm2/io": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@pm2/io/-/io-4.3.5.tgz", - "integrity": "sha512-CY/a6Nw72vrlp/FPx38l4jfEHp4gNEbo8i+WlSJ2cnWO6VE6CKmnC1zb4yQLvdP8f3EuzzoOBZVq6aGN20M82Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.0.tgz", + "integrity": "sha512-3rToDVJaRoob5Lq8+7Q2TZFruoEkdORxwzFpZaqF4bmH6Bkd7kAbdPrI/z8X6k1Meq5rTtScM7MmDgppH6aLlw==", "requires": { "@opencensus/core": "0.0.9", "@opencensus/propagation-b3": "0.0.8", - "@pm2/agent-node": "^1.1.10", "async": "~2.6.1", - "debug": "4.1.1", + "debug": "~4.3.1", "eventemitter2": "^6.3.1", "require-in-the-middle": "^5.0.0", "semver": "6.3.0", @@ -236,54 +6605,77 @@ "tslib": "1.9.3" }, "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "requires": { - "ms": "^2.1.1" + "lodash": "^4.17.14" } }, "eventemitter2": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.3.tgz", - "integrity": "sha512-t0A2msp6BzOf+QAcI6z9XMktLj52OjGQg+8SJH6v5+3uxNpWYRR3wQmfA+6xtMU9kOC59qk9licus5dYcrYkMQ==" + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" } } }, "@pm2/js-api": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.6.0.tgz", - "integrity": "sha512-ZgM/0yI8s3FRyxP01wI5UzDrVTecS/SmD98z25C9fsHo2Wz3JB1DtS4uIBlPopq2/R5HIQynTUJPDNn4qo1d/Q==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.6.7.tgz", + "integrity": "sha512-jiJUhbdsK+5C4zhPZNnyA3wRI01dEc6a2GhcQ9qI38DyIk+S+C8iC3fGjcjUbt/viLYKPjlAaE+hcT2/JMQPXw==", "requires": { "async": "^2.6.3", - "axios": "^0.19.0", - "debug": "~3.2.6", + "axios": "^0.21.0", + "debug": "~4.3.1", "eventemitter2": "^6.3.1", "ws": "^7.0.0" }, "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "requires": { + "lodash": "^4.17.14" + } + }, "eventemitter2": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.3.tgz", - "integrity": "sha512-t0A2msp6BzOf+QAcI6z9XMktLj52OjGQg+8SJH6v5+3uxNpWYRR3wQmfA+6xtMU9kOC59qk9licus5dYcrYkMQ==" + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", + "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" + }, + "ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "requires": {} } } }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + "@pm2/pm2-version-check": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz", + "integrity": "sha512-SXsM27SGH3yTWKc2fKR4SYNxsmnvuBQ9dd6QHtEWmiZ/VqaOYPAIlS8+vMcn27YLtAEBGvNRSh3TPNvtjZgfqA==", + "requires": { + "debug": "^4.3.1" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true }, "@types/json5": { "version": "0.0.29", @@ -291,30 +6683,51 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, - "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + }, "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" }, "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { - "es6-promisify": "^5.0.0" + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" } }, "ajv": { - "version": "6.12.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", - "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -337,138 +6750,110 @@ } }, "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "requires": { "sprintf-js": "~1.0.2" - }, - "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - } } }, + "argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz", + "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=", + "dev": true + }, "array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" } }, "array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "es-abstract": "^1.19.0" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "requires": { + "tslib": "^2.0.1" }, "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" } } }, - "ast-types": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.1.tgz", - "integrity": "sha512-pfSiukbt23P1qMhNnsozLzhMLBs7EEeXqPyvPmnuZM+RMfwfqwDbSVKYflgGuVI7/VehR4oMks0igzdNAg4VeQ==", - "requires": { - "tslib": "^2.0.1" - } - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "requires": { - "lodash": "^4.17.14" - } - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "async-listener": { "version": "0.6.10", @@ -487,56 +6872,41 @@ } }, "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "requires": { - "follow-redirects": "1.5.10" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "follow-redirects": "^1.14.0" } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "basic-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } }, "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "blessed": { "version": "0.1.81", "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", "integrity": "sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=" }, + "bodec": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", + "integrity": "sha1-vIUVVUMPI8n3ZQp172TGqUw0GMw=" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -554,15 +6924,146 @@ "fill-range": "^7.0.1" } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserslist": { + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", + "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001312", + "electron-to-chromium": "^1.4.71", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "c8": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.0.tgz", + "integrity": "sha512-XqPyj1uvlHMr+Y1IeRndC2X5P7iJzJlEJwBpCdBbq2JocXOgJfr+JVfJkyNMGROke5LfKrhSFXGFXnwnRJAUJw==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.2", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.0.1", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.0.2", + "rimraf": "^3.0.0", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^8.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.7" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "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" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + } + } + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } }, "callsites": { "version": "3.1.0", @@ -570,10 +7071,37 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001312", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", + "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", + "dev": true + }, + "chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -584,33 +7112,86 @@ "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY=" }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "chokidar": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", - "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "requires": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.4.0" + "readdirp": "~3.6.0" } }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, "cli-tableau": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/cli-tableau/-/cli-tableau-2.0.1.tgz", "integrity": "sha512-he+WTicka9cl0Fg/y+YyxcN6/bfQ/1O3QmgxRXDhABKqLzvoOSM4fMzp39uMyLBulAFuywD2N7UaoQE7WaADxQ==", "requires": { "chalk": "3.0.0" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "codecov": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/codecov/-/codecov-3.8.3.tgz", + "integrity": "sha512-Y8Hw+V3HgR7V71xWH2vQ9lyS358CbGCldWlJFR0JirqoGtOoas3R3/OclRTvgUYFK29mmJICDPauVKmpqbwhOA==", + "dev": true, + "requires": { + "argv": "0.0.2", + "ignore-walk": "3.0.4", + "js-yaml": "3.14.1", + "teeny-request": "7.1.1", + "urlgrey": "1.0.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } }, "color-convert": { "version": "2.0.1", @@ -625,31 +7206,26 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - }, "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "confusing-browser-globals": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", - "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", "dev": true }, "continuation-local-storage": { @@ -661,23 +7237,29 @@ "emitter-listener": "^1.1.1" } }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "corser": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=" }, - "cron": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/cron/-/cron-1.8.2.tgz", - "integrity": "sha512-Gk2c4y6xKEO8FSAUTklqtfSr7oTq0CiPQeLBG5Fl0qoXpZyMcj1SG59YL+hqq04bu6/IuEA7lMkYDAplQNKkyg==", - "requires": { - "moment-timezone": "^0.5.x" - } + "croner": { + "version": "4.1.97", + "resolved": "https://registry.npmjs.org/croner/-/croner-4.1.97.tgz", + "integrity": "sha512-/f6gpQuxDaqXu+1kwQYSckUglPaOrHdbIlBAu0YuW8/Cdb45XwXYNUBXg3r/9Mo6n540Kn/smKcZWko5x99KrQ==" }, "cross-spawn": { "version": "7.0.3", @@ -690,28 +7272,65 @@ "which": "^2.0.1" } }, + "culvert": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", + "integrity": "sha1-lQL18BVKLVoioCPnn3HMk2+m728=" + }, "data-uri-to-buffer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", - "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==" }, "dayjs": { - "version": "1.8.34", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.34.tgz", - "integrity": "sha512-Olb+E6EoMvdPmAMq2QoucuyZycKHjTlBXmRx8Ada+wGtq4SIXuDCdtoaX4KkK0yjf1fJLnwXQURr8gQKWKaybw==" + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==" }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" } }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } }, "define-properties": { "version": "1.1.3", @@ -723,19 +7342,36 @@ } }, "degenerator": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", - "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", "requires": { - "ast-types": "0.x.x", - "escodegen": "1.x.x", - "esprima": "3.x.x" + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" } }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "didyoumean2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/didyoumean2/-/didyoumean2-4.2.0.tgz", + "integrity": "sha512-o8KZ9RERbXaPgvXklxuLwD4RotaV5trShsNXaA/y1h5e4u6qmtv5I6enJsst9l8R1b/eqFQFwfPAiTf+FgHAQQ==", + "requires": { + "@babel/runtime": "^7.10.2", + "leven": "^3.1.0", + "lodash.deburr": "^4.1.0" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true }, "doctrine": { "version": "3.0.0", @@ -746,17 +7382,20 @@ "esutils": "^2.0.2" } }, - "ecstatic": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", - "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "requires": { - "he": "^1.1.1", - "mime": "^1.6.0", - "minimist": "^1.1.0", - "url-join": "^2.0.5" + "safe-buffer": "^5.0.1" } }, + "electron-to-chromium": { + "version": "1.4.75", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.75.tgz", + "integrity": "sha512-LxgUNeu3BVU7sXaKjUDD9xivocQLxFtq6wgERrutdY/yIOps3ODOZExK1jg8DTEg4U8TUCb5MLGeWFOYuxjF3Q==", + "dev": true + }, "emitter-listener": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", @@ -766,46 +7405,44 @@ } }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "enquirer": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz", - "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "requires": { - "ansi-colors": "^3.2.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" + "ansi-colors": "^4.1.1" } }, "es-abstract": { - "version": "1.18.0-next.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", - "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "dev": true, "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" } }, "es-to-primitive": { @@ -819,29 +7456,21 @@ "is-symbol": "^1.0.2" } }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-regexp": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/escape-regexp/-/escape-regexp-0.0.1.tgz", - "integrity": "sha1-9EvaEtRbvfnLf4Yu5+SCez3TIlQ=" + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "escodegen": { "version": "1.14.3", @@ -855,202 +7484,178 @@ "source-map": "~0.6.1" }, "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } } } }, "eslint": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.9.0.tgz", - "integrity": "sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", + "integrity": "sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.1.3", + "@eslint/eslintrc": "^1.1.0", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^1.3.0", - "espree": "^7.3.0", - "esquery": "^1.2.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.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^5.2.3", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "dependencies": { - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "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" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" + "is-glob": "^4.0.3" } } } }, "eslint-config-airbnb-base": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", - "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", "dev": true, "requires": { - "confusing-browser-globals": "^1.0.9", - "object.assign": "^4.1.0", - "object.entries": "^1.1.2" + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "debug": "^3.2.7", + "resolve": "^1.20.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", "dev": true, "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" + "debug": "^3.2.7", + "find-up": "^2.1.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, "eslint-plugin-import": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", - "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "version": "2.25.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", + "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", "dev": true, "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.3", - "eslint-module-utils": "^2.6.0", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.2", "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.12.0" }, "dependencies": { "debug": { @@ -1063,21 +7668,14 @@ } }, "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "^2.0.2" } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1087,28 +7685,44 @@ } }, "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "requires": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } } }, "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, "esm": { @@ -1117,34 +7731,34 @@ "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" }, "espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" } }, "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -1159,9 +7773,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -1186,17 +7800,17 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-json-patch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.0.tgz", + "integrity": "sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA==" + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1208,24 +7822,41 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", + "dev": true, + "requires": { + "punycode": "^1.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, "fclone": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=" }, "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { - "flat-cache": "^2.0.1" + "flat-cache": "^3.0.4" } }, "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==" }, "fill-range": { "version": "7.0.1", @@ -1235,6 +7866,17 @@ "to-regex-range": "^5.0.1" } }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -1244,27 +7886,58 @@ "locate-path": "^2.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, "follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + "version": "1.14.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", + "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true + }, + "fs-extra": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } }, "fs.realpath": { "version": "1.0.0", @@ -1272,9 +7945,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "optional": true }, "ftp": { @@ -1284,26 +7957,12 @@ "requires": { "readable-stream": "1.1.x", "xregexp": "2.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - } } }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -1311,38 +7970,101 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "get-uri": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.4.tgz", - "integrity": "sha512-v7LT/s8kVjs+Tx0ykk1I+H/rbpzkHvuIq87LmeXptcf5sNWm9uQiwjNAt94SJPA1zOlCntmnOlJvVWKmzsxG8Q==", + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "requires": { - "data-uri-to-buffer": "1", - "debug": "2", - "extend": "~3.0.2", - "file-uri-to-path": "1", - "ftp": "~0.3.10", - "readable-stream": "2" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "requires": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "requires": { - "ms": "2.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" } } }, + "git-node-fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", + "integrity": "sha1-SbIV4kLr5Dqkx1Ybu6SZUhdSCA8=" + }, + "git-sha1": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/git-sha1/-/git-sha1-0.1.2.tgz", + "integrity": "sha1-WZrBkrcYdYJeE6RF86bgURjC90U=" + }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1353,69 +8075,126 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "requires": { "is-glob": "^4.0.1" } }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, + "hackchat-server": { + "version": "2.2.27", + "resolved": "https://registry.npmjs.org/hackchat-server/-/hackchat-server-2.2.27.tgz", + "integrity": "sha512-ojTngxzBO9OYj12510XsoUEddMYbE3qf7AsRkyBfNStyiNKIMWG8/kyZkLsr/f/CIYKJZCQ3/Es6Cu6t/FBHvA==", + "requires": { + "didyoumean2": "^4.2.0", + "enquirer": "^2.3.6", + "esm": "^3.2.25", + "fs-extra": "^10.0.0", + "ws": "^8.2.1", + "yargs": "^17.1.1" + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "requires": { + "whatwg-encoding": "^2.0.0" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" } }, "http-proxy": { @@ -1429,53 +8208,42 @@ } }, "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "requires": { - "agent-base": "4", - "debug": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" } }, "http-server": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", - "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.0.tgz", + "integrity": "sha512-5lYsIcZtf6pdR8tCtzAHTWrAveo4liUlJdWc7YafwK/maPgYHs+VNP6KpCClmUnSorJrARVMXqtT055zBv11Yg==", "requires": { - "basic-auth": "^1.0.3", - "colors": "^1.4.0", + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", "corser": "^2.0.1", - "ecstatic": "^3.3.2", - "http-proxy": "^1.18.0", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", "minimist": "^1.2.5", "opener": "^1.5.1", - "portfinder": "^1.0.25", + "portfinder": "^1.0.28", "secure-compare": "3.0.1", - "union": "~0.5.0" + "union": "~0.5.0", + "url-join": "^4.0.1" } }, "https-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", - "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" + "agent-base": "6", + "debug": "4" } }, "iconv-lite": { @@ -1487,15 +8255,24 @@ } }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "ignore-walk": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -1508,6 +8285,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1522,16 +8305,35 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } }, "is-binary-path": { "version": "2.1.0", @@ -1541,17 +8343,38 @@ "binary-extensions": "^2.0.0" } }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-callable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", - "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "requires": { + "has": "^1.0.3" + } + }, "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-extglob": { "version": "2.1.1", @@ -1559,23 +8382,22 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "requires": { "is-extglob": "^2.1.1" } }, "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true }, "is-number": { @@ -1583,30 +8405,88 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "has-tostringtag": "^1.0.0" } }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -1618,6 +8498,99 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "js-git": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", + "integrity": "sha1-UvplWrYYd9bxB578ZTS1VPMeVEQ=", + "requires": { + "bodec": "^0.1.0", + "culvert": "^0.1.2", + "git-sha1": "^0.1.2", + "pako": "^0.2.5" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1625,23 +8598,28 @@ "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true } } }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1654,6 +8632,12 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "optional": true + }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -1663,30 +8647,76 @@ "minimist": "^1.2.0" } }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "lazy": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=" }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, "locate-path": { @@ -1700,15 +8730,94 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.deburr": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", + "integrity": "sha1-3bG7s+8HRYwBd7oH3hRCLLAz/5s=" + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "lowdb": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-3.0.0.tgz", + "integrity": "sha512-9KZRulmIcU8fZuWiaM0d5e2/nPnrFyXkeXVpqT+MJS+vgbgOf1EbtvgQmba8HwUFgDl1oeZR6XqEJnkJmQdKmg==", + "requires": { + "steno": "^2.1.0" + } + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -1717,30 +8826,166 @@ "yallist": "^3.0.2" } }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "mocha": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", + "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "dev": true, "requires": { - "minimist": "^1.2.5" + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.2.0", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "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" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + } } }, "module-details-from-path": { @@ -1748,19 +8993,6 @@ "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" }, - "moment": { - "version": "2.27.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", - "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" - }, - "moment-timezone": { - "version": "0.5.31", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", - "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", - "requires": { - "moment": ">= 2.9.0" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1771,6 +9003,12 @@ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, + "nanoid": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -1785,33 +9023,47 @@ "debug": "^3.2.6", "iconv-lite": "^0.4.4", "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } } }, "netmask": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", - "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==" }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "whatwg-url": "^5.0.0" } }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, + "node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1833,11 +9085,159 @@ } } }, + "nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "dependencies": { + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" }, "object-keys": { "version": "1.1.1", @@ -1846,80 +9246,37 @@ "dev": true }, "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", "has-symbols": "^1.0.1", "object-keys": "^1.1.1" } }, "object.entries": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", - "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "has": "^1.0.3" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "es-abstract": "^1.19.1" } }, "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "es-abstract": "^1.19.1" } }, "once": { @@ -1931,21 +9288,22 @@ } }, "opener": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", - "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==" + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" }, "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "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": { @@ -1966,6 +9324,15 @@ "p-limit": "^1.1.0" } }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -1973,42 +9340,48 @@ "dev": true }, "pac-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.1.tgz", - "integrity": "sha512-44DUg21G/liUZ48dJpUSjZnFfZro/0K5JTyFYLBcmh9+T6Ooi4/i4efwUiEy0+4oQusCBqWdhv16XohIj1GqnQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", "requires": { - "agent-base": "^4.2.0", - "debug": "^4.1.1", - "get-uri": "^2.0.0", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^3.0.0", - "pac-resolver": "^3.0.0", + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", "raw-body": "^2.2.0", - "socks-proxy-agent": "^4.0.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } + "socks-proxy-agent": "5" } }, "pac-resolver": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", - "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", + "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", "requires": { - "co": "^4.6.0", - "degenerator": "^1.0.4", + "degenerator": "^3.0.1", "ip": "^1.1.5", - "netmask": "^1.0.6", - "thunkify": "^2.1.2" + "netmask": "^2.0.1" } }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2018,15 +9391,6 @@ "callsites": "^3.0.0" } }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -2045,130 +9409,172 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" - }, - "pidusage": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.18.tgz", - "integrity": "sha512-Y/VfKfh3poHjMEINxU+gJTeVOBjiThQeFAmzR7z56HSNiMx+etl+yBhk42nRPciPYt/VZl8DQLVXNC6P5vH11A==", - "requires": { - "safe-buffer": "^5.1.2" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pidusage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.0.tgz", + "integrity": "sha512-8VJLToXhj+RYZGNVw8oxc7dS54iCQXUJ+MDFHezQ/fwF5B8W4OWodAMboc1wb08S/4LiHwAmkT4ohf/d3YPPsw==", + "requires": { + "safe-buffer": "^5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { - "find-up": "^2.1.0" + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } } }, "pm2": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/pm2/-/pm2-4.4.1.tgz", - "integrity": "sha512-ece2zqVvSg29tIGdznKqk07IwVaO4mX7zLBMVxbJQMfvxpQUotLLERDW0v/RYMHtzj1bX8MLsDUsmPiIbEszKg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.0.tgz", + "integrity": "sha512-PO5hMVhQ85cTszFM++6v07Me9hPJMkFbHjkFigtMMk+La8ty2wCi2dlBTeZYJDhPUSjK8Ccltpq2buNRcyMOTw==", "requires": { - "@pm2/agent": "~1.0.2", - "@pm2/io": "~4.3.5", - "@pm2/js-api": "~0.6.0", - "@pm2/pm2-version-check": "^1.0.3", + "@pm2/agent": "~2.0.0", + "@pm2/io": "~5.0.0", + "@pm2/js-api": "~0.6.7", + "@pm2/pm2-version-check": "latest", "async": "~3.2.0", "blessed": "0.1.81", "chalk": "3.0.0", - "chokidar": "^3.3.0", + "chokidar": "^3.5.1", "cli-tableau": "^2.0.0", "commander": "2.15.1", - "cron": "1.8.2", + "croner": "~4.1.92", "dayjs": "~1.8.25", - "debug": "4.1.1", - "enquirer": "2.3.5", + "debug": "^4.3.1", + "enquirer": "2.3.6", "eventemitter2": "5.0.1", "fclone": "1.0.11", "mkdirp": "1.0.4", "needle": "2.4.0", - "pidusage": "2.0.18", - "pm2-axon": "3.3.0", - "pm2-axon-rpc": "0.5.1", + "pidusage": "~3.0", + "pm2-axon": "~4.0.1", + "pm2-axon-rpc": "~0.7.1", "pm2-deploy": "~1.0.2", "pm2-multimeter": "^0.1.2", + "pm2-sysmonit": "^1.2.8", "promptly": "^2", - "ps-list": "6.3.0", "semver": "^7.2", - "source-map-support": "0.5.16", + "source-map-support": "0.5.19", "sprintf-js": "1.1.2", - "systeminformation": "^4.23.3", - "vizion": "0.2.13", + "vizion": "~2.2.1", "yamljs": "0.3.0" }, "dependencies": { - "@pm2/pm2-version-check": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.3.tgz", - "integrity": "sha512-SBuYsh+o35knItbRW97vl5/5nEc5c5DYP7PxjyPLOfmm9bMaDsVeATXjXMBy6+KLlyrYWHZxGbfXe003NnHClg==", + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "requires": { - "debug": "^4.1.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" } } }, "pm2-axon": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pm2-axon/-/pm2-axon-3.3.0.tgz", - "integrity": "sha512-dAFlFYRuFbFjX7oAk41zT+dx86EuaFX/TgOp5QpUKRKwxb946IM6ydnoH5sSTkdI2pHSVZ+3Am8n/l0ocr7jdQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pm2-axon/-/pm2-axon-4.0.1.tgz", + "integrity": "sha512-kES/PeSLS8orT8dR5jMlNl+Yu4Ty3nbvZRmaAtROuVm9nYYGiaoXqqKQqQYzWQzMYWUKHMQTvBlirjE5GIIxqg==", "requires": { "amp": "~0.3.1", "amp-message": "~0.1.1", - "debug": "^3.0", - "escape-regexp": "0.0.1" + "debug": "^4.3.1", + "escape-string-regexp": "^4.0.0" } }, "pm2-axon-rpc": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/pm2-axon-rpc/-/pm2-axon-rpc-0.5.1.tgz", - "integrity": "sha512-hT8gN3/j05895QLXpwg+Ws8PjO4AVID6Uf9StWpud9HB2homjc1KKCcI0vg9BNOt56FmrqKDT1NQgheIz35+sA==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz", + "integrity": "sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw==", "requires": { - "debug": "^3.0" + "debug": "^4.3.1" } }, "pm2-deploy": { @@ -2188,6 +9594,36 @@ "charm": "~0.1.1" } }, + "pm2-sysmonit": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/pm2-sysmonit/-/pm2-sysmonit-1.2.8.tgz", + "integrity": "sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA==", + "optional": true, + "requires": { + "async": "^3.2.0", + "debug": "^4.3.1", + "pidusage": "^2.0.21", + "systeminformation": "^5.7", + "tx2": "~1.0.4" + }, + "dependencies": { + "pidusage": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", + "integrity": "sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA==", + "optional": true, + "requires": { + "safe-buffer": "^5.2.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "optional": true + } + } + }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -2196,24 +9632,49 @@ "async": "^2.6.2", "debug": "^3.1.1", "mkdirp": "^0.5.5" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "requires": { + "lodash": "^4.17.14" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + } } }, "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, "promptly": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/promptly/-/promptly-2.2.0.tgz", @@ -2223,28 +9684,18 @@ } }, "proxy-agent": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.1.1.tgz", - "integrity": "sha512-WudaR0eTsDx33O3EJE16PjBRZWcX8GqCEeERw1W3hZJgH/F2a46g7jty6UGty6NeJ4CKQy8ds2CJPMiyeqaTvw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", "requires": { - "agent-base": "^4.2.0", + "agent-base": "^6.0.0", "debug": "4", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^3.0.0", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", "lru-cache": "^5.1.1", - "pac-proxy-agent": "^3.0.1", + "pac-proxy-agent": "^5.0.0", "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^4.0.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } + "socks-proxy-agent": "^5.0.0" } }, "proxy-from-env": { @@ -2252,11 +9703,6 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "ps-list": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/ps-list/-/ps-list-6.3.0.tgz", - "integrity": "sha512-qau0czUSB0fzSlBOQt0bo+I2v6R+xiQdj78e1BR/Qjfl5OHWJ/urXi8+ilw1eHe+5hSeDI1wrwVTgDp2wst4oA==" - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -2264,17 +9710,29 @@ "dev": true }, "qs": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } }, "raw-body": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", - "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.0.tgz", + "integrity": "sha512-XpyZ6O7PVu3ItMQl0LslfsRoKxMOxi3SzDkrOtxMES5AqLFpYjQCryxI4LGygUN2jL+RgFsPkMPPlG7cg/47+A==", "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.3", + "bytes": "3.1.2", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } @@ -2287,101 +9745,79 @@ "mute-stream": "~0.0.4" } }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, "readdirp": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", - "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "requires": { "picomatch": "^2.2.1" } }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, "require-in-the-middle": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.0.3.tgz", - "integrity": "sha512-p/ICV8uMlqC4tjOYabLMxAWCIKa0YUQgZZ6KDM0xgXJNgdGQ1WmL2A07TwmrZw+wi6ITUFKzH5v3n+ENEyXVkA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", + "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", "requires": { "debug": "^4.1.1", "module-details-from-path": "^1.0.3", "resolve": "^1.12.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } } }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "requires": { - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-from": { @@ -2391,18 +9827,18 @@ "dev": true }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, "run-series": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.8.tgz", - "integrity": "sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg==" + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz", + "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==" }, "safe-buffer": { "version": "5.1.2", @@ -2425,14 +9861,47 @@ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "shebang-command": { "version": "2.0.0", @@ -2454,79 +9923,43 @@ "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - } + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" } }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, "smart-buffer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", - "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "socks": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", - "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", "requires": { - "ip": "1.1.5", - "smart-buffer": "^4.1.0" + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" } }, "socks-proxy-agent": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", - "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", "requires": { - "agent-base": "~4.2.1", - "socks": "~2.3.2" - }, - "dependencies": { - "agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", - "requires": { - "es6-promisify": "^5.0.0" - } - } + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" } }, "source-map": { @@ -2535,144 +9968,50 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-support": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", - "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" } }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", - "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", - "dev": true - }, "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "steno": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/steno/-/steno-2.1.0.tgz", + "integrity": "sha512-mauOsiaqTNGFkWqIfwcm3y/fq+qKKaIWf1vf3ocOuTdco9XoHCO2AGF1gFYXuZFSWuP38Q8LBHBGJv2KnJSXyA==" + }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "stubs": "^3.0.0" } }, "string_decoder": { @@ -2680,13 +10019,42 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" } }, "strip-bom": { @@ -2701,6 +10069,12 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2709,22 +10083,47 @@ "has-flag": "^4.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, "systeminformation": { - "version": "4.27.3", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.27.3.tgz", - "integrity": "sha512-0Nc8AYEK818h7FI+bbe/kj7xXsMD5zOHvO9alUqQH/G4MHXu5tHQfWqC/bzWOk4JtoQPhnyLgxMYncDA2eeSBw==", + "version": "5.11.4", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.11.4.tgz", + "integrity": "sha512-rh7bjpjP5whUaTknim5CiGdAiKZcgWhmbmxjzBRXDWqUc/k67bz2OP+03DdcX6/SN/CDSAi/NeUwM5o2gjHJoA==", "optional": true }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "teeny-request": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.1.1.tgz", + "integrity": "sha512-iwY6rkW5DDGq8hE2YgNQlKbptYpY5Nn2xecjQiNjOXWbKzPGUfmeUBCSQbbr306d7Z7U2N0TPl+/SwYRfua1Dg==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" } }, "text-table": { @@ -2733,10 +10132,11 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "thunkify": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", - "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=" + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true }, "to-regex-range": { "version": "5.0.1", @@ -2747,14 +10147,20 @@ } }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true }, "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", + "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", "dev": true, "requires": { "@types/json5": "^0.0.29", @@ -2764,29 +10170,66 @@ } }, "tslib": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", - "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==" + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, "tv4": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=" }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "tx2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tx2/-/tx2-1.0.5.tgz", + "integrity": "sha512-sJ24w0y03Md/bxzK4FU8J8JveYYUbSs2FViLJ2D/8bytSiyPRbuE3DyL/9UKYXTZlV3yXq0L8GLlhobTnekCVg==", + "optional": true, "requires": { - "prelude-ls": "~1.1.2" + "json-stringify-safe": "^5.0.1" } }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "union": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", @@ -2795,29 +10238,38 @@ "qs": "^6.4.0" } }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { "punycode": "^2.1.0" } }, "url-join": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", - "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "urlgrey": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-1.0.0.tgz", + "integrity": "sha512-hJfIzMPJmI9IlLkby8QrsCykQ+SXDeO2W5Q9QTW3QpqZVTx4a/K7p8/5q+/isD8vsbVaFgql/gvAoQCRQ2Cb5w==", + "dev": true, + "requires": { + "fast-url-parser": "^1.1.3" + } }, "uuid": { "version": "3.4.0", @@ -2825,36 +10277,94 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } } }, "vizion": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/vizion/-/vizion-0.2.13.tgz", - "integrity": "sha1-ExTN7is0EW+fWxJIU2+V2/zW718=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vizion/-/vizion-2.2.1.tgz", + "integrity": "sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww==", "requires": { - "async": "1.5" + "async": "^2.6.3", + "git-node-fs": "^1.0.0", + "ini": "^1.3.5", + "js-git": "^0.7.8" }, "dependencies": { "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "requires": { + "lodash": "^4.17.14" + } } } }, + "vm2": { + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.8.tgz", + "integrity": "sha512-/1PYg/BwdKzMPo8maOZ0heT7DLI0DAFTm7YQaz/Lim9oIaFZsJs3EdtalvXuBfZwczNwsYhju75NW4d6E+4q+w==", + "requires": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "requires": { + "iconv-lite": "0.6.3" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2864,35 +10374,79 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "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" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, + "workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "requires": { - "mkdirp": "^0.5.1" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, "ws": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz", - "integrity": "sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA==" + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "requires": {} }, "xregexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -2906,6 +10460,57 @@ "argparse": "^1.0.7", "glob": "^7.0.5" } + }, + "yargs": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==" + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index 6be4671..3861229 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "hack.chat-v2", - "version": "2.1.93", + "version": "2.2.0", + "type": "module", "description": "a minimal distraction free chat application", - "main": "index.js", + "main": "main.mjs", "repository": { "type": "git", "url": "git+https://github.com/hack-chat/main.git" @@ -12,26 +13,38 @@ "npm": ">= 6.7.0" }, "scripts": { - "start": "pm2 startOrReload pm2.config.js", - "stop": "pm2 stop pm2.config.js && pm2 delete pm2.config.js", + "start": "pm2 startOrReload pm2.config.cjs", + "stop": "pm2 stop pm2.config.cjs && pm2 delete pm2.config.cjs", "logs": "pm2 logs", "clear": "pm2 flush", "status": "pm2 list", - "refresh": "pm2 flush && pm2 stop pm2.config.js && pm2 delete pm2.config.js", - "postinstall": "cd ./server && npm install && npm run config", - "lint": "eslint --ignore-path .gitignore -- ./server ", - "lint:fix": "eslint --ignore-path .gitignore --fix -- ./server " + "refresh": "pm2 flush && pm2 stop pm2.config.cjs && pm2 delete pm2.config.cjs", + "postinstall": "npm run config", + "config": "node ./scripts/config.js", + "lint": "eslint -- . ", + "lint:fix": "eslint --fix -- . ", + "test_run": "cls && npm run refresh && npm start && npm run logs && npm run stop", + "test": "npm run lint && c8 mocha --exit ./test/*.test.js", + "makedocs": "jsdoc -c jsdoc.json" }, "author": "Marzavec", - "license": "WTFPL", + "license": "MIT", "dependencies": { - "esm": "^3.2.25", - "http-server": "^0.12.3", - "pm2": "^4.4.1" + "enquirer": "^2.3.6", + "hackchat-server": "^2.2.27", + "http-server": "^14.1.0", + "jsonwebtoken": "^8.5.1", + "lowdb": "^3.0.0", + "pm2": "^5.2.0" }, "devDependencies": { - "eslint": "^7.9.0", - "eslint-config-airbnb-base": "^14.2.0", - "eslint-plugin-import": "^2.22.0" + "c8": "^7.11.0", + "chai": "^4.3.6", + "codecov": "^3.8.3", + "eslint": "^8.9.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.25.4", + "mocha": "^9.2.1", + "nyc": "^15.1.0" } } diff --git a/pm2.config.js b/pm2.config.cjs similarity index 79% rename from pm2.config.js rename to pm2.config.cjs index 491f8e1..364373a 100644 --- a/pm2.config.js +++ b/pm2.config.cjs @@ -1,13 +1,11 @@ module.exports = { apps : [{ - name : 'hackchat-websocket', - node_args : '-r esm', - script : './server/main.js', - instances: 1, + name: 'hackchat-websocket', + script: './main.mjs', autorestart: true, max_memory_restart: '2G', exec_mode: 'fork', - watch : false, + watch: false, env: { NODE_ENV: 'development' }, diff --git a/scripts/config.js b/scripts/config.js new file mode 100644 index 0000000..89d3d80 --- /dev/null +++ b/scripts/config.js @@ -0,0 +1,191 @@ +/* eslint-disable no-await-in-loop */ +/* eslint import/no-unresolved: 0 */ + +import fs from 'fs'; +import { Low, JSONFile } from 'lowdb'; +import crypto from 'crypto'; +import enquirerPkg from 'enquirer'; + +const { + Select, + Confirm, + Password, + Input, +} = enquirerPkg; + +// required file paths +const SessionLocation = './session.key'; +const SaltLocation = './salt.key'; +const AppConfigLocation = './config.json'; + +// default configuration options +const defaultConfig = { + adminTrip: '', + globalMods: [], + publicChannels: [], + permissions: [], +}; + +// standard / default channel list +const defaultChannels = [ + 'lounge', + 'meta', + 'math', + 'physics', + 'chemistry', + 'technology', + 'programming', + 'games', + 'banana', +]; + +// load the configuration data +const adapter = new JSONFile(AppConfigLocation); +const config = new Low(adapter); + +// check for missing cert, generate if needed +const checkCert = async () => { + if (fs.existsSync(SessionLocation) === false) { + const prompt = new Confirm({ + name: 'certDialogue', + message: 'Missing session key, create new?', + }); + + if (await prompt.run() !== false) { + const data = crypto.randomBytes(4096); + + fs.writeFile(SessionLocation, data, (err) => { + if (err) throw err; + }); + } + } else { + console.log('Found existing session key.'); + } +}; + +// check for missing or uninitialized config +const checkConfig = async () => { + await config.read(); + + if (config.data === null) { + config.data = defaultConfig; + await config.write(); + } +}; + +// check for missing or uninitialized salt +const checkTripSalt = async () => { + if (fs.existsSync(SaltLocation) === false) { + const prompt = new Confirm({ + name: 'overwrite', + message: 'Missing trip salt, create new?', + }); + + if (await prompt.run() !== false) { + const data = crypto.randomBytes(4096); + + fs.writeFileSync(SaltLocation, data); + } + } else { + console.log('Found existing trip salt.'); + } +}; + +// verify config has an admin account +const checkPermissions = async () => { + if (typeof config.data.adminTrip === 'undefined' || config.data.adminTrip === '') { + const salt = fs.readFileSync(SaltLocation); + + const prompt = new Password({ + name: 'adminPassword', + message: 'What is your admin password?', + }); + + const password = await prompt.run(); + + const sha = crypto.createHash('sha256'); + sha.update(password + salt); + config.data.adminTrip = sha.digest('base64').substr(0, 6); + + await config.write(); + } else { + console.log(`Found admin trip: ${config.data.adminTrip}`); + } +}; + +// prompt user for a channel name +const getChannel = async () => { + const chanPrompt = new Input({ + message: 'New channel name:', + }); + + const chan = await chanPrompt.run(); + + return chan; +}; + +// prompt user to save standard channels or input their own +const setupChannels = async () => { + const standardMode = 'Use standard channels'; + const manualMode = 'Manual input'; + const modePrompt = new Select({ + name: 'mode', + message: 'How would you like to setup the public channels?', + choices: [ + standardMode, + manualMode, + ], + }); + + const mode = await modePrompt.run(); + + if (mode === standardMode) { + config.data.publicChannels = defaultChannels; + + await config.write(); + } else { + const channels = []; + let newChannel = ''; + + for (;;) { + console.log('(Leave blank to finish) Channels:', channels.join(', ')); + newChannel = await getChannel(); + + if (newChannel === '') { + break; + } else { + channels.push(newChannel); + } + } + + config.data.publicChannels = channels; + + await config.write(); + } +}; + +// check if pulic channels have been initialized +const checkPublicChannels = async () => { + if (typeof config.data.publicChannels === 'undefined' || config.data.publicChannels.length === 0) { + const prompt = new Confirm({ + name: 'addChannels', + message: 'Missing public channels, setup now?', + }); + + if (await prompt.run() !== false) { + await setupChannels(); + } + } else { + console.log('Found existing public channels.'); + } +}; + +// start checking +await checkCert(); +await checkConfig(); +await checkTripSalt(); +await checkPermissions(); +await checkPublicChannels(); + +// done! +console.log('Config completed!'); diff --git a/server/main.js b/server/main.js deleted file mode 100644 index 55b116b..0000000 --- a/server/main.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * HackChat main server entry point - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ - -// import and initialize the core application -import CoreApp from './src/serverLib/CoreApp'; - -const coreApp = new CoreApp(); -coreApp.init(); diff --git a/server/package-lock.json b/server/package-lock.json deleted file mode 100644 index 8049c6c..0000000 --- a/server/package-lock.json +++ /dev/null @@ -1,357 +0,0 @@ -{ - "name": "hack.chat-v2", - "version": "2.1.93", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "ascii-captcha": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/ascii-captcha/-/ascii-captcha-0.0.3.tgz", - "integrity": "sha1-NAtO1oVYOHEHsJVzBC/kc4v0mPk=" - }, - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - }, - "common-tags": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", - "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" - }, - "dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" - }, - "deep-equal": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", - "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=" - }, - "didyoumean2": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/didyoumean2/-/didyoumean2-4.0.0.tgz", - "integrity": "sha512-7+OMIHqPDJ4uxeExQx8cSk26oD3KUloAQzi2R+3rmTU4IHvSDDmWZTQ6bmC4+MTw61DkYoh5ARxwS9MRoz0t2A==", - "requires": { - "leven": "^3.1.0", - "lodash.deburr": "^4.1.0" - } - }, - "esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" - }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "i": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", - "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, - "lodash.deburr": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz", - "integrity": "sha1-3bG7s+8HRYwBd7oH3hRCLLAz/5s=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" - }, - "ncp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz", - "integrity": "sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "pkginfo": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", - "integrity": "sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=" - }, - "prompt": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.0.0.tgz", - "integrity": "sha1-jlcSPDlquYiJf7Mn/Trtw+c15P4=", - "requires": { - "colors": "^1.1.2", - "pkginfo": "0.x.x", - "read": "1.0.x", - "revalidator": "0.1.x", - "utile": "0.3.x", - "winston": "2.1.x" - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "requires": { - "mute-stream": "~0.0.4" - } - }, - "readdir-recursive": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/readdir-recursive/-/readdir-recursive-0.0.4.tgz", - "integrity": "sha1-mvQ1q6nFi9gNvclIi025up8SMB8=" - }, - "revalidator": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", - "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=" - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "utile": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/utile/-/utile-0.3.0.tgz", - "integrity": "sha1-E1LDQOuCDk2N26A5pPv6oy7U7zo=", - "requires": { - "async": "~0.9.0", - "deep-equal": "~0.2.1", - "i": "0.3.x", - "mkdirp": "0.x.x", - "ncp": "1.0.x", - "rimraf": "2.x.x" - } - }, - "winston": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.1.1.tgz", - "integrity": "sha1-PJNJ0ZYgf9G9/51LxD73JRDjoS4=", - "requires": { - "async": "~1.0.0", - "colors": "1.0.x", - "cycle": "1.0.x", - "eyes": "0.1.x", - "isstream": "0.1.x", - "pkginfo": "0.3.x", - "stack-trace": "0.0.x" - }, - "dependencies": { - "async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" - }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" - }, - "pkginfo": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", - "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "ws": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", - "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==" - } - } -} diff --git a/server/package.json b/server/package.json deleted file mode 100644 index a6459d7..0000000 --- a/server/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "hack.chat-v2", - "version": "2.1.93", - "description": "a minimal distraction free chat application", - "main": "main.js", - "repository": { - "type": "git", - "url": "git+https://github.com/hack-chat/main.git" - }, - "engines": { - "node": ">= 8.10.0", - "npm": ">= 5.7.1" - }, - "scripts": { - "start": "node -r esm main.js", - "config": "node -r esm src/scripts/configure.js" - }, - "author": "Marzavec", - "license": "WTFPL", - "dependencies": { - "ascii-captcha": "0.0.3", - "chalk": "^3.0.0", - "common-tags": "^1.8.0", - "dateformat": "^3.0.3", - "didyoumean2": "^4.0.0", - "esm": "^3.2.25", - "fs-extra": "^8.1.0", - "prompt": "^1.0.0", - "readdir-recursive": "0.0.4", - "ws": "^7.2.3" - } -} diff --git a/server/src/scripts/configLib/SetupWizard.js b/server/src/scripts/configLib/SetupWizard.js deleted file mode 100644 index 3bb0823..0000000 --- a/server/src/scripts/configLib/SetupWizard.js +++ /dev/null @@ -1,115 +0,0 @@ -/* eslint no-bitwise: 0 */ -/* eslint global-require: 0 */ -/* eslint class-methods-use-this: 0 */ -/* eslint no-param-reassign: 0 */ -/* eslint no-console: 0 */ - -import { - start as _start, - get, -} from 'prompt'; - -/** - * Server setup wizard, quick server setup and all that jazz. . . - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - * @todo Convert to use the `enquirer` package instead - */ -class SetupWizard { - /** - * Create a `SetupWizard` instance for initializing the server's config.json - * @param {Object} serverConfig reference to the server config class - */ - constructor(serverConfig) { - this.serverConfig = serverConfig; - } - - /** - * Roll a d20 and begin the wizarding process - */ - async start() { - // load the current config to use as defaults, if available - const currentConfig = await this.serverConfig.load() || {}; - - // auto generate the salt if not currrently created - currentConfig.tripSalt = currentConfig.tripSalt - || [...Array(Math.floor(Math.random() * 1024) + 1024)].map(() => (~~(Math.random() * 36)).toString(36)).join(''); - - // load the setup questions & set their defaults - const questions = require('../setupSchema/Questions.js'); - questions.properties = this.setQuestionDefaults(questions.properties, currentConfig); - - // force password re-entry - questions.properties.adminTrip.default = ''; - questions.properties.adminTrip.required = true; - - // output the packages setup banner - require('../setupSchema/Banner.js'); - - // let's start playing 20 questions - _start(); - get(questions, (err, result) => this.finalize(err, result)); - } - - /** - * Compares the currently loaded config with the stock questions, adds a default - * and required option to the question - * @param {Object} questions the set of questions from /setupSchema - * @param {Object} currentConfig the current server options - */ - setQuestionDefaults(questions, currentConfig) { - Object.keys(questions).forEach((qName) => { - if (typeof currentConfig[qName] !== 'undefined') { - questions[qName].default = currentConfig[qName]; - questions[qName].required = false; - } else { - questions[qName].required = true; - } - }); - - return questions; - } - - /** - * Looks like all the questions have been answered, check for errors or save - * the new config file - * - * @param {Object} err any errors generated by Prompt - * @param {Object} result the answers / new config setup - */ - async finalize(err, result) { - // output errors and die if needed - if (err) { - console.error(err); - process.exit(0); - } - - // initialize default mods config - if (typeof result.mods === 'undefined') { - result.mods = []; - } - - // If we should log errors with the err stack when they occur. - // See: CommandManager.js - if (typeof result.logErrDetailed === 'undefined') { - result.logErrDetailed = false; - } - - // finally create the actual JSON file - try { - this.serverConfig.config = result; - await this.serverConfig.save(); - } catch (e) { - console.error(`Couldn't write config to ${this.serverConfig.configPath} - ${e.stack}`); - } - - // output the packages final notice before quitting - require('../setupSchema/Footer.js'); - - process.exit(0); - } -} - -export default SetupWizard; diff --git a/server/src/scripts/configure.js b/server/src/scripts/configure.js deleted file mode 100644 index d96e0df..0000000 --- a/server/src/scripts/configure.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Server configuration script, to (re)configure server options - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ - -// import required classes -import { join } from 'path'; -import ConfigManager from '../serverLib/ConfigManager'; -import SetupWizard from './configLib/SetupWizard'; - -// import and initialize configManager & dependencies -const serverConfig = new ConfigManager(join(__dirname, '../..')); -const setup = new SetupWizard(serverConfig); - -setup.start(); diff --git a/server/src/scripts/setupSchema/Banner.js b/server/src/scripts/setupSchema/Banner.js deleted file mode 100644 index 5bb2066..0000000 --- a/server/src/scripts/setupSchema/Banner.js +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint no-console: 0 */ - -/** - * This script will be run before the package starts asking for the config data, - * used to output a simple guide for the coming questions, or to spam some sexy - * ascii art at the user. - * - */ - -import { stripIndents } from 'common-tags'; -import chalk from 'chalk'; - -// gotta have that sexy console -console.log(stripIndents` - ${chalk.magenta('°º¤ø,¸¸,ø¤º°`°º¤ø,¸,ø¤°º¤ø,¸¸,ø¤º°`°º¤ø,¸°º¤ø,¸¸,ø¤º°`°º¤ø')} - ${chalk.gray('--------------(') + chalk.white(' HackChat Setup Wizard v2.0 ') + chalk.gray(')--------------')} - ${chalk.magenta('°º¤ø,¸¸,ø¤º°`°º¤ø,¸,ø¤°º¤ø,¸¸,ø¤º°`°º¤ø,¸°º¤ø,¸¸,ø¤º°`°º¤ø')} - - For advanced setup, see the documentation at: - ${chalk.green('https://github.com/hack-chat/main/tree/master/documentation')} - - ${chalk.white('Note:')} ${chalk.green('npm/yarn run config')} will re-run this utility. - - You will now be asked for the following: - - ${chalk.magenta(' Salt')}, the salt for username trip - - ${chalk.magenta('Admin Name')}, the initial admin username - - ${chalk.magenta('Admin Pass')}, the initial admin password - - ${chalk.magenta(' Port')}, the port for the websocket - \u200b -`); diff --git a/server/src/scripts/setupSchema/Footer.js b/server/src/scripts/setupSchema/Footer.js deleted file mode 100644 index 98b65a5..0000000 --- a/server/src/scripts/setupSchema/Footer.js +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint no-console: 0 */ - -/** - * This script will be run once all questions have finished and no errors have - * occured. You can congratulate the user on their fine choice in software usage - * - */ - -console.log(''); -console.log('Config generated! You may now start the server normally.'); -console.log(''); diff --git a/server/src/scripts/setupSchema/Questions.js b/server/src/scripts/setupSchema/Questions.js deleted file mode 100644 index b62834f..0000000 --- a/server/src/scripts/setupSchema/Questions.js +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint no-undef: 0 */ -/* eslint global-require: 0 */ - -/** - * This object contains Prompt ( https://www.npmjs.com/package/prompt ) style - * questions that the SetupWizard will require an answer to. Questions are asked - * in the order they are specified here. - * - * The resulting config.json file will be used by the server, accessed by the - * name specified. IE, a valid use is; config.adminName - * - */ - -const Questions = { - properties: { - tripSalt: { - description: 'Salt (leave as default)', - type: 'string', - hidden: true, - replace: '*', - before: (value) => { - salt = value; - return value; - }, - }, - - adminName: { - description: 'Admin Nickname', - pattern: /^"?[a-zA-Z0-9_]+"?$/, - type: 'string', - message: 'Nicks can only contain letters, numbers and underscores', - before: (value) => value.replace(/"/g, ''), - }, - - adminTrip: { - type: 'string', - hidden: true, - replace: '*', - description: 'Admin Password', - message: 'You must enter or re-enter a password', - before: (value) => { - const crypto = require('crypto'); - const sha = crypto.createHash('sha256'); - sha.update(value + salt); - return sha.digest('base64').substr(0, 6); - }, - }, - - websocketPort: { - type: 'integer', - message: 'The port may only be a number!', - description: 'Websocket Port', - default: '6060', - }, - }, -}; - -module.exports = Questions; diff --git a/server/src/serverLib/CommandManager.js b/server/src/serverLib/CommandManager.js deleted file mode 100644 index c1d9426..0000000 --- a/server/src/serverLib/CommandManager.js +++ /dev/null @@ -1,313 +0,0 @@ -/* eslint no-console: 0 */ - -import { - basename, - join, - sep, - dirname, - relative, -} from 'path'; -import didYouMean from 'didyoumean2'; - -// default command modules path -const CmdDir = 'src/commands'; - -/** - * Commands / protocol manager- loads, validates and handles command execution - * @property {Array} commands - Array of currently loaded command modules - * @property {Array} categories - Array of command modules categories - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ -class CommandManager { - /** - * Create a `CommandManager` instance for handling commands/protocol - * - * @param {Object} core Reference to the global core object - */ - constructor(core) { - /** - * Stored reference to the core - * @type {CoreApp} - */ - this.core = core; - - /** - * Command module storage - * @type {Array} - */ - this.commands = []; - - /** - * Command module category names (based off directory or module meta) - * @type {Array} - */ - this.categories = []; - - /** - * Full path to config.json file - * @type {String} - */ - if (typeof this.core.config.logErrDetailed === 'undefined') { - this.core.config.logErrDetailed = false; - } - } - - /** - * (Re)initializes name spaces for commands and starts load routine - * @public - * @return {String} Module errors or empty if none - */ - loadCommands() { - this.commands = []; - this.categories = []; - - const commandImports = this.core.dynamicImports.getImport(CmdDir); - let cmdErrors = ''; - Object.keys(commandImports).forEach((file) => { - const command = commandImports[file]; - const name = basename(file); - cmdErrors += this.validateAndLoad(command, file, name); - }); - - return cmdErrors; - } - - /** - * Checks the module after having been `require()`ed in and reports errors - * @param {Object} command reference to the newly loaded object - * @param {String} file file path to the module - * @param {String} name command (`cmd`) name - * @private - * @return {String} Module errors or empty if none - */ - validateAndLoad(command, file, name) { - const error = this.validateCommand(command); - - if (error) { - const errText = `Failed to load command module '${name}': ${error}`; - console.log(errText); - return errText; - } - - if (!command.category) { - const base = join(this.core.dynamicImports.base, 'commands'); - - let category = 'Uncategorized'; - if (file.indexOf(sep) > -1) { - category = dirname(relative(base, file)) - .replace(new RegExp(sep.replace('\\', '\\\\'), 'g'), '/'); - } - - // eslint-disable-next-line no-param-reassign - command.info.category = category; - - if (this.categories.indexOf(category) === -1) { - this.categories.push(category); - } - } - - if (typeof command.init === 'function') { - try { - command.init(this.core); - } catch (err) { - const errText = `Failed to initialize '${name}': ${err}`; - console.log(errText); - return errText; - } - } - - this.commands.push(command); - - return ''; - } - - /** - * Checks the module after having been `require()`ed in and reports errors - * @param {Object} object reference to the newly loaded object - * @private - * @return {String} Module errors or null if none - */ - // eslint-disable-next-line class-methods-use-this - validateCommand(object) { - if (typeof object !== 'object') { return 'command setup is invalid'; } - if (typeof object.run !== 'function') { return 'run function is missing'; } - if (typeof object.info !== 'object') { return 'info object is missing'; } - if (typeof object.info.name !== 'string') { return 'info object is missing a valid name field'; } - - return null; - } - - /** - * Pulls all command names from a passed `category` - * @param {String} category [Optional] filter return results by this category - * @public - * @return {Array} Array of command modules matching the category - */ - all(category) { - return !category ? this.commands : this.commands.filter( - (c) => c.info.category.toLowerCase() === category.toLowerCase(), - ); - } - - /** - * All category names - * @public - * @readonly - * @return {Array} Array of command category names - */ - get categoriesList() { - return this.categories; - } - - /** - * Pulls command by name or alias - * @param {String} name name or alias of command - * @public - * @return {Object} Target command module object - */ - get(name) { - return this.findBy('name', name) - || this.commands.find( - (command) => command.info.aliases instanceof Array - && command.info.aliases.indexOf(name) > -1, - ); - } - - /** - * Pulls command by arbitrary search of the `module.info` attribute - * @param {String} key name or alias of command - * @param {String} value name or alias of command - * @public - * @return {Object} Target command module object - */ - findBy(key, value) { - return this.commands.find((c) => c.info[key] === value); - } - - /** - * Runs `initHooks` function on any modules that utilize the event - * @private - * @param {Object} server main server object - */ - initCommandHooks(server) { - this.commands.filter((c) => typeof c.initHooks !== 'undefined').forEach( - (c) => c.initHooks(server), - ); - } - - /** - * Finds and executes the requested command, or fails with semi-intelligent error - * @param {Object} server main server reference - * @param {Object} socket calling socket reference - * @param {Object} data command structure passed by socket (client) - * @public - * @return {*} Arbitrary module return data - */ - handleCommand(server, socket, data) { - // Try to find command first - const command = this.get(data.cmd); - - if (command) { - return this.execute(command, server, socket, data); - } - - // Then fail with helpful (sorta) message - return this.handleFail(server, socket, data); - } - - /** - * Requested command failure handler, attempts to find command and reports back - * @param {Object} server main server reference - * @param {Object} socket calling socket reference - * @param {Object} data command structure passed by socket (client) - * @private - * @return {*} Arbitrary module return data - */ - handleFail(server, socket, data) { - const maybe = didYouMean(data.cmd, this.all().map((c) => c.info.name), { - threshold: 5, - thresholdType: 'edit-distance', - }); - - if (maybe) { - // Found a suggestion, pass it on to their dyslexic self - return this.handleCommand(server, socket, { - cmd: 'socketreply', - cmdKey: server.cmdKey, - text: `Command not found, did you mean: \`${maybe}\`?`, - }); - } - - // Request so mangled that I don't even. . . - return this.handleCommand(server, socket, { - cmd: 'socketreply', - cmdKey: server.cmdKey, - text: 'Unknown command', - }); - } - - /** - * Attempt to execute the requested command, fail if err or bad params - * @param {Object} command target command module - * @param {Object} server main server reference - * @param {Object} socket calling socket reference - * @param {Object} data command structure passed by socket (client) - * @private - * @return {*} Arbitrary module return data - */ - async execute(command, server, socket, payload) { - if (typeof command.requiredData !== 'undefined') { - const missing = []; - for (let i = 0, len = command.requiredData.length; i < len; i += 1) { - if (typeof payload[command.requiredData[i]] === 'undefined') { missing.push(command.requiredData[i]); } - } - - if (missing.length > 0) { - console.log(`Failed to execute '${ - command.info.name - }': missing required ${missing.join(', ')}\n\n`); - - this.handleCommand(server, socket, { - cmd: 'socketreply', - cmdKey: server.cmdKey, - text: `Failed to execute '${ - command.info.name - }': missing required ${missing.join(', ')}\n\n`, - }); - - return null; - } - } - - try { - return await command.run({ - core: this.core, - server, - socket, - payload, - }); - } catch (err) { - const errText = `Failed to execute '${command.info.name}': `; - - // If we have more detail enabled, then we get the trace - // if it isn't, or the property doesn't exist, then we'll get only the message - if (this.core.config.logErrDetailed === true) { - console.log(errText + err.stack); - } else { - console.log(errText + err.toString()); - } - - this.handleCommand(server, socket, { - cmd: 'socketreply', - cmdKey: server.cmdKey, - text: errText + err.toString(), - }); - - return null; - } - } -} - -export default CommandManager; diff --git a/server/src/serverLib/ConfigManager.js b/server/src/serverLib/ConfigManager.js deleted file mode 100644 index 85224f1..0000000 --- a/server/src/serverLib/ConfigManager.js +++ /dev/null @@ -1,105 +0,0 @@ -/* eslint no-console: 0 */ - -import dateFormat from 'dateformat'; -import { - existsSync, - ensureFileSync, - readJsonSync, - copySync, - writeJSONSync, - removeSync, -} from 'fs-extra'; -import { resolve } from 'path'; - -/** - * Server configuration manager, handling loading, creation, parsing and saving - * of the main config.json file - * @property {String} base - Base path that all imports are required in from - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ -class ConfigManager { - /** - * Create a `ConfigManager` instance for managing application settings - * @param {String} basePath executing directory name; __dirname - */ - constructor(basePath = __dirname) { - /** - * Full path to config.json file - * @type {String} - */ - this.configPath = resolve(basePath, 'config/config.json'); - - if (!existsSync(this.configPath)) { - ensureFileSync(this.configPath); - } - } - - /** - * Loads config.json (main server config) into memory - * @public - * @return {(JSON|Boolean)} False if the config.json could not be loaded - */ - async load() { - try { - this.config = readJsonSync(this.configPath); - } catch (e) { - return false; - } - - return this.config; - } - - /** - * Creates backup of current config into configPath - * @private - * @return {String} Backed up config.json path - */ - backup() { - const backupPath = `${this.configPath}.${dateFormat('dd-mm-yy-HH-MM-ss')}.bak`; - copySync(this.configPath, backupPath); - - return backupPath; - } - - /** - * First makes a backup of the current `config.json`, then writes current config - * to disk - * @public - * @return {Boolean} False on failure - */ - save() { - const backupPath = this.backup(); - - try { - writeJSONSync(this.configPath, this.config, { - // Indent with two spaces - spaces: 2, - }); - removeSync(backupPath); - - return true; - } catch (err) { - console.log(`Failed to save config file: ${err}`); - - return false; - } - } - - /** - * Updates current config[`key`] with `value` then writes changes to disk - * @param {*} key arbitrary configuration key - * @param {*} value new value to change `key` to - * @public - * @return {Boolean} False on failure - */ - set(key, value) { - const realKey = `${key}`; - this.config[realKey] = value; - - return this.save(); - } -} - -export default ConfigManager; diff --git a/server/src/serverLib/CoreApp.js b/server/src/serverLib/CoreApp.js deleted file mode 100644 index 5fb7233..0000000 --- a/server/src/serverLib/CoreApp.js +++ /dev/null @@ -1,95 +0,0 @@ -/* eslint no-console: 0 */ - -import { join } from 'path'; -import { - CommandManager, - ConfigManager, - ImportsManager, - MainServer, - StatsManager, -} from '.'; - -/** - * The core app builds all required classes and maintains a central - * reference point across the app - * @property {ConfigManager} configManager - Provides loading and saving of the server config - * @property {Object} config - The current json config object - * @property {ImportsManager} dynamicImports - Dynamic require interface allowing hot reloading - * @property {CommandManager} commands - Manages and executes command modules - * @property {StatsManager} stats - Stores and adjusts arbritary stat data - * @property {MainServer} server - Main websocket server reference - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ -class CoreApp { - /** - * Load config then initialize children - * @public - * @return {void} - */ - async init() { - await this.buildConfigManager(); - - this.buildImportManager(); - this.buildCommandsManager(); - this.buildStatsManager(); - this.buildMainServer(); - } - - /** - * Creates a new instance of the ConfigManager, loads and checks - * the server config - * @private - * @return {void} - */ - async buildConfigManager() { - this.configManager = new ConfigManager(join(__dirname, '../..')); - this.config = await this.configManager.load(); - - if (this.config === false) { - console.error('Missing config.json, have you run: npm run config'); - process.exit(0); - } - } - - /** - * Creates a new instance of the ImportsManager - * @private - * @return {void} - */ - buildImportManager() { - this.dynamicImports = new ImportsManager(join(__dirname, '../..')); - } - - /** - * Creates a new instance of the CommandManager and loads the command modules - * @private - * @return {void} - */ - buildCommandsManager() { - this.commands = new CommandManager(this); - this.commands.loadCommands(); - } - - /** - * Creates a new instance of the StatsManager and sets the server start time - * @private - * @return {void} - */ - buildStatsManager() { - this.stats = new StatsManager(this); - this.stats.set('start-time', process.hrtime()); - } - - /** - * Creates a new instance of the MainServer - * @private - * @return {void} - */ - buildMainServer() { - this.server = new MainServer(this); - } -} - -export { CoreApp as default }; diff --git a/server/src/serverLib/ImportsManager.js b/server/src/serverLib/ImportsManager.js deleted file mode 100644 index ac429a0..0000000 --- a/server/src/serverLib/ImportsManager.js +++ /dev/null @@ -1,124 +0,0 @@ -/* eslint global-require: 0 */ -/* eslint no-console: 0 */ - -import { - resolve, - basename as _basename, - relative, -} from 'path'; -import RecursiveRead from 'readdir-recursive'; - -/** - * Import managment base, used to load commands/protocol and configuration objects - * @property {String} base - Base path that all imports are required in from - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ -class ImportsManager { - /** - * Create an `ImportsManager` instance for (re)loading classes and config - * @param {String} basePath executing directory name; default __dirname - */ - constructor(basePath) { - /** - * Stored reference to the base directory path - * @type {String} - */ - this.basePath = basePath; - - /** - * Data holder for imported modules - * @type {Object} - */ - this.imports = {}; - } - - /** - * Pull base path that all imports are required in from - * @public - * @type {String} readonly - */ - get base() { - return this.basePath; - } - - /** - * Gather all js files from target directory, then verify and load - * @param {String} dirName The name of the dir to load, relative to the basePath - * @private - * @return {String} Load errors or empty if none - */ - loadDir(dirName) { - const dir = resolve(this.basePath, dirName); - - let errorText = ''; - try { - RecursiveRead.fileSync(dir).forEach((file) => { - const basename = _basename(file); - if (basename.startsWith('_') || !basename.endsWith('.js')) return; - - let imported; - try { - imported = require(file); // eslint-disable-line import/no-dynamic-require - - if (!this.imports[dirName]) { - this.imports[dirName] = {}; - } - - this.imports[dirName][file] = imported; - } catch (e) { - const err = `Unable to load modules from ${dirName} (${relative(dir, file)})\n${e}`; - errorText += err; - console.error(err); - } - }); - } catch (e) { - const err = `Unable to load modules from ${dirName}\n${e}`; - errorText += err; - console.error(err); - return errorText; - } - - return errorText; - } - - /** - * Unlink references to each loaded module, pray to google that gc knows it's job, - * then reinitialize this class to start the reload - * @public - * @return {String} Load errors or empty if none - */ - reloadDirCache() { - let errorText = ''; - - Object.keys(this.imports).forEach((dir) => { - Object.keys(this.imports[dir]).forEach((mod) => { - delete require.cache[require.resolve(mod)]; - }); - - errorText += this.loadDir(dir); - }); - - return errorText; - } - - /** - * Pull reference to imported modules that were imported from dirName, or - * load required directory if not found - * @param {String} dirName The name of the dir to load, relative to the _base path. - * @public - * @return {Object} Object containing command module paths and structs - */ - getImport(dirName) { - const imported = this.imports[dirName]; - - if (!imported) { - this.loadDir(dirName); - } - - return { ...this.imports[dirName] }; - } -} - -export default ImportsManager; diff --git a/server/src/serverLib/MainServer.js b/server/src/serverLib/MainServer.js deleted file mode 100644 index 745507d..0000000 --- a/server/src/serverLib/MainServer.js +++ /dev/null @@ -1,548 +0,0 @@ -/* eslint no-bitwise: 0 */ -/* eslint no-console: 0 */ - -import { - Server as WsServer, - OPEN as SocketReady, -} from 'ws'; -import { createHash } from 'crypto'; -import RateLimiter from './RateLimiter'; - -import { ServerConst } from '../utility/Constants'; - -/** - * Main websocket server handling communications and connection events - * @property {RateLimiter} police - Main rate limit handler - * @property {String} cmdKey - Internal use command key - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ -class MainServer extends WsServer { - /** - * Create a HackChat server instance - * @param {CoreApp} core Reference to the global core object - */ - constructor(core) { - super({ port: core.config.websocketPort }); - - /** - * Stored reference to the core - * @type {CoreApp} - */ - this.core = core; - - /** - * Command key used to verify internal commands - * @type {String} - */ - this.internalCmdKey = [...Array(Math.floor(Math.random() * 128) + 128)].map(() => (~~(Math.random() * 36)).toString(36)).join(''); - - /** - * Salt used to hash a clients ip - * @type {String} - */ - this.ipSalt = [...Array(Math.floor(Math.random() * 128) + 128)].map(() => (~~(Math.random() * 36)).toString(36)).join(''); - - /** - * Data store for command hooks - * @type {Object} - */ - this.hooks = {}; - - /** - * Main rate limit tracker - * @type {RateLimiter} - */ - this.police = new RateLimiter(); - - /** - * Black listed command names - * @type {Object} - */ - this.cmdBlacklist = {}; - - /** - * Stored info about the last server error - * @type {ErrorEvent} - */ - this.lastErr = null; - - this.setupServer(); - this.loadHooks(); - } - - /** - * Internal command key getter. Used to verify that internal only commands - * originate internally and not from a connected client - * @todo Update to a structure that cannot be passed through json - * @type {String} - * @public - * @readonly - */ - get cmdKey() { - return this.internalCmdKey; - } - - /** - * Create ping interval and setup server event listeners - * @private - * @return {void} - */ - setupServer() { - this.heartBeat = setInterval(() => this.beatHeart(), ServerConst.PulseSpeed); - - this.on('error', (err) => { - this.handleError(err); - }); - - this.on('connection', (socket, request) => { - this.newConnection(socket, request); - }); - } - - /** - * Send empty `ping` frame to each client - * @private - * @return {void} - */ - beatHeart() { - const targetSockets = this.findSockets({}); - - if (targetSockets.length === 0) { - return; - } - - for (let i = 0, l = targetSockets.length; i < l; i += 1) { - try { - if (targetSockets[i].readyState === SocketReady) { - targetSockets[i].ping(); - } - } catch (e) { /* yolo */ } - } - } - - /** - * Bind listeners for the new socket created on connection to this class - * @param {ws#WebSocket} socket New socket object - * @param {Object} request Initial headers of the new connection - * @private - * @return {void} - */ - newConnection(socket, request) { - const newSocket = socket; - - newSocket.address = request.headers['x-forwarded-for'] || request.connection.remoteAddress; - - newSocket.on('message', (data) => { - this.handleData(socket, data); - }); - - newSocket.on('close', () => { - this.handleClose(socket); - }); - - newSocket.on('error', (err) => { - this.handleError(err); - }); - } - - /** - * Handle incoming messages from clients, parse and check command, then hand-off - * @param {ws#WebSocket} socket Calling socket object - * @param {String} data Message sent from client - * @private - * @return {void} - */ - handleData(socket, data) { - // Don't penalize yet, but check whether IP is rate-limited - if (this.police.frisk(socket.address, 0)) { - this.core.commands.handleCommand(this, socket, { - cmd: 'socketreply', - cmdKey: this.cmdKey, - text: 'You are being rate-limited or blocked.', - }); - - return; - } - - // Penalize here, but don't do anything about it - this.police.frisk(socket.address, 1); - - // Ignore ridiculously large packets - if (data.length > 65536) { - return; - } - - // Start sent data verification - let payload = null; - try { - payload = JSON.parse(data); - } catch (e) { - // Client sent malformed json, gtfo - socket.close(); - } - - if (payload === null) { - return; - } - - /** - * @todo make the following more flexible - * Issue #1: hard coded `cmd` check - * Issue #2: hard coded `cmd` value checks - */ - if (typeof payload.cmd !== 'string') { - return; - } - - if (typeof socket.channel === 'undefined' && (payload.cmd !== 'join' && payload.cmd !== 'session' && payload.cmd !== 'chat')) { - return; - } - - if (typeof this.cmdBlacklist[payload.cmd] === 'function') { - return; - } - // End @todo // - - // Execute `in` (incoming data) hooks and process results - payload = this.executeHooks('in', socket, payload); - - if (typeof payload === 'string') { - // A hook malfunctioned, reply with error - this.core.commands.handleCommand(this, socket, { - cmd: 'socketreply', - cmdKey: this.cmdKey, - text: payload, - }); - - return; - } if (payload === false) { - // A hook requested this data be dropped - return; - } - - // Finished verification & hooks, pass to command modules - this.core.commands.handleCommand(this, socket, payload); - } - - /** - * Pass socket close event to disconnection command module - * @param {ws#WebSocket} socket Closing socket object - * @private - * @return {void} - */ - handleClose(socket) { - this.core.commands.handleCommand(this, socket, { - cmd: 'disconnect', - cmdKey: this.cmdKey, - }); - } - - /** - * "Handle" server or socket errors - * @param {ErrorEvent} err The sad stuff - * @private - * @return {void} - */ - handleError(err) { - this.lastErr = err; - console.log(`Server error: ${err}`); - } - - /** - * Send data payload to specific socket/client - * @param {Object} payload Object to convert to json for transmission - * @param {ws#WebSocket} socket The target client - * @example - * server.send({ - * cmd: 'info', - * text: 'Only targetSocket will see this' - * }, targetSocket); - * @public - * @return {void} - */ - send(payload, socket) { - let outgoingPayload = payload; - - // Add timestamp to command - outgoingPayload.time = Date.now(); - - // Execute `in` (incoming data) hooks and process results - outgoingPayload = this.executeHooks('out', socket, outgoingPayload); - - if (typeof outgoingPayload === 'string') { - // A hook malfunctioned, reply with error - this.core.commands.handleCommand(this, socket, { - cmd: 'socketreply', - cmdKey: this.cmdKey, - text: outgoingPayload, - }); - - return; - } if (outgoingPayload === false) { - // A hook requested this data be dropped - return; - } - - try { - if (socket.readyState === SocketReady) { - socket.send(JSON.stringify(outgoingPayload)); - } - } catch (e) { console.error(e); } - } - - /** - * Overload function for `this.send()` - * @param {Object} payload Object to convert to json for transmission - * @param {ws#WebSocket} socket The target client - * @example - * server.reply({ - * cmd: 'info', - * text: 'Only targetSocket will see this' - * }, targetSocket); - * @public - * @return {void} - */ - reply(payload, socket) { - this.send(payload, socket); - } - - /** - * Finds sockets/clients that meet the filter requirements, then passes the data to them - * @param {Object} payload Object to convert to json for transmission - * @param {Object} filter see `this.findSockets()` - * @example - * server.broadcast({ - * cmd: 'info', - * text: 'Everyone in "programming" will see this' - * }, { channel: 'programming' }); - * @public - * @return {Boolean} False if no clients matched the filter, true if data sent - */ - broadcast(payload, filter) { - const targetSockets = this.findSockets(filter); - - if (targetSockets.length === 0) { - return false; - } - - for (let i = 0, l = targetSockets.length; i < l; i += 1) { - this.send(payload, targetSockets[i]); - } - - return true; - } - - /** - * Finds sockets/clients that meet the filter requirements, returns result as array - * @param {Object} data Object to convert to json for transmission - * @param {Object} filter The socket must of equal or greater attribs matching `filter` - * @example - * // match all sockets: - * `filter` = {} - * // match any socket where socket.channel === 'programming' - * `filter` = { channel: 'programming' } - * // match any socket where - * // socket.channel === 'programming' && socket.nick === 'Marzavec' - * `filter` = { channel: 'programming', nick: 'Marzavec' } - * @public - * @return {Array} Clients who matched the filter requirements - */ - findSockets(filter) { - const filterAttribs = Object.keys(filter); - const reqCount = filterAttribs.length; - let curMatch; - const matches = []; - this.clients.forEach((socket) => { - // for (const socket of this.clients) { - curMatch = 0; - - for (let i = 0; i < reqCount; i += 1) { - if (typeof socket[filterAttribs[i]] !== 'undefined') { - switch (typeof filter[filterAttribs[i]]) { - case 'object': { - if (Array.isArray(filter[filterAttribs[i]])) { - if (filter[filterAttribs[i]].indexOf(socket[filterAttribs[i]]) !== -1) { - curMatch += 1; - } - } else if (socket[filterAttribs[i]] === filter[filterAttribs[i]]) { - curMatch += 1; - } - break; - } - - case 'function': { - if (filter[filterAttribs[i]](socket[filterAttribs[i]])) { - curMatch += 1; - } - break; - } - - default: { - if (socket[filterAttribs[i]] === filter[filterAttribs[i]]) { - curMatch += 1; - } - break; - } - } - } - } - - if (curMatch === reqCount) { - matches.push(socket); - } - }); - - return matches; - } - - /** - * Hashes target socket's remote address using non-static variable length salt - * encodes and shortens the output, returns that value - * @param {(ws#WebSocket|String)} target Either the target socket or ip as string - * @example - * let userHash = server.getSocketHash('1.2.3.4'); - * let userHash = server.getSocketHash(client); - * @public - * @return {String} Hashed client connection string - */ - getSocketHash(target) { - const sha = createHash('sha256'); - - if (typeof target === 'string') { - sha.update(target + this.ipSalt); - } else { - sha.update(target.address + this.ipSalt); - } - - return sha.digest('base64').substr(0, 15); - } - - /** - * (Re)loads all command module hooks, then sorts their order of operation by - * priority, ascending (0 being highest priority) - * @public - * @return {void} - */ - loadHooks() { - // clear current hooks (if any) - this.clearHooks(); - // notify each module to register their hooks (if any) - this.core.commands.initCommandHooks(this); - - let curHooks = []; - let hookObj = []; - - if (typeof this.hooks.in !== 'undefined') { - // start sorting, with incoming first - curHooks = [...this.hooks.in.keys()]; - for (let i = 0, j = curHooks.length; i < j; i += 1) { - hookObj = this.hooks.in.get(curHooks[i]); - hookObj.sort((h1, h2) => h1.priority - h2.priority); - this.hooks.in.set(hookObj); - } - } - - if (typeof this.hooks.out !== 'undefined') { - // then outgoing - curHooks = [...this.hooks.out.keys()]; - for (let i = 0, j = curHooks.length; i < j; i += 1) { - hookObj = this.hooks.out.get(curHooks[i]); - hookObj.sort((h1, h2) => h1.priority - h2.priority); - this.hooks.out.set(hookObj); - } - } - } - - /** - * Adds a target function to an array of hooks. Hooks are executed either before - * processing user input (`in`) or before sending data back to the client (`out`) - * and allows a module to modify each payload before moving forward - * @param {String} type The type of event, typically `in` (incoming) or `out` (outgoing) - * @param {String} command Should match the desired `cmd` attrib of the payload - * @param {Function} hookFunction Target function to execute, should accept - * `server`, `socket` and `payload` as parameters - * @param {Number} priority Execution priority, hooks with priority 1 will be executed before - * hooks with priority 200 for example - * @example - * // Create hook to add "and stuff" to every chat line - * server.registerHook('in', 'chat', (server, socket, payload) => payload.text += ' and stuff'); - * @public - * @return {void} - */ - registerHook(type, command, hookFunction, priority = 25) { - if (typeof this.hooks[type] === 'undefined') { - this.hooks[type] = new Map(); - } - - if (!this.hooks[type].has(command)) { - this.hooks[type].set(command, []); - } - - this.hooks[type].get(command).push({ - run: hookFunction, - priority, - }); - } - - /** - * Loops through registered hooks & processes the results. Returned data will - * be one of three possiblities: - * A payload (modified or not) that will continue through the data flow - * A boolean false to indicate halting the data through flow - * A string which indicates an error occured in executing the hook - * @param {String} type The type of event, typically `in` (incoming) or `out` (outgoing) - * @param {ws#WebSocket} socket Either target client or client (depends on `type`) - * @param {Object} payload Either incoming data from client or outgoing data (depends on `type`) - * @public - * @return {Object|Boolean} - */ - executeHooks(type, socket, payload) { - const command = payload.cmd; - let newPayload = payload; - - if (typeof this.hooks[type] !== 'undefined') { - if (this.hooks[type].has(command)) { - const hooks = this.hooks[type].get(command); - - for (let i = 0, j = hooks.length; i < j; i += 1) { - try { - newPayload = hooks[i].run({ - core: this.core, - server: this, - socket, - payload: newPayload, - }); - } catch (err) { - const errText = `Hook failure, '${type}', '${command}': `; - if (this.core.config.logErrDetailed === true) { - console.log(errText + err.stack); - } else { - console.log(errText + err.toString()); - } - return errText + err.toString(); - } - - // A hook function may choose to return false to prevent all further processing - if (newPayload === false) { - return false; - } - } - } - } - - return newPayload; - } - - /** - * Wipe server hooks to make ready for module reload calls - * @public - * @return {void} - */ - clearHooks() { - this.hooks = {}; - } -} - -export default MainServer; diff --git a/server/src/serverLib/RateLimiter.js b/server/src/serverLib/RateLimiter.js deleted file mode 100644 index 9e526b7..0000000 --- a/server/src/serverLib/RateLimiter.js +++ /dev/null @@ -1,139 +0,0 @@ -import { RateLimits } from '../utility/Constants'; - -/** - * Tracks frequency of occurances based on `id` (remote address), then allows or - * denies command execution based on comparison with `threshold` - * @property {Object} data - The current stats data - * @author Marzavec ( https://github.com/marzavec ) - * @author Andrew Belt ( https://github.com/AndrewBelt ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ -class RateLimiter { - /** - * Create a ratelimiter instance - */ - constructor() { - /** - * Data holder rate limit records - * @type {Object} - */ - this.records = {}; - - /** - * Time in milliseconds to decrement ratelimit weight - * @type {Number} - */ - this.halflife = RateLimits.halflife; - - /** - * Weight until ratelimited - * @type {Number} - */ - this.threshold = RateLimits.threshold; - - /** - * Stores the associated connection fingerprint with record id - * @type {Array} - */ - this.hashes = []; - } - - /** - * Finds current score by `id` - * @param {String} id target id / address - * @private - * @return {Object} Object containing the record meta - */ - search(id) { - let record = this.records[id]; - - if (!record) { - this.records[id] = { - time: Date.now(), - score: 0, - }; - - record = this.records[id]; - } - - return record; - } - - /** - * Adjusts the current ratelimit score by `deltaScore` - * @param {String} id target id / address - * @param {Number} deltaScore amount to adjust current score by - * @example - * // Penalize by 1 and store if connection is ratelimited or not - * let isLimited = police.frisk(socket.address, 1); - * @public - * @return {Boolean} True if record threshold has been exceeded - */ - frisk(id, deltaScore) { - const record = this.search(id); - - if (record.arrested) { - return true; - } - - // eslint-disable-next-line no-restricted-properties - record.score *= Math.pow(2, -(Date.now() - record.time) / this.halflife); - record.score += deltaScore; - record.time = Date.now(); - - if (record.score >= this.threshold) { - return true; - } - - return false; - } - - /** - * Statically set server to no longer accept traffic from `id` - * @param {String} id target id / address - * @example - * // Usage within a command module: - * let badClient = server.findSockets({ channel: socket.channel, nick: targetNick }); - * server.police.arrest(badClient[0].address, badClient[0].hash); - * @public - * @return {void} - */ - arrest(id, hash) { - const record = this.search(id); - - record.arrested = true; - this.hashes[hash] = id; - } - - /** - * Remove statically assigned limit from `id` - * @param {String} id target id / address - * @example - * // Usage within a command module: - * server.police.pardon('targetHashOrIP'); - * @public - * @return {void} - */ - pardon(id) { - let targetId = id; - if (typeof this.hashes[targetId] !== 'undefined') { - targetId = this.hashes[targetId]; - } - - const record = this.search(targetId); - record.arrested = false; - } - - /** - * Clear all records - * @public - * @return {void} - */ - clear() { - this.records = {}; - this.hashes = []; - } -} - -export default RateLimiter; diff --git a/server/src/serverLib/StatsManager.js b/server/src/serverLib/StatsManager.js deleted file mode 100644 index b6e4f97..0000000 --- a/server/src/serverLib/StatsManager.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Simple generic stats collection script for events occurances (etc) - * @property {Object} data - The current stats data - * @author Marzavec ( https://github.com/marzavec ) - * @version v2.0.0 - * @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) - */ -class StatsManager { - /** - * Create a stats instance - */ - constructor() { - /** - * Data holder for the stats class - * @type {Object} - */ - this.data = {}; - } - - /** - * Retrieve value of arbitrary `key` reference - * @param {String} key Reference to the arbitrary store name - * @example - * // Find previously set `start-time` - * stats.get('start-time'); - * @public - * @return {*} Data referenced by `key` - */ - get(key) { - return this.data[key]; - } - - /** - * Set value of arbitrary `key` reference - * @param {String} key Reference to the arbitrary store name - * @param {Number} value New value for `key` - * @example - * // Set `start-time` - * stats.set('start-time', process.hrtime()); - * @public - * @return {void} - */ - set(key, value) { - this.data[key] = value; - } - - /** - * Increase value of arbitrary `key` reference, by 1 or `amount` - * @param {String} key Reference to the arbitrary store name - * @param {?Number} [amount=1] Value to increase `key` by, or 1 if omitted - * @example - * // Increment by `amount` - * stats.increment('users', 6); - * // Increment by 1 - * stats.increment('users'); - * @public - * @return {void} - */ - increment(key, amount = 1) { - this.set(key, (this.get(key) || 0) + amount); - } - - /** - * Reduce value of arbitrary `key` reference, by 1 or `amount` - * @param {String} key Reference to the arbitrary store name - * @param {?Number} [amount=1] Value to decrease `key` by, or 1 if omitted - * @example - * // Decrement by `amount` - * stats.decrement('users', 6); - * // Decrement by 1 - * stats.decrement('users'); - * @public - * @return {void} - */ - decrement(key, amount = 1) { - this.set(key, (this.get(key) || 0) - amount); - } -} - -module.exports = StatsManager; diff --git a/server/src/serverLib/index.js b/server/src/serverLib/index.js deleted file mode 100644 index 21cfa14..0000000 --- a/server/src/serverLib/index.js +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint global-require: 0 */ - -export const CommandManager = require('./CommandManager').default; -export const ConfigManager = require('./ConfigManager').default; -export const ImportsManager = require('./ImportsManager').default; -export const MainServer = require('./MainServer').default; -export const RateLimiter = require('./RateLimiter').default; -export const StatsManager = require('./StatsManager'); diff --git a/server/src/utility/Constants.js b/server/src/utility/Constants.js deleted file mode 100644 index 6836421..0000000 --- a/server/src/utility/Constants.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Rate limit options - * @typedef {Object} RateLimits - * @property {number} halflife Time in milliseconds to decrement ratelimit weight - * @property {number} threshold Weight until ratelimited - */ -exports.RateLimits = { - halflife: 30 * 1000, - threshold: 25, -}; - -/** - * Websocket server options - * @typedef {Object} ServerConst - * @property {number} PulseSpeed Time in milliseconds to ping each client - */ -exports.ServerConst = { - PulseSpeed: 16 * 1000, -}; diff --git a/test/addmod.test.js b/test/addmod.test.js new file mode 100644 index 0000000..fb32def --- /dev/null +++ b/test/addmod.test.js @@ -0,0 +1,78 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/admin/addmod.js'; +let importedModule; + +const mockPayload = { + cmd: 'addmod', + trip: 'newTrip', +} + +describe('Checking addmod module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by an admin', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should add new trip to the config', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(mocks.core.appConfig.data.globalMods[0].trip).to.equal(mockPayload.trip); + }); + + it('should inform the new mod', async () => { + mocks.server.findSockets = () => { + return [{}]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + mocks.core.appConfig.data.globalMods = []; + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/ban.test.js b/test/ban.test.js new file mode 100644 index 0000000..99af113 --- /dev/null +++ b/test/ban.test.js @@ -0,0 +1,145 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/ban.js'; +let importedModule; + +const mockPayload = { + cmd: 'ban', + userid: 1234, +} + +describe('Checking ban module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should check for invalid legacy params', async () => { + mocks.authedSocket.hcProtocol = 1; + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should verify legacy params', async () => { + mocks.authedSocket.hcProtocol = 1; + mockPayload.nick = 5431; + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should accept legacy params', async () => { + mocks.authedSocket.hcProtocol = 1; + mockPayload.nick = 'lies'; + mocks.server.findSockets = (filterObj) => { + return false; + } + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should check for invalid params', async () => { + mocks.authedSocket.hcProtocol = 2; + mockPayload.userid = 'test'; + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should not ban mods', async () => { + mocks.authedSocket.hcProtocol = 2; + mockPayload.userid = 1234; + + mocks.server.findSockets = (filterObj) => { + return [mocks.authedSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should blacklist the ip', async () => { + mocks.authedSocket.hcProtocol = 2; + mockPayload.userid = 1234; + + mocks.server.findSockets = (filterObj) => { + if (typeof filterObj.level === 'function') { + filterObj.level(); + } + + return [mocks.plebSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(mocks.server.police.addresses[0]).to.be.a('string'); + }); + +}); \ No newline at end of file diff --git a/test/changecolor.test.js b/test/changecolor.test.js new file mode 100644 index 0000000..47500bb --- /dev/null +++ b/test/changecolor.test.js @@ -0,0 +1,126 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/changecolor.js'; +let importedModule; + +const mockPayload = { + cmd: 'changecolor', + color: '#000000', +} + +describe('Checking changecolor module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should ratelimit if required', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should check for invalid color type', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changecolor', + color: false, + }, + }); + + expect(resp).to.be.false; + }); + + it('should check for invalid color', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changecolor', + color: 'This is an invalid color', + }, + }); + + expect(resp).to.be.true; + }); + + it('should allow a color reset', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changecolor', + color: 'reset', + }, + }); + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should hook chat text to register /color', async () => { + const resp = importedModule.colorCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changecolor', + color: 'reset', + }, + }); + + expect(resp).to.be.false; + }); +}); \ No newline at end of file diff --git a/test/changenick.test.js b/test/changenick.test.js new file mode 100644 index 0000000..cdc6c39 --- /dev/null +++ b/test/changenick.test.js @@ -0,0 +1,253 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/changenick.js'; +let importedModule; + +const mockPayload = { + cmd: 'changenick', + nick: 'newNick', +} + +describe('Checking changenick module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should ratelimit if required', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should validate nick param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changenick', + nick: 1234, + }, + }); + + expect(resp).to.be.true; + }); + + it('should verify nick param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changenick', + nick: 'this is invalid', + }, + }); + + expect(resp).to.be.true; + }); + + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should prevent admin impersonation', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changenick', + nick: 'admin', + }, + }); + + expect(resp).to.be.true; + }); + + it('should not update if there is no change', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changenick', + nick: 'lies', + }, + }); + + expect(resp).to.be.true; + }); + + it('should allow them to change case', async () => { + const origFindSockets = mocks.server.findSockets; + mocks.server.findSockets = (filterObj) => { + if (typeof filterObj.nick === 'function') { + filterObj.nick('lies'); + } + + return [mocks.plebSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changenick', + nick: 'Lies', + }, + }); + + mocks.server.findSockets = origFindSockets; + + expect(resp).to.be.true; + }); + + it('should not update if that nick exists', async () => { + const origFindSockets = mocks.server.findSockets; + mocks.server.findSockets = (filterObj) => { + if (typeof filterObj.nick === 'function') { + filterObj.nick('lies'); + } + + return [mocks.plebSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.findSockets = origFindSockets; + + expect(resp).to.be.true; + }); + + it('should output new user details to the channel', async () => { + const origFindSockets = mocks.server.findSockets; + const legacySocket = Object.assign({}, mocks.plebSocket); + legacySocket.hcProtocol = 1; + mocks.server.findSockets = (data) => { + if (typeof data.nick !== 'undefined' ) { + return []; + } + + return [mocks.plebSocket, legacySocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.findSockets = origFindSockets; + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should hook should validate text input', async () => { + const resp = importedModule.nickCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: false, + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook should verify text starts with /nick', async () => { + const resp = importedModule.nickCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: 'No slash command', + }, + }); + + expect(resp).to.be.an('object'); + }); + + it('should hook should run with /nick', async () => { + const resp = importedModule.nickCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/nick test', + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook fail on mangled input', async () => { + const resp = importedModule.nickCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/nick ', + }, + }); + + expect(resp).to.be.false; + }); +}); \ No newline at end of file diff --git a/test/channels.test.js b/test/channels.test.js new file mode 100644 index 0000000..a4587b3 --- /dev/null +++ b/test/channels.test.js @@ -0,0 +1,65 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/utility/_Channels.js'; +let importedModule; + +describe('Checking channels module', () => { + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should reject empty channels', async () => { + const resp = importedModule.canJoinChannel('', {}); + expect(resp).to.be.a('number'); + }); + + it('should reject too long of channels', async () => { + const resp = importedModule.canJoinChannel('a'.repeat(121), {}); + expect(resp).to.be.a('number'); + }); + + it('should get channel data', async () => { + const newConfig = Object.assign({}, mocks.core.appConfig.data); + newConfig.permissions['test'] = {}; + const resp = importedModule.getChannelSettings(mocks.core.appConfig.data, 'test'); + expect(resp).to.be.an('object'); + }); + + it('should return empty array findUsers', async () => { + const resp = importedModule.findUsers({}, {}); + expect(resp).to.be.an('array'); + }); + + it('should limit results', async () => { + const oldFS = mocks.server.findSockets; + mocks.server.findSockets = (filterObj) => { + return [1, 2, 3]; + } + const resp = importedModule.findUsers(mocks.server, { + userid: 1234, + }, 1); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.an('array'); + }); + + it('should respond to banned sockets', async () => { + const newSocket = Object.assign({}, mocks.plebSocket); + newSocket.banned = true; + + const resp = importedModule.canJoinChannel('test', newSocket); + + expect(resp).to.be.an('number'); + }); + + it('should provide duplicate user checks', async () => { + const newSocket = Object.assign({}, mocks.plebSocket); + + const resp = importedModule.socketInChannel(mocks.server, 'test', newSocket); + + expect(resp).to.be.an('object'); + }); +}) \ No newline at end of file diff --git a/test/chat.test.js b/test/chat.test.js new file mode 100644 index 0000000..9615572 --- /dev/null +++ b/test/chat.test.js @@ -0,0 +1,198 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/chat.js'; +let importedModule; + +const mockPayload = { + cmd: 'chat', + channel: 'cake', + text: 'testing', +} + +describe('Checking chat module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should ratelimit on invalid text', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + channel: 'cake', + text: [], + }, + }); + + expect(resp).to.be.false; + }); + + it('should ratelimit if required', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should add sender admin label', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should add sender mod label', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.level = 999999; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should add color', async () => { + const newSocket = Object.assign({}, mocks.plebSocket); + newSocket.color = '000000'; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should hook for / based commands', async () => { + const resp = importedModule.commandCheckIn({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.an('object'); + }); + + it('should validate hook text param', async () => { + const resp = importedModule.commandCheckIn({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + channel: 'cake', + text: false, + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook for /myhash', async () => { + const resp = importedModule.commandCheckIn({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + channel: 'cake', + text: '/myhash', + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook for failed / commands, validating text input', async () => { + const resp = importedModule.finalCmdCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + channel: 'cake', + text: false, + }, + }); + + expect(resp).to.be.false; + }); + + it('should final hook should ignore if input doesnt start with /', async () => { + const resp = importedModule.finalCmdCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + channel: 'cake', + text: 'test', + }, + }); + + expect(resp).to.be.an('object'); + }); +}); \ No newline at end of file diff --git a/test/disconnect.test.js b/test/disconnect.test.js new file mode 100644 index 0000000..3ccdf18 --- /dev/null +++ b/test/disconnect.test.js @@ -0,0 +1,80 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/internal/disconnect.js'; +let importedModule; + +const mockPayload = { + cmd: 'disconnect', +} + +describe('Checking disconnect module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only internally', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should broadcast online remove event', async () => { + mockPayload.cmdKey = 'test'; + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should not broadcast online remove event if there is a duplicate', async () => { + const origFindSockets = mocks.server.findSockets; + mocks.server.findSockets = (data) => { + return []; + } + + mockPayload.cmdKey = 'test'; + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.findSockets = origFindSockets; + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/dumb.test.js b/test/dumb.test.js new file mode 100644 index 0000000..2c463c3 --- /dev/null +++ b/test/dumb.test.js @@ -0,0 +1,366 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/dumb.js'; +let importedModule; + +const mockPayload = { + cmd: 'dumb', + nick: 'nick', + channel: 'cake', + userid: 1234, + allies: [], +} + +describe('Checking dumb module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module export functions + it('should export a random channel function', async () => { + const resp = importedModule.getChannel(); + + expect(resp).to.be.a('string'); + }); + + it('should export a common channel function', async () => { + const resp = importedModule.getChannel('common'); + + expect(resp).to.be.a('string'); + }); + + it('should initialize', async () => { + mocks.core.muzzledHashes = undefined; + const resp = importedModule.init(mocks.core); + + expect(mocks.core.muzzledHashes).to.be.an('object'); + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should shadow block whisper attempts', async () => { + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + + const resp = importedModule.whisperCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'whisper', + text: [], + channel: 'cake', + }, + }); + + expect(resp).to.be.false; + }); + + it('should shadow block chat attempts, validating input', async () => { + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + + const resp = importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: [], + channel: 'cake', + }, + }); + + expect(resp).to.be.false; + }); + + it('should shadow block chat attempts', async () => { + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + + const resp = importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: 'test', + channel: 'cake', + }, + }); + + expect(resp).to.be.false; + }); + + it('should shadow block chat attempts, checking for trips', async () => { + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + const newSocket = Object.assign({}, mocks.plebSocket); + newSocket.trip = 'test'; + + const resp = importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'chat', + text: 'test', + channel: 'cake', + }, + }); + + expect(resp).to.be.false; + }); + + it('should shadow block chat attempts, checking for color', async () => { + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + const newSocket = Object.assign({}, mocks.plebSocket); + newSocket.color = '000000'; + + const resp = importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'chat', + text: 'test', + channel: 'cake', + }, + }); + + expect(resp).to.be.false; + }); + + it('should shadow block chat attempts, checking for allies', async () => { + mocks.core.muzzledHashes['testHash'] = { + dumb: true, + allies: [1234], + }; + mocks.plebSocket.hcProtocol = 1; + const newSocket = Object.assign({}, mocks.plebSocket); + + const resp = importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'chat', + text: 'test', + channel: 'cake', + }, + }); + + expect(resp).to.be.false; + }); + + it('should shadow block invite attempts', async () => { + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: [], + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + + it('should shadow block invite attempts with ratelimiting', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: [], + channel: 'cake', + }, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should verify userid params on shadow block invite attempts', async () => { + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 2; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + userid: '1234', + text: [], + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + + it('should verify channel params on shadow block invite attempts', async () => { + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 2; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + userid: 1234, + text: [], + channel: false, + }, + }); + + expect(resp).to.be.true; + }); + + it('should accept an allies param', async () => { + mockPayload.allies = [1234, 5678]; + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should accept legacy params', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'dumb', + nick: false, + }, + }); + + expect(resp).to.be.true; + }); + + it('should accept params', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 2; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'dumb', + userid : false, + }, + }); + + expect(resp).to.be.true; + }); + + it('should handle users not found', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 2; + + const oldFS = mocks.server.findSockets; + mocks.server.findSockets = (filterObj) => { + return false; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'dumb', + userid : 0, + }, + }); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.true; + }); + + it('should not muzzle mods', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 2; + + const oldFS = mocks.server.findSockets; + mocks.server.findSockets = (filterObj) => { + return [newSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'dumb', + userid : 0, + }, + }); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/emote.test.js b/test/emote.test.js new file mode 100644 index 0000000..26765c8 --- /dev/null +++ b/test/emote.test.js @@ -0,0 +1,113 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/emote.js'; +let importedModule; + +const mockPayload = { + cmd: 'emote', + channel: 'cake', + text: 'testing', +} + +describe('Checking emote module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should not accept empty text', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'emote', + text: false, + }, + }); + + expect(resp).to.be.false; + }); + + it('should ratelimit if required', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should include a users trip', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.trip = 'test'; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should hook a /me text command, verifying params', async () => { + const resp = importedModule.emoteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'chat', + text: false, + }, + }); + + expect(resp).to.be.false; + }); +}); \ No newline at end of file diff --git a/test/forcecolor.test.js b/test/forcecolor.test.js new file mode 100644 index 0000000..be00c1d --- /dev/null +++ b/test/forcecolor.test.js @@ -0,0 +1,194 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/forcecolor.js'; +let importedModule; + +const mockPayload = { + cmd: 'forcecolor', + userid: 1234, + color: '#000000', +} + +describe('Checking forcecolor module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should check for invalid nick', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'changecolor', + nick: false, + color: false, + }, + }); + + expect(resp).to.be.true; + }); + + it('should check for invalid color', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'changecolor', + nick: 'lies', + color: false, + }, + }); + + expect(resp).to.be.true; + }); + + it('should check accept color reset', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'changecolor', + nick: 'lies', + color: 'reset', + }, + }); + + expect(resp).to.be.true; + }); + + it('should check accept color', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'changecolor', + nick: 'lies', + color: 'invalid color', + }, + }); + + expect(resp).to.be.true; + }); + + it('should handle users not found', async () => { + const oldFS = mocks.server.findSockets; + mocks.server.findSockets = (filterObj) => { + return false; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'changecolor', + nick: 'lies', + color: '#000000', + }, + }); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.true; + }); + + it('should alert to invalid user', async () => { + const oldFS = mocks.server.findSockets; + mocks.server.findSockets = (filterObj) => { + return [mocks.plebSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'changecolor', + nick: 'lies', + color: '#000000', + }, + }); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.true; + }); + + it('should not color mods', async () => { + const oldFS = mocks.server.findSockets; + mocks.server.findSockets = (filterObj) => { + return [mocks.authedSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'changecolor', + nick: 'lies', + color: '#000000', + }, + }); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should validate chat text in hook', async () => { + const resp = importedModule.colorCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'chat', + }, + }); + + expect(resp).to.be.false; + }); +}); \ No newline at end of file diff --git a/test/help.test.js b/test/help.test.js new file mode 100644 index 0000000..d1fa2fd --- /dev/null +++ b/test/help.test.js @@ -0,0 +1,182 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/help.js'; +let importedModule; + +const mockPayload = { + cmd: 'help', + channel: 'cake', +} + +describe('Checking help module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should ratelimit if required', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should verify user input', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'help', + command: false, + }, + }); + + expect(resp).to.be.true; + }); + + it('should output over view', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'help', + }, + }); + + expect(resp).to.be.true; + }); + + it('should output specific info', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'help', + command: 'test', + }, + }); + + expect(resp).to.be.true; + }); + + it('should handle unknown commands', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'help', + command: 'undef', + }, + }); + + expect(resp).to.be.true; + }); + + it('should handle unknown aliases', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'help', + command: 'noalias', + }, + }); + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should hook /help, verify params', async () => { + const resp = importedModule.helpCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: false, + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook /help', async () => { + const resp = importedModule.helpCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/help', + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook /help', async () => { + const resp = importedModule.helpCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: 'no cmd', + }, + }); + + expect(resp).to.be.an('object'); + }); + +}); \ No newline at end of file diff --git a/test/invite.test.js b/test/invite.test.js new file mode 100644 index 0000000..e590371 --- /dev/null +++ b/test/invite.test.js @@ -0,0 +1,230 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/invite.js'; +let importedModule; + +const mockPayload = { + cmd: 'invite', + channel: 'cake', + text: 'testing', +} + +describe('Checking invite module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module export functions + it('should export a random channel function', async () => { + const resp = importedModule.getChannel(); + + expect(resp).to.be.a('string'); + }); + + it('should export a common channel function', async () => { + const resp = importedModule.getChannel('common'); + + expect(resp).to.be.a('string'); + }); + + // module main function + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should ratelimit if required', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should validate channel legacy param', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'invite', + nick: 'test', + }, + }); + + expect(resp).to.be.true; + }); + + it('should validate nick legacy param', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'invite', + channel: 1234, + }, + }); + + expect(resp).to.be.true; + }); + + it('should validate userid param', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 2; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'invite', + userid: 1234, + }, + }); + + expect(resp).to.be.true; + }); + + it('should validate channel param', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 2; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'invite', + channel: 1234, + }, + }); + + expect(resp).to.be.true; + }); + + it('should handle user 404', async () => { + const oldFS = mocks.server.findSockets; + mockPayload.nick = 'lies'; + mocks.server.findSockets = (filterObj) => { + return false; + } + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'invite', + channel: 'cake', + nick: 'lies', + userid: 1234, + }, + }); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.true; + }); + + it('should handle legacy users', async () => { + const oldFS = mocks.server.findSockets; + mockPayload.nick = 'lies'; + mocks.server.findSockets = (filterObj) => { + return [{ + hcProtocol: 1, + }]; + } + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'invite', + channel: 'cake', + nick: 'lies', + userid: 1234, + }, + }); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.true; + }); + + it('should handle invites', async () => { + const oldFS = mocks.server.findSockets; + mockPayload.nick = 'lies'; + mocks.server.findSockets = (filterObj) => { + return [{ + hcProtocol: 2, + }]; + } + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 2; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'invite', + channel: 'cake', + nick: 'lies', + userid: 1234, + }, + }); + + mocks.server.findSockets = oldFS; + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/join.test.js b/test/join.test.js new file mode 100644 index 0000000..6867d2d --- /dev/null +++ b/test/join.test.js @@ -0,0 +1,288 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/join.js'; +let importedModule; + +const mockPayload = { + cmd: 'join', + channel: 'cake', + text: 'testing', +} + +describe('Checking join module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should ratelimit if required', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should upgrade legacy users', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 'test#test', + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + + it('should fail on invalid channels', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 'test#test', + channel: false, + }, + }); + + expect(resp).to.be.true; + }); + + it('should allow join only if not already joined', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.channel = undefined; + newSocket.hcProtocol = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 'test#test', + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + + it('should allow join only user has a valid name', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.channel = undefined; + newSocket.hcProtocol = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 't e s t#test', + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + + it('should prevent admin impersonation', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.channel = undefined; + newSocket.hcProtocol = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 'admin#test', + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + + it('should prevent two of the same name in the same channel', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.channel = undefined; + newSocket.hcProtocol = undefined; + + mocks.server.findSockets = (filterObj) => { + return false; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 'admin#test', + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + + it('should announce new user', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.channel = undefined; + newSocket.hcProtocol = undefined; + + mocks.server.findSockets = (filterObj) => { + if (filterObj.nick) { + if (typeof filterObj.nick === 'function') { + filterObj.nick('nick'); + } + + return false; + } else { + return [mocks.plebSocket]; + } + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 'admin#test', + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + + it('should restore a join', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + + const resp = await importedModule.restoreJoin({ + server: mocks.server, + socket: newSocket, + channel: 'test', + }); + + expect(resp).to.be.true; + }); + + it('should accept a restoration refusal', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.banned = true; + + const resp = await importedModule.restoreJoin({ + server: mocks.server, + socket: newSocket, + channel: 'test', + }); + + expect(resp).to.be.true; + }); + + it('should account for duplicate connections', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + const newServer = Object.assign({}, mocks.server); + const origFindSockets = mocks.server.findSockets; + + newServer.findSockets = (filterObj) => { + if (typeof filterObj.nick !== 'undefined') { + filterObj.nick('nick'); + } + return [mocks.authedSocket]; + } + + const resp = await importedModule.restoreJoin({ + server: newServer, + socket: newSocket, + channel: 'test', + }); + + mocks.server.findSockets = origFindSockets; + + expect(resp).to.be.true; + }); + + it('should handle non-duplicate connections', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + const newServer = Object.assign({}, mocks.server); + const origFindSockets = mocks.server.findSockets; + let alreadyRan = false; + + newServer.findSockets = (filterObj) => { + if (alreadyRan === false) { + alreadyRan = true; + return [mocks.authedSocket]; + } + + return []; + } + + const resp = await importedModule.restoreJoin({ + server: newServer, + socket: newSocket, + channel: 'test', + }); + + mocks.server.findSockets = origFindSockets; + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/kick.test.js b/test/kick.test.js new file mode 100644 index 0000000..dd78403 --- /dev/null +++ b/test/kick.test.js @@ -0,0 +1,171 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/kick.js'; +let importedModule; + +const mockPayload = { + cmd: 'kick', + userid: 1234, + to: 'no_cake', +} + +describe('Checking kick module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should validate legacy params', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'kick', + }, + }); + + expect(resp).to.be.true; + }); + + it('should handle no users found', async () => { + mocks.authedSocket.hcProtocol = 2; + mocks.server.findSockets = (filterObj) => { + if (typeof filterObj.nick === 'function') { + filterObj.nick('lies'); + } + + return []; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'kick', + userid: 1234, + to: 'test', + }, + }); + + expect(resp).to.be.true; + }); + + it('should validate params', async () => { + mocks.server.findSockets = (filterObj) => { + if (typeof filterObj.nick === 'function') { + filterObj.nick('lies'); + } + + return [mocks.plebSocket]; + } + + mocks.authedSocket.hcProtocol = 2; + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'kick', + userid: false, + }, + }); + + expect(resp).to.be.true; + }); + + it('should accept a "to" param', async () => { + mocks.authedSocket.hcProtocol = 2; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'kick', + userid: 1234, + to: 'test', + }, + }); + + expect(resp).to.be.true; + }); + + it('should kick to random channel', async () => { + mocks.authedSocket.hcProtocol = 2; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'kick', + userid: 1234, + }, + }); + + expect(resp).to.be.true; + }); + + it('should not kick mods', async () => { + mocks.authedSocket.hcProtocol = 2; + mocks.server.findSockets = (filterObj) => { + if (typeof filterObj.nick === 'function') { + filterObj.nick('lies'); + } + + return [mocks.authedSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'kick', + userid: 1234, + to: 'test', + }, + }); + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/legacyFunctions.test.js b/test/legacyFunctions.test.js new file mode 100644 index 0000000..d0b3f92 --- /dev/null +++ b/test/legacyFunctions.test.js @@ -0,0 +1,52 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/utility/_LegacyFunctions.js'; +let importedModule; + +describe('Checking legacyFunctions module', () => { + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should handle pass and password', async () => { + const resp = importedModule.upgradeLegacyJoin(mocks.server, mocks.plebSocket, { + nick: 'test#test', + password: 'test', + }); + expect(resp).to.be.an('object'); + }); + + it('should handle mod label', async () => { + const resp = importedModule.legacyLevelToLabel(9999999); + expect(resp).to.equal('admin'); + }); + + it('should handle mod label', async () => { + const resp = importedModule.legacyLevelToLabel(999999); + expect(resp).to.equal('mod'); + }); + + it('should provide duplicate user checks', async () => { + const newSocket = Object.assign({}, mocks.plebSocket); + newSocket.trip = false; + + const resp = importedModule.legacyWhisperOut({ + cmd: 'whisper', + }, newSocket); + + expect(resp).to.be.an('object'); + }); + + it('should apply missing user id', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.userid = undefined; + + const resp = importedModule.upgradeLegacyJoin(mocks.server, newSocket, { + nick: 'test#test', + password: 'test', + }); + expect(resp).to.be.an('object'); + }); +}) \ No newline at end of file diff --git a/test/listusers.test.js b/test/listusers.test.js new file mode 100644 index 0000000..ff107eb --- /dev/null +++ b/test/listusers.test.js @@ -0,0 +1,68 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/admin/listusers.js'; +let importedModule; + +const mockPayload = { + cmd: 'listusers', +} + +describe('Checking listusers module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by an admin', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should send a reply', async () => { + mocks.server.findSockets = (filterObj) => { + if (typeof filterObj.channel === 'function') { + filterObj.channel(); + } + + return [{}]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/mockImports.js b/test/mockImports.js new file mode 100644 index 0000000..48df539 --- /dev/null +++ b/test/mockImports.js @@ -0,0 +1,115 @@ +const mocks = { + core: { + sessionKey: 'test', + appConfig: { + data: { + globalMods: [], + permissions: [], + channels: { + test: { + owned: false, + } + }, + tripSalt: 'test', + adminTrip: '', + }, + write: async () => '', + }, + muzzledHashes: [], + stats: { + increment: () => 1, + decrement: () => 1, + get: () => 1, + set: () => 1, + }, + dynamicImports: { + reloadDirCache: () => '', + }, + commands: { + reloadCommands: () => '', + commands: [], + categoriesList: ['test'], + all: () => [{ + info: { + name: 'test', + category: 'test', + }, + }], + get: (name) => { + if (name === 'undef') { + return undefined; + } else if(name === 'noalias') { + return { + info: { + name: 'test', + category: 'test', + } + } + } else { + return { + info: { + name: 'test', + category: 'test', + aliases: ['testing'], + } + } + } + }, + }, + configManager: { + save: () => true, + }, + }, + server : { + police: { + addresses: [], + frisk: () => false, + arrest: (address) => mocks.server.police.addresses.push(address), + }, + findSockets: () => [], + reply: () => true, + broadcast: (data, filterObj) => { + if (typeof filterObj.level === 'function') { + filterObj.level(); + } + + return true; + }, + send: () => true, + cmdKey: 'test', + registerHook: () => true, + loadHooks: () => true, + clients: [{ + channel: 'cake', + address: '127.0.0.1', + }], + getSocketHash: () => 'test', + }, + plebSocket: { + level: 100, + address: '127.0.0.1', + channel: 'cake', + channels: [], + terminate: () => true, + nick: 'lies', + hcProtocol: 2, + hash: 'testHash', + uType: 'user', + userid: 1234, + }, + authedSocket: { + level: 9999999, + address: '127.0.0.1', + channel: 'cake', + channels: [], + terminate: () => true, + hcProtocol: 2, + nick: '[ignore this]', + trip: 'and this', + hash: 'testHash', + uType: 'admin', + userid: 1234, + }, +}; + +export default mocks; diff --git a/test/morestats.test.js b/test/morestats.test.js new file mode 100644 index 0000000..e79ef2e --- /dev/null +++ b/test/morestats.test.js @@ -0,0 +1,95 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/morestats.js'; +let importedModule; + +const mockPayload = { + cmd: 'morestats', + channel: 'cake', +} + +describe('Checking morestats module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable by all', async () => { + const newSocket = Object.assign({}, mocks.plebSocket); + newSocket.channel = 'programming'; + mocks.server.clients = [ + newSocket, + ]; + mocks.core.stats.get = (type) => { + if (type === 'start-time') { + return process.hrtime(); + } + + return false; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should validate params with /stats', async () => { + const resp = importedModule.statsCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + }, + }); + + expect(resp).to.be.false; + }); + + it('should run with /stats', async () => { + const resp = importedModule.statsCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/stats', + }, + }); + + expect(resp).to.be.false; + }); + +}); \ No newline at end of file diff --git a/test/ping.test.js b/test/ping.test.js new file mode 100644 index 0000000..c5fd541 --- /dev/null +++ b/test/ping.test.js @@ -0,0 +1,50 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/ping.js'; +let importedModule; + +const mockPayload = { + cmd: 'ping', + channel: 'cake', + text: 'testing', +} + +describe('Checking ping module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable by all', async () => { + expect(() => importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + })).not.to.throw(); + }); + +}); \ No newline at end of file diff --git a/test/reload.test.js b/test/reload.test.js new file mode 100644 index 0000000..80f4b08 --- /dev/null +++ b/test/reload.test.js @@ -0,0 +1,89 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/admin/reload.js'; +let importedModule; + +const mockPayload = { + cmd: 'reload', +} + +describe('Checking reload module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by an admin', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should reload server commands', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should report reload errors', async () => { + mocks.core.commands.reloadCommands = () => 'This is an error'; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: + mockPayload, + }); + + mocks.core.commands.reloadCommands = () => ''; + + expect(resp).to.be.true; + }); + + it('should report an optional reason', async () => { + mockPayload.reason = 'This is a reason'; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/removemod.test.js b/test/removemod.test.js new file mode 100644 index 0000000..555199c --- /dev/null +++ b/test/removemod.test.js @@ -0,0 +1,76 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/admin/removemod.js'; +let importedModule; + +const mockPayload = { + cmd: 'removemod', + trip: 'newTrip', +} + +describe('Checking removemod module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by an admin', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should remove trip from the config', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(mocks.core.appConfig.data.globalMods[0]).to.be.undefined; + }); + + it('should inform the ex-mod', async () => { + mocks.server.findSockets = () => { + return [{}]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/saveconfig.test.js b/test/saveconfig.test.js new file mode 100644 index 0000000..8da22ae --- /dev/null +++ b/test/saveconfig.test.js @@ -0,0 +1,92 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/admin/saveconfig.js'; +let importedModule; + +const mockPayload = { + cmd: 'saveconfig', +} + +describe('Checking saveconfig module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by an admin', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should force a config save', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should report errors', async () => { + mocks.core.appConfig.write = () => { + throw new Error; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + mocks.core.appConfig.write = () => ''; + + expect(resp).to.be.true; + }); + + it('should broadcast save notice', async () => { + mocks.server.findSockets = (filterObj) => { + return [mocks.plebSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/session.test.js b/test/session.test.js new file mode 100644 index 0000000..c977155 --- /dev/null +++ b/test/session.test.js @@ -0,0 +1,250 @@ +import { expect } from 'chai'; +import jsonwebtoken from 'jsonwebtoken'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/session.js'; +let importedModule; + +const mockPayload = { + cmd: 'session', + token: 'testing', +} + +describe('Checking session module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should initialize', async () => { + const resp = importedModule.init(mocks.core); + expect(mocks.core).to.be.an('object'); + }); + + it('should provide current session string', async () => { + const newCore = Object.assign({}, mocks.core); + + const resp = await importedModule.getSession(mocks.plebSocket, newCore); + + expect(resp).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + it('should initialize', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.sessionKey = undefined; + const resp = importedModule.init(newCore); + + expect(newCore.sessionKey).to.not.equal(undefined); + }); + + // module main function + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should notify about required token', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + }, + }); + + expect(resp).to.be.false; + }); + + it('should notify about invalid token', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + token: 'false', + }, + }); + + expect(resp).to.be.false; + }); + + it('should accept valid token', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.sessionKey = 'test'; + const token = jsonwebtoken.sign({ + nick: 'test', + channel: 'test', + }, newCore.sessionKey); + + const resp = await importedModule.run({ + core: newCore, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + token: token, + }, + }); + + expect(resp).to.be.false; + }); + + it('should require a session channel value', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.sessionKey = 'test'; + const token = jsonwebtoken.sign({ + test: 'test', + }, newCore.sessionKey); + + const resp = await importedModule.run({ + core: newCore, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + token: token, + }, + }); + + expect(resp).to.be.false; + }); + + it('should require session channels value', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.sessionKey = 'test'; + const token = jsonwebtoken.sign({ + channel: 'test', + }, newCore.sessionKey); + + const resp = await importedModule.run({ + core: newCore, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + token: token, + }, + }); + + expect(resp).to.be.false; + }); + + it('should require session color value', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.sessionKey = 'test'; + const token = jsonwebtoken.sign({ + channel: 'test', + channels: ['test'], + }, newCore.sessionKey); + + const resp = await importedModule.run({ + core: newCore, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + token: token, + }, + }); + + expect(resp).to.be.false; + }); + + it('should require session isBot value', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.sessionKey = 'test'; + const token = jsonwebtoken.sign({ + channel: 'test', + channels: ['test'], + color: 'ffffff', + }, newCore.sessionKey); + + const resp = await importedModule.run({ + core: newCore, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + token: token, + }, + }); + + expect(resp).to.be.false; + }); + + it('should require session level value', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.sessionKey = 'test'; + const token = jsonwebtoken.sign({ + channel: 'test', + channels: ['test'], + color: 'ffffff', + isBot: false, + }, newCore.sessionKey); + + const resp = await importedModule.run({ + core: newCore, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + token: token, + }, + }); + + expect(resp).to.be.false; + }); + + it('should require session level value', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.sessionKey = 'test'; + const token = jsonwebtoken.sign({ + channel: 'test', + channels: ['test'], + color: 'ffffff', + isBot: false, + nick: 'test', + }, newCore.sessionKey); + + const resp = await importedModule.run({ + core: newCore, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'session', + token: token, + }, + }); + + expect(resp).to.be.false; + }); +}); \ No newline at end of file diff --git a/test/shout.test.js b/test/shout.test.js new file mode 100644 index 0000000..923148a --- /dev/null +++ b/test/shout.test.js @@ -0,0 +1,65 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/admin/shout.js'; +let importedModule; + +const mockPayload = { + cmd: 'shout', + text: 'This is a shout', +} + +describe('Checking shout module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by an admin', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should do the broadcast', async () => { + mocks.server.findSockets = () => { + return [{}]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/socketreply.test.js b/test/socketreply.test.js new file mode 100644 index 0000000..2919bbc --- /dev/null +++ b/test/socketreply.test.js @@ -0,0 +1,61 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/internal/socketreply.js'; +let importedModule; + +const mockPayload = { + cmd: 'disconnect', +} + +describe('Checking socketreply module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only internally', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should broadcast warning event', async () => { + mockPayload.cmdKey = 'test'; + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); +}); \ No newline at end of file diff --git a/test/speak.test.js b/test/speak.test.js new file mode 100644 index 0000000..1215b9c --- /dev/null +++ b/test/speak.test.js @@ -0,0 +1,71 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/speak.js'; +let importedModule; + +const mockPayload = { + cmd: 'speak', + ip: '127.0.0.1', +} + +describe('Checking speak module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should initialize', async () => { + mocks.core.muzzledHashes = undefined; + const resp = importedModule.init(mocks.core); + + expect(mocks.core.muzzledHashes).to.be.an('object'); + }); + + it('should validate params', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'speak', + }, + }); + + expect(resp).to.be.true; + }); + +}); \ No newline at end of file diff --git a/test/stats.test.js b/test/stats.test.js new file mode 100644 index 0000000..d2a7c2c --- /dev/null +++ b/test/stats.test.js @@ -0,0 +1,48 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/stats.js'; +let importedModule; + +const mockPayload = { + cmd: 'stats', +} + +describe('Checking stats module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable by all', async () => { + expect(() => importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + })).not.to.throw(); + }); + +}); \ No newline at end of file diff --git a/test/uac.test.js b/test/uac.test.js new file mode 100644 index 0000000..be017e1 --- /dev/null +++ b/test/uac.test.js @@ -0,0 +1,67 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/utility/_UAC.js'; +let importedModule; + +describe('Checking UAC module', () => { + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should handle channel owners', async () => { + const resp = importedModule.isChannelOwner(9999999); + expect(resp).to.be.true; + }); + + it('should handle channel mods', async () => { + const resp = importedModule.isChannelModerator(9999999); + expect(resp).to.be.true; + }); + + it('should handle channel mods', async () => { + const resp = importedModule.isChannelTrusted(9999999); + expect(resp).to.be.true; + }); + + it('should handle channel mods', async () => { + const resp = importedModule.isTrustedUser(9999999); + expect(resp).to.be.true; + }); + + it('should return false on bad nickname', async () => { + const resp = importedModule.verifyNickname(); + expect(resp).to.be.false; + }); + + it('should return default perms', async () => { + const resp = importedModule.getUserPerms(false); + expect(resp).to.be.an('object'); + }); + + it('should return admin level labels', async () => { + const newConfig = Object.assign({}, mocks.core.appConfig.data); + newConfig.adminTrip = 'Tt8H7c'; + const resp = importedModule.getUserPerms('test', 'salt', newConfig, 'cake'); + expect(resp).to.be.an('object'); + }); + + it('should return mod level labels', async () => { + const newConfig = Object.assign({}, mocks.core.appConfig.data); + newConfig.globalMods = [{ + trip: 'Tt8H7c', + }]; + const resp = importedModule.getUserPerms('test', 'salt', newConfig, 'cake'); + expect(resp).to.be.an('object'); + }); + + it('should return ownership info', async () => { + const newConfig = Object.assign({}, mocks.core.appConfig.data); + newConfig.permissions['cake'] = { + owned: true, + }; + const resp = importedModule.getUserPerms('test', 'salt', newConfig, 'cake'); + expect(resp).to.be.an('object'); + }); +}) \ No newline at end of file diff --git a/test/unban.test.js b/test/unban.test.js new file mode 100644 index 0000000..e986014 --- /dev/null +++ b/test/unban.test.js @@ -0,0 +1,64 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/unban.js'; +let importedModule; + +const mockPayload = { + cmd: 'unban', + ip: '127.0.0.1', +} + +describe('Checking unban module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should require ip or hash', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'ban', + }, + }); + + expect(resp).to.be.true; + }); + +}); \ No newline at end of file diff --git a/test/unbanall.test.js b/test/unbanall.test.js new file mode 100644 index 0000000..f716b7d --- /dev/null +++ b/test/unbanall.test.js @@ -0,0 +1,50 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/unbanall.js'; +let importedModule; + +const mockPayload = { + cmd: 'unbanall', +} + +describe('Checking unbanall module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + +}); \ No newline at end of file diff --git a/test/whisper.test.js b/test/whisper.test.js new file mode 100644 index 0000000..4e45332 --- /dev/null +++ b/test/whisper.test.js @@ -0,0 +1,269 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/whisper.js'; +let importedModule; + +const mockPayload = { + cmd: 'whisper', + text: 'testing', + userid: 1234, + nick: 'test', +} + +describe('Checking whisper module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should be invokable by all', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should reject invalid text', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'whisper', + text: false, + }, + }); + + expect(resp).to.be.false; + }); + + it('should handle legacy users', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should ratelimit if required', async () => { + const oldRL = mocks.server.police.frisk; + mocks.server.police.frisk = () => true; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + mocks.server.police.frisk = oldRL; + + expect(resp).to.be.true; + }); + + it('should handle 404 users', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + mocks.server.findSockets = (filterObj) => { + return false; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should handle legacy users in', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + mocks.server.findSockets = (filterObj) => { + return [mocks.authedSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should handle legacy users out', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.hcProtocol = 1; + + mocks.server.findSockets = (filterObj) => { + return [newSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should handle users out', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + + mocks.server.findSockets = (filterObj) => { + return [newSocket]; + } + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should hook for /whisper chat commands, verifying params', async () => { + const resp = importedModule.whisperCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: false, + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook for /whisper chat commands', async () => { + const resp = importedModule.whisperCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/whisper user stuff', + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook for /w chat commands', async () => { + const resp = importedModule.whisperCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/w user stuff', + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook for /w chat commands, validating params', async () => { + const resp = importedModule.whisperCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/whisper ', + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook for /reply chat commands', async () => { + const resp = importedModule.whisperCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/reply ', + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook for /r chat commands', async () => { + const resp = importedModule.whisperCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: '/r ', + }, + }); + + expect(resp).to.be.false; + }); + + it('should hook only certain triggers', async () => { + const resp = importedModule.whisperCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'chat', + text: 'normal text', + }, + }); + + expect(resp).to.be.an('object'); + }); +}); \ No newline at end of file From b80b5ca9d13931558adb70daa2181b714b7195a6 Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 22 Jun 2022 13:42:46 -0500 Subject: [PATCH 20/37] Removed obsolete test cases --- test/changenick.test.js | 14 -------------- test/join.test.js | 19 ------------------- 2 files changed, 33 deletions(-) diff --git a/test/changenick.test.js b/test/changenick.test.js index cdc6c39..09c5fea 100644 --- a/test/changenick.test.js +++ b/test/changenick.test.js @@ -91,20 +91,6 @@ describe('Checking changenick module', () => { expect(resp).to.be.true; }); - - it('should prevent admin impersonation', async () => { - const resp = await importedModule.run({ - core: mocks.core, - server: mocks.server, - socket: mocks.plebSocket, - payload: { - cmd: 'changenick', - nick: 'admin', - }, - }); - - expect(resp).to.be.true; - }); it('should not update if there is no change', async () => { const resp = await importedModule.run({ diff --git a/test/join.test.js b/test/join.test.js index 6867d2d..2da3bca 100644 --- a/test/join.test.js +++ b/test/join.test.js @@ -139,25 +139,6 @@ describe('Checking join module', () => { expect(resp).to.be.true; }); - it('should prevent admin impersonation', async () => { - const newSocket = Object.assign({}, mocks.authedSocket); - newSocket.channel = undefined; - newSocket.hcProtocol = undefined; - - const resp = await importedModule.run({ - core: mocks.core, - server: mocks.server, - socket: newSocket, - payload: { - cmd: 'join', - nick: 'admin#test', - channel: 'cake', - }, - }); - - expect(resp).to.be.true; - }); - it('should prevent two of the same name in the same channel', async () => { const newSocket = Object.assign({}, mocks.authedSocket); newSocket.channel = undefined; From 99822079833cc14d83715d1c8f3982a9cf2c7a7b Mon Sep 17 00:00:00 2001 From: marzavec Date: Thu, 11 Aug 2022 09:40:43 -0500 Subject: [PATCH 21/37] Extended trip length to ten characters --- commands/utility/_UAC.js | 4 +++- scripts/config.js | 4 +++- test/uac.test.js | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/commands/utility/_UAC.js b/commands/utility/_UAC.js index f003288..96a9332 100644 --- a/commands/utility/_UAC.js +++ b/commands/utility/_UAC.js @@ -15,6 +15,8 @@ const { createHash, } = await import('crypto'); +const TripLength = 10; + /** * Object defining labels for default permission ranges * @typedef {Object} levels @@ -150,7 +152,7 @@ export function getUserPerms(pass, salt, config, channel) { const sha = createHash('sha256'); sha.update(pass + salt); - const trip = sha.digest('base64').substr(0, 6); + const trip = sha.digest('base64').substr(0, TripLength); // check if user is global admin if (trip === config.adminTrip) { diff --git a/scripts/config.js b/scripts/config.js index 89d3d80..eb8e875 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -18,6 +18,8 @@ const SessionLocation = './session.key'; const SaltLocation = './salt.key'; const AppConfigLocation = './config.json'; +const TripLength = 10; + // default configuration options const defaultConfig = { adminTrip: '', @@ -105,7 +107,7 @@ const checkPermissions = async () => { const sha = crypto.createHash('sha256'); sha.update(password + salt); - config.data.adminTrip = sha.digest('base64').substr(0, 6); + config.data.adminTrip = sha.digest('base64').substr(0, TripLength); await config.write(); } else { diff --git a/test/uac.test.js b/test/uac.test.js index be017e1..f64bada 100644 --- a/test/uac.test.js +++ b/test/uac.test.js @@ -42,7 +42,7 @@ describe('Checking UAC module', () => { it('should return admin level labels', async () => { const newConfig = Object.assign({}, mocks.core.appConfig.data); - newConfig.adminTrip = 'Tt8H7c'; + newConfig.adminTrip = 'Tt8H7clbL9'; const resp = importedModule.getUserPerms('test', 'salt', newConfig, 'cake'); expect(resp).to.be.an('object'); }); @@ -50,7 +50,7 @@ describe('Checking UAC module', () => { it('should return mod level labels', async () => { const newConfig = Object.assign({}, mocks.core.appConfig.data); newConfig.globalMods = [{ - trip: 'Tt8H7c', + trip: 'Tt8H7clbL9', }]; const resp = importedModule.getUserPerms('test', 'salt', newConfig, 'cake'); expect(resp).to.be.an('object'); From 7c612871f4e075cf48238cae7fe354aa333df4dd Mon Sep 17 00:00:00 2001 From: MinusGix Date: Thu, 1 Jun 2023 13:16:12 -0500 Subject: [PATCH 22/37] Impl updateMessage command --- client/client.js | 118 ++++++++++++++++++++++++++++----- commands/core/chat.js | 76 ++++++++++++++++----- commands/core/updateMessage.js | 97 +++++++++++++++++++++++++++ commands/utility/_Text.js | 21 ++++++ 4 files changed, 276 insertions(+), 36 deletions(-) create mode 100644 commands/core/updateMessage.js create mode 100644 commands/utility/_Text.js diff --git a/client/client.js b/client/client.js index d333178..0bebc59 100644 --- a/client/client.js +++ b/client/client.js @@ -15,7 +15,7 @@ var markdownOptions = { langPrefix: '', linkify: true, linkTarget: '_blank" rel="noreferrer', - typographer: true, + typographer: true, quotes: `""''`, doHighlight: true, @@ -25,12 +25,12 @@ var markdownOptions = { if (lang && hljs.getLanguage(lang)) { try { return hljs.highlight(lang, str).value; - } catch (__) {} + } catch (__) { } } try { return hljs.highlightAuto(str).value; - } catch (__) {} + } catch (__) { } return ''; } @@ -67,20 +67,20 @@ md.renderer.rules.image = function (tokens, idx, options) { return ''; } - return '' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(src)) + ''; + return '' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(src)) + ''; }; md.renderer.rules.link_open = function (tokens, idx, options) { var title = tokens[idx].title ? (' title="' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].title)) + '"') : ''; - var target = options.linkTarget ? (' target="' + options.linkTarget + '"') : ''; - return ''; + var target = options.linkTarget ? (' target="' + options.linkTarget + '"') : ''; + return ''; }; -md.renderer.rules.text = function(tokens, idx) { +md.renderer.rules.text = function (tokens, idx) { tokens[idx].content = Remarkable.utils.escapeHtml(tokens[idx].content); if (tokens[idx].content.indexOf('?') !== -1) { - tokens[idx].content = tokens[idx].content.replace(/(^|\s)(\?)\S+?(?=[,.!?:)]?\s|$)/gm, function(match) { + tokens[idx].content = tokens[idx].content.replace(/(^|\s)(\?)\S+?(?=[,.!?:)]?\s|$)/gm, function (match) { var channelLink = Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(match.trim())); var whiteSpace = ''; if (match[0] !== '?') { @@ -90,7 +90,7 @@ md.renderer.rules.text = function(tokens, idx) { }); } - return tokens[idx].content; + return tokens[idx].content; }; md.use(remarkableKatex); @@ -164,6 +164,34 @@ var myChannel = window.location.search.replace(/^\?/, ''); var lastSent = [""]; var lastSentPos = 0; +/** + * Stores active messages + * These are messages that can be edited. + * @type {{ customId: string, userid: number, sent: number, text: string, elem: HTMLElement }[]} + */ +var activeMessages = []; + +setInterval(function () { + var editTimeout = 6 * 60 * 1000; + var now = Date.now(); + for (var i = 0; i < activeMessages.length; i++) { + if (now - activeMessages[i].sent > editTimeout) { + activeMessages.splice(i, 1); + i--; + } + } +}, 30 * 1000); + +function addActiveMessage(customId, userid, text, elem) { + activeMessages.push({ + customId, + userid, + sent: Date.now(), + text, + elem, + }); +} + /** Notification switch and local storage behavior **/ var notifySwitch = document.getElementById("notify-switch") var notifySetting = localStorageGet("notify-api") @@ -364,7 +392,59 @@ var COMMANDS = { if (ignoredUsers.indexOf(args.nick) >= 0) { return; } - pushMessage(args); + + var elem = pushMessage(args); + + if (typeof (args.customId) === 'string') { + addActiveMessage(args.customId, args.userid, args.text, elem); + } + }, + + updateMessage: function (args) { + var customId = args.customId; + var mode = args.mode; + + if (!mode) { + return; + } + + var message; + for (var i = 0; i < activeMessages.length; i++) { + var msg = activeMessages[i]; + if (msg.userid === args.userid && msg.customId === customId) { + message = msg; + break; + } + } + + if (!message) { + return; + } + + var textElem = message.elem.querySelector('.text'); + if (!textElem) { + return; + } + + var newText = message.text; + if (mode === 'overwrite') { + newText = args.text; + } else if (mode === 'append') { + newText += args.text; + } else if (mode === 'prepend') { + newText = args.text + newText; + } + + message.text = newText; + + // Scroll to bottom if necessary + var atBottom = isAtBottom(); + + textElem.innerHTML = md.render(newText); + + if (atBottom) { + window.scrollTo(0, document.body.scrollHeight); + } }, info: function (args) { @@ -518,6 +598,8 @@ function pushMessage(args) { unread += 1; updateTitle(); + + return messageEl; } function insertAtCursor(text) { @@ -705,8 +787,8 @@ $('#sidebar').onmouseleave = document.ontouchstart = function (event) { var e = event.toElement || event.relatedTarget; try { if (e.parentNode == this || e == this) { - return; - } + return; + } } catch (e) { return; } if (!$('#pin-sidebar').checked) { @@ -734,8 +816,8 @@ if (localStorageGet('joined-left') == 'false') { if (localStorageGet('parse-latex') == 'false') { $('#parse-latex').checked = false; - md.inline.ruler.disable([ 'katex' ]); - md.block.ruler.disable([ 'katex' ]); + md.inline.ruler.disable(['katex']); + md.block.ruler.disable(['katex']); } $('#pin-sidebar').onchange = function (e) { @@ -750,11 +832,11 @@ $('#parse-latex').onchange = function (e) { var enabled = !!e.target.checked; localStorageSet('parse-latex', enabled); if (enabled) { - md.inline.ruler.enable([ 'katex' ]); - md.block.ruler.enable([ 'katex' ]); + md.inline.ruler.enable(['katex']); + md.block.ruler.enable(['katex']); } else { - md.inline.ruler.disable([ 'katex' ]); - md.block.ruler.disable([ 'katex' ]); + md.inline.ruler.disable(['katex']); + md.block.ruler.disable(['katex']); } } diff --git a/commands/core/chat.js b/commands/core/chat.js index fdd8eb9..8c4cca1 100644 --- a/commands/core/chat.js +++ b/commands/core/chat.js @@ -6,33 +6,64 @@ * @module chat */ +import { parseText } from '../utility/_Text.js'; import { isAdmin, isModerator, } from '../utility/_UAC.js'; +export const MAX_MESSAGE_ID_LENGTH = 6; /** - * Check and trim string provided by remote client - * @param {string} text - Subject string - * @private - * @todo Move into utility module - * @return {string|boolean} - */ -const parseText = (text) => { - // verifies user input is text - if (typeof text !== 'string') { - return false; + * The time in milliseconds before a message is considered stale, and thus no longer allowed + * to be edited. + * @type {number} + */ +const ACTIVE_TIMEOUT = 5 * 60 * 1000; +/** + * The time in milliseconds that a check for stale messages should be performed. + * @type {number} + */ +const TIMEOUT_CHECK_INTERVAL = 30 * 1000; + +/** + * Stores active messages that can be edited. + * @type {{ customId: string, userid: number, sent: number }[]} + */ +export const ACTIVE_MESSAGES = []; + +/** + * Cleans up stale messages. + * @public + * @return {void} + */ +export function cleanActiveMessages() { + const now = Date.now(); + for (let i = 0; i < ACTIVE_MESSAGES.length; i++) { + const message = ACTIVE_MESSAGES[i]; + if (now - message.sent > ACTIVE_TIMEOUT) { + ACTIVE_MESSAGES.splice(i, 1); + i--; + } } +} - let sanitizedText = text; +// TODO: This won't get cleared on module reload. +setInterval(cleanActiveMessages, TIMEOUT_CHECK_INTERVAL); - // strip newlines from beginning and end - sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); - // replace 3+ newlines with just 2 newlines - sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n'); - - return sanitizedText; -}; +/** + * Adds a message to the active messages map. + * @public + * @param {string} id + * @param {number} userid + * @return {void} + */ +export function addActiveMessage(customId, userid) { + ACTIVE_MESSAGES.push({ + customId, + userid, + sent: Date.now(), + }); +} /** * Executes when invoked by a remote client @@ -61,6 +92,13 @@ export async function run({ }, socket); } + const customId = payload.customId; + + if (typeof (customId) === 'string' && customId.length > MAX_MESSAGE_ID_LENGTH) { + // There's a limit on the custom id length. + return server.police.frisk(socket.address, 13); + } + // build chat payload const outgoingPayload = { cmd: 'chat', @@ -70,6 +108,7 @@ export async function run({ channel: socket.channel, text, level: socket.level, + customId, }; if (isAdmin(socket.level)) { @@ -86,6 +125,7 @@ export async function run({ outgoingPayload.color = socket.color; } + addActiveMessage(outgoingPayload.customId, socket.userid); // broadcast to channel peers server.broadcast(outgoingPayload, { channel: socket.channel }); diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js new file mode 100644 index 0000000..564a936 --- /dev/null +++ b/commands/core/updateMessage.js @@ -0,0 +1,97 @@ +import { parseText } from "../utility/_Text.js"; +import { isAdmin, isModerator } from "../utility/_UAC.js"; +import { ACTIVE_MESSAGES, MAX_MESSAGE_ID_LENGTH } from "./chat.js"; + +export async function run({ core, server, socket, payload }) { + // undefined | "overwrite" | "append" | "prepend" + let mode = payload.mode; + + if (!mode) { + mode = 'overwrite'; + } + + if (mode !== 'overwrite' && mode !== 'append' && mode !== 'prepend') { + return server.police.frisk(socket.address, 13); + } + + const customId = payload.customId; + + if (!customId || typeof customId !== "string" || customId.length > MAX_MESSAGE_ID_LENGTH) { + return server.police.frisk(socket.address, 13); + } + + let text = payload.text; + + if (typeof (text) !== 'string') { + return server.police.frisk(socket.address, 13); + } + + if (mode === 'overwrite') { + text = parseText(text); + + if (text === '') { + text = '\u0000'; + } + } + + if (!text) { + return server.police.frisk(socket.address, 13); + } + + // TODO: What score should we use for this? It isn't as space filling as chat messages. + // But we also don't want a massive growing message. + // Or flashing between huge and small. Etc. + + let message; + for (let i = 0; i < ACTIVE_MESSAGES.length; i++) { + const msg = ACTIVE_MESSAGES[i]; + + if (msg.userid === socket.userid && msg.customId === customId) { + message = ACTIVE_MESSAGES[i]; + break; + } + } + + if (!message) { + return server.police.frisk(socket.address, 6); + } + + const outgoingPayload = { + cmd: 'updateMessage', + userid: socket.userid, + channel: socket.channel, + level: socket.level, + mode, + text, + customId: message.customId, + }; + + if (isAdmin(socket.level)) { + outgoingPayload.admin = true; + } else if (isModerator(socket.level)) { + outgoingPayload.mod = true; + } + + server.broadcast(outgoingPayload, { channel: socket.channel }); + + return true; +} + +export const requiredData = ['text', 'customId']; + +/** + * Module meta information + * @public + * @typedef {Object} updateMessage/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'updateMessage', + category: 'core', + description: 'Update a message you have sent.', + usage: ` + API: { cmd: 'updateMessage', mode: 'overwrite'|'append'|'prepand', text: '',customId: '' }`, +}; diff --git a/commands/utility/_Text.js b/commands/utility/_Text.js new file mode 100644 index 0000000..05939da --- /dev/null +++ b/commands/utility/_Text.js @@ -0,0 +1,21 @@ +/** + * Check and trim string provided by remote client + * @public + * @param {string} text - Subject string + * @return {string|null} + */ +export const parseText = (text) => { + // verifies user input is text + if (typeof text !== 'string') { + return null; + } + + let sanitizedText = text; + + // strip newlines from beginning and end + sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); + // replace 3+ newlines with just 2 newlines + sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n'); + + return sanitizedText; +}; From 889e5e4c1cb1b8489e9759833ccedc72d63d1bc2 Mon Sep 17 00:00:00 2001 From: MinusGix Date: Mon, 5 Jun 2023 12:54:14 -0500 Subject: [PATCH 23/37] Roughly fix/improve behavior of input on some mobile devices --- client/client.js | 17 ++++++++++++++--- client/index.html | 2 +- client/style.css | 5 ++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/client/client.js b/client/client.js index 0bebc59..f40e3f3 100644 --- a/client/client.js +++ b/client/client.js @@ -756,12 +756,23 @@ $('#chatinput').onkeydown = function (e) { } } +// from https://stackoverflow.com/questions/11381673/detecting-a-mobile-browser +function checkIsMobileOrTablet() { + let check = false; + (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); + return check; +}; + +var isMobileOrTablet = checkIsMobileOrTablet(); + function updateInputSize() { var atBottom = isAtBottom(); + if (!isMobileOrTablet) { + var input = $('#chatinput'); + input.style.height = 0; + input.style.height = input.scrollHeight + 'px'; + } - var input = $('#chatinput'); - input.style.height = 0; - input.style.height = input.scrollHeight + 'px'; document.body.style.marginBottom = $('#footer').offsetHeight + 'px'; if (atBottom) { diff --git a/client/index.html b/client/index.html index ca623ec..86658d9 100644 --- a/client/index.html +++ b/client/index.html @@ -24,7 +24,7 @@
-
+
diff --git a/client/style.css b/client/style.css index 56a8396..db535fb 100644 --- a/client/style.css +++ b/client/style.css @@ -102,6 +102,7 @@ ul li { } .text p { margin: 0; + color: #ac3939 !important; } #footer { position: fixed; @@ -213,10 +214,8 @@ img { } @media only screen and (max-width: 600px) { - .messages { - border: none; - } #messages { + border: none; padding: 0.5em; } .message { From cdd4754a8e1e4ed71ca5532f6508fa19b9d309c2 Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 7 Jun 2023 13:00:02 -0500 Subject: [PATCH 24/37] Update style.css --- client/style.css | 1 - 1 file changed, 1 deletion(-) diff --git a/client/style.css b/client/style.css index db535fb..93471d8 100644 --- a/client/style.css +++ b/client/style.css @@ -102,7 +102,6 @@ ul li { } .text p { margin: 0; - color: #ac3939 !important; } #footer { position: fixed; From aa65cbf8a16ac8f097d5f01a53c3abce2649e460 Mon Sep 17 00:00:00 2001 From: carrot <68383195+AnnikaV9@users.noreply.github.com> Date: Tue, 21 Nov 2023 22:31:15 +0800 Subject: [PATCH 25/37] Fix typo in `updateMessage` usage info --- commands/core/updateMessage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js index 564a936..9318420 100644 --- a/commands/core/updateMessage.js +++ b/commands/core/updateMessage.js @@ -93,5 +93,5 @@ export const info = { category: 'core', description: 'Update a message you have sent.', usage: ` - API: { cmd: 'updateMessage', mode: 'overwrite'|'append'|'prepand', text: '',customId: '' }`, + API: { cmd: 'updateMessage', mode: 'overwrite'|'append'|'prepend', text: '', customId: '' }`, }; From b8fd2fb93175f15d0f19f4aa4f8a473f1e6a4735 Mon Sep 17 00:00:00 2001 From: carrot <68383195+AnnikaV9@users.noreply.github.com> Date: Tue, 21 Nov 2023 22:35:12 +0800 Subject: [PATCH 26/37] Add `complete` mode to `updateMessage` --- client/client.js | 4 ++++ commands/core/updateMessage.js | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/client/client.js b/client/client.js index f40e3f3..d40d779 100644 --- a/client/client.js +++ b/client/client.js @@ -412,6 +412,10 @@ var COMMANDS = { for (var i = 0; i < activeMessages.length; i++) { var msg = activeMessages[i]; if (msg.userid === args.userid && msg.customId === customId) { + if (mode === 'complete') { + activeMessages.splice(i, 1); + return; + } message = msg; break; } diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js index 9318420..af1a6f1 100644 --- a/commands/core/updateMessage.js +++ b/commands/core/updateMessage.js @@ -3,14 +3,14 @@ import { isAdmin, isModerator } from "../utility/_UAC.js"; import { ACTIVE_MESSAGES, MAX_MESSAGE_ID_LENGTH } from "./chat.js"; export async function run({ core, server, socket, payload }) { - // undefined | "overwrite" | "append" | "prepend" + // undefined | "overwrite" | "append" | "prepend" | "complete" let mode = payload.mode; if (!mode) { mode = 'overwrite'; } - if (mode !== 'overwrite' && mode !== 'append' && mode !== 'prepend') { + if (mode !== 'overwrite' && mode !== 'append' && mode !== 'prepend' && mode !== 'complete') { return server.police.frisk(socket.address, 13); } @@ -93,5 +93,5 @@ export const info = { category: 'core', description: 'Update a message you have sent.', usage: ` - API: { cmd: 'updateMessage', mode: 'overwrite'|'append'|'prepend', text: '', customId: '' }`, + API: { cmd: 'updateMessage', mode: 'overwrite'|'append'|'prepend'|'complete', text: '', customId: '' }`, }; From 2ee96543ca29b88df8dae2fd8fe24004620b495a Mon Sep 17 00:00:00 2001 From: carrot <68383195+AnnikaV9@users.noreply.github.com> Date: Thu, 23 Nov 2023 09:52:51 +0800 Subject: [PATCH 27/37] Remove from `ACTIVE_MESSAGES` when sending `complete` --- commands/core/updateMessage.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js index af1a6f1..8d4e4cf 100644 --- a/commands/core/updateMessage.js +++ b/commands/core/updateMessage.js @@ -48,6 +48,9 @@ export async function run({ core, server, socket, payload }) { if (msg.userid === socket.userid && msg.customId === customId) { message = ACTIVE_MESSAGES[i]; + if (mode === 'complete') { + ACTIVE_MESSAGES.splice(i, 1); + } break; } } From 051d488c2168f98b1928e437621ec3f1feb12493 Mon Sep 17 00:00:00 2001 From: carrot <68383195+AnnikaV9@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:42:49 +0800 Subject: [PATCH 28/37] Revert "Remove from `ACTIVE_MESSAGES` when sending `complete`" As it would cause race conditions. This reverts commit 2ee96543ca29b88df8dae2fd8fe24004620b495a. --- commands/core/updateMessage.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js index 8d4e4cf..af1a6f1 100644 --- a/commands/core/updateMessage.js +++ b/commands/core/updateMessage.js @@ -48,9 +48,6 @@ export async function run({ core, server, socket, payload }) { if (msg.userid === socket.userid && msg.customId === customId) { message = ACTIVE_MESSAGES[i]; - if (mode === 'complete') { - ACTIVE_MESSAGES.splice(i, 1); - } break; } } From 15135978cfe4d75dfa6c85fff5ad3b472e813e36 Mon Sep 17 00:00:00 2001 From: carrot <68383195+AnnikaV9@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:07:24 +0800 Subject: [PATCH 29/37] Mark message for deletion on next cleanup --- commands/core/chat.js | 3 ++- commands/core/updateMessage.js | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/commands/core/chat.js b/commands/core/chat.js index 8c4cca1..5ba3dee 100644 --- a/commands/core/chat.js +++ b/commands/core/chat.js @@ -40,7 +40,7 @@ export function cleanActiveMessages() { const now = Date.now(); for (let i = 0; i < ACTIVE_MESSAGES.length; i++) { const message = ACTIVE_MESSAGES[i]; - if (now - message.sent > ACTIVE_TIMEOUT) { + if (now - message.sent > ACTIVE_TIMEOUT || message.toDelete) { ACTIVE_MESSAGES.splice(i, 1); i--; } @@ -62,6 +62,7 @@ export function addActiveMessage(customId, userid) { customId, userid, sent: Date.now(), + toDelete: false, }); } diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js index af1a6f1..880d96c 100644 --- a/commands/core/updateMessage.js +++ b/commands/core/updateMessage.js @@ -48,6 +48,9 @@ export async function run({ core, server, socket, payload }) { if (msg.userid === socket.userid && msg.customId === customId) { message = ACTIVE_MESSAGES[i]; + if (mode === 'complete') { + ACTIVE_MESSAGES[i].toDelete = true; + } break; } } From fe6685468cdf784c69e58aba0edcf87c089229e0 Mon Sep 17 00:00:00 2001 From: marzavec Date: Thu, 21 Dec 2023 23:14:03 -0800 Subject: [PATCH 30/37] four new modules --- LICENSE | 21 - commands/admin/removemod.js | 2 +- commands/core/chat.js | 57 +- commands/core/join.js | 2 +- commands/core/morestats.js | 2 +- commands/core/session.js | 34 +- commands/core/updateMessage.js | 49 +- commands/mod/disablecaptcha.js | 86 + commands/mod/dumb.js | 1 + commands/mod/enablecaptcha.js | 279 +++ commands/mod/lockroom.js | 332 +++ commands/mod/speak.js | 3 +- commands/mod/unlockroom.js | 89 + commands/utility/_Text.js | 10 + commands/utility/_UAC.js | 6 +- documentation/admin_addmod.js.html | 4 +- documentation/admin_listusers.js.html | 2 +- documentation/admin_reload.js.html | 5 +- documentation/admin_removemod.js.html | 8 +- documentation/admin_saveconfig.js.html | 6 +- documentation/admin_shout.js.html | 2 +- documentation/core_changecolor.js.html | 2 +- documentation/core_changenick.js.html | 16 +- documentation/core_chat.js.html | 2 +- documentation/core_emote.js.html | 2 +- documentation/core_help.js.html | 2 +- documentation/core_invite.js.html | 2 +- documentation/core_join.js.html | 27 +- documentation/core_morestats.js.html | 2 +- documentation/core_ping.js.html | 2 +- documentation/core_session.js.html | 31 +- documentation/core_stats.js.html | 2 +- documentation/core_whisper.js.html | 2 +- documentation/index.html | 2 +- documentation/internal_disconnect.js.html | 18 +- documentation/internal_socketreply.js.html | 2 +- documentation/mod_ban.js.html | 2 +- documentation/mod_dumb.js.html | 3 +- documentation/mod_forcecolor.js.html | 2 +- documentation/mod_kick.js.html | 2 +- documentation/mod_speak.js.html | 3 +- documentation/mod_unban.js.html | 2 +- documentation/mod_unbanall.js.html | 2 +- documentation/module-addmod.html | 2 +- documentation/module-ban.html | 2 +- documentation/module-changecolor.html | 2 +- documentation/module-changenick.html | 10 +- documentation/module-chat.html | 2 +- documentation/module-disconnect.html | 8 +- documentation/module-dumb.html | 2 +- documentation/module-emote.html | 2 +- documentation/module-forcecolor.html | 2 +- documentation/module-help.html | 2 +- documentation/module-invite.html | 2 +- documentation/module-join.html | 8 +- documentation/module-kick.html | 2 +- documentation/module-listusers.html | 2 +- documentation/module-morestats.html | 2 +- documentation/module-ping.html | 2 +- documentation/module-reload.html | 4 +- documentation/module-removemod.html | 6 +- documentation/module-saveconfig.html | 4 +- documentation/module-session.html | 6 +- documentation/module-shout.html | 2 +- documentation/module-socketreply.html | 2 +- documentation/module-speak.html | 2 +- documentation/module-stats.html | 2 +- documentation/module-unban.html | 2 +- documentation/module-unbanall.html | 2 +- documentation/module-whisper.html | 2 +- documentation/scripts/linenumber.js | 40 +- documentation/scripts/prettify/lang-css.js | 4 +- documentation/scripts/prettify/prettify.js | 153 +- package-lock.json | 2275 ++++++++++---------- package.json | 9 +- scripts/config.js | 4 +- test/changenick.test.js | 14 + test/chat.test.js | 28 + test/disablecaptcha.test.js | 100 + test/dumb.test.js | 151 +- test/enablecaptcha.test.js | 222 ++ test/join.test.js | 19 + test/lockroom.test.js | 413 ++++ test/mockImports.js | 10 + test/speak.test.js | 56 + test/text.test.js | 19 + test/uac.test.js | 4 +- test/unlockroom.test.js | 113 + test/updateMessage.test.js | 233 ++ 89 files changed, 3654 insertions(+), 1429 deletions(-) delete mode 100644 LICENSE create mode 100644 commands/mod/disablecaptcha.js create mode 100644 commands/mod/enablecaptcha.js create mode 100644 commands/mod/lockroom.js create mode 100644 commands/mod/unlockroom.js create mode 100644 test/disablecaptcha.test.js create mode 100644 test/enablecaptcha.test.js create mode 100644 test/lockroom.test.js create mode 100644 test/text.test.js create mode 100644 test/unlockroom.test.js create mode 100644 test/updateMessage.test.js diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f0e18e1..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2022 marzavec - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/commands/admin/removemod.js b/commands/admin/removemod.js index fe7c28c..d01db82 100644 --- a/commands/admin/removemod.js +++ b/commands/admin/removemod.js @@ -48,7 +48,7 @@ export async function run({ for (let i = 0, l = targetMod.length; i < l; i += 1) { // downgrade privileges - targetMod[i].uType = 'user'; /* @legacy */ + targetMod[i].uType = 'user'; targetMod[i].level = levels.default; // inform ex-mod diff --git a/commands/core/chat.js b/commands/core/chat.js index 5ba3dee..8e15539 100644 --- a/commands/core/chat.js +++ b/commands/core/chat.js @@ -6,43 +6,51 @@ * @module chat */ -import { parseText } from '../utility/_Text.js'; +import { + parseText, +} from '../utility/_Text.js'; import { isAdmin, isModerator, } from '../utility/_UAC.js'; +/** + * Maximum length of the customId property + * @type {number} + */ export const MAX_MESSAGE_ID_LENGTH = 6; + /** - * The time in milliseconds before a message is considered stale, and thus no longer allowed - * to be edited. - * @type {number} - */ + * The time in milliseconds before a message is considered stale, and thus no longer allowed + * to be edited. + * @type {number} + */ const ACTIVE_TIMEOUT = 5 * 60 * 1000; + /** - * The time in milliseconds that a check for stale messages should be performed. - * @type {number} - */ + * The time in milliseconds that a check for stale messages should be performed. + * @type {number} + */ const TIMEOUT_CHECK_INTERVAL = 30 * 1000; /** - * Stores active messages that can be edited. - * @type {{ customId: string, userid: number, sent: number }[]} - */ + * Stores active messages that can be edited. + * @type {{ customId: string, userid: number, sent: number }[]} + */ export const ACTIVE_MESSAGES = []; /** - * Cleans up stale messages. - * @public - * @return {void} - */ + * Cleans up stale messages. + * @public + * @return {void} + */ export function cleanActiveMessages() { const now = Date.now(); - for (let i = 0; i < ACTIVE_MESSAGES.length; i++) { + for (let i = 0; i < ACTIVE_MESSAGES.length; i += 1) { const message = ACTIVE_MESSAGES[i]; if (now - message.sent > ACTIVE_TIMEOUT || message.toDelete) { ACTIVE_MESSAGES.splice(i, 1); - i--; + i -= 1; } } } @@ -51,12 +59,12 @@ export function cleanActiveMessages() { setInterval(cleanActiveMessages, TIMEOUT_CHECK_INTERVAL); /** - * Adds a message to the active messages map. - * @public - * @param {string} id - * @param {number} userid - * @return {void} - */ + * Adds a message to the active messages map. + * @public + * @param {string} id + * @param {number} userid + * @return {void} + */ export function addActiveMessage(customId, userid) { ACTIVE_MESSAGES.push({ customId, @@ -93,7 +101,7 @@ export async function run({ }, socket); } - const customId = payload.customId; + const { customId } = payload; if (typeof (customId) === 'string' && customId.length > MAX_MESSAGE_ID_LENGTH) { // There's a limit on the custom id length. @@ -127,6 +135,7 @@ export async function run({ } addActiveMessage(outgoingPayload.customId, socket.userid); + // broadcast to channel peers server.broadcast(outgoingPayload, { channel: socket.channel }); diff --git a/commands/core/join.js b/commands/core/join.js index 8956376..6e327bd 100644 --- a/commands/core/join.js +++ b/commands/core/join.js @@ -49,7 +49,7 @@ export async function run({ } // `join` is the legacy entry point, check if it needs to be upgraded - if (typeof socket.hcProtocol === 'undefined') { + if (typeof socket.hcProtocol === 'undefined' || socket.hcProtocol === 1) { payload = upgradeLegacyJoin(server, socket, payload); } diff --git a/commands/core/morestats.js b/commands/core/morestats.js index 93cdc5c..02ea8af 100644 --- a/commands/core/morestats.js +++ b/commands/core/morestats.js @@ -37,7 +37,7 @@ export async function run({ core, server, socket }) { // gather connection and channel count const ips = {}; const channels = {}; - // @todo use public channels from core.appConfig.data + // @todo use public channel flag const publicChanCounts = { lounge: 0, meta: 0, diff --git a/commands/core/session.js b/commands/core/session.js index eebed57..5be594a 100644 --- a/commands/core/session.js +++ b/commands/core/session.js @@ -2,9 +2,9 @@ /** * @author Marzavec ( https://github.com/marzavec ) - * @summary Restore session + * @summary Create or restore session * @version 1.0.0 - * @description Restore previous state by session + * @description Restore previous state by session or create new session * @module session */ @@ -24,9 +24,9 @@ import { const SessionLocation = './session.key'; /** - * Get a fresh session string for target socket - * @param {Object} socket - * @param {Object} core + * Get a new json web token for the provided socket + * @param {*} socket + * @param {*} core * @returns {object} */ export function getSession(socket, core) { @@ -39,7 +39,7 @@ export function getSession(socket, core) { nick: socket.nick, trip: socket.trip, userid: socket.userid, - uType: socket.uType, /* @legacy */ + uType: socket.uType, muzzled: socket.muzzled || false, banned: socket.banned || false, }, core.sessionKey, { @@ -49,8 +49,8 @@ export function getSession(socket, core) { /** * Reply to target socket with session failure notice - * @param {Object} server - * @param {Object} socket + * @param {*} server + * @param {*} socket * @returns {boolean} */ function notifyFailure(server, socket) { @@ -136,13 +136,21 @@ export async function run({ socket.nick = session.nick; socket.trip = session.trip; socket.userid = session.userid; - socket.uType = session.uType; /* @legacy */ + socket.uType = session.uType; socket.muzzled = session.muzzled; socket.banned = session.banned; socket.hash = server.getSocketHash(socket); socket.hcProtocol = 2; + // dispatch info + server.reply({ + cmd: 'session', + restored: true, + token: getSession(socket, core), + channels: socket.channels, + }, socket); + for (let i = 0, j = session.channels.length; i < j; i += 1) { restoreJoin({ core, @@ -152,14 +160,6 @@ export async function run({ }, true); } - // dispatch updated session - server.reply({ - cmd: 'session', - restored: true, - token: getSession(socket, core), - channels: socket.channels, - }, socket); - return true; } diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js index 880d96c..752ca2b 100644 --- a/commands/core/updateMessage.js +++ b/commands/core/updateMessage.js @@ -1,10 +1,35 @@ -import { parseText } from "../utility/_Text.js"; -import { isAdmin, isModerator } from "../utility/_UAC.js"; -import { ACTIVE_MESSAGES, MAX_MESSAGE_ID_LENGTH } from "./chat.js"; +/** + * @author MinusGix ( https://github.com/MinusGix ) + * @summary Change target message + * @version v1.0.0 + * @description Will alter a previously sent message using that message's customId + * @module updateMessage + */ -export async function run({ core, server, socket, payload }) { +import { + parseText, +} from '../utility/_Text.js'; +import { + isAdmin, + isModerator, +} from '../utility/_UAC.js'; +import { + ACTIVE_MESSAGES, + MAX_MESSAGE_ID_LENGTH, +} from './chat.js'; + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + server, socket, payload, +}) { // undefined | "overwrite" | "append" | "prepend" | "complete" - let mode = payload.mode; + const { customId } = payload; + let { mode, text } = payload; if (!mode) { mode = 'overwrite'; @@ -14,14 +39,10 @@ export async function run({ core, server, socket, payload }) { return server.police.frisk(socket.address, 13); } - const customId = payload.customId; - - if (!customId || typeof customId !== "string" || customId.length > MAX_MESSAGE_ID_LENGTH) { + if (!customId || typeof customId !== 'string' || customId.length > MAX_MESSAGE_ID_LENGTH) { return server.police.frisk(socket.address, 13); } - let text = payload.text; - if (typeof (text) !== 'string') { return server.police.frisk(socket.address, 13); } @@ -43,7 +64,7 @@ export async function run({ core, server, socket, payload }) { // Or flashing between huge and small. Etc. let message; - for (let i = 0; i < ACTIVE_MESSAGES.length; i++) { + for (let i = 0; i < ACTIVE_MESSAGES.length; i += 1) { const msg = ACTIVE_MESSAGES[i]; if (msg.userid === socket.userid && msg.customId === customId) { @@ -80,6 +101,12 @@ export async function run({ core, server, socket, payload }) { return true; } +/** + * The following payload properties are required to invoke this module: + * "text", "customId" + * @public + * @typedef {Array} addmod/requiredData + */ export const requiredData = ['text', 'customId']; /** diff --git a/commands/mod/disablecaptcha.js b/commands/mod/disablecaptcha.js new file mode 100644 index 0000000..ff310c7 --- /dev/null +++ b/commands/mod/disablecaptcha.js @@ -0,0 +1,86 @@ +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Disables the captcha + * @version 1.0.0 + * @description Disables the captcha on the channel specified in the channel property, + * default is current channel + * @module disablecaptcha + */ + +import { + isModerator, +} from '../utility/_UAC.js'; + +/** + * Automatically executes once after server is ready + * @param {Object} core - Reference to core enviroment object + * @public + * @return {void} + */ +export async function init(core) { + if (typeof core.captchas === 'undefined') { + core.captchas = {}; + } +} + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + core, server, socket, payload, +}) { + // increase rate limit chance and ignore if not admin or mod + if (!isModerator(socket.level)) { + return server.police.frisk(socket.address, 10); + } + + let targetChannel; + + if (typeof payload.channel !== 'string') { + if (typeof socket.channel !== 'string') { // @todo Multichannel + return false; // silently fail + } + + targetChannel = socket.channel; + } else { + targetChannel = payload.channel; + } + + if (!core.captchas[targetChannel]) { + return server.reply({ + cmd: 'info', + text: 'Captcha is not enabled.', + channel: socket.channel, // @todo Multichannel + }, socket); + } + + core.captchas[targetChannel] = false; + + server.broadcast({ + cmd: 'info', + text: `Captcha disabled on: ${targetChannel}`, + channel: false, // @todo Multichannel, false for global info + }, { channel: targetChannel, level: isModerator }); + + return true; +} + +/** + * Module meta information + * @public + * @typedef {Object} disablecaptcha/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'disablecaptcha', + category: 'moderators', + description: 'Disables the captcha on the channel specified in the channel property, default is current channel', + usage: ` + API: { cmd: 'disablecaptcha', channel: '' }`, +}; diff --git a/commands/mod/lockroom.js b/commands/mod/lockroom.js new file mode 100644 index 0000000..babcd7e --- /dev/null +++ b/commands/mod/lockroom.js @@ -0,0 +1,332 @@ +/* eslint no-param-reassign: 0 */ + +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Locks the channel + * @version 1.0.0 + * @description Locks a channel preventing default levels from joining + * @module lockroom + */ + +import { + levels, + isTrustedUser, + isModerator, + verifyNickname, + getUserPerms, +} from '../utility/_UAC.js'; +import { + upgradeLegacyJoin, + legacyLevelToLabel, +} from '../utility/_LegacyFunctions.js'; +import { + Errors, +} from '../utility/_Constants.js'; +import { + canJoinChannel, +} from '../utility/_Channels.js'; + +const danteQuotes = [ + 'Do not be afraid; our fate cannot be taken from us; it is a gift.', + 'In the middle of the journey of our life I found myself within a dark woods where the straight way was lost.', + 'There is no greater sorrow then to recall our times of joy in wretchedness.', + 'They yearn for what they fear for.', + 'Through me you go into a city of weeping; through me you go into eternal pain; through me you go amongst the lost people', + 'From there we came outside and saw the stars', + 'But the stars that marked our starting fall away. We must go deeper into greater pain, for it is not permitted that we stay.', + 'Hope not ever to see Heaven. I have come to lead you to the other shore; into eternal darkness; into fire and into ice.', + 'As little flowers, which the chill of night has bent and huddled, when the white sun strikes, grow straight and open fully on their stems, so did I, too, with my exhausted force.', + 'At grief so deep the tongue must wag in vain; the language of our sense and memory lacks the vocabulary of such pain.', + 'Thence we came forth to rebehold the stars.', + 'He is, most of all, l\'amor che move il sole e l\'altre stelle.', + 'The poets leave hell and again behold the stars.', + 'One ought to be afraid of nothing other then things possessed of power to do us harm, but things innoucuous need not be feared.', + 'As phantoms frighten beasts when shadows fall.', + 'We were men once, though we\'ve become trees', + 'Here pity only lives when it is dead', + 'Lasciate ogne speranza, voi ch\'intrate.', + 'There is no greater sorrow than thinking back upon a happy time in misery', + 'My thoughts were full of other things When I wandered off the path.', +]; + +/** + * Automatically executes once after server is ready + * @param {Object} core - Reference to core enviroment object + * @public + * @return {void} + */ +export async function init(core) { + if (typeof core.locked === 'undefined') { + core.locked = {}; + } +} + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + core, server, socket, payload, +}) { + // increase rate limit chance and ignore if not admin or mod + if (!isModerator(socket.level)) { + return server.police.frisk(socket.address, 10); + } + + let targetChannel; + + if (typeof payload.channel !== 'string') { + if (typeof socket.channel !== 'string') { // @todo Multichannel + return false; // silently fail + } + + targetChannel = socket.channel; + } else { + targetChannel = payload.channel; + } + + if (core.locked[targetChannel]) { + return server.reply({ + cmd: 'info', + text: 'Channel is already locked.', + channel: socket.channel, // @todo Multichannel + }, socket); + } + + // apply lock flag to channel list + core.locked[targetChannel] = true; + + // inform mods + server.broadcast({ + cmd: 'info', + text: `Channel: ?${targetChannel} lock enabled by [${socket.trip}]${socket.nick}`, + channel: false, // @todo Multichannel, false for global info + }, { level: isModerator }); + + return true; +} + +/** + * Automatically executes once after server is ready to register this modules hooks + * @param {Object} server - Reference to server enviroment object + * @public + * @return {void} + */ +export function initHooks(server) { + server.registerHook('in', 'changenick', this.changeNickCheck.bind(this), 1); + server.registerHook('in', 'whisper', this.whisperCheck.bind(this), 1); + server.registerHook('in', 'chat', this.chatCheck.bind(this), 1); + server.registerHook('in', 'invite', this.inviteCheck.bind(this), 1); + server.registerHook('in', 'join', this.joinCheck.bind(this), 1); +} + +/** + * Executes every time an incoming changenick command is invoked; + * hook incoming changenick commands, reject them if the channel is 'purgatory' + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ +export function changeNickCheck({ + socket, payload, +}) { + if (socket.channel === 'purgatory') { // @todo Multichannel update + return false; + } + + return payload; +} + +/** + * Executes every time an incoming whisper command is invoked; + * hook incoming whisper commands, reject them if the channel is 'purgatory' + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ +export function whisperCheck({ + socket, payload, +}) { + if (socket.channel === 'purgatory') { // @todo Multichannel update + return false; + } + + return payload; +} + +/** + * Executes every time an incoming chat command is invoked; + * hook incoming chat commands, reject them if the channel is 'purgatory' + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ +export function chatCheck({ + socket, payload, +}) { + if (socket.channel === 'purgatory') { + if (socket.level >= levels.moderator) { + return payload; + } + + return false; + } + + return payload; +} + +/** + * Executes every time an incoming invite command is invoked; + * hook incoming invite commands, reject them if the channel is 'purgatory' + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ +export function inviteCheck({ + socket, payload, +}) { + if (socket.channel === 'purgatory') { + return false; + } + + return payload; +} + +/** + * Executes every time an incoming join command is invoked; + * hook incoming join commands, shunt them to purgatory if needed + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {{Object|boolean|string}} Object = same/altered payload, + * false = suppress action, + * string = error + */ +export function joinCheck({ + core, server, socket, payload, +}) { + // check if target channel is locked + if (typeof core.locked[payload.channel] === 'undefined' || core.locked[payload.channel] !== true) { + if (payload.channel !== 'purgatory') { + return payload; + } + } + + // `join` is the legacy entry point, check if it needs to be upgraded + if (typeof socket.hcProtocol === 'undefined') { + payload = upgradeLegacyJoin(server, socket, payload); + } + + // store payload values + const { channel, nick, pass } = payload; + + // check if a client is able to join target channel + const mayJoin = canJoinChannel(channel, socket); + if (mayJoin !== true) { + return server.reply({ + cmd: 'warn', + text: 'You may not join that channel.', + id: mayJoin, + channel: false, // @todo Multichannel, false for global event + }, socket); + } + + // calling socket already in a channel + // @todo multichannel update, will remove + if (typeof socket.channel !== 'undefined') { + return server.reply({ + cmd: 'warn', // @todo Remove this + text: 'Joining more than one channel is not currently supported', + id: Errors.Join.ALREADY_JOINED, + channel: false, // @todo Multichannel, false for global event + }, socket); + } + // end todo + + // validates the user input for `nick` + if (verifyNickname(nick, socket) !== true) { + return server.reply({ + cmd: 'warn', + text: 'Nickname must consist of up to 24 letters, numbers, and underscores', + id: Errors.Join.INVALID_NICK, + channel: false, // @todo Multichannel, false for global event + }, socket); + } + + // get trip and level + const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel); + + // store the user values + const userInfo = { + nick, + trip, + uType: legacyLevelToLabel(level), + hash: socket.hash, + level, + userid: socket.userid, + isBot: socket.isBot, + color: socket.color, + channel, + }; + + // check if trip is allowed + if (userInfo.uType === 'user') { + if (userInfo.trip == null || isTrustedUser(level) === false) { + const origNick = userInfo.nick; + const origChannel = payload.channel; + + // not allowed, shunt to purgatory + payload.channel = 'purgatory'; + + // lost souls have no names + if (origChannel === 'purgatory') { + // someone is pulling a Dante + payload.nick = `Dante_${Math.random().toString(36).substr(2, 8)}`; + } else { + payload.nick = `${Math.random().toString(36).substr(2, 8)}${Math.random().toString(36).substr(2, 8)}`; + } + + setTimeout(() => { + server.reply({ + cmd: 'info', + text: danteQuotes[Math.floor(Math.random() * danteQuotes.length)], + channel: 'purgatory', // @todo Multichannel + }, socket); + }, 100); + + server.broadcast({ + cmd: 'info', + text: `${payload.nick} is: ${origNick}\ntrip: ${userInfo.trip || 'none'}\ntried to join: ?${origChannel}\nhash: ${userInfo.hash}`, + channel: 'purgatory', // @todo Multichannel, false for global info + }, { channel: 'purgatory', level: isModerator }); + } + } + + return payload; +} + +/** + * Module meta information + * @public + * @typedef {Object} kick/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'lockroom', + category: 'moderators', + description: 'Locks a channel preventing default levels from joining', + usage: ` + API: { cmd: 'lockroom', channel: '' }`, +}; diff --git a/commands/mod/speak.js b/commands/mod/speak.js index 69330ad..0c988d9 100644 --- a/commands/mod/speak.js +++ b/commands/mod/speak.js @@ -94,6 +94,7 @@ export async function run({ * @property {string} name - Module command name * @property {string} category - Module category name * @property {string} description - Information about module + * @property {Array} aliases - An array of alternative cmd names * @property {string} usage - Information about module usage */ export const info = { @@ -102,5 +103,5 @@ export const info = { description: 'Pardon a dumb user to be able to speak again', aliases: ['unmuzzle', 'unmute'], usage: ` - API: { cmd: 'speak', ip/hash: '' }`, }; diff --git a/commands/mod/unlockroom.js b/commands/mod/unlockroom.js new file mode 100644 index 0000000..9fcfebb --- /dev/null +++ b/commands/mod/unlockroom.js @@ -0,0 +1,89 @@ +/* eslint no-console: 0 */ + +/** + * @author Marzavec ( https://github.com/marzavec ) + * @summary Unlock target channel + * @version 1.0.0 + * @description Unlocks a channel allowing anyone to join + * @module unlockroom + */ + +import { + isModerator, +} from '../utility/_UAC.js'; + +/** + * Automatically executes once after server is ready + * @param {Object} core - Reference to core enviroment object + * @public + * @return {void} + */ +export async function init(core) { + if (typeof core.locked === 'undefined') { + core.locked = {}; + } +} + +/** + * Executes when invoked by a remote client + * @param {Object} env - Enviroment object with references to core, server, socket & payload + * @public + * @return {void} + */ +export async function run({ + core, server, socket, payload, +}) { + // increase rate limit chance and ignore if not admin or mod + if (!isModerator(socket.level)) { + return server.police.frisk(socket.address, 10); + } + + let targetChannel; + + if (typeof payload.channel !== 'string') { + if (typeof socket.channel !== 'string') { // @todo Multichannel + return false; // silently fail + } + + targetChannel = socket.channel; + } else { + targetChannel = payload.channel; + } + + if (!core.locked[targetChannel]) { + return server.reply({ + cmd: 'info', + text: 'Channel is not locked.', + channel: socket.channel, // @todo Multichannel + }, socket); + } + + core.locked[targetChannel] = false; + + server.broadcast({ + cmd: 'info', + text: `Channel: ?${targetChannel} unlocked by [${socket.trip}]${socket.nick}`, + channel: targetChannel, // @todo Multichannel, false for global info + }, { channel: targetChannel, level: isModerator }); + + console.log(`Channel: ?${targetChannel} unlocked by [${socket.trip}]${socket.nick} in ${socket.channel}`); + + return true; +} + +/** + * Module meta information + * @public + * @typedef {Object} unlockroom/info + * @property {string} name - Module command name + * @property {string} category - Module category name + * @property {string} description - Information about module + * @property {string} usage - Information about module usage + */ +export const info = { + name: 'unlockroom', + category: 'moderators', + description: 'Unlock the current channel you are in or target channel as specified', + usage: ` + API: { cmd: 'unlockroom', channel: '' }`, +}; diff --git a/commands/utility/_Text.js b/commands/utility/_Text.js index 05939da..308ad63 100644 --- a/commands/utility/_Text.js +++ b/commands/utility/_Text.js @@ -1,3 +1,13 @@ +/* eslint import/prefer-default-export: 0 */ + +/** + * @author MinusGix ( https://github.com/MinusGix ) + * @summary General string helper functions + * @version v1.0.0 + * @description A library of several commonly used string functions + * @module Text + */ + /** * Check and trim string provided by remote client * @public diff --git a/commands/utility/_UAC.js b/commands/utility/_UAC.js index 96a9332..320392e 100644 --- a/commands/utility/_UAC.js +++ b/commands/utility/_UAC.js @@ -15,8 +15,6 @@ const { createHash, } = await import('crypto'); -const TripLength = 10; - /** * Object defining labels for default permission ranges * @typedef {Object} levels @@ -110,7 +108,7 @@ export function getUserDetails(socket) { return { nick: socket.nick, trip: socket.trip || '', - uType: socket.uType, /* @legacy */ + uType: socket.uType, hash: socket.hash, level: socket.level, userid: socket.userid, @@ -152,7 +150,7 @@ export function getUserPerms(pass, salt, config, channel) { const sha = createHash('sha256'); sha.update(pass + salt); - const trip = sha.digest('base64').substr(0, TripLength); + const trip = sha.digest('base64').substr(0, 6); // check if user is global admin if (trip === config.adminTrip) { diff --git a/documentation/admin_addmod.js.html b/documentation/admin_addmod.js.html index eacf973..63e1265 100644 --- a/documentation/admin_addmod.js.html +++ b/documentation/admin_addmod.js.html @@ -56,7 +56,7 @@ export async function run({ } // add new trip to config - core.appConfig.data.globalMods.push({ trip: payload.trip }); + core.config.mods.push({ trip: payload.trip }); // find targets current connections const newMod = server.findSockets({ trip: payload.trip }); @@ -150,7 +150,7 @@ export const info = {
diff --git a/documentation/admin_listusers.js.html b/documentation/admin_listusers.js.html index fa199b7..705a369 100644 --- a/documentation/admin_listusers.js.html +++ b/documentation/admin_listusers.js.html @@ -119,7 +119,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/admin_reload.js.html b/documentation/admin_reload.js.html index f3831f5..6759d6a 100644 --- a/documentation/admin_reload.js.html +++ b/documentation/admin_reload.js.html @@ -54,7 +54,8 @@ export async function run({ } // do command reload and store results - let loadResult = await core.commands.reloadCommands(); + let loadResult = core.dynamicImports.reloadDirCache(); + loadResult += core.commands.loadCommands(); // clear and rebuild all module hooks server.loadHooks(); @@ -113,7 +114,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/admin_removemod.js.html b/documentation/admin_removemod.js.html index 5d40cd2..9422420 100644 --- a/documentation/admin_removemod.js.html +++ b/documentation/admin_removemod.js.html @@ -57,9 +57,7 @@ export async function run({ // remove trip from config // eslint-disable-next-line no-param-reassign - core.appConfig.data.globalMods = core.appConfig.data.globalMods.filter( - (mod) => mod.trip !== payload.trip, - ); + core.config.mods = core.config.mods.filter((mod) => mod.trip !== payload.trip); // find targets current connections const targetMod = server.findSockets({ trip: payload.trip }); @@ -76,7 +74,7 @@ export async function run({ for (let i = 0, l = targetMod.length; i < l; i += 1) { // downgrade privileges - targetMod[i].uType = 'user'; /* @legacy */ + targetMod[i].uType = 'user'; targetMod[i].level = levels.default; // inform ex-mod @@ -155,7 +153,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/admin_saveconfig.js.html b/documentation/admin_saveconfig.js.html index a3af560..696eb3d 100644 --- a/documentation/admin_saveconfig.js.html +++ b/documentation/admin_saveconfig.js.html @@ -52,9 +52,7 @@ export async function run({ core, server, socket }) { } // attempt save, notify of failure - try { - await core.appConfig.write(); - } catch (err) { + if (!core.configManager.save()) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Failed to save config, check logs.', @@ -104,7 +102,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/admin_shout.js.html b/documentation/admin_shout.js.html index 40b6367..b76de12 100644 --- a/documentation/admin_shout.js.html +++ b/documentation/admin_shout.js.html @@ -100,7 +100,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_changecolor.js.html b/documentation/core_changecolor.js.html index 5241ad8..202b272 100644 --- a/documentation/core_changecolor.js.html +++ b/documentation/core_changecolor.js.html @@ -200,7 +200,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_changenick.js.html b/documentation/core_changenick.js.html index f666107..33ed8cd 100644 --- a/documentation/core_changenick.js.html +++ b/documentation/core_changenick.js.html @@ -48,7 +48,7 @@ import { * @return {void} */ export async function run({ - server, socket, payload, + core, server, socket, payload, }) { const { channel } = socket; @@ -77,6 +77,18 @@ export async function run({ }, socket); } + // prevent admin impersonation + // @todo prevent mod impersonation + if (newNick.toLowerCase() === core.config.adminName.toLowerCase()) { + server.police.frisk(socket.address, 4); + + return server.reply({ + cmd: 'warn', // @todo Add numeric error code as `id` + text: 'You are not the admin, liar!', + channel, // @todo Multichannel + }, socket); + } + if (newNick == previousNick) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` @@ -255,7 +267,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_chat.js.html b/documentation/core_chat.js.html index 0243531..915af4d 100644 --- a/documentation/core_chat.js.html +++ b/documentation/core_chat.js.html @@ -237,7 +237,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_emote.js.html b/documentation/core_emote.js.html index e81a524..1832c4a 100644 --- a/documentation/core_emote.js.html +++ b/documentation/core_emote.js.html @@ -204,7 +204,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_help.js.html b/documentation/core_help.js.html index 7a3eaae..c337611 100644 --- a/documentation/core_help.js.html +++ b/documentation/core_help.js.html @@ -176,7 +176,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_invite.js.html b/documentation/core_invite.js.html index 7920f80..b33aeaf 100644 --- a/documentation/core_invite.js.html +++ b/documentation/core_invite.js.html @@ -165,7 +165,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_join.js.html b/documentation/core_join.js.html index bba3e25..518fa80 100644 --- a/documentation/core_join.js.html +++ b/documentation/core_join.js.html @@ -27,7 +27,6 @@
/* eslint no-param-reassign: 0 */
-/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
 
 /**
   * @author Marzavec ( https://github.com/marzavec )
@@ -37,9 +36,6 @@
   * @module join
   */
 
-import {
-  getSession,
-} from './session.js';
 import {
   canJoinChannel,
   socketInChannel,
@@ -118,7 +114,7 @@ export async function run({
   }
 
   // get trip and level
-  const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel);
+  const { trip, level } = getUserPerms(pass, core.config, channel);
 
   // store the user values
   const userInfo = {
@@ -133,6 +129,13 @@ export async function run({
     channel,
   };
 
+  // prevent admin impersonation
+  if (nick.toLowerCase() === core.config.adminName.toLowerCase()) {
+    if (userInfo.trip !== 'Admin') {
+      userInfo.nick = `Fake${userInfo.nick}`;
+    }
+  }
+
   // check if the nickname already exists in the channel
   const userExists = server.findSockets({
     channel,
@@ -177,7 +180,6 @@ export async function run({
   socket.channel = channel; /* @legacy */
   // @todo multi-channel patch
   // socket.channels.push(channel);
-  socket.channels = [channel];
 
   nicks.push(userInfo.nick); /* @legacy */
   users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo });
@@ -190,14 +192,6 @@ export async function run({
     channel, // @todo Multichannel (?)
   }, socket);
 
-  // update client with new session info
-  server.reply({
-    cmd: 'session',
-    restored: false,
-    token: getSession(socket, core),
-    channels: socket.channels,
-  }, socket);
-
   // stats are fun
   core.stats.increment('users-joined');
 
@@ -276,9 +270,6 @@ export function restoreJoin({
     channel, // @todo Multichannel (?)
   }, socket);
 
-  socket.channel = channel; /* @legacy */
-  socket.channels.push(channel);
-
   return true;
 }
 
@@ -314,7 +305,7 @@ export const info = {
 
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_morestats.js.html b/documentation/core_morestats.js.html index 07b3fad..4e37b5a 100644 --- a/documentation/core_morestats.js.html +++ b/documentation/core_morestats.js.html @@ -206,7 +206,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_ping.js.html b/documentation/core_ping.js.html index 9285bc0..fd0cb6f 100644 --- a/documentation/core_ping.js.html +++ b/documentation/core_ping.js.html @@ -74,7 +74,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_session.js.html b/documentation/core_session.js.html index 4d37721..78c58a0 100644 --- a/documentation/core_session.js.html +++ b/documentation/core_session.js.html @@ -26,7 +26,7 @@
-
/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
+            
/* eslint no-param-reassign: 0 */
 
 /**
   * @author Marzavec ( https://github.com/marzavec )
@@ -49,7 +49,7 @@ import {
   restoreJoin,
 } from './join.js';
 
-const SessionLocation = './session.key';
+const CertLocation = './cert.key';
 
 /**
   *
@@ -67,10 +67,10 @@ export function getSession(socket, core) {
     nick: socket.nick,
     trip: socket.trip,
     userid: socket.userid,
-    uType: socket.uType, /* @legacy */
-    muzzled: socket.muzzled || false,
-    banned: socket.banned || false,
-  }, core.sessionKey, {
+    uType: socket.uType,
+    muzzled: socket.muzzled,
+    banned: socket.banned,
+  }, core.cert, {
     expiresIn: '7 days',
   });
 }
@@ -106,7 +106,7 @@ export async function run({
 
   let session = false;
   try {
-    session = jsonwebtoken.verify(payload.token, core.sessionKey);
+    session = jsonwebtoken.verify(payload.token, core.cert);
   } catch (err) {
     return notifyFailure(server, socket);
   }
@@ -120,7 +120,7 @@ export async function run({
     return notifyFailure(server, socket);
   }
 
-  if (typeof session.color !== 'string' && typeof session.color !== 'boolean') {
+  if (typeof session.color !== 'string') {
     return notifyFailure(server, socket);
   }
 
@@ -157,14 +157,15 @@ export async function run({
   }
 
   // populate socket info with validated session
-  socket.channels = [];
+  socket.channel = session.channel;
+  socket.channels = session.channels;
   socket.color = session.color;
   socket.isBot = session.isBot;
   socket.level = session.level;
   socket.nick = session.nick;
   socket.trip = session.trip;
   socket.userid = session.userid;
-  socket.uType = session.uType; /* @legacy */
+  socket.uType = session.uType;
   socket.muzzled = session.muzzled;
   socket.banned = session.banned;
 
@@ -179,12 +180,12 @@ export async function run({
     channels: socket.channels,
   }, socket);
 
-  for (let i = 0, j = session.channels.length; i < j; i += 1) {
+  for (let i = 0, j = socket.channels.length; i < j; i += 1) {
     restoreJoin({
       core,
       server,
       socket,
-      channel: session.channels[i],
+      channel: socket.channels[i],
     }, true);
   }
 
@@ -199,8 +200,8 @@ export async function run({
   */
 export function init(core) {
   // load the encryption key if required
-  if (typeof core.sessionKey === 'undefined') {
-    core.sessionKey = fs.readFileSync(SessionLocation);
+  if (typeof core.cert === 'undefined') {
+    core.cert = fs.readFileSync(CertLocation);
   }
 }
 
@@ -235,7 +236,7 @@ export const info = {
 
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_stats.js.html b/documentation/core_stats.js.html index 1b25125..b16c7b9 100644 --- a/documentation/core_stats.js.html +++ b/documentation/core_stats.js.html @@ -101,7 +101,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/core_whisper.js.html b/documentation/core_whisper.js.html index f82308d..351c19c 100644 --- a/documentation/core_whisper.js.html +++ b/documentation/core_whisper.js.html @@ -273,7 +273,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/index.html b/documentation/index.html index 2c1c319..310280f 100644 --- a/documentation/index.html +++ b/documentation/index.html @@ -96,7 +96,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/internal_disconnect.js.html b/documentation/internal_disconnect.js.html index 35dd4b8..e83bd69 100644 --- a/documentation/internal_disconnect.js.html +++ b/documentation/internal_disconnect.js.html @@ -34,10 +34,6 @@ * @module disconnect */ -import { - socketInChannel, -} from '../utility/_Channels.js'; - /** * Executes when invoked by a remote client * @param {Object} env - Enviroment object with references to core, server, socket & payload @@ -53,14 +49,10 @@ export async function run({ server, socket, payload }) { // send leave notice to client peers // @todo Multichannel update if (socket.channel) { - const isDuplicate = socketInChannel(server, socket.channel, socket); - - if (isDuplicate === false) { - server.broadcast({ - cmd: 'onlineRemove', - nick: socket.nick, - }, { channel: socket.channel }); - } + server.broadcast({ + cmd: 'onlineRemove', + nick: socket.nick, + }, { channel: socket.channel }); } // commit close just in case @@ -108,7 +100,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/internal_socketreply.js.html b/documentation/internal_socketreply.js.html index f1f6455..144e062 100644 --- a/documentation/internal_socketreply.js.html +++ b/documentation/internal_socketreply.js.html @@ -93,7 +93,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/mod_ban.js.html b/documentation/mod_ban.js.html index 9471b5e..9e61eb0 100644 --- a/documentation/mod_ban.js.html +++ b/documentation/mod_ban.js.html @@ -157,7 +157,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/mod_dumb.js.html b/documentation/mod_dumb.js.html index f197c42..7ae8eae 100644 --- a/documentation/mod_dumb.js.html +++ b/documentation/mod_dumb.js.html @@ -389,6 +389,7 @@ export function whisperCheck({ * @property {string} name - Module command name * @property {string} category - Module category name * @property {string} description - Information about module + * @property {Array} aliases - An array of alternative cmd names * @property {string} usage - Information about module usage */ export const info = { @@ -415,7 +416,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/mod_forcecolor.js.html b/documentation/mod_forcecolor.js.html index 232b4e5..f8610d7 100644 --- a/documentation/mod_forcecolor.js.html +++ b/documentation/mod_forcecolor.js.html @@ -241,7 +241,7 @@ Text: /forcecolor <target nick> <color as hex>`,
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/mod_kick.js.html b/documentation/mod_kick.js.html index 650b684..6b65861 100644 --- a/documentation/mod_kick.js.html +++ b/documentation/mod_kick.js.html @@ -194,7 +194,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/mod_speak.js.html b/documentation/mod_speak.js.html index c9566c7..a9c6eb4 100644 --- a/documentation/mod_speak.js.html +++ b/documentation/mod_speak.js.html @@ -122,6 +122,7 @@ export async function run({ * @property {string} name - Module command name * @property {string} category - Module category name * @property {string} description - Information about module + * @property {Array} aliases - An array of alternative cmd names * @property {string} usage - Information about module usage */ export const info = { @@ -148,7 +149,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/mod_unban.js.html b/documentation/mod_unban.js.html index 1ed956a..ecf73cc 100644 --- a/documentation/mod_unban.js.html +++ b/documentation/mod_unban.js.html @@ -133,7 +133,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/mod_unbanall.js.html b/documentation/mod_unbanall.js.html index 8e4c416..a2ce97f 100644 --- a/documentation/mod_unbanall.js.html +++ b/documentation/mod_unbanall.js.html @@ -106,7 +106,7 @@ export const info = {
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-addmod.html b/documentation/module-addmod.html index 1e4b182..3e7e7a5 100644 --- a/documentation/module-addmod.html +++ b/documentation/module-addmod.html @@ -595,7 +595,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-ban.html b/documentation/module-ban.html index bf7061d..661f988 100644 --- a/documentation/module-ban.html +++ b/documentation/module-ban.html @@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-changecolor.html b/documentation/module-changecolor.html index 337cb77..f684538 100644 --- a/documentation/module-changecolor.html +++ b/documentation/module-changecolor.html @@ -893,7 +893,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-changenick.html b/documentation/module-changenick.html index 10b4082..d74189c 100644 --- a/documentation/module-changenick.html +++ b/documentation/module-changenick.html @@ -255,7 +255,7 @@
Source:
@@ -410,7 +410,7 @@
Source:
@@ -784,7 +784,7 @@
Source:
@@ -857,7 +857,7 @@
Source:
@@ -893,7 +893,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-chat.html b/documentation/module-chat.html index 2df83e7..bc4fba8 100644 --- a/documentation/module-chat.html +++ b/documentation/module-chat.html @@ -1038,7 +1038,7 @@ assumes a failed chat command invocation and will reject with notice
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-disconnect.html b/documentation/module-disconnect.html index 46e4209..47db03c 100644 --- a/documentation/module-disconnect.html +++ b/documentation/module-disconnect.html @@ -255,7 +255,7 @@
Source:
@@ -486,7 +486,7 @@
Source:
@@ -559,7 +559,7 @@
Source:
@@ -595,7 +595,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-dumb.html b/documentation/module-dumb.html index 4316c2f..4c86f9f 100644 --- a/documentation/module-dumb.html +++ b/documentation/module-dumb.html @@ -1264,7 +1264,7 @@ shadow-prevent all whispers from muzzled users
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-emote.html b/documentation/module-emote.html index c1c2541..229f5c4 100644 --- a/documentation/module-emote.html +++ b/documentation/module-emote.html @@ -894,7 +894,7 @@ hooks chat commands checking for /me
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-forcecolor.html b/documentation/module-forcecolor.html index ca2ecb6..56be862 100644 --- a/documentation/module-forcecolor.html +++ b/documentation/module-forcecolor.html @@ -894,7 +894,7 @@ hooks chat commands checking for /forcecolor
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-help.html b/documentation/module-help.html index e905547..f43fd20 100644 --- a/documentation/module-help.html +++ b/documentation/module-help.html @@ -821,7 +821,7 @@ hooks chat commands checking for /help
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-invite.html b/documentation/module-invite.html index 8e4d552..d635329 100644 --- a/documentation/module-invite.html +++ b/documentation/module-invite.html @@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-join.html b/documentation/module-join.html index 4fca6e6..6b8470b 100644 --- a/documentation/module-join.html +++ b/documentation/module-join.html @@ -97,7 +97,7 @@
Source:
@@ -255,7 +255,7 @@
Source:
@@ -486,7 +486,7 @@
Source:
@@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-kick.html b/documentation/module-kick.html index f522c78..1101b23 100644 --- a/documentation/module-kick.html +++ b/documentation/module-kick.html @@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-listusers.html b/documentation/module-listusers.html index 7ecfac1..e4a23c2 100644 --- a/documentation/module-listusers.html +++ b/documentation/module-listusers.html @@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-morestats.html b/documentation/module-morestats.html index f6b1b34..a26cabd 100644 --- a/documentation/module-morestats.html +++ b/documentation/module-morestats.html @@ -821,7 +821,7 @@ hooks chat commands checking for /stats
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-ping.html b/documentation/module-ping.html index 087e342..eb93b1a 100644 --- a/documentation/module-ping.html +++ b/documentation/module-ping.html @@ -473,7 +473,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-reload.html b/documentation/module-reload.html index 9b69736..7ebbebb 100644 --- a/documentation/module-reload.html +++ b/documentation/module-reload.html @@ -486,7 +486,7 @@
Source:
@@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-removemod.html b/documentation/module-removemod.html index 89443c9..3611d20 100644 --- a/documentation/module-removemod.html +++ b/documentation/module-removemod.html @@ -486,7 +486,7 @@
Source:
@@ -559,7 +559,7 @@
Source:
@@ -595,7 +595,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-saveconfig.html b/documentation/module-saveconfig.html index 9e7635c..00bfd34 100644 --- a/documentation/module-saveconfig.html +++ b/documentation/module-saveconfig.html @@ -486,7 +486,7 @@
Source:
@@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-session.html b/documentation/module-session.html index b6056eb..1ebaa0b 100644 --- a/documentation/module-session.html +++ b/documentation/module-session.html @@ -429,7 +429,7 @@
Source:
@@ -989,7 +989,7 @@
Source:
@@ -1025,7 +1025,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-shout.html b/documentation/module-shout.html index b1d7fea..4cdbbfb 100644 --- a/documentation/module-shout.html +++ b/documentation/module-shout.html @@ -595,7 +595,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-socketreply.html b/documentation/module-socketreply.html index 295fb88..9cb906a 100644 --- a/documentation/module-socketreply.html +++ b/documentation/module-socketreply.html @@ -596,7 +596,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-speak.html b/documentation/module-speak.html index 8c26b26..1db6710 100644 --- a/documentation/module-speak.html +++ b/documentation/module-speak.html @@ -677,7 +677,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-stats.html b/documentation/module-stats.html index fbe8aef..3a11bab 100644 --- a/documentation/module-stats.html +++ b/documentation/module-stats.html @@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-unban.html b/documentation/module-unban.html index 91cf840..e455524 100644 --- a/documentation/module-unban.html +++ b/documentation/module-unban.html @@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-unbanall.html b/documentation/module-unbanall.html index 917a661..408a449 100644 --- a/documentation/module-unbanall.html +++ b/documentation/module-unbanall.html @@ -522,7 +522,7 @@
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/module-whisper.html b/documentation/module-whisper.html index 5d5aea7..dfaa035 100644 --- a/documentation/module-whisper.html +++ b/documentation/module-whisper.html @@ -902,7 +902,7 @@ hooks chat commands checking for /whisper
- Documentation generated by JSDoc 3.6.6 on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time) + Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time)
diff --git a/documentation/scripts/linenumber.js b/documentation/scripts/linenumber.js index 4354785..f355ce2 100644 --- a/documentation/scripts/linenumber.js +++ b/documentation/scripts/linenumber.js @@ -1,25 +1,25 @@ -/*global document */ +/* global document */ (() => { - const source = document.getElementsByClassName('prettyprint source linenums'); - let i = 0; - let lineNumber = 0; - let lineId; - let lines; - let totalLines; - let anchorHash; + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; - if (source && source[0]) { - anchorHash = document.location.hash.substring(1); - lines = source[0].getElementsByTagName('li'); - totalLines = lines.length; + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; - for (; i < totalLines; i++) { - lineNumber++; - lineId = `line${lineNumber}`; - lines[i].id = lineId; - if (lineId === anchorHash) { - lines[i].className += ' selected'; - } - } + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } } + } })(); diff --git a/documentation/scripts/prettify/lang-css.js b/documentation/scripts/prettify/lang-css.js index 041e1f5..b258dc8 100644 --- a/documentation/scripts/prettify/lang-css.js +++ b/documentation/scripts/prettify/lang-css.js @@ -1,2 +1,2 @@ -PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", -/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); +PR.registerLangHandler(PR.createSimpleLexer([['pln', /^[\t\n\f\r ]+/, null, ' \t\r\n ']], [['str', /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], ['str', /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], ['lang-css-str', /^url\(([^"')]*)\)/i], ['kwd', /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, null], ['lang-css-kw', /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i], ['com', /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], ['com', + /^(?:<\!--|--\>)/], ['lit', /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], ['lit', /^#[\da-f]{3,6}/i], ['pln', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], ['pun', /^[^\s\w"']+/]]), ['css']); PR.registerLangHandler(PR.createSimpleLexer([], [['kwd', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]), ['css-kw']); PR.registerLangHandler(PR.createSimpleLexer([], [['str', /^[^"')]+/]]), ['css-str']); diff --git a/documentation/scripts/prettify/prettify.js b/documentation/scripts/prettify/prettify.js index eef5ad7..bf2f003 100644 --- a/documentation/scripts/prettify/prettify.js +++ b/documentation/scripts/prettify/prettify.js @@ -1,28 +1,125 @@ -var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; -(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= -[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), -l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, -q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, -q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, -"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), -a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} -for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], -"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], -H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], -J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ -I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), -["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", -/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), -["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", -hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= -!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p= '0' && b <= '7' ? parseInt(a.substring(1), 8) : b === 'u' || b === 'x' ? parseInt(a.substring(2), 16) : a.charCodeAt(1); } function e(a) { if (a < 32) return (a < 16 ? '\\x0' : '\\x') + a.toString(16); a = String.fromCharCode(a); if (a === '\\' || a === '-' || a === '[' || a === ']')a = `\\${a}`; return a; } function h(a) { + for (var f = a.substring(1, a.length - 1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g), a = [], b = [], o = f[0] === '^', c = o ? 1 : 0, i = f.length; c < i; ++c) { var j = f[c]; if (/\\[bdsw]/i.test(j))a.push(j); else { var j = m(j); var d; c + 2 < i && f[c + 1] === '-' ? (d = m(f[c + 2]), c += 2) : d = j; b.push([j, d]); d < 65 || j > 122 || (d < 65 || j > 90 || b.push([Math.max(65, j) | 32, Math.min(d, 90) | 32]), d < 97 || j > 122 || b.push([Math.max(97, j) & -33, Math.min(d, 122) & -33])); } }b.sort((a, f) => a[0] - f[0] || f[1] - a[1]); f = []; j = [NaN, NaN]; for (c = 0; c < b.length; ++c)i = b[c], i[0] <= j[1] + 1 ? j[1] = Math.max(j[1], i[1]) : f.push(j = i); b = ['[']; o && b.push('^'); b.push.apply(b, a); for (c = 0; c +< f.length; ++c)i = f[c], b.push(e(i[0])), i[1] > i[0] && (i[1] + 1 > i[0] && b.push('-'), b.push(e(i[1]))); b.push(']'); return b.join(''); + } function y(a) { + for (var f = a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g), b = f.length, d = [], c = 0, i = 0; c < b; ++c) { var j = f[c]; j === '(' ? ++i : j.charAt(0) === '\\' && (j = +j.substring(1)) && j <= i && (d[j] = -1); } for (c = 1; c < d.length; ++c)d[c] === -1 && (d[c] = ++t); for (i = c = 0; c < b; ++c) { + j = f[c], j === '(' ? (++i, d[i] === void 0 && (f[c] = '(?:')) : j.charAt(0) === '\\' +&& (j = +j.substring(1)) && j <= i && (f[c] = `\\${d[i]}`); + } for (i = c = 0; c < b; ++c)f[c] === '^' && f[c + 1] !== '^' && (f[c] = ''); if (a.ignoreCase && s) for (c = 0; c < b; ++c)j = f[c], a = j.charAt(0), j.length >= 2 && a === '[' ? f[c] = h(j) : a !== '\\' && (f[c] = j.replace(/[A-Za-z]/g, (a) => { a = a.charCodeAt(0); return `[${String.fromCharCode(a & -33, a | 32)}]`; })); return f.join(''); + } for (var t = 0, s = !1, l = !1, p = 0, d = a.length; p < d; ++p) { var g = a[p]; if (g.ignoreCase)l = !0; else if (/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, ''))) { s = !0; l = !1; break; } } for (var r = { + b: 8, t: 9, n: 10, v: 11, f: 12, r: 13, + }, n = [], p = 0, d = a.length; p < d; ++p) { g = a[p]; if (g.global || g.multiline) throw Error(`${g}`); n.push(`(?:${y(g)})`); } return RegExp(n.join('|'), l ? 'gi' : 'g'); + } function M(a) { + function m(a) { + switch (a.nodeType) { + case 1: if (e.test(a.className)) break; for (var g = a.firstChild; g; g = g.nextSibling)m(g); g = a.nodeName; if (g === 'BR' || g === 'LI')h[s] = '\n', t[s << 1] = y++, t[s++ << 1 | 1] = a; break; case 3: case 4: g = a.nodeValue, g.length && (g = p ? g.replace(/\r\n?/g, '\n') : g.replace(/[\t\n\r ]+/g, ' '), h[s] = g, t[s << 1] = y, y += g.length, + t[s++ << 1 | 1] = a); + } + } var e = /(?:^|\s)nocode(?:\s|$)/; var h = []; var y = 0; var t = []; var s = 0; let l; a.currentStyle ? l = a.currentStyle.whiteSpace : window.getComputedStyle && (l = document.defaultView.getComputedStyle(a, q).getPropertyValue('white-space')); var p = l && l.substring(0, 3) === 'pre'; m(a); return { a: h.join('').replace(/\n$/, ''), c: t }; + } function B(a, m, e, h) { m && (a = { a: m, d: a }, e(a), h.push.apply(h, a.e)); } function x(a, m) { + function e(a) { + for (var l = a.d, p = [l, 'pln'], d = 0, g = a.a.match(y) || [], r = {}, n = 0, z = g.length; n < z; ++n) { + const f = g[n]; let b = r[f]; let o = void 0; var c; if (typeof b +=== 'string')c = !1; else { var i = h[f.charAt(0)]; if (i)o = f.match(i[1]), b = i[0]; else { for (c = 0; c < t; ++c) if (i = m[c], o = f.match(i[1])) { b = i[0]; break; }o || (b = 'pln'); } if ((c = b.length >= 5 && b.substring(0, 5) === 'lang-') && !(o && typeof o[1] === 'string'))c = !1, b = 'src'; c || (r[f] = b); }i = d; d += f.length; if (c) { c = o[1]; let j = f.indexOf(c); let k = j + c.length; o[2] && (k = f.length - o[2].length, j = k - c.length); b = b.substring(5); B(l + i, f.substring(0, j), e, p); B(l + i + j, c, C(b, c), p); B(l + i + k, f.substring(k), e, p); } else p.push(l + i, b); + }a.e = p; + } var h = {}; let y; (function () { + for (var e = a.concat(m), + l = [], p = {}, d = 0, g = e.length; d < g; ++d) { let r = e[d]; let n = r[3]; if (n) for (let k = n.length; --k >= 0;)h[n.charAt(k)] = r; r = r[1]; n = `${r}`; p.hasOwnProperty(n) || (l.push(r), p[n] = q); }l.push(/[\S\s]/); y = L(l); + }()); var t = m.length; return e; + } function u(a) { + const m = []; const e = []; a.tripleQuotedStrings ? m.push(['str', /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, q, "'\""]) : a.multiLineStrings ? m.push(['str', /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, + q, "'\"`"]) : m.push(['str', /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, q, "\"'"]); a.verbatimStrings && e.push(['str', /^@"(?:[^"]|"")*(?:"|$)/, q]); let h = a.hashComments; h && (a.cStyleComments ? (h > 1 ? m.push(['com', /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, '#']) : m.push(['com', /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/, q, '#']), e.push(['str', /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, q])) : m.push(['com', /^#[^\n\r]*/, + q, '#'])); a.cStyleComments && (e.push(['com', /^\/\/[^\n\r]*/, q]), e.push(['com', /^\/\*[\S\s]*?(?:\*\/|$)/, q])); a.regexLiterals && e.push(['lang-regex', /^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]); (h = a.types) && e.push(['typ', h]); a = (`${a.keywords}`).replace( + /^ | $/g, + '', + ); a.length && e.push(['kwd', RegExp(`^(?:${a.replace(/[\s,]+/g, '|')})\\b`), q]); m.push(['pln', /^\s+/, q, ' \r\n\t\xa0']); e.push(['lit', /^@[$_a-z][\w$@]*/i, q], ['typ', /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], ['pln', /^[$_a-z][\w$@]*/i, q], ['lit', /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, q, '0123456789'], ['pln', /^\\[\S\s]?/, q], ['pun', /^.[^\s\w"-$'./@\\`]*/, q]); return x(m, e); + } function D(a, m) { + function e(a) { + switch (a.nodeType) { + case 1: if (k.test(a.className)) break; if (a.nodeName === 'BR') { + h(a), + a.parentNode && a.parentNode.removeChild(a); + } else for (a = a.firstChild; a; a = a.nextSibling)e(a); break; case 3: case 4: if (p) { let b = a.nodeValue; const d = b.match(t); if (d) { const c = b.substring(0, d.index); a.nodeValue = c; (b = b.substring(d.index + d[0].length)) && a.parentNode.insertBefore(s.createTextNode(b), a.nextSibling); h(a); c || a.parentNode.removeChild(a); } } + } + } function h(a) { + function b(a, d) { const e = d ? a.cloneNode(!1) : a; var f = a.parentNode; if (f) { var f = b(f, 1); let g = a.nextSibling; f.appendChild(e); for (let h = g; h; h = g)g = h.nextSibling, f.appendChild(h); } return e; } + for (;!a.nextSibling;) if (a = a.parentNode, !a) return; for (var a = b(a.nextSibling, 0), e; (e = a.parentNode) && e.nodeType === 1;)a = e; d.push(a); + } var k = /(?:^|\s)nocode(?:\s|$)/; var t = /\r\n?|\n/; var s = a.ownerDocument; let l; a.currentStyle ? l = a.currentStyle.whiteSpace : window.getComputedStyle && (l = s.defaultView.getComputedStyle(a, q).getPropertyValue('white-space')); var p = l && l.substring(0, 3) === 'pre'; for (l = s.createElement('LI'); a.firstChild;)l.appendChild(a.firstChild); for (var d = [l], g = 0; g < d.length; ++g)e(d[g]); m === (m | 0) && d[0].setAttribute( + 'value', + m, + ); const r = s.createElement('OL'); r.className = 'linenums'; for (var n = Math.max(0, m - 1 | 0) || 0, g = 0, z = d.length; g < z; ++g)l = d[g], l.className = `L${(g + n) % 10}`, l.firstChild || l.appendChild(s.createTextNode('\xa0')), r.appendChild(l); a.appendChild(r); + } function k(a, m) { for (let e = m.length; --e >= 0;) { const h = m[e]; A.hasOwnProperty(h) ? window.console && console.warn('cannot override language handler %s', h) : A[h] = a; } } function C(a, m) { if (!a || !A.hasOwnProperty(a))a = /^\s*= o && (h += 2); e >= c && (a += 2); + } + } catch (w) { 'console' in window && console.log(w && w.stack ? w.stack : w); } + } var v = ['break,continue,do,else,for,if,return,while']; var w = [[v, 'auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile'], + 'catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof']; const F = [w, 'alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where']; const G = [w, 'abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient']; + const H = [G, 'as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var']; var w = [w, 'debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN']; const I = [v, 'and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None']; + const J = [v, 'alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END']; var v = [v, 'case,done,elif,esac,eval,fi,function,in,local,set,then,until']; const K = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/; const N = /\S/; const O = u({ + keywords: [F, H, w, `caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END${ + I}`, J, v], + hashComments: !0, + cStyleComments: !0, + multiLineStrings: !0, + regexLiterals: !0, + }); var A = {}; k(O, ['default-code']); k( + x([], [['pln', /^[^]*(?:>|$)/], ['com', /^<\!--[\S\s]*?(?:--\>|$)/], ['lang-', /^<\?([\S\s]+?)(?:\?>|$)/], ['lang-', /^<%([\S\s]+?)(?:%>|$)/], ['pun', /^(?:<[%?]|[%?]>)/], ['lang-', /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], ['lang-js', /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], ['lang-css', /^]*>([\S\s]*?)(<\/style\b[^>]*>)/i], ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i]]), + ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl'], + ); k(x([['pln', /^\s+/, q, ' \t\r\n'], ['atv', /^(?:"[^"]*"?|'[^']*'?)/, q, "\"'"]], [['tag', /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], ['atn', /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], ['lang-uq.val', /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], ['pun', /^[/<->]+/], ['lang-js', /^on\w+\s*=\s*"([^"]+)"/i], ['lang-js', /^on\w+\s*=\s*'([^']+)'/i], ['lang-js', /^on\w+\s*=\s*([^\s"'>]+)/i], ['lang-css', /^style\s*=\s*"([^"]+)"/i], ['lang-css', /^style\s*=\s*'([^']+)'/i], ['lang-css', + /^style\s*=\s*([^\s"'>]+)/i]]), ['in.tag']); k(x([], [['atv', /^[\S\s]+/]]), ['uq.val']); k(u({ + keywords: F, hashComments: !0, cStyleComments: !0, types: K, + }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']); k(u({ keywords: 'null,true,false' }), ['json']); k(u({ + keywords: H, hashComments: !0, cStyleComments: !0, verbatimStrings: !0, types: K, + }), ['cs']); k(u({ keywords: G, cStyleComments: !0 }), ['java']); k(u({ keywords: v, hashComments: !0, multiLineStrings: !0 }), ['bsh', 'csh', 'sh']); k( + u({ + keywords: I, hashComments: !0, multiLineStrings: !0, tripleQuotedStrings: !0, + }), + ['cv', 'py'], + ); k(u({ + keywords: 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END', hashComments: !0, multiLineStrings: !0, regexLiterals: !0, + }), ['perl', 'pl', 'pm']); k(u({ + keywords: J, hashComments: !0, multiLineStrings: !0, regexLiterals: !0, + }), ['rb']); k(u({ keywords: w, cStyleComments: !0, regexLiterals: !0 }), ['js']); k(u({ + keywords: 'all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes', + hashComments: 3, + cStyleComments: !0, + multilineStrings: !0, + tripleQuotedStrings: !0, + regexLiterals: !0, + }), ['coffee']); k(x([], [['str', /^[\S\s]+/]]), ['regex']); window.prettyPrintOne = function (a, m, e) { const h = document.createElement('PRE'); h.innerHTML = a; e && D(h, e); E({ g: m, i: e, h }); return h.innerHTML; }; window.prettyPrint = function (a) { + function m() { + for (let e = window.PR_SHOULD_USE_CONTINUATION ? l.now() + 250 : Infinity; p < h.length && l.now() < e; p++) { + const n = h[p]; var k = n.className; if (k.indexOf('prettyprint') >= 0) { + var k = k.match(g); var f; var b; if (b = !k) { b = n; for (var o = void 0, c = b.firstChild; c; c = c.nextSibling) var i = c.nodeType, o = i === 1 ? o ? b : c : i === 3 ? N.test(c.nodeValue) ? b : o : o; b = (f = o === b ? void 0 : o) && f.tagName === 'CODE'; }b && (k = f.className.match(g)); k && (k = k[1]); b = !1; for (o = n.parentNode; o; o = o.parentNode) if ((o.tagName === 'pre' || o.tagName === 'code' || o.tagName === 'xmp') && o.className && o.className.indexOf('prettyprint') >= 0) { b = !0; break; }b || ((b = (b = n.className.match(/\blinenums\b(?::(\d+))?/)) ? b[1] && b[1].length ? +b[1] : !0 : !1) && D(n, b), d = { g: k, h: n, i: b }, E(d)); + } + }p < h.length ? setTimeout( + m, + 250, + ) : a && a(); + } for (var e = [document.getElementsByTagName('pre'), document.getElementsByTagName('code'), document.getElementsByTagName('xmp')], h = [], k = 0; k < e.length; ++k) for (let t = 0, s = e[k].length; t < s; ++t)h.push(e[k][t]); var e = q; var l = Date; l.now || (l = { now() { return +new Date(); } }); var p = 0; let d; var g = /\blang(?:uage)?-([\w.]+)(?!\S)/; m(); + }; window.PR = { + createSimpleLexer: x, + registerLangHandler: k, + sourceDecorator: u, + PR_ATTRIB_NAME: 'atn', + PR_ATTRIB_VALUE: 'atv', + PR_COMMENT: 'com', + PR_DECLARATION: 'dec', + PR_KEYWORD: 'kwd', + PR_LITERAL: 'lit', + PR_NOCODE: 'nocode', + PR_PLAIN: 'pln', + PR_PUNCTUATION: 'pun', + PR_SOURCE: 'src', + PR_STRING: 'str', + PR_TAG: 'tag', + PR_TYPE: 'typ', + }; +}()); diff --git a/package-lock.json b/package-lock.json index 5d3a2c1..ac0bc6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,13 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "ascii-captcha": "^0.0.3", "enquirer": "^2.3.6", "hackchat-server": "^2.2.27", "http-server": "^14.1.0", - "jsonwebtoken": "^8.5.1", + "jsonwebtoken": "^9.0.2", "lowdb": "^3.0.0", - "pm2": "^5.2.0" + "pm2": "^5.3.0" }, "devDependencies": { "c8": "^7.11.0", @@ -45,17 +46,89 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { "version": "7.17.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", @@ -96,13 +169,10 @@ } }, "node_modules/@babel/core/node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, "bin": { "json5": "lib/cli.js" }, @@ -111,37 +181,29 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@babel/helper-compilation-targets": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", @@ -161,59 +223,43 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -263,21 +309,30 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -307,13 +362,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -358,13 +413,13 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { "node": ">=0.8.0" @@ -373,7 +428,7 @@ "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { "node": ">=4" @@ -392,9 +447,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -415,34 +470,34 @@ } }, "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -459,12 +514,13 @@ } }, "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -643,29 +699,52 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@opencensus/core": { @@ -684,9 +763,9 @@ } }, "node_modules/@opencensus/core/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -719,17 +798,17 @@ } }, "node_modules/@opencensus/propagation-b3/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } }, "node_modules/@pm2/agent": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.1.tgz", - "integrity": "sha512-QKHMm6yexcvdDfcNE7PL9D6uEjoQPGRi+8dh+rc4Hwtbpsbh5IAvZbz3BVGjcd4HaX6pt2xGpOohG7/Y2L4QLw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.3.tgz", + "integrity": "sha512-xkqqCoTf5VsciMqN0vb9jthW7olVAi4KRFNddCc7ZkeJZ3i8QwZANr4NSH2H5DvseRFHq7MiPspRY/EWAFWWTg==", "dependencies": { "async": "~3.2.0", "chalk": "~3.0.0", @@ -741,11 +820,16 @@ "nssocket": "0.6.0", "pm2-axon": "~4.0.1", "pm2-axon-rpc": "~0.7.0", - "proxy-agent": "~5.0.0", - "semver": "~7.2.0", + "proxy-agent": "~6.3.0", + "semver": "~7.5.0", "ws": "~7.4.0" } }, + "node_modules/@pm2/agent/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, "node_modules/@pm2/agent/node_modules/chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -758,16 +842,10 @@ "node": ">=8" } }, - "node_modules/@pm2/agent/node_modules/semver": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz", - "integrity": "sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "node_modules/@pm2/agent/node_modules/dayjs": { + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==" }, "node_modules/@pm2/agent/node_modules/ws": { "version": "7.4.6", @@ -790,9 +868,9 @@ } }, "node_modules/@pm2/io": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.0.tgz", - "integrity": "sha512-3rToDVJaRoob5Lq8+7Q2TZFruoEkdORxwzFpZaqF4bmH6Bkd7kAbdPrI/z8X6k1Meq5rTtScM7MmDgppH6aLlw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.2.tgz", + "integrity": "sha512-XAvrNoQPKOyO/jJyCu8jPhLzlyp35MEf7w/carHXmWKddPzeNOFSEpSEqMzPDawsvpxbE+i918cNN+MwgVsStA==", "dependencies": { "@opencensus/core": "0.0.9", "@opencensus/propagation-b3": "0.0.8", @@ -800,7 +878,7 @@ "debug": "~4.3.1", "eventemitter2": "^6.3.1", "require-in-the-middle": "^5.0.0", - "semver": "6.3.0", + "semver": "~7.5.4", "shimmer": "^1.2.0", "signal-exit": "^3.0.3", "tslib": "1.9.3" @@ -809,26 +887,10 @@ "node": ">=6.0" } }, - "node_modules/@pm2/io/node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, "node_modules/@pm2/io/node_modules/eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" - }, - "node_modules/@pm2/io/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" }, "node_modules/@pm2/js-api": { "version": "0.6.7", @@ -845,23 +907,15 @@ "node": ">=4.0" } }, - "node_modules/@pm2/js-api/node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, "node_modules/@pm2/js-api/node_modules/eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" }, "node_modules/@pm2/js-api/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "engines": { "node": ">=8.3.0" }, @@ -890,10 +944,16 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, "engines": { "node": ">= 6" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -916,6 +976,7 @@ "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -932,18 +993,11 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "dependencies": { "debug": "4" }, @@ -983,12 +1037,12 @@ "node_modules/amp": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", - "integrity": "sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0=" + "integrity": "sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw==" }, "node_modules/amp-message": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", - "integrity": "sha1-p48cmJlQh602GSpBKY5NtJ49/EU=", + "integrity": "sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg==", "dependencies": { "amp": "0.3.1" } @@ -1106,6 +1160,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ascii-captcha": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/ascii-captcha/-/ascii-captcha-0.0.3.tgz", + "integrity": "sha512-dxpezvW1gO/qZTUiLuVEkuuo4YPdX6figilAgbtXfSvyHqXZhZnzSwxdZKQpS/8btIH2S/2k072NHJ4WHoG4pg==" + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1127,14 +1186,17 @@ } }, "node_modules/ast-types/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } }, "node_modules/async-listener": { "version": "0.6.10", @@ -1149,9 +1211,9 @@ } }, "node_modules/async-listener/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -1180,6 +1242,14 @@ "node": ">= 0.8" } }, + "node_modules/basic-ftp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", + "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1202,7 +1272,7 @@ "node_modules/bodec": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", - "integrity": "sha1-vIUVVUMPI8n3ZQp172TGqUw0GMw=" + "integrity": "sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==" }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -1263,14 +1333,6 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/c8": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.0.tgz", @@ -1653,11 +1715,6 @@ "safe-buffer": "~5.1.1" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, "node_modules/corser": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", @@ -1688,20 +1745,20 @@ "node_modules/culvert": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", - "integrity": "sha1-lQL18BVKLVoioCPnn3HMk2+m728=" + "integrity": "sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==" }, "node_modules/data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz", + "integrity": "sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==", "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/dayjs": { - "version": "1.8.36", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", - "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==" + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { "version": "4.3.3", @@ -1743,7 +1800,8 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true }, "node_modules/default-require-extensions": { "version": "3.0.0", @@ -1779,25 +1837,16 @@ } }, "node_modules/degenerator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", - "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", "dependencies": { - "ast-types": "^0.13.2", - "escodegen": "^1.8.1", - "esprima": "^4.0.0", - "vm2": "^3.9.8" + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" + "node": ">= 14" } }, "node_modules/didyoumean2": { @@ -1949,73 +1998,25 @@ } }, "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dependencies": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" + "estraverse": "^5.2.0", + "esutils": "^2.0.2" }, "bin": { "escodegen": "bin/escodegen.js", "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": ">=4.0" + "node": ">=6.0" }, "optionalDependencies": { "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/eslint": { "version": "8.9.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", @@ -2088,9 +2089,9 @@ } }, "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2204,15 +2205,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/eslint-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", @@ -2307,15 +2299,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -2328,19 +2311,10 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "engines": { "node": ">=4.0" } @@ -2356,7 +2330,7 @@ "node_modules/eventemitter2": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", - "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=" + "integrity": "sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==" }, "node_modules/eventemitter3": { "version": "4.0.7", @@ -2370,9 +2344,9 @@ "dev": true }, "node_modules/fast-json-patch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.0.tgz", - "integrity": "sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", @@ -2383,7 +2357,8 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true }, "node_modules/fast-url-parser": { "version": "1.1.3", @@ -2403,7 +2378,7 @@ "node_modules/fclone": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", - "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=" + "integrity": "sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw==" }, "node_modules/file-entry-cache": { "version": "6.0.1", @@ -2417,14 +2392,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", - "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", - "engines": { - "node": ">= 6" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2576,22 +2543,13 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", - "dependencies": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -2617,9 +2575,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" @@ -2664,19 +2622,33 @@ } }, "node_modules/get-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", - "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz", + "integrity": "sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==", "dependencies": { - "@tootallnate/once": "1", - "data-uri-to-buffer": "3", - "debug": "4", - "file-uri-to-path": "2", - "fs-extra": "^8.1.0", - "ftp": "^0.3.10" + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.0", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/get-uri/node_modules/fs-extra": { @@ -2695,7 +2667,7 @@ "node_modules/get-uri/node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -2711,12 +2683,12 @@ "node_modules/git-node-fs": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", - "integrity": "sha1-SbIV4kLr5Dqkx1Ybu6SZUhdSCA8=" + "integrity": "sha512-bLQypt14llVXBg0S0u8q8HmU7g9p3ysH+NvVlae5vILuUvs759665HvmR5+wb04KjHyjFcDRxdYb4kyNnluMUQ==" }, "node_modules/git-sha1": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/git-sha1/-/git-sha1-0.1.2.tgz", - "integrity": "sha1-WZrBkrcYdYJeE6RF86bgURjC90U=" + "integrity": "sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg==" }, "node_modules/glob": { "version": "7.2.0", @@ -2878,6 +2850,17 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -2903,21 +2886,6 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", @@ -2935,6 +2903,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, "dependencies": { "@tootallnate/once": "1", "agent-base": "6", @@ -2974,6 +2943,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -3079,9 +3049,9 @@ } }, "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" }, "node_modules/is-bigint": { "version": "1.0.4", @@ -3135,11 +3105,11 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3337,11 +3307,6 @@ "node": ">=0.10.0" } }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3385,9 +3350,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -3455,7 +3420,7 @@ "node_modules/js-git": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", - "integrity": "sha1-UvplWrYYd9bxB578ZTS1VPMeVEQ=", + "integrity": "sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA==", "dependencies": { "bodec": "^0.1.0", "culvert": "^0.1.2", @@ -3514,13 +3479,13 @@ "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "optional": true }, "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -3541,9 +3506,9 @@ } }, "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", @@ -3554,19 +3519,11 @@ "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.5.4" }, "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" + "node": ">=12", + "npm": ">=6" } }, "node_modules/jwa": { @@ -3591,7 +3548,7 @@ "node_modules/lazy": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", - "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=", + "integrity": "sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==", "engines": { "node": ">=0.2.0" } @@ -3735,11 +3692,11 @@ } }, "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" } }, "node_modules/make-dir": { @@ -3758,9 +3715,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -3805,9 +3762,9 @@ } }, "node_modules/mocha": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", - "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", "dev": true, "dependencies": { "@ungap/promise-all-settled": "1.1.2", @@ -3823,9 +3780,9 @@ "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "3.0.4", + "minimatch": "4.2.1", "ms": "2.1.3", - "nanoid": "3.2.0", + "nanoid": "3.3.1", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -3879,15 +3836,15 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/mocha/node_modules/ms": { @@ -3980,7 +3937,7 @@ "node_modules/module-details-from-path": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", - "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" }, "node_modules/ms": { "version": "2.1.2", @@ -3993,9 +3950,9 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -4091,7 +4048,7 @@ "node_modules/nssocket": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz", - "integrity": "sha1-Wflvb/MhVm8zxw99vu7N/cBxVPo=", + "integrity": "sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==", "dependencies": { "eventemitter2": "~0.4.14", "lazy": "~1.0.11" @@ -4103,7 +4060,7 @@ "node_modules/nssocket/node_modules/eventemitter2": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==" }, "node_modules/nyc": { "version": "15.1.0", @@ -4436,35 +4393,85 @@ } }, "node_modules/pac-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", - "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4", - "get-uri": "3", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "5", - "pac-resolver": "^5.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "5" + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" }, "engines": { - "node": ">= 8" + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/pac-resolver": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", - "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", + "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", "dependencies": { - "degenerator": "^3.0.1", - "ip": "^1.1.5", - "netmask": "^2.0.1" + "degenerator": "^5.0.0", + "ip": "^1.1.8", + "netmask": "^2.0.2" }, "engines": { - "node": ">= 8" + "node": ">= 14" } }, "node_modules/package-hash": { @@ -4485,7 +4492,7 @@ "node_modules/pako": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" }, "node_modules/parent-module": { "version": "1.0.1", @@ -4557,9 +4564,9 @@ } }, "node_modules/pidusage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.0.tgz", - "integrity": "sha512-8VJLToXhj+RYZGNVw8oxc7dS54iCQXUJ+MDFHezQ/fwF5B8W4OWodAMboc1wb08S/4LiHwAmkT4ohf/d3YPPsw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.2.tgz", + "integrity": "sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==", "dependencies": { "safe-buffer": "^5.2.1" }, @@ -4669,9 +4676,9 @@ } }, "node_modules/pm2": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.0.tgz", - "integrity": "sha512-PO5hMVhQ85cTszFM++6v07Me9hPJMkFbHjkFigtMMk+La8ty2wCi2dlBTeZYJDhPUSjK8Ccltpq2buNRcyMOTw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.3.0.tgz", + "integrity": "sha512-xscmQiAAf6ArVmKhjKTeeN8+Td7ZKnuZFFPw1DGkdFPR/0Iyx+m+1+OpCdf9+HQopX3VPc9/wqPQHqVOfHum9w==", "dependencies": { "@pm2/agent": "~2.0.0", "@pm2/io": "~5.0.0", @@ -4680,11 +4687,11 @@ "async": "~3.2.0", "blessed": "0.1.81", "chalk": "3.0.0", - "chokidar": "^3.5.1", + "chokidar": "^3.5.3", "cli-tableau": "^2.0.0", "commander": "2.15.1", "croner": "~4.1.92", - "dayjs": "~1.8.25", + "dayjs": "~1.11.5", "debug": "^4.3.1", "enquirer": "2.3.6", "eventemitter2": "5.0.1", @@ -4698,7 +4705,7 @@ "pm2-multimeter": "^0.1.2", "promptly": "^2", "semver": "^7.2", - "source-map-support": "0.5.19", + "source-map-support": "0.5.21", "sprintf-js": "1.1.2", "vizion": "~2.2.1", "yamljs": "0.3.0" @@ -4774,6 +4781,12 @@ "tx2": "~1.0.4" } }, + "node_modules/pm2-sysmonit/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "optional": true + }, "node_modules/pm2-sysmonit/node_modules/pidusage": { "version": "2.0.21", "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", @@ -4806,6 +4819,11 @@ ], "optional": true }, + "node_modules/pm2/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, "node_modules/pm2/node_modules/chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -4836,14 +4854,6 @@ "node": ">= 0.12.0" } }, - "node_modules/portfinder/node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, "node_modules/portfinder/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -4893,21 +4903,72 @@ } }, "node_modules/proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", - "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", + "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", "dependencies": { - "agent-base": "^6.0.0", - "debug": "4", - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^5.0.0", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^5.0.0" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" }, "engines": { - "node": ">= 8" + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/proxy-from-env": { @@ -4947,20 +5008,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/raw-body": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.0.tgz", - "integrity": "sha512-XpyZ6O7PVu3ItMQl0LslfsRoKxMOxi3SzDkrOtxMES5AqLFpYjQCryxI4LGygUN2jL+RgFsPkMPPlG7cg/47+A==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -4972,17 +5019,6 @@ "node": ">=0.8" } }, - "node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5032,13 +5068,16 @@ } }, "node_modules/require-in-the-middle": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", - "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz", + "integrity": "sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==", "dependencies": { "debug": "^4.1.1", "module-details-from-path": "^1.0.3", - "resolve": "^1.12.0" + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=6" } }, "node_modules/require-main-filename": { @@ -5053,11 +5092,11 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -5132,9 +5171,9 @@ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5176,11 +5215,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5235,11 +5269,11 @@ } }, "node_modules/socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dependencies": { - "ip": "^1.1.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" }, "engines": { @@ -5248,18 +5282,50 @@ } }, "node_modules/socks-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", "dependencies": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks/node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5269,9 +5335,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -5299,14 +5365,6 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/steno": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/steno/-/steno-2.1.0.tgz", @@ -5327,11 +5385,6 @@ "stubs": "^3.0.0" } }, - "node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5432,9 +5485,9 @@ } }, "node_modules/systeminformation": { - "version": "5.11.4", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.11.4.tgz", - "integrity": "sha512-rh7bjpjP5whUaTknim5CiGdAiKZcgWhmbmxjzBRXDWqUc/k67bz2OP+03DdcX6/SN/CDSAi/NeUwM5o2gjHJoA==", + "version": "5.21.20", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.21.20.tgz", + "integrity": "sha512-AyS1fNc+MDoAJtFknFbbo587H8h6yejJwM+H9rVusnOToIEkiMehMyD5JM7o3j55Cto20MawIZrcgNMgd4BfOQ==", "optional": true, "os": [ "darwin", @@ -5522,14 +5575,6 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -5556,7 +5601,7 @@ "node_modules/tv4": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", - "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=", + "integrity": "sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==", "engines": { "node": ">= 0.8.0" } @@ -5646,14 +5691,6 @@ "node": ">= 10.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -5729,29 +5766,6 @@ "node": ">=4.0" } }, - "node_modules/vizion/node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/vm2": { - "version": "3.9.8", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.8.tgz", - "integrity": "sha512-/1PYg/BwdKzMPo8maOZ0heT7DLI0DAFTm7YQaz/Lim9oIaFZsJs3EdtalvXuBfZwczNwsYhju75NW4d6E+4q+w==", - "dependencies": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" - }, - "bin": { - "vm2": "bin/vm2" - }, - "engines": { - "node": ">=6.0" - } - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -5828,9 +5842,10 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -5894,14 +5909,6 @@ } } }, - "node_modules/xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", - "engines": { - "node": "*" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -5910,11 +5917,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, "node_modules/yamljs": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", @@ -6016,12 +6018,71 @@ } }, "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/compat-data": { @@ -6054,39 +6115,29 @@ }, "dependencies": { "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { @@ -6102,49 +6153,36 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true }, "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-imports": { @@ -6182,18 +6220,24 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { @@ -6214,13 +6258,13 @@ } }, "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -6256,19 +6300,19 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, "supports-color": { @@ -6283,9 +6327,9 @@ } }, "@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true }, "@babel/runtime": { @@ -6297,31 +6341,31 @@ } }, "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "dependencies": { @@ -6334,12 +6378,13 @@ } }, "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -6477,26 +6522,43 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@opencensus/core": { @@ -6512,9 +6574,9 @@ }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" } } }, @@ -6540,16 +6602,16 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" } } }, "@pm2/agent": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.1.tgz", - "integrity": "sha512-QKHMm6yexcvdDfcNE7PL9D6uEjoQPGRi+8dh+rc4Hwtbpsbh5IAvZbz3BVGjcd4HaX6pt2xGpOohG7/Y2L4QLw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.3.tgz", + "integrity": "sha512-xkqqCoTf5VsciMqN0vb9jthW7olVAi4KRFNddCc7ZkeJZ3i8QwZANr4NSH2H5DvseRFHq7MiPspRY/EWAFWWTg==", "requires": { "async": "~3.2.0", "chalk": "~3.0.0", @@ -6561,11 +6623,16 @@ "nssocket": "0.6.0", "pm2-axon": "~4.0.1", "pm2-axon-rpc": "~0.7.0", - "proxy-agent": "~5.0.0", - "semver": "~7.2.0", + "proxy-agent": "~6.3.0", + "semver": "~7.5.0", "ws": "~7.4.0" }, "dependencies": { + "async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -6575,10 +6642,10 @@ "supports-color": "^7.1.0" } }, - "semver": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.2.3.tgz", - "integrity": "sha512-utbW9Z7ZxVvwiIWkdOMLOR9G/NFXh2aRucghkVrEMJWuC++r3lCkBC3LwqBinyHzGMAJxY5tn6VakZGHObq5ig==" + "dayjs": { + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", + "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==" }, "ws": { "version": "7.4.6", @@ -6589,9 +6656,9 @@ } }, "@pm2/io": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.0.tgz", - "integrity": "sha512-3rToDVJaRoob5Lq8+7Q2TZFruoEkdORxwzFpZaqF4bmH6Bkd7kAbdPrI/z8X6k1Meq5rTtScM7MmDgppH6aLlw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.2.tgz", + "integrity": "sha512-XAvrNoQPKOyO/jJyCu8jPhLzlyp35MEf7w/carHXmWKddPzeNOFSEpSEqMzPDawsvpxbE+i918cNN+MwgVsStA==", "requires": { "@opencensus/core": "0.0.9", "@opencensus/propagation-b3": "0.0.8", @@ -6599,29 +6666,16 @@ "debug": "~4.3.1", "eventemitter2": "^6.3.1", "require-in-the-middle": "^5.0.0", - "semver": "6.3.0", + "semver": "~7.5.4", "shimmer": "^1.2.0", "signal-exit": "^3.0.3", "tslib": "1.9.3" }, "dependencies": { - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } - }, "eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" } } }, @@ -6637,23 +6691,15 @@ "ws": "^7.0.0" }, "dependencies": { - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } - }, "eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==" + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", + "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} } } @@ -6669,7 +6715,13 @@ "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" }, "@types/istanbul-lib-coverage": { "version": "2.0.4", @@ -6692,7 +6744,8 @@ "acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true }, "acorn-jsx": { "version": "5.3.2", @@ -6701,15 +6754,11 @@ "dev": true, "requires": {} }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" - }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, "requires": { "debug": "4" } @@ -6739,12 +6788,12 @@ "amp": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", - "integrity": "sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0=" + "integrity": "sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw==" }, "amp-message": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", - "integrity": "sha1-p48cmJlQh602GSpBKY5NtJ49/EU=", + "integrity": "sha512-JqutcFwoU1+jhv7ArgW38bqrE+LQdcRv4NxNw0mp0JHQyB6tXesWRjtYKlDgHRY2o3JE5UTaBGUK8kSWUdxWUg==", "requires": { "amp": "0.3.1" } @@ -6829,6 +6878,11 @@ "es-abstract": "^1.19.0" } }, + "ascii-captcha": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/ascii-captcha/-/ascii-captcha-0.0.3.tgz", + "integrity": "sha512-dxpezvW1gO/qZTUiLuVEkuuo4YPdX6figilAgbtXfSvyHqXZhZnzSwxdZKQpS/8btIH2S/2k072NHJ4WHoG4pg==" + }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -6844,16 +6898,19 @@ }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" } } }, "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "requires": { + "lodash": "^4.17.14" + } }, "async-listener": { "version": "0.6.10", @@ -6865,9 +6922,9 @@ }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" } } }, @@ -6892,6 +6949,11 @@ "safe-buffer": "5.1.2" } }, + "basic-ftp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", + "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -6905,7 +6967,7 @@ "bodec": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", - "integrity": "sha1-vIUVVUMPI8n3ZQp172TGqUw0GMw=" + "integrity": "sha512-Ylo+MAo5BDUq1KA3f3R/MFhh+g8cnHmo8bz3YPGhI1znrMaf77ol1sfvYJzsw3nTE+Y2GryfDxBaR+AqpAkEHQ==" }, "brace-expansion": { "version": "1.1.11", @@ -6953,11 +7015,6 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, "c8": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.0.tgz", @@ -7246,11 +7303,6 @@ "safe-buffer": "~5.1.1" } }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, "corser": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", @@ -7275,17 +7327,17 @@ "culvert": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/culvert/-/culvert-0.1.2.tgz", - "integrity": "sha1-lQL18BVKLVoioCPnn3HMk2+m728=" + "integrity": "sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==" }, "data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz", + "integrity": "sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==" }, "dayjs": { - "version": "1.8.36", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", - "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==" + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "debug": { "version": "4.3.3", @@ -7313,7 +7365,8 @@ "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true }, "default-require-extensions": { "version": "3.0.0", @@ -7342,21 +7395,15 @@ } }, "degenerator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", - "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", "requires": { - "ast-types": "^0.13.2", - "escodegen": "^1.8.1", - "esprima": "^4.0.0", - "vm2": "^3.9.8" + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" } }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, "didyoumean2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/didyoumean2/-/didyoumean2-4.2.0.tgz", @@ -7473,52 +7520,14 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "requires": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1", "source-map": "~0.6.1" - }, - "dependencies": { - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "~1.1.2" - } - } } }, "eslint": { @@ -7588,9 +7597,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -7692,14 +7701,6 @@ "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "eslint-utils": { @@ -7753,14 +7754,6 @@ "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "esrecurse": { @@ -7770,20 +7763,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" }, "esutils": { "version": "2.0.3", @@ -7793,7 +7778,7 @@ "eventemitter2": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", - "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=" + "integrity": "sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==" }, "eventemitter3": { "version": "4.0.7", @@ -7807,9 +7792,9 @@ "dev": true }, "fast-json-patch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.0.tgz", - "integrity": "sha512-IhpytlsVTRndz0hU5t0/MGzS/etxLlfrpG5V5M9mVbuj9TrJLWaMfsox9REM5rkuGX0T+5qjpe8XA1o0gZ42nA==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" }, "fast-json-stable-stringify": { "version": "2.1.0", @@ -7820,7 +7805,8 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true }, "fast-url-parser": { "version": "1.1.3", @@ -7842,7 +7828,7 @@ "fclone": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", - "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=" + "integrity": "sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw==" }, "file-entry-cache": { "version": "6.0.1", @@ -7853,11 +7839,6 @@ "flat-cache": "^3.0.4" } }, - "file-uri-to-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", - "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==" - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -7950,19 +7931,10 @@ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "optional": true }, - "ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", - "requires": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - } - }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -7982,9 +7954,9 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true }, "get-intrinsic": { @@ -8014,18 +7986,24 @@ } }, "get-uri": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", - "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz", + "integrity": "sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==", "requires": { - "@tootallnate/once": "1", - "data-uri-to-buffer": "3", - "debug": "4", - "file-uri-to-path": "2", - "fs-extra": "^8.1.0", - "ftp": "^0.3.10" + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.0", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -8039,7 +8017,7 @@ "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "requires": { "graceful-fs": "^4.1.6" } @@ -8054,12 +8032,12 @@ "git-node-fs": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/git-node-fs/-/git-node-fs-1.0.0.tgz", - "integrity": "sha1-SbIV4kLr5Dqkx1Ybu6SZUhdSCA8=" + "integrity": "sha512-bLQypt14llVXBg0S0u8q8HmU7g9p3ysH+NvVlae5vILuUvs759665HvmR5+wb04KjHyjFcDRxdYb4kyNnluMUQ==" }, "git-sha1": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/git-sha1/-/git-sha1-0.1.2.tgz", - "integrity": "sha1-WZrBkrcYdYJeE6RF86bgURjC90U=" + "integrity": "sha512-2e/nZezdVlyCopOCYHeW0onkbZg7xP1Ad6pndPy1rCygeRykefUS6r7oA5cJRGEFvseiaz5a/qUHFVX1dd6Isg==" }, "glob": { "version": "7.2.0", @@ -8166,6 +8144,14 @@ } } }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -8185,18 +8171,6 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, "http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", @@ -8211,6 +8185,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, "requires": { "@tootallnate/once": "1", "agent-base": "6", @@ -8241,6 +8216,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, "requires": { "agent-base": "6", "debug": "4" @@ -8322,9 +8298,9 @@ } }, "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" }, "is-bigint": { "version": "1.0.4", @@ -8360,11 +8336,11 @@ "dev": true }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "requires": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "is-date-object": { @@ -8487,11 +8463,6 @@ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -8526,9 +8497,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -8583,7 +8554,7 @@ "js-git": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/js-git/-/js-git-0.7.8.tgz", - "integrity": "sha1-UvplWrYYd9bxB578ZTS1VPMeVEQ=", + "integrity": "sha512-+E5ZH/HeRnoc/LW0AmAyhU+mNcWBzAKE+30+IDMLSLbbK+Tdt02AdkOKq9u15rlJsDEGFqtgckc8ZM59LhhiUA==", "requires": { "bodec": "^0.1.0", "culvert": "^0.1.2", @@ -8635,13 +8606,13 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "optional": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -8657,9 +8628,9 @@ } }, "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", "requires": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", @@ -8670,14 +8641,7 @@ "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } + "semver": "^7.5.4" } }, "jwa": { @@ -8702,7 +8666,7 @@ "lazy": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", - "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=" + "integrity": "sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==" }, "leven": { "version": "3.1.0", @@ -8819,12 +8783,9 @@ } }, "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" }, "make-dir": { "version": "3.1.0", @@ -8836,9 +8797,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -8867,9 +8828,9 @@ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, "mocha": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", - "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", "dev": true, "requires": { "@ungap/promise-all-settled": "1.1.2", @@ -8885,9 +8846,9 @@ "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "3.0.4", + "minimatch": "4.2.1", "ms": "2.1.3", - "nanoid": "3.2.0", + "nanoid": "3.3.1", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -8918,9 +8879,9 @@ } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -8991,7 +8952,7 @@ "module-details-from-path": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", - "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" }, "ms": { "version": "2.1.2", @@ -9004,9 +8965,9 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true }, "natural-compare": { @@ -9072,7 +9033,7 @@ "nssocket": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz", - "integrity": "sha1-Wflvb/MhVm8zxw99vu7N/cBxVPo=", + "integrity": "sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==", "requires": { "eventemitter2": "~0.4.14", "lazy": "~1.0.11" @@ -9081,7 +9042,7 @@ "eventemitter2": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==" } } }, @@ -9340,29 +9301,64 @@ "dev": true }, "pac-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", - "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4", - "get-uri": "3", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "5", - "pac-resolver": "^5.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "5" + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" + }, + "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "requires": { + "debug": "^4.3.4" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + } } }, "pac-resolver": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", - "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", + "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", "requires": { - "degenerator": "^3.0.1", - "ip": "^1.1.5", - "netmask": "^2.0.1" + "degenerator": "^5.0.0", + "ip": "^1.1.8", + "netmask": "^2.0.2" } }, "package-hash": { @@ -9380,7 +9376,7 @@ "pako": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" }, "parent-module": { "version": "1.0.1", @@ -9431,9 +9427,9 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pidusage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.0.tgz", - "integrity": "sha512-8VJLToXhj+RYZGNVw8oxc7dS54iCQXUJ+MDFHezQ/fwF5B8W4OWodAMboc1wb08S/4LiHwAmkT4ohf/d3YPPsw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.2.tgz", + "integrity": "sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==", "requires": { "safe-buffer": "^5.2.1" }, @@ -9506,9 +9502,9 @@ } }, "pm2": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.0.tgz", - "integrity": "sha512-PO5hMVhQ85cTszFM++6v07Me9hPJMkFbHjkFigtMMk+La8ty2wCi2dlBTeZYJDhPUSjK8Ccltpq2buNRcyMOTw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.3.0.tgz", + "integrity": "sha512-xscmQiAAf6ArVmKhjKTeeN8+Td7ZKnuZFFPw1DGkdFPR/0Iyx+m+1+OpCdf9+HQopX3VPc9/wqPQHqVOfHum9w==", "requires": { "@pm2/agent": "~2.0.0", "@pm2/io": "~5.0.0", @@ -9517,11 +9513,11 @@ "async": "~3.2.0", "blessed": "0.1.81", "chalk": "3.0.0", - "chokidar": "^3.5.1", + "chokidar": "^3.5.3", "cli-tableau": "^2.0.0", "commander": "2.15.1", "croner": "~4.1.92", - "dayjs": "~1.8.25", + "dayjs": "~1.11.5", "debug": "^4.3.1", "enquirer": "2.3.6", "eventemitter2": "5.0.1", @@ -9536,12 +9532,17 @@ "pm2-sysmonit": "^1.2.8", "promptly": "^2", "semver": "^7.2", - "source-map-support": "0.5.19", + "source-map-support": "0.5.21", "sprintf-js": "1.1.2", "vizion": "~2.2.1", "yamljs": "0.3.0" }, "dependencies": { + "async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -9607,6 +9608,12 @@ "tx2": "~1.0.4" }, "dependencies": { + "async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "optional": true + }, "pidusage": { "version": "2.0.21", "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", @@ -9634,14 +9641,6 @@ "mkdirp": "^0.5.5" }, "dependencies": { - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } - }, "debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -9684,18 +9683,54 @@ } }, "proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", - "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", + "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", "requires": { - "agent-base": "^6.0.0", - "debug": "4", - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^5.0.0", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^5.0.0" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "requires": { + "debug": "^4.3.4" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + } } }, "proxy-from-env": { @@ -9726,17 +9761,6 @@ "safe-buffer": "^5.1.0" } }, - "raw-body": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.0.tgz", - "integrity": "sha512-XpyZ6O7PVu3ItMQl0LslfsRoKxMOxi3SzDkrOtxMES5AqLFpYjQCryxI4LGygUN2jL+RgFsPkMPPlG7cg/47+A==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -9745,17 +9769,6 @@ "mute-stream": "~0.0.4" } }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -9790,13 +9803,13 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-in-the-middle": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", - "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz", + "integrity": "sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==", "requires": { "debug": "^4.1.1", "module-details-from-path": "^1.0.3", - "resolve": "^1.12.0" + "resolve": "^1.22.1" } }, "require-main-filename": { @@ -9811,11 +9824,11 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "requires": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -9861,9 +9874,9 @@ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" }, @@ -9898,11 +9911,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -9944,22 +9952,47 @@ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "requires": { - "ip": "^1.1.5", + "ip": "^2.0.0", "smart-buffer": "^4.2.0" + }, + "dependencies": { + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + } } }, "socks-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", - "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", "requires": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "requires": { + "debug": "^4.3.4" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + } } }, "source-map": { @@ -9968,9 +10001,9 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -9995,11 +10028,6 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, "steno": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/steno/-/steno-2.1.0.tgz", @@ -10014,11 +10042,6 @@ "stubs": "^3.0.0" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -10089,9 +10112,9 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "systeminformation": { - "version": "5.11.4", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.11.4.tgz", - "integrity": "sha512-rh7bjpjP5whUaTknim5CiGdAiKZcgWhmbmxjzBRXDWqUc/k67bz2OP+03DdcX6/SN/CDSAi/NeUwM5o2gjHJoA==", + "version": "5.21.20", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.21.20.tgz", + "integrity": "sha512-AyS1fNc+MDoAJtFknFbbo587H8h6yejJwM+H9rVusnOToIEkiMehMyD5JM7o3j55Cto20MawIZrcgNMgd4BfOQ==", "optional": true }, "teeny-request": { @@ -10146,11 +10169,6 @@ "is-number": "^7.0.0" } }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -10177,7 +10195,7 @@ "tv4": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", - "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=" + "integrity": "sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==" }, "tx2": { "version": "1.0.5", @@ -10243,11 +10261,6 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -10310,25 +10323,6 @@ "git-node-fs": "^1.0.0", "ini": "^1.3.5", "js-git": "^0.7.8" - }, - "dependencies": { - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } - } - } - }, - "vm2": { - "version": "3.9.8", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.8.tgz", - "integrity": "sha512-/1PYg/BwdKzMPo8maOZ0heT7DLI0DAFTm7YQaz/Lim9oIaFZsJs3EdtalvXuBfZwczNwsYhju75NW4d6E+4q+w==", - "requires": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" } }, "webidl-conversions": { @@ -10394,9 +10388,10 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true }, "workerpool": { "version": "6.2.0", @@ -10437,21 +10432,11 @@ "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", "requires": {} }, - "xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=" - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, "yamljs": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", diff --git a/package.json b/package.json index 3861229..a5e8980 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hack.chat-v2", - "version": "2.2.0", + "version": "2.2.1", "type": "module", "description": "a minimal distraction free chat application", "main": "main.mjs", @@ -27,15 +27,16 @@ "test": "npm run lint && c8 mocha --exit ./test/*.test.js", "makedocs": "jsdoc -c jsdoc.json" }, - "author": "Marzavec", + "author": "marzavec", "license": "MIT", "dependencies": { + "ascii-captcha": "^0.0.3", "enquirer": "^2.3.6", "hackchat-server": "^2.2.27", "http-server": "^14.1.0", - "jsonwebtoken": "^8.5.1", + "jsonwebtoken": "^9.0.2", "lowdb": "^3.0.0", - "pm2": "^5.2.0" + "pm2": "^5.3.0" }, "devDependencies": { "c8": "^7.11.0", diff --git a/scripts/config.js b/scripts/config.js index eb8e875..89d3d80 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -18,8 +18,6 @@ const SessionLocation = './session.key'; const SaltLocation = './salt.key'; const AppConfigLocation = './config.json'; -const TripLength = 10; - // default configuration options const defaultConfig = { adminTrip: '', @@ -107,7 +105,7 @@ const checkPermissions = async () => { const sha = crypto.createHash('sha256'); sha.update(password + salt); - config.data.adminTrip = sha.digest('base64').substr(0, TripLength); + config.data.adminTrip = sha.digest('base64').substr(0, 6); await config.write(); } else { diff --git a/test/changenick.test.js b/test/changenick.test.js index 09c5fea..cdc6c39 100644 --- a/test/changenick.test.js +++ b/test/changenick.test.js @@ -91,6 +91,20 @@ describe('Checking changenick module', () => { expect(resp).to.be.true; }); + + it('should prevent admin impersonation', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'changenick', + nick: 'admin', + }, + }); + + expect(resp).to.be.true; + }); it('should not update if there is no change', async () => { const resp = await importedModule.run({ diff --git a/test/chat.test.js b/test/chat.test.js index 9615572..dfeaa90 100644 --- a/test/chat.test.js +++ b/test/chat.test.js @@ -121,6 +121,23 @@ describe('Checking chat module', () => { expect(resp).to.be.true; }); + it('should reject too long of customId', async () => { + const newPayload = { ...mockPayload }; + newPayload.customId = '1234567890'; + + const newSocket = { ...mocks.plebSocket }; + newSocket.color = '000000'; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: newPayload, + }); + + expect(resp).to.be.false; + }); + it('should initialize hooks', async () => { expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); }); @@ -195,4 +212,15 @@ describe('Checking chat module', () => { expect(resp).to.be.an('object'); }); + + it('should cleanup old active messages', async () => { + importedModule.ACTIVE_MESSAGES.push({ + customId: '1234', + userid: 1234, + sent: 0, + toDelete: false, + }); + + expect(() => importedModule.cleanActiveMessages()).not.to.throw(); + }); }); \ No newline at end of file diff --git a/test/disablecaptcha.test.js b/test/disablecaptcha.test.js new file mode 100644 index 0000000..079dc08 --- /dev/null +++ b/test/disablecaptcha.test.js @@ -0,0 +1,100 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/disablecaptcha.js'; +let importedModule; + +const mockPayload = { + cmd: 'disablecaptcha', +} + +const mockChannelPayload = { + cmd: 'disablecaptcha', + channel: 'test', +} + +describe('Checking disablecaptcha module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + it('should initialize', async () => { + mocks.core.captchas = undefined; + const resp = importedModule.init(mocks.core); + + expect(mocks.core.captchas).to.be.an('object'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should accept a channel param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChannelPayload, + }); + + expect(resp).to.be.true; + }); + + it('should accept no channel param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should fail on missing channel data', async () => { + const origChannel = mocks.authedSocket.channel; + mocks.authedSocket.channel = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + mocks.authedSocket.channel = origChannel; + + expect(resp).to.be.false; + }); + +}); \ No newline at end of file diff --git a/test/dumb.test.js b/test/dumb.test.js index 2c463c3..0608dd1 100644 --- a/test/dumb.test.js +++ b/test/dumb.test.js @@ -191,25 +191,30 @@ describe('Checking dumb module', () => { expect(resp).to.be.false; }); - it('should shadow block invite attempts', async () => { - mocks.core.muzzledHashes['testHash'] = true; + it('should shadow block chat attempts, checking for allies', async () => { + mocks.core.muzzledHashes['testHash'] = { + dumb: true, + allies: [1234], + }; mocks.plebSocket.hcProtocol = 1; + const newSocket = Object.assign({}, mocks.plebSocket); + newSocket.hash = 'cantcatchme'; - const resp = importedModule.inviteCheck({ + const resp = importedModule.chatCheck({ core: mocks.core, server: mocks.server, - socket: mocks.plebSocket, + socket: newSocket, payload: { cmd: 'chat', - text: [], + text: 'test', channel: 'cake', }, }); - expect(resp).to.be.true; + expect(resp).to.be.an('object'); }); - it('should shadow block invite attempts with ratelimiting', async () => { + it('should ratelimit invites', async () => { const oldRL = mocks.server.police.frisk; mocks.server.police.frisk = () => true; @@ -221,9 +226,9 @@ describe('Checking dumb module', () => { server: mocks.server, socket: mocks.plebSocket, payload: { - cmd: 'chat', - text: [], - channel: 'cake', + cmd: 'invite', + userid: 12, + channel: 'test', }, }); @@ -232,7 +237,7 @@ describe('Checking dumb module', () => { expect(resp).to.be.true; }); - it('should verify userid params on shadow block invite attempts', async () => { + it('should validate v2 clients userid param', async () => { mocks.core.muzzledHashes['testHash'] = true; mocks.plebSocket.hcProtocol = 2; @@ -241,17 +246,16 @@ describe('Checking dumb module', () => { server: mocks.server, socket: mocks.plebSocket, payload: { - cmd: 'chat', - userid: '1234', - text: [], - channel: 'cake', + cmd: 'invite', + userid: 'test', + channel: 1, }, }); expect(resp).to.be.true; }); - it('should verify channel params on shadow block invite attempts', async () => { + it('should validate v2 clients channel param', async () => { mocks.core.muzzledHashes['testHash'] = true; mocks.plebSocket.hcProtocol = 2; @@ -260,16 +264,123 @@ describe('Checking dumb module', () => { server: mocks.server, socket: mocks.plebSocket, payload: { - cmd: 'chat', - userid: 1234, - text: [], - channel: false, + cmd: 'invite', + userid: 12, + channel: 1, }, }); expect(resp).to.be.true; }); + it('should give warning if user is missing', async () => { + const origFindSockets = mocks.server.findSockets; + mocks.server.findSockets = () => false; + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 2; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'invite', + userid: 12, + channel: 'test', + }, + }); + + mocks.server.findSockets = origFindSockets; + + expect(resp).to.be.true; + }); + + it('should handle v2 output', async () => { + const origFindSockets = mocks.server.findSockets; + mocks.server.findSockets = () => [mocks.plebSocket]; + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 2; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'invite', + userid: 12, + channel: 'test', + }, + }); + + mocks.server.findSockets = origFindSockets; + + expect(resp).to.be.false; + }); + + it('should validate v1 clients channel', async () => { + const origPlebSocket = {...mocks.plebSocket}; + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + mocks.plebSocket.channel = undefined; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'invite', + nick: 'test', + channel: 1, + }, + }); + + mocks.plebSocket = origPlebSocket; + + expect(resp).to.be.true; + }); + + it('should validate v1 clients nick param', async () => { + const origPlebSocket = {...mocks.plebSocket}; + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'invite', + nick: 0, + channel: 'test', + }, + }); + + mocks.plebSocket = origPlebSocket; + + expect(resp).to.be.true; + }); + + it('should handle v1 output', async () => { + const origPlebSocket = {...mocks.plebSocket}; + mocks.core.muzzledHashes['testHash'] = true; + mocks.plebSocket.hcProtocol = 1; + + const resp = importedModule.inviteCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'invite', + nick: 'test', + channel: 'test', + }, + }); + + mocks.plebSocket = origPlebSocket; + + expect(resp).to.be.false; + }); + it('should accept an allies param', async () => { mockPayload.allies = [1234, 5678]; const resp = await importedModule.run({ diff --git a/test/enablecaptcha.test.js b/test/enablecaptcha.test.js new file mode 100644 index 0000000..677bf50 --- /dev/null +++ b/test/enablecaptcha.test.js @@ -0,0 +1,222 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/enablecaptcha.js'; +let importedModule; + +const targetChannel = 'test'; + +const mockPayload = { + cmd: 'enablecaptcha', +} + +const mockChannelPayload = { + cmd: 'enablecaptcha', + channel: targetChannel, +} + +const mockBadChatPayload = { + cmd: 'chat', + text: {}, +} + +const mockChatPayload = { + cmd: 'chat', + text: 'asdf', +} + +const mockJoinPayload = { + cmd: 'join', + nick: 'test#test', + channel: 'test', +} + +describe('Checking enablecaptcha module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + it('should initialize', async () => { + mocks.core.captchas = undefined; + const resp = importedModule.init(mocks.core); + + expect(mocks.core.captchas).to.be.an('object'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should accept a channel param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChannelPayload, + }); + + expect(resp).to.be.true; + }); + + it('should accept no channel param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should fail on missing channel data', async () => { + const origChannel = mocks.authedSocket.channel; + mocks.authedSocket.channel = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + mocks.authedSocket.channel = origChannel; + + expect(resp).to.be.false; + }); + + it('should fail if already enabled', async () => { + const origCaptchas = mocks.core.captchas; + mocks.core.captchas = { [mocks.authedSocket.channel]: true }; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + mocks.core.captchas = origCaptchas; + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + it('should reject chat if not text', async () => { + const resp = await importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockBadChatPayload, + }); + + expect(resp).to.be.false; + }); + + it('should return if channel is not enabled', async () => { + const resp = await importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChatPayload, + }); + + expect(resp).to.be.an('object'); + }); + + it('should disconnect on failed captcha', async () => { + mocks.authedSocket.captcha = {}; + mocks.authedSocket.captcha.awaiting = true; + + const resp = await importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChatPayload, + }); + + expect(resp).to.be.false; + }); + + it('should join with correct phrase', async () => { + mocks.authedSocket.captcha = {}; + mocks.authedSocket.captcha.awaiting = true; + mocks.authedSocket.captcha.solution = mockChatPayload.text; + + const resp = await importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChatPayload, + }); + + expect(resp).to.be.false; + }); + + it('should handle legacy clients', async () => { + mocks.authedSocket.captcha = {}; + mocks.authedSocket.captcha.awaiting = true; + mocks.authedSocket.captcha.solution = mockChatPayload.text; + + const origProtocol = mocks.authedSocket.hcProtocol; + mocks.authedSocket.hcProtocol = 1; + + const resp = await importedModule.chatCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChatPayload, + }); + + mocks.authedSocket.hcProtocol = origProtocol; + + expect(resp).to.be.false; + }); + + it('should hook join commands', async () => { + mocks.core.captchas = {}; + + const resp = await importedModule.joinCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockJoinPayload, + }); + + expect(resp).to.be.an('object'); + }); + +}); \ No newline at end of file diff --git a/test/join.test.js b/test/join.test.js index 2da3bca..6867d2d 100644 --- a/test/join.test.js +++ b/test/join.test.js @@ -139,6 +139,25 @@ describe('Checking join module', () => { expect(resp).to.be.true; }); + it('should prevent admin impersonation', async () => { + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.channel = undefined; + newSocket.hcProtocol = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 'admin#test', + channel: 'cake', + }, + }); + + expect(resp).to.be.true; + }); + it('should prevent two of the same name in the same channel', async () => { const newSocket = Object.assign({}, mocks.authedSocket); newSocket.channel = undefined; diff --git a/test/lockroom.test.js b/test/lockroom.test.js new file mode 100644 index 0000000..aab81ee --- /dev/null +++ b/test/lockroom.test.js @@ -0,0 +1,413 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/lockroom.js'; +let importedModule; + +const targetChannel = 'test'; + +const mockPayload = { + cmd: 'lockroom', +} + +const mockChannelPayload = { + cmd: 'lockroom', + channel: targetChannel, +} + +const mockBadChatPayload = { + cmd: 'chat', + text: {}, +} + +const mockChatPayload = { + cmd: 'chat', + text: 'asdf', +} + +const mockJoinPayload = { + cmd: 'join', + nick: 'test#test', + channel: 'test', +} + +const timeout = (ms) => { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +describe('Checking lockroom module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + it('should initialize', async () => { + mocks.core.locked = undefined; + const resp = importedModule.init(mocks.core); + + expect(mocks.core.locked).to.be.an('object'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should accept a channel param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChannelPayload, + }); + + expect(resp).to.be.true; + }); + + it('should accept no channel param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should fail on missing channel data', async () => { + const origChannel = mocks.authedSocket.channel; + mocks.authedSocket.channel = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + mocks.authedSocket.channel = origChannel; + + expect(resp).to.be.false; + }); + + it('should fail if already enabled', async () => { + mocks.core.locked = { test: true }; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChannelPayload, + }); + + mocks.core.locked = {}; + + expect(resp).to.be.true; + }); + + it('should initialize hooks', async () => { + expect(() => importedModule.initHooks(mocks.server)).not.to.throw(); + }); + + // change nick hook checks + it('should prevent name changes in purgatory channel', async () => { + const origChannel = mocks.authedSocket.channel; + mocks.authedSocket.channel = 'purgatory'; + + const resp = await importedModule.changeNickCheck({ + socket: mocks.authedSocket, + payload: { + cmd: 'changenick', + nick: 'test', + }, + }); + + mocks.authedSocket.channel = origChannel; + + expect(resp).to.be.false; + }); + + it('should ignore name changes in other channels', async () => { + const resp = await importedModule.changeNickCheck({ + socket: mocks.authedSocket, + payload: { + cmd: 'changenick', + nick: 'test', + }, + }); + + expect(resp).to.be.an('object'); + }); + + // whisper hook checks + it('should prevent whispers in purgatory channel', async () => { + const origChannel = mocks.authedSocket.channel; + mocks.authedSocket.channel = 'purgatory'; + + const resp = await importedModule.whisperCheck({ + socket: mocks.authedSocket, + payload: { + cmd: 'whisper', + }, + }); + + mocks.authedSocket.channel = origChannel; + + expect(resp).to.be.false; + }); + + it('should ignore whispers in other channels', async () => { + const resp = await importedModule.whisperCheck({ + socket: mocks.authedSocket, + payload: { + cmd: 'whisper', + }, + }); + + expect(resp).to.be.an('object'); + }); + + // chat hook checks + it('should prevent chats in purgatory channel', async () => { + const plebSocket = { ...mocks.plebSocket }; + plebSocket.channel = 'purgatory'; + + const resp = await importedModule.chatCheck({ + socket: plebSocket, + payload: { + cmd: 'chat', + text: 'test', + }, + }); + + expect(resp).to.be.false; + }); + + it('should allow mods to speak though', async () => { + const origChannel = mocks.authedSocket.channel; + mocks.authedSocket.channel = 'purgatory'; + + const resp = await importedModule.chatCheck({ + socket: mocks.authedSocket, + payload: { + cmd: 'chat', + text: 'test', + }, + }); + + mocks.authedSocket.channel = origChannel; + + expect(resp).to.be.an('object'); + }); + + it('should ignore chats in other channels', async () => { + const resp = await importedModule.chatCheck({ + socket: mocks.authedSocket, + payload: { + cmd: 'chat', + text: 'test', + }, + }); + + expect(resp).to.be.an('object'); + }); + + // invite hook checks + it('should prevent invites in purgatory channel', async () => { + const plebSocket = { ...mocks.plebSocket }; + plebSocket.channel = 'purgatory'; + + const resp = await importedModule.inviteCheck({ + socket: plebSocket, + payload: { + cmd: 'chat', + text: 'test', + }, + }); + + expect(resp).to.be.false; + }); + + it('should ignore invites in other channels', async () => { + const resp = await importedModule.inviteCheck({ + socket: mocks.authedSocket, + payload: { + cmd: 'chat', + text: 'test', + }, + }); + + expect(resp).to.be.an('object'); + }); + + // join hook checks + it('should ignore join if no lock record', async () => { + mocks.core.locked = {}; + + const resp = await importedModule.joinCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'join', + channel: 'test', + nick: 'test', + pass: 'test', + }, + }); + + expect(resp).to.be.an('object'); + }); + + it('should ignore join if not locked or purgatory', async () => { + mocks.core.locked = { test: false }; + + const resp = await importedModule.joinCheck({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'join', + channel: 'test', + nick: 'test', + pass: 'test', + }, + }); + + expect(resp).to.be.an('object'); + }); + + it('should allow v2 into purgatory', async () => { + const plebSocket = { ...mocks.plebSocket }; + plebSocket.channel = 'used'; + mocks.core.locked = {}; + + const resp = await importedModule.joinCheck({ + core: mocks.core, + server: mocks.server, + socket: plebSocket, + payload: { + cmd: 'join', + channel: 'purgatory', + nick: 'test', + }, + }); + + expect(resp).to.be.true; + }); + + it('should allow v1 into purgatory', async () => { + const plebSocket = { ...mocks.plebSocket }; + plebSocket.channel = undefined; + plebSocket.hcProtocol = undefined; + mocks.core.locked = {}; + + const resp = await importedModule.joinCheck({ + core: mocks.core, + server: mocks.server, + socket: plebSocket, + payload: { + cmd: 'join', + channel: 'purgatory', + nick: 'thisnameistoolongandwillberejected', + }, + }); + + expect(resp).to.be.true; + }); + + it('should wait for the timeout to run', async () => { + const mockServer = { ...mocks.server }; + const plebSocket = { ...mocks.plebSocket }; + + plebSocket.channel = undefined; + plebSocket.hcProtocol = undefined; + mocks.core.locked = {}; + + mockServer.reply = () => {}; + + await importedModule.joinCheck({ + core: mocks.core, + server: mockServer, + socket: plebSocket, + payload: { + cmd: 'join', + channel: 'purgatory', + nick: 'test', + }, + }); + }); + + it('should do channel checking', async () => { + const plebSocket = { ...mocks.plebSocket }; + plebSocket.channel = undefined; + plebSocket.hcProtocol = undefined; + plebSocket.banned = true; + mocks.core.locked = {}; + + const resp = await importedModule.joinCheck({ + core: mocks.core, + server: mocks.server, + socket: plebSocket, + payload: { + cmd: 'join', + channel: 'purgatory', + nick: 'test', + pass: 'test', + }, + }); + + expect(resp).to.be.true; + }); + + it('should use dante if not needed', async () => { + const mockServer = { ...mocks.server }; + const plebSocket = { ...mocks.plebSocket }; + + plebSocket.channel = undefined; + plebSocket.hcProtocol = undefined; + mocks.core.locked = { lockedChan: true }; + + mockServer.reply = () => {}; + + const resp = await importedModule.joinCheck({ + core: mocks.core, + server: mockServer, + socket: plebSocket, + payload: { + cmd: 'join', + channel: 'lockedChan', + nick: 'test', + }, + }); + }); +}); \ No newline at end of file diff --git a/test/mockImports.js b/test/mockImports.js index 48df539..5b9627b 100644 --- a/test/mockImports.js +++ b/test/mockImports.js @@ -1,6 +1,7 @@ const mocks = { core: { sessionKey: 'test', + appConfig: { data: { globalMods: [], @@ -15,18 +16,23 @@ const mocks = { }, write: async () => '', }, + muzzledHashes: [], + stats: { increment: () => 1, decrement: () => 1, get: () => 1, set: () => 1, }, + dynamicImports: { reloadDirCache: () => '', }, + commands: { reloadCommands: () => '', + handleCommand: () => '', commands: [], categoriesList: ['test'], all: () => [{ @@ -56,10 +62,12 @@ const mocks = { } }, }, + configManager: { save: () => true, }, }, + server : { police: { addresses: [], @@ -85,6 +93,7 @@ const mocks = { }], getSocketHash: () => 'test', }, + plebSocket: { level: 100, address: '127.0.0.1', @@ -97,6 +106,7 @@ const mocks = { uType: 'user', userid: 1234, }, + authedSocket: { level: 9999999, address: '127.0.0.1', diff --git a/test/speak.test.js b/test/speak.test.js index 1215b9c..4806771 100644 --- a/test/speak.test.js +++ b/test/speak.test.js @@ -68,4 +68,60 @@ describe('Checking speak module', () => { expect(resp).to.be.true; }); + it('should accept payload.ip as a string', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'speak', + ip: '127.0.0.1', + }, + }); + + expect(resp).to.be.true; + }); + + it('should accept payload.hash as a string', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'speak', + hash: 'pretendthisisahash', + }, + }); + + expect(resp).to.be.true; + }); + + it('should unmuzzle all if payload.ip is *', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'speak', + ip: '*', + }, + }); + + expect(resp).to.be.true; + }); + + it('should unmuzzle all if payload.hash is *', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: { + cmd: 'speak', + hash: '*', + }, + }); + + expect(resp).to.be.true; + }); + }); \ No newline at end of file diff --git a/test/text.test.js b/test/text.test.js new file mode 100644 index 0000000..2a1cbdf --- /dev/null +++ b/test/text.test.js @@ -0,0 +1,19 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/utility/_Text.js'; +let importedModule; + +describe('Checking _Text module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should return null if not text', () => { + const resp = importedModule.parseText([]); + + expect(resp).to.be.null; + }); +}); \ No newline at end of file diff --git a/test/uac.test.js b/test/uac.test.js index f64bada..be017e1 100644 --- a/test/uac.test.js +++ b/test/uac.test.js @@ -42,7 +42,7 @@ describe('Checking UAC module', () => { it('should return admin level labels', async () => { const newConfig = Object.assign({}, mocks.core.appConfig.data); - newConfig.adminTrip = 'Tt8H7clbL9'; + newConfig.adminTrip = 'Tt8H7c'; const resp = importedModule.getUserPerms('test', 'salt', newConfig, 'cake'); expect(resp).to.be.an('object'); }); @@ -50,7 +50,7 @@ describe('Checking UAC module', () => { it('should return mod level labels', async () => { const newConfig = Object.assign({}, mocks.core.appConfig.data); newConfig.globalMods = [{ - trip: 'Tt8H7clbL9', + trip: 'Tt8H7c', }]; const resp = importedModule.getUserPerms('test', 'salt', newConfig, 'cake'); expect(resp).to.be.an('object'); diff --git a/test/unlockroom.test.js b/test/unlockroom.test.js new file mode 100644 index 0000000..7836d3b --- /dev/null +++ b/test/unlockroom.test.js @@ -0,0 +1,113 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/mod/unlockroom.js'; +let importedModule; + +const mockPayload = { + cmd: 'unlockroom', +} + +const mockChannelPayload = { + cmd: 'unlockroom', + channel: 'test', +} + +describe('Checking unlockroom module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + it('should initialize', async () => { + mocks.core.locked = undefined; + const resp = importedModule.init(mocks.core); + + expect(mocks.core.locked).to.be.an('object'); + }); + + // module main function + it('should be invokable only by a mod', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: mockPayload, + }); + + expect(resp).to.be.false; + }); + + it('should accept a channel param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockChannelPayload, + }); + + expect(resp).to.be.true; + }); + + it('should accept no channel param', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + + it('should fail on missing channel data', async () => { + const origChannel = mocks.authedSocket.channel; + mocks.authedSocket.channel = undefined; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + mocks.authedSocket.channel = origChannel; + + expect(resp).to.be.false; + }); + + it('should unlock if locked', async () => { + mocks.core.locked = { [mocks.authedSocket.channel]: true }; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.authedSocket, + payload: mockPayload, + }); + + expect(resp).to.be.true; + }); + +}); \ No newline at end of file diff --git a/test/updateMessage.test.js b/test/updateMessage.test.js new file mode 100644 index 0000000..42dea79 --- /dev/null +++ b/test/updateMessage.test.js @@ -0,0 +1,233 @@ +import { expect } from 'chai'; +import mocks from './mockImports.js'; + +const modulePath = '../commands/core/updateMessage.js'; +let importedModule; + +const mockPayload = { + cmd: 'updateMessage', +} + +const mockChannelPayload = { + cmd: 'updateMessage', + channel: 'test', +} + +describe('Checking unlockroom module', () => { + // module meta data + it('should be importable', async () => { + importedModule = await import(modulePath); + expect(importedModule).to.not.be.a('string'); + }); + + it('should be named', async () => { + expect(importedModule.info.name).to.be.a('string'); + }); + + it('should be categorized', async () => { + expect(importedModule.info.category).to.be.a('string'); + }); + + it('should be described', async () => { + expect(importedModule.info.description).to.be.a('string'); + }); + + it('should be documented', async () => { + expect(importedModule.info.usage).to.be.a('string'); + }); + + it('should be invokable', async () => { + expect(importedModule.run).to.be.a('function'); + }); + + // module main function + it('should default the mode param if missing', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + customId: '1234', + text: 'test', + }, + }); + + expect(resp).to.be.false; + }); + + it('should reject if mode is invalid', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + customId: '1234', + text: 'test', + mode: 'poop', + }, + }); + + expect(resp).to.be.false; + }); + + it('should reject if customId is missing', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + text: 'test', + mode: 'overwrite', + }, + }); + + expect(resp).to.be.false; + }); + + it('should reject if customId is not text', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + text: 'test', + customId: {}, + mode: 'overwrite', + }, + }); + + expect(resp).to.be.false; + }); + + it('should reject if customId is not too long', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + text: 'test', + customId: `A`.repeat(importedModule.MAX_MESSAGE_ID_LENGTH * 2), + mode: 'overwrite', + }, + }); + + expect(resp).to.be.false; + }); + + it('should reject if text is not text', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + text: {}, + customId: `A`, + mode: 'overwrite', + }, + }); + + expect(resp).to.be.false; + }); + + it('should change text to null if empty', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + text: '', + customId: `A`, + mode: 'overwrite', + }, + }); + + expect(resp).to.be.false; + }); + + it('should otherwise reject empty text', async () => { + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + text: '', + customId: `A`, + mode: 'prepend', + }, + }); + + expect(resp).to.be.false; + }); + + it('should delete active message records', async () => { + const chatModule = await import('../commands/core/chat.js'); + + chatModule.ACTIVE_MESSAGES.push({ + customId: 'asdf', + userid: 1234, + sent: 0, + toDelete: false, + }); + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: mocks.plebSocket, + payload: { + cmd: 'updateMessage', + text: 'a', + customId: 'asdf', + mode: 'complete', + }, + }); + + expect(resp).to.be.true; + }); + + it('should mark if sent by mod', async () => { + const newSocket = { ...mocks.authedSocket }; + newSocket.level = 999999; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'updateMessage', + text: 'a', + customId: 'asdf', + mode: 'append', + }, + }); + + expect(resp).to.be.true; + }); + + it('should mark if sent by admin', async () => { + const newSocket = { ...mocks.authedSocket }; + newSocket.level = 9999999; + + const resp = await importedModule.run({ + core: mocks.core, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'updateMessage', + text: 'a', + customId: 'asdf', + mode: 'append', + }, + }); + + expect(resp).to.be.true; + }); + +}); \ No newline at end of file From 61c0be77d568fb9add0f15ef4dbdfb37319a5fbb Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 27 Dec 2023 00:26:49 -0800 Subject: [PATCH 31/37] hackchat-server 2.3 update --- commands/admin/addmod.js | 2 +- commands/admin/listusers.js | 2 +- commands/admin/reload.js | 2 +- commands/admin/removemod.js | 2 +- commands/admin/saveconfig.js | 2 +- commands/admin/shout.js | 2 +- commands/core/changecolor.js | 2 +- commands/core/changenick.js | 2 +- commands/core/chat.js | 6 +++--- commands/core/emote.js | 4 ++-- commands/core/help.js | 2 +- commands/core/invite.js | 2 +- commands/core/join.js | 2 +- commands/core/updateMessage.js | 10 +++++----- commands/core/whisper.js | 4 ++-- commands/internal/disconnect.js | 2 +- commands/internal/socketreply.js | 2 +- commands/mod/ban.js | 2 +- commands/mod/disablecaptcha.js | 2 +- commands/mod/dumb.js | 10 +++++----- commands/mod/enablecaptcha.js | 4 ++-- commands/mod/forcecolor.js | 2 +- commands/mod/kick.js | 2 +- commands/mod/lockroom.js | 2 +- commands/mod/speak.js | 2 +- commands/mod/unban.js | 2 +- commands/mod/unbanall.js | 2 +- commands/mod/unlockroom.js | 2 +- documentation/admin_addmod.js.html | 2 +- documentation/admin_listusers.js.html | 2 +- documentation/admin_reload.js.html | 2 +- documentation/admin_removemod.js.html | 2 +- documentation/admin_saveconfig.js.html | 2 +- documentation/admin_shout.js.html | 2 +- documentation/core_changecolor.js.html | 2 +- documentation/core_changenick.js.html | 4 ++-- documentation/core_chat.js.html | 4 ++-- documentation/core_emote.js.html | 4 ++-- documentation/core_help.js.html | 2 +- documentation/core_invite.js.html | 2 +- documentation/core_join.js.html | 2 +- documentation/core_whisper.js.html | 4 ++-- documentation/internal_disconnect.js.html | 2 +- documentation/internal_socketreply.js.html | 2 +- documentation/mod_ban.js.html | 2 +- documentation/mod_dumb.js.html | 10 +++++----- documentation/mod_forcecolor.js.html | 2 +- documentation/mod_kick.js.html | 2 +- documentation/mod_speak.js.html | 2 +- documentation/mod_unban.js.html | 2 +- documentation/mod_unbanall.js.html | 2 +- package.json | 2 +- 52 files changed, 73 insertions(+), 73 deletions(-) diff --git a/commands/admin/addmod.js b/commands/admin/addmod.js index 204c38f..a1631de 100644 --- a/commands/admin/addmod.js +++ b/commands/admin/addmod.js @@ -24,7 +24,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // add new trip to config diff --git a/commands/admin/listusers.js b/commands/admin/listusers.js index f5081f0..7a02c43 100644 --- a/commands/admin/listusers.js +++ b/commands/admin/listusers.js @@ -23,7 +23,7 @@ import { export async function run({ server, socket }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // find all users currently in a channel diff --git a/commands/admin/reload.js b/commands/admin/reload.js index aa4d212..5f39733 100644 --- a/commands/admin/reload.js +++ b/commands/admin/reload.js @@ -22,7 +22,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // do command reload and store results diff --git a/commands/admin/removemod.js b/commands/admin/removemod.js index d01db82..e8ddacf 100644 --- a/commands/admin/removemod.js +++ b/commands/admin/removemod.js @@ -24,7 +24,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // remove trip from config diff --git a/commands/admin/saveconfig.js b/commands/admin/saveconfig.js index 1407c94..90072b8 100644 --- a/commands/admin/saveconfig.js +++ b/commands/admin/saveconfig.js @@ -20,7 +20,7 @@ import { export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // attempt save, notify of failure diff --git a/commands/admin/shout.js b/commands/admin/shout.js index 3e5914a..a68a156 100644 --- a/commands/admin/shout.js +++ b/commands/admin/shout.js @@ -19,7 +19,7 @@ import { export async function run({ server, socket, payload }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // send text to all channels diff --git a/commands/core/changecolor.js b/commands/core/changecolor.js index 5143c7b..8326b2a 100644 --- a/commands/core/changecolor.js +++ b/commands/core/changecolor.js @@ -30,7 +30,7 @@ export async function run({ }) { const { channel } = socket; - if (server.police.frisk(socket.address, 1)) { + if (server.police.frisk(socket, 1)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing colors too fast. Wait a moment before trying again.', diff --git a/commands/core/changenick.js b/commands/core/changenick.js index 664561e..184e966 100644 --- a/commands/core/changenick.js +++ b/commands/core/changenick.js @@ -24,7 +24,7 @@ export async function run({ }) { const { channel } = socket; - if (server.police.frisk(socket.address, 6)) { + if (server.police.frisk(socket, 6)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing nicknames too fast. Wait a moment before trying again.', diff --git a/commands/core/chat.js b/commands/core/chat.js index 8e15539..b8ed943 100644 --- a/commands/core/chat.js +++ b/commands/core/chat.js @@ -88,12 +88,12 @@ export async function run({ if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } // check for spam const score = text.length / 83 / 4; - if (server.police.frisk(socket.address, score)) { + if (server.police.frisk(socket, score)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', @@ -105,7 +105,7 @@ export async function run({ if (typeof (customId) === 'string' && customId.length > MAX_MESSAGE_ID_LENGTH) { // There's a limit on the custom id length. - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } // build chat payload diff --git a/commands/core/emote.js b/commands/core/emote.js index e080504..0f00eda 100644 --- a/commands/core/emote.js +++ b/commands/core/emote.js @@ -41,12 +41,12 @@ export async function run({ server, socket, payload }) { if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.address, 8); + return server.police.frisk(socket, 8); } // check for spam const score = text.length / 83 / 4; - if (server.police.frisk(socket.address, score)) { + if (server.police.frisk(socket, score)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/commands/core/help.js b/commands/core/help.js index b8e70b2..dab5ba5 100644 --- a/commands/core/help.js +++ b/commands/core/help.js @@ -16,7 +16,7 @@ export async function run({ core, server, socket, payload, }) { // check for spam - if (server.police.frisk(socket.address, 2)) { + if (server.police.frisk(socket, 2)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/commands/core/invite.js b/commands/core/invite.js index 09b2670..2121157 100644 --- a/commands/core/invite.js +++ b/commands/core/invite.js @@ -40,7 +40,7 @@ export async function run({ core, server, socket, payload, }) { // check for spam - if (server.police.frisk(socket.address, 2)) { + if (server.police.frisk(socket, 2)) { return server.reply({ cmd: 'warn', text: 'You are sending invites too fast. Wait a moment before trying again.', diff --git a/commands/core/join.js b/commands/core/join.js index 6e327bd..81e154d 100644 --- a/commands/core/join.js +++ b/commands/core/join.js @@ -39,7 +39,7 @@ export async function run({ core, server, socket, payload, }) { // check for spam - if (server.police.frisk(socket.address, 3)) { + if (server.police.frisk(socket, 3)) { return server.reply({ cmd: 'warn', text: 'You are joining channels too fast. Wait a moment and try again.', diff --git a/commands/core/updateMessage.js b/commands/core/updateMessage.js index 752ca2b..8459bfc 100644 --- a/commands/core/updateMessage.js +++ b/commands/core/updateMessage.js @@ -36,15 +36,15 @@ export async function run({ } if (mode !== 'overwrite' && mode !== 'append' && mode !== 'prepend' && mode !== 'complete') { - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } if (!customId || typeof customId !== 'string' || customId.length > MAX_MESSAGE_ID_LENGTH) { - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } if (typeof (text) !== 'string') { - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } if (mode === 'overwrite') { @@ -56,7 +56,7 @@ export async function run({ } if (!text) { - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } // TODO: What score should we use for this? It isn't as space filling as chat messages. @@ -77,7 +77,7 @@ export async function run({ } if (!message) { - return server.police.frisk(socket.address, 6); + return server.police.frisk(socket, 6); } const outgoingPayload = { diff --git a/commands/core/whisper.js b/commands/core/whisper.js index 317c756..7a2ae17 100644 --- a/commands/core/whisper.js +++ b/commands/core/whisper.js @@ -59,12 +59,12 @@ export async function run({ server, socket, payload }) { if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } // check for spam const score = text.length / 83 / 4; - if (server.police.frisk(socket.address, score)) { + if (server.police.frisk(socket, score)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/commands/internal/disconnect.js b/commands/internal/disconnect.js index cef5913..292c0c3 100644 --- a/commands/internal/disconnect.js +++ b/commands/internal/disconnect.js @@ -19,7 +19,7 @@ import { export async function run({ server, socket, payload }) { if (payload.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // send leave notice to client peers diff --git a/commands/internal/socketreply.js b/commands/internal/socketreply.js index 3c4405c..6042937 100644 --- a/commands/internal/socketreply.js +++ b/commands/internal/socketreply.js @@ -16,7 +16,7 @@ export async function run({ server, socket, payload }) { if (payload.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // send warning to target socket diff --git a/commands/mod/ban.js b/commands/mod/ban.js index a791ec9..abd41ec 100644 --- a/commands/mod/ban.js +++ b/commands/mod/ban.js @@ -29,7 +29,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input diff --git a/commands/mod/disablecaptcha.js b/commands/mod/disablecaptcha.js index ff310c7..61eab0b 100644 --- a/commands/mod/disablecaptcha.js +++ b/commands/mod/disablecaptcha.js @@ -34,7 +34,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } let targetChannel; diff --git a/commands/mod/dumb.js b/commands/mod/dumb.js index 54578d1..ea602ac 100644 --- a/commands/mod/dumb.js +++ b/commands/mod/dumb.js @@ -82,7 +82,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input @@ -205,7 +205,7 @@ export function chatCheck({ * May expose the ratelimiting lines from `chat` and use that * @todo one day #lazydev */ - server.police.frisk(socket.address, 9); + server.police.frisk(socket, 9); return false; } @@ -227,7 +227,7 @@ export function inviteCheck({ }) { if (core.muzzledHashes[socket.hash]) { // check for spam - if (server.police.frisk(socket.address, 2)) { + if (server.police.frisk(socket, 2)) { return server.reply({ cmd: 'warn', text: 'You are sending invites too fast. Wait a moment before trying again.', @@ -308,12 +308,12 @@ export function whisperCheck({ if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } // check for spam const score = text.length / 83 / 4; - if (server.police.frisk(socket.address, score)) { + if (server.police.frisk(socket, score)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/commands/mod/enablecaptcha.js b/commands/mod/enablecaptcha.js index 571326a..0992219 100644 --- a/commands/mod/enablecaptcha.js +++ b/commands/mod/enablecaptcha.js @@ -51,7 +51,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } let targetChannel; @@ -141,7 +141,7 @@ export function chatCheck({ return false; } - server.police.frisk(socket.address, 7); + server.police.frisk(socket, 7); socket.terminate(); return false; diff --git a/commands/mod/forcecolor.js b/commands/mod/forcecolor.js index c5be5bd..8c53caf 100644 --- a/commands/mod/forcecolor.js +++ b/commands/mod/forcecolor.js @@ -37,7 +37,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } const { channel } = socket; diff --git a/commands/mod/kick.js b/commands/mod/kick.js index 7520c86..09506c4 100644 --- a/commands/mod/kick.js +++ b/commands/mod/kick.js @@ -29,7 +29,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input diff --git a/commands/mod/lockroom.js b/commands/mod/lockroom.js index babcd7e..d2eb10c 100644 --- a/commands/mod/lockroom.js +++ b/commands/mod/lockroom.js @@ -72,7 +72,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } let targetChannel; diff --git a/commands/mod/speak.js b/commands/mod/speak.js index 0c988d9..ded8802 100644 --- a/commands/mod/speak.js +++ b/commands/mod/speak.js @@ -35,7 +35,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input diff --git a/commands/mod/unban.js b/commands/mod/unban.js index 2c04b02..16405b2 100644 --- a/commands/mod/unban.js +++ b/commands/mod/unban.js @@ -21,7 +21,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input diff --git a/commands/mod/unbanall.js b/commands/mod/unbanall.js index 83f5afc..93133d2 100644 --- a/commands/mod/unbanall.js +++ b/commands/mod/unbanall.js @@ -19,7 +19,7 @@ import { export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // remove arrest records diff --git a/commands/mod/unlockroom.js b/commands/mod/unlockroom.js index 9fcfebb..fc217d0 100644 --- a/commands/mod/unlockroom.js +++ b/commands/mod/unlockroom.js @@ -35,7 +35,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } let targetChannel; diff --git a/documentation/admin_addmod.js.html b/documentation/admin_addmod.js.html index 63e1265..94ee2a3 100644 --- a/documentation/admin_addmod.js.html +++ b/documentation/admin_addmod.js.html @@ -52,7 +52,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // add new trip to config diff --git a/documentation/admin_listusers.js.html b/documentation/admin_listusers.js.html index 705a369..c2d28a0 100644 --- a/documentation/admin_listusers.js.html +++ b/documentation/admin_listusers.js.html @@ -51,7 +51,7 @@ import { export async function run({ server, socket }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // find all users currently in a channel diff --git a/documentation/admin_reload.js.html b/documentation/admin_reload.js.html index 6759d6a..fa80ba2 100644 --- a/documentation/admin_reload.js.html +++ b/documentation/admin_reload.js.html @@ -50,7 +50,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // do command reload and store results diff --git a/documentation/admin_removemod.js.html b/documentation/admin_removemod.js.html index 9422420..5c79041 100644 --- a/documentation/admin_removemod.js.html +++ b/documentation/admin_removemod.js.html @@ -52,7 +52,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // remove trip from config diff --git a/documentation/admin_saveconfig.js.html b/documentation/admin_saveconfig.js.html index 696eb3d..336418e 100644 --- a/documentation/admin_saveconfig.js.html +++ b/documentation/admin_saveconfig.js.html @@ -48,7 +48,7 @@ import { export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // attempt save, notify of failure diff --git a/documentation/admin_shout.js.html b/documentation/admin_shout.js.html index b76de12..68b9e61 100644 --- a/documentation/admin_shout.js.html +++ b/documentation/admin_shout.js.html @@ -47,7 +47,7 @@ import { export async function run({ server, socket, payload }) { // increase rate limit chance and ignore if not admin if (!isAdmin(socket.level)) { - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // send text to all channels diff --git a/documentation/core_changecolor.js.html b/documentation/core_changecolor.js.html index 202b272..e63a2c2 100644 --- a/documentation/core_changecolor.js.html +++ b/documentation/core_changecolor.js.html @@ -58,7 +58,7 @@ export async function run({ }) { const { channel } = socket; - if (server.police.frisk(socket.address, 1)) { + if (server.police.frisk(socket, 1)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing colors too fast. Wait a moment before trying again.', diff --git a/documentation/core_changenick.js.html b/documentation/core_changenick.js.html index 33ed8cd..1715f7f 100644 --- a/documentation/core_changenick.js.html +++ b/documentation/core_changenick.js.html @@ -52,7 +52,7 @@ export async function run({ }) { const { channel } = socket; - if (server.police.frisk(socket.address, 6)) { + if (server.police.frisk(socket, 6)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are changing nicknames too fast. Wait a moment before trying again.', @@ -80,7 +80,7 @@ export async function run({ // prevent admin impersonation // @todo prevent mod impersonation if (newNick.toLowerCase() === core.config.adminName.toLowerCase()) { - server.police.frisk(socket.address, 4); + server.police.frisk(socket, 4); return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` diff --git a/documentation/core_chat.js.html b/documentation/core_chat.js.html index 915af4d..f41697e 100644 --- a/documentation/core_chat.js.html +++ b/documentation/core_chat.js.html @@ -76,12 +76,12 @@ export async function run({ if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } // check for spam const score = text.length / 83 / 4; - if (server.police.frisk(socket.address, score)) { + if (server.police.frisk(socket, score)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/documentation/core_emote.js.html b/documentation/core_emote.js.html index 1832c4a..f4392c3 100644 --- a/documentation/core_emote.js.html +++ b/documentation/core_emote.js.html @@ -69,12 +69,12 @@ export async function run({ server, socket, payload }) { if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.address, 8); + return server.police.frisk(socket, 8); } // check for spam const score = text.length / 83 / 4; - if (server.police.frisk(socket.address, score)) { + if (server.police.frisk(socket, score)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/documentation/core_help.js.html b/documentation/core_help.js.html index c337611..a062853 100644 --- a/documentation/core_help.js.html +++ b/documentation/core_help.js.html @@ -44,7 +44,7 @@ export async function run({ core, server, socket, payload, }) { // check for spam - if (server.police.frisk(socket.address, 2)) { + if (server.police.frisk(socket, 2)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/documentation/core_invite.js.html b/documentation/core_invite.js.html index b33aeaf..0b8023b 100644 --- a/documentation/core_invite.js.html +++ b/documentation/core_invite.js.html @@ -68,7 +68,7 @@ export async function run({ core, server, socket, payload, }) { // check for spam - if (server.police.frisk(socket.address, 2)) { + if (server.police.frisk(socket, 2)) { return server.reply({ cmd: 'warn', text: 'You are sending invites too fast. Wait a moment before trying again.', diff --git a/documentation/core_join.js.html b/documentation/core_join.js.html index 518fa80..50a162d 100644 --- a/documentation/core_join.js.html +++ b/documentation/core_join.js.html @@ -63,7 +63,7 @@ export async function run({ core, server, socket, payload, }) { // check for spam - if (server.police.frisk(socket.address, 3)) { + if (server.police.frisk(socket, 3)) { return server.reply({ cmd: 'warn', text: 'You are joining channels too fast. Wait a moment and try again.', diff --git a/documentation/core_whisper.js.html b/documentation/core_whisper.js.html index 351c19c..dcc81b9 100644 --- a/documentation/core_whisper.js.html +++ b/documentation/core_whisper.js.html @@ -87,12 +87,12 @@ export async function run({ server, socket, payload }) { if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } // check for spam const score = text.length / 83 / 4; - if (server.police.frisk(socket.address, score)) { + if (server.police.frisk(socket, score)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/documentation/internal_disconnect.js.html b/documentation/internal_disconnect.js.html index e83bd69..5379738 100644 --- a/documentation/internal_disconnect.js.html +++ b/documentation/internal_disconnect.js.html @@ -43,7 +43,7 @@ export async function run({ server, socket, payload }) { if (payload.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // send leave notice to client peers diff --git a/documentation/internal_socketreply.js.html b/documentation/internal_socketreply.js.html index 144e062..1f233bd 100644 --- a/documentation/internal_socketreply.js.html +++ b/documentation/internal_socketreply.js.html @@ -44,7 +44,7 @@ export async function run({ server, socket, payload }) { if (payload.cmdKey !== server.cmdKey) { // internal command attempt by client, increase rate limit chance and ignore - return server.police.frisk(socket.address, 20); + return server.police.frisk(socket, 20); } // send warning to target socket diff --git a/documentation/mod_ban.js.html b/documentation/mod_ban.js.html index 9e61eb0..d87bc9b 100644 --- a/documentation/mod_ban.js.html +++ b/documentation/mod_ban.js.html @@ -57,7 +57,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input diff --git a/documentation/mod_dumb.js.html b/documentation/mod_dumb.js.html index 7ae8eae..5227833 100644 --- a/documentation/mod_dumb.js.html +++ b/documentation/mod_dumb.js.html @@ -110,7 +110,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input @@ -233,7 +233,7 @@ export function chatCheck({ * May expose the ratelimiting lines from `chat` and use that * @todo one day #lazydev */ - server.police.frisk(socket.address, 9); + server.police.frisk(socket, 9); return false; } @@ -255,7 +255,7 @@ export function inviteCheck({ }) { if (core.muzzledHashes[socket.hash]) { // check for spam - if (server.police.frisk(socket.address, 2)) { + if (server.police.frisk(socket, 2)) { return server.reply({ cmd: 'warn', text: 'You are sending invites too fast. Wait a moment before trying again.', @@ -336,12 +336,12 @@ export function whisperCheck({ if (!text) { // lets not send objects or empty text, yea? - return server.police.frisk(socket.address, 13); + return server.police.frisk(socket, 13); } // check for spam const score = text.length / 83 / 4; - if (server.police.frisk(socket.address, score)) { + if (server.police.frisk(socket, score)) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.', diff --git a/documentation/mod_forcecolor.js.html b/documentation/mod_forcecolor.js.html index f8610d7..93c07ae 100644 --- a/documentation/mod_forcecolor.js.html +++ b/documentation/mod_forcecolor.js.html @@ -65,7 +65,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } const { channel } = socket; diff --git a/documentation/mod_kick.js.html b/documentation/mod_kick.js.html index 6b65861..9ca38e9 100644 --- a/documentation/mod_kick.js.html +++ b/documentation/mod_kick.js.html @@ -57,7 +57,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input diff --git a/documentation/mod_speak.js.html b/documentation/mod_speak.js.html index a9c6eb4..1e6fb78 100644 --- a/documentation/mod_speak.js.html +++ b/documentation/mod_speak.js.html @@ -63,7 +63,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input diff --git a/documentation/mod_unban.js.html b/documentation/mod_unban.js.html index ecf73cc..45d2427 100644 --- a/documentation/mod_unban.js.html +++ b/documentation/mod_unban.js.html @@ -49,7 +49,7 @@ export async function run({ }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // check user input diff --git a/documentation/mod_unbanall.js.html b/documentation/mod_unbanall.js.html index a2ce97f..d1ae5fe 100644 --- a/documentation/mod_unbanall.js.html +++ b/documentation/mod_unbanall.js.html @@ -47,7 +47,7 @@ import { export async function run({ core, server, socket }) { // increase rate limit chance and ignore if not admin or mod if (!isModerator(socket.level)) { - return server.police.frisk(socket.address, 10); + return server.police.frisk(socket, 10); } // remove arrest records diff --git a/package.json b/package.json index a5e8980..61b70af 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "dependencies": { "ascii-captcha": "^0.0.3", "enquirer": "^2.3.6", - "hackchat-server": "^2.2.27", + "hackchat-server": "^2.3.0", "http-server": "^14.1.0", "jsonwebtoken": "^9.0.2", "lowdb": "^3.0.0", From 2a5a9c150cda5b7d70a435f645e3c5ba867e78b4 Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 27 Dec 2023 00:38:18 -0800 Subject: [PATCH 32/37] added mod perks --- commands/core/join.js | 5 +++++ commands/core/session.js | 6 ++++++ commands/mod/lockroom.js | 3 +-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/commands/core/join.js b/commands/core/join.js index 81e154d..b4b2364 100644 --- a/commands/core/join.js +++ b/commands/core/join.js @@ -151,6 +151,11 @@ export async function run({ // socket.channels.push(channel); socket.channels = [channel]; + // global mod perks + if (isModerator(socket.level)) { + socket.ratelimitImmune = true; + } + nicks.push(userInfo.nick); /* @legacy */ users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo }); diff --git a/commands/core/session.js b/commands/core/session.js index 5be594a..58e965b 100644 --- a/commands/core/session.js +++ b/commands/core/session.js @@ -12,6 +12,7 @@ import fs from 'fs'; import jsonwebtoken from 'jsonwebtoken'; import { + isModerator, verifyNickname, } from '../utility/_UAC.js'; import { @@ -140,6 +141,11 @@ export async function run({ socket.muzzled = session.muzzled; socket.banned = session.banned; + // global mod perks + if (isModerator(socket.level)) { + socket.ratelimitImmune = true; + } + socket.hash = server.getSocketHash(socket); socket.hcProtocol = 2; diff --git a/commands/mod/lockroom.js b/commands/mod/lockroom.js index d2eb10c..c27d612 100644 --- a/commands/mod/lockroom.js +++ b/commands/mod/lockroom.js @@ -9,7 +9,6 @@ */ import { - levels, isTrustedUser, isModerator, verifyNickname, @@ -173,7 +172,7 @@ export function chatCheck({ socket, payload, }) { if (socket.channel === 'purgatory') { - if (socket.level >= levels.moderator) { + if (isModerator(socket.level)) { return payload; } From 70ee8a7969e3e14a07505dced72e8862df57efe5 Mon Sep 17 00:00:00 2001 From: marzavec Date: Wed, 27 Dec 2023 00:51:52 -0800 Subject: [PATCH 33/37] please ignore this commit Oops --- commands/core/join.js | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/core/join.js b/commands/core/join.js index b4b2364..e6a56e9 100644 --- a/commands/core/join.js +++ b/commands/core/join.js @@ -27,6 +27,7 @@ import { verifyNickname, getUserPerms, getUserDetails, + isModerator, } from '../utility/_UAC.js'; /** From 3eafe9d766ca7ba38a46a56991d87eb416f54e4c Mon Sep 17 00:00:00 2001 From: marzavec Date: Thu, 28 Dec 2023 23:17:33 -0800 Subject: [PATCH 34/37] added hash of a modules source to help module output --- commands/core/help.js | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/commands/core/help.js b/commands/core/help.js index dab5ba5..8152896 100644 --- a/commands/core/help.js +++ b/commands/core/help.js @@ -51,6 +51,7 @@ export async function run({ } else { reply += `# ${command.info.name} command:\n| | |\n|---:|---|\n`; reply += `|**Name:**|${command.info.name}|\n`; + reply += `|**Hash:**|${command.info.srcHash}|\n`; reply += `|**Aliases:**|${typeof command.info.aliases !== 'undefined' ? command.info.aliases.join(', ') : 'None'}|\n`; reply += `|**Category:**|${command.info.category.replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())}|\n`; reply += `|**Required Parameters:**|${command.requiredData || 'None'}|\n`; diff --git a/package.json b/package.json index 61b70af..df14c18 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "dependencies": { "ascii-captcha": "^0.0.3", "enquirer": "^2.3.6", - "hackchat-server": "^2.3.0", + "hackchat-server": "^2.3.1", "http-server": "^14.1.0", "jsonwebtoken": "^9.0.2", "lowdb": "^3.0.0", From 961a030a727c011bc44da0bf7ce85eb070d8c353 Mon Sep 17 00:00:00 2001 From: marzavec Date: Fri, 29 Dec 2023 22:09:24 -0800 Subject: [PATCH 35/37] unit test update Back to 100% coverage --- package-lock.json | 18 +++++++++--------- test/addmod.test.js | 13 ++++++++----- test/join.test.js | 26 ++++++++++++++++++++++++++ test/removemod.test.js | 14 ++++++++++---- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index ac0bc6b..f9b4c2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "hack.chat-v2", - "version": "2.2.0", + "version": "2.2.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "hack.chat-v2", - "version": "2.2.0", + "version": "2.2.1", "hasInstallScript": true, "license": "MIT", "dependencies": { "ascii-captcha": "^0.0.3", "enquirer": "^2.3.6", - "hackchat-server": "^2.2.27", + "hackchat-server": "^2.3.1", "http-server": "^14.1.0", "jsonwebtoken": "^9.0.2", "lowdb": "^3.0.0", @@ -2750,9 +2750,9 @@ } }, "node_modules/hackchat-server": { - "version": "2.2.27", - "resolved": "https://registry.npmjs.org/hackchat-server/-/hackchat-server-2.2.27.tgz", - "integrity": "sha512-ojTngxzBO9OYj12510XsoUEddMYbE3qf7AsRkyBfNStyiNKIMWG8/kyZkLsr/f/CIYKJZCQ3/Es6Cu6t/FBHvA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/hackchat-server/-/hackchat-server-2.3.1.tgz", + "integrity": "sha512-q287JzAP3shM1pBq6ZG9BUza0bCuunz4R9hV5jgBEwAvJtp+t8P4ZNL8XpSnGe7Rcc9pkhg26uHMZ7TtUL5MYQ==", "dependencies": { "didyoumean2": "^4.2.0", "enquirer": "^2.3.6", @@ -8081,9 +8081,9 @@ "dev": true }, "hackchat-server": { - "version": "2.2.27", - "resolved": "https://registry.npmjs.org/hackchat-server/-/hackchat-server-2.2.27.tgz", - "integrity": "sha512-ojTngxzBO9OYj12510XsoUEddMYbE3qf7AsRkyBfNStyiNKIMWG8/kyZkLsr/f/CIYKJZCQ3/Es6Cu6t/FBHvA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/hackchat-server/-/hackchat-server-2.3.1.tgz", + "integrity": "sha512-q287JzAP3shM1pBq6ZG9BUza0bCuunz4R9hV5jgBEwAvJtp+t8P4ZNL8XpSnGe7Rcc9pkhg26uHMZ7TtUL5MYQ==", "requires": { "didyoumean2": "^4.2.0", "enquirer": "^2.3.6", diff --git a/test/addmod.test.js b/test/addmod.test.js index fb32def..3b58bb1 100644 --- a/test/addmod.test.js +++ b/test/addmod.test.js @@ -38,8 +38,10 @@ describe('Checking addmod module', () => { // module main function it('should be invokable only by an admin', async () => { + const newCore = Object.assign({}, mocks.core); + const resp = await importedModule.run({ - core: mocks.core, + core: newCore, server: mocks.server, socket: mocks.plebSocket, payload: mockPayload, @@ -49,8 +51,10 @@ describe('Checking addmod module', () => { }); it('should add new trip to the config', async () => { + const newCore = Object.assign({}, mocks.core); + const resp = await importedModule.run({ - core: mocks.core, + core: newCore, server: mocks.server, socket: mocks.authedSocket, payload: mockPayload, @@ -60,18 +64,17 @@ describe('Checking addmod module', () => { }); it('should inform the new mod', async () => { + const newCore = Object.assign({}, mocks.core); mocks.server.findSockets = () => { return [{}]; } const resp = await importedModule.run({ - core: mocks.core, + core: newCore, server: mocks.server, socket: mocks.authedSocket, payload: mockPayload, }); - - mocks.core.appConfig.data.globalMods = []; expect(resp).to.be.true; }); diff --git a/test/join.test.js b/test/join.test.js index 6867d2d..ad7fafe 100644 --- a/test/join.test.js +++ b/test/join.test.js @@ -181,6 +181,32 @@ describe('Checking join module', () => { expect(resp).to.be.true; }); + it('should provide mod perks', async () => { + const newCore = Object.assign({}, mocks.core); + newCore.appConfig.data.globalMods = [ + { + trip: 'XVeP3T', + } + ]; + + const newSocket = Object.assign({}, mocks.authedSocket); + newSocket.channel = undefined; + newSocket.hcProtocol = undefined; + + const resp = await importedModule.run({ + core: newCore, + server: mocks.server, + socket: newSocket, + payload: { + cmd: 'join', + nick: 'admin#test', + channel: 'cake', + }, + }); + + expect(newSocket.ratelimitImmune).to.be.true; + }); + it('should announce new user', async () => { const newSocket = Object.assign({}, mocks.authedSocket); newSocket.channel = undefined; diff --git a/test/removemod.test.js b/test/removemod.test.js index 555199c..a84d1f6 100644 --- a/test/removemod.test.js +++ b/test/removemod.test.js @@ -6,7 +6,7 @@ let importedModule; const mockPayload = { cmd: 'removemod', - trip: 'newTrip', + trip: 'XVeP3T', } describe('Checking removemod module', () => { @@ -38,8 +38,10 @@ describe('Checking removemod module', () => { // module main function it('should be invokable only by an admin', async () => { + const newCore = Object.assign({}, mocks.core); + const resp = await importedModule.run({ - core: mocks.core, + core: newCore, server: mocks.server, socket: mocks.plebSocket, payload: mockPayload, @@ -49,8 +51,10 @@ describe('Checking removemod module', () => { }); it('should remove trip from the config', async () => { + const newCore = Object.assign({}, mocks.core); + const resp = await importedModule.run({ - core: mocks.core, + core: newCore, server: mocks.server, socket: mocks.authedSocket, payload: mockPayload, @@ -60,12 +64,14 @@ describe('Checking removemod module', () => { }); it('should inform the ex-mod', async () => { + const newCore = Object.assign({}, mocks.core); + mocks.server.findSockets = () => { return [{}]; } const resp = await importedModule.run({ - core: mocks.core, + core: newCore, server: mocks.server, socket: mocks.authedSocket, payload: mockPayload, From 4d7ec411d392cfa4a0ffef3c6d88171ae2d0798c Mon Sep 17 00:00:00 2001 From: marzavec Date: Fri, 29 Dec 2023 22:44:29 -0800 Subject: [PATCH 36/37] syncing new themes from master branch --- client/client.js | 12 +- client/schemes/Ubuntu.css | 51 ++++ client/schemes/amoled.css | 50 ++++ client/schemes/carrot.css | 55 ++++ client/schemes/fried-egg.css | 50 ++++ client/schemes/gruvbox-light.css | 50 ++++ client/schemes/lax.css | 69 +++++ client/schemes/rainbow.css | 71 +++++ client/schemes/retro.css | 285 +++++++++++++++++++++ client/schemes/tk-night.css | 54 ++++ client/vendor/hljs/styles/tk-night.min.css | 1 + 11 files changed, 747 insertions(+), 1 deletion(-) create mode 100644 client/schemes/Ubuntu.css create mode 100644 client/schemes/amoled.css create mode 100644 client/schemes/carrot.css create mode 100644 client/schemes/fried-egg.css create mode 100644 client/schemes/gruvbox-light.css create mode 100644 client/schemes/lax.css create mode 100644 client/schemes/rainbow.css create mode 100644 client/schemes/retro.css create mode 100644 client/schemes/tk-night.css create mode 100644 client/vendor/hljs/styles/tk-night.min.css diff --git a/client/client.js b/client/client.js index d40d779..1f99177 100644 --- a/client/client.js +++ b/client/client.js @@ -960,7 +960,16 @@ var schemes = [ 'pop', 'railscasts', 'solarized', - 'tomorrow' + 'tomorrow', + 'tk-night', + 'carrot', + 'lax', + 'Ubuntu', + 'gruvbox-light', + 'fried-egg', + 'rainbow', + 'amoled', + 'retro' ]; var highlights = [ @@ -970,6 +979,7 @@ var highlights = [ 'darcula', 'github', 'rainbow', + 'tk-night', 'tomorrow', 'xcode', 'zenburn' diff --git a/client/schemes/Ubuntu.css b/client/schemes/Ubuntu.css new file mode 100644 index 0000000..5544858 --- /dev/null +++ b/client/schemes/Ubuntu.css @@ -0,0 +1,51 @@ +body { + background-color: #2C001E; + color: #E95420; +} +input, +textarea { + color: #ccc; + background-color: #111; +} +.message { + border-left: 1px solid #2C001E; +} +.refmessage { + border-left: 1px solid #2C001E; +} +.nick { + color: #E95420; +} +.trip { + color: #AEA79F; +} +.text a { + color: #00AA00; +} +.admin .nick { + color: #ac4142; +} +.mod .nick { + color: #1FAD83; +} +.me .nick { + color: #b854d4; +} +.info .nick, +.info .text { + color: #00AA22; +} +.warn .nick, +.warn .text { + color: #CFB017; +} +#footer { + background: #2C001E; +} +#sidebar { + background: #2C001E; + border-color: #5E2750; +} +#charform { + border-color: #5E2750; +} diff --git a/client/schemes/amoled.css b/client/schemes/amoled.css new file mode 100644 index 0000000..695838b --- /dev/null +++ b/client/schemes/amoled.css @@ -0,0 +1,50 @@ +body { + background: #000000; + color: #a6a28c; +} +input, +textarea { + color: #a6a28c; +} +.message { + border-left: #000000; +} +.refmessage { + border-left: #000000; +} +.nick { + color: #778fd8; +} +.trip { + color: #6e6b5e; +} +.text a { + color: #ffffff; +} +.admin .nick { + color: #d73737; +} +.mod .nick { + color: #36b08c; +} +.me .nick { + color: #b479c5; +} +.info .nick, +.info .text { + color: #97ca7d; +} +.warn .nick, +.warn .text { + color: #cfb017; +} +#footer { + background: #000000; +} +#sidebar { + background: #000000; + border-color: #000000; +} +#chatform { + border-color: #000000; +} diff --git a/client/schemes/carrot.css b/client/schemes/carrot.css new file mode 100644 index 0000000..8419df2 --- /dev/null +++ b/client/schemes/carrot.css @@ -0,0 +1,55 @@ +body { + background: #000000; + color: #ee600d; +} +input, +textarea { + color: #ee600d; +} + +.message { + border-left: 1px solid #ee600d; +} +.refmessage { + border-left: 1px solid #ee600d; +} +.nick { + color: #1db80f; +} +.trip { + color: #7cbb81; +} +.text a { + color: #97ff97ef; +} +.admin .nick { + color: #ffffff; +} +.mod .nick { + color: #00ffaa; +} +.me .nick { + color: #33ff00; +} +.info .nick, +.info .text { + color: #ee600d; +} +.warn .nick, +.warn .text { + color: #ffbb00; +} + +#footer { + background: #000000; +} + +#sidebar { + background: #000000; + border-color: #000000; +} + +#chatform { + border-color: #ee600d; +} + diff --git a/client/schemes/fried-egg.css b/client/schemes/fried-egg.css new file mode 100644 index 0000000..d86f606 --- /dev/null +++ b/client/schemes/fried-egg.css @@ -0,0 +1,50 @@ +body { + background: #f7f7f7; + color: #000000; +} +input, +textarea { + color: #000000; +} +.message { + border-left: 1px solid rgba(146, 121, 38, 0.6); +} +.refmessage { + border-left: 1px solid rgb(146, 121, 38) +} +.nick { + color: #ffd700; +} +.trip { + color: #8b8263 +} +.text a { + color: #000000; +} +.admin .nick { + color: #ff632a; +} +.mod .nick { + color: #cd853f; +} +.me .nick { + color: #ff7b00; +} +.info .nick, +.info .text { + color: #a37939; +} +.warn .nick, +.warn .text { + color: #ff0000; +} +#footer { + background: #ffffff; +} +#sidebar { + background: #ffcc26; + border-color: #a0522d; +} +#chatform { + border-color: #8b8263; +} \ No newline at end of file diff --git a/client/schemes/gruvbox-light.css b/client/schemes/gruvbox-light.css new file mode 100644 index 0000000..1fea197 --- /dev/null +++ b/client/schemes/gruvbox-light.css @@ -0,0 +1,50 @@ +body { + background: #fbf1c7; + color: #3c3836; +} +input, +textarea { + color: #3c3836; +} +.message { + border-left: 1px solid rgba(125, 122, 104, 0.5); +} +.refmessage { + border-left: 1px solid rgba(125, 122, 104, 1); +} +.nick { + color: #427b58; +} +.trip { + color: #7c6f64; +} +.text a { + color: #3c3836; +} +.admin .nick { + color: #9d0006; +} +.mod .nick { + color: #8f3f71; +} +.me .nick { + color: #79740e; +} +.info .nick, +.info .text { + color: #b57614; +} +.warn .nick, +.warn .text { + color: #b57614; +} +#footer { + background: #fbf1c7; +} +#sidebar { + background: #a89984; + border-color: #7d7a68; +} +#chatform { + border-color: #7d7a68; +} diff --git a/client/schemes/lax.css b/client/schemes/lax.css new file mode 100644 index 0000000..05d9b0d --- /dev/null +++ b/client/schemes/lax.css @@ -0,0 +1,69 @@ +:root { + color-scheme: dark!important; + scrollbar-color: #8e8e8e #151515; +} + +body { + background: #151515; + color: #8e8e8e; +} +pre { + margin-top: 0.3rem; + margin-bottom: 0.3rem; + overflow: hidden; + padding: 0.1rem; + font-weight: 400; + background: #1d1f21; + border: 0; + border-radius: 3px; +} +code{ + background: #444; +} + +input, +textarea { + color: #8e8e8e; +} +.message { + border-left: 1px solid rgba(116, 115, 105, 0.1); +} +.refmessage { + border-left: 1px solid rgba(116, 115, 105, 1); +} +.nick { + color: #6699cc; +} +.trip { + color: #515151; +} +.text a { + color: #5c9c9f; +} +.admin .nick { + color: #f2777a; +} +.mod .nick { + color: #66cccc; +} +.me .nick { + color: #cc99cc; +} +.info .nick, +.info .text { + color: #3e9353; +} +.warn .nick, +.warn .text { + color: #ffcc66; +} +#footer { + background: #151515; +} +#sidebar { + background: #111; + border-color: #20201e; +} +#chatform { + border-color: rgba(116, 115, 105, 0.15); +} diff --git a/client/schemes/rainbow.css b/client/schemes/rainbow.css new file mode 100644 index 0000000..bf567d9 --- /dev/null +++ b/client/schemes/rainbow.css @@ -0,0 +1,71 @@ +body { + background: #111; + color: #ccc; +} +input, +textarea { + color: #a6a28c; +} +.message { + border-left: 1px solid rgba(125, 122, 104, 0.5) !important; +} +.refmessage { + border-left: 1px solid rgba(125, 122, 104, 1) !important; +} +.nick { + background: linear-gradient(to right, #6666ff, #0099ff , #00ff00, #ff3399, #6666ff); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + animation: rainbow_animation 6s ease-in-out infinite; + background-size: 400% 100%; +} +.trip { + color: #777; +} +.text a { + color: #e8e4cf; +} +.admin .nick { + background: linear-gradient(to right, #6666ff, #0099ff , #00ff00, #ff3399, #6666ff); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + animation: rainbow_animation 6s ease-in-out infinite; + background-size: 400% 100%; +} +.mod .nick { + background: linear-gradient(to right, #6666ff, #0099ff , #00ff00, #ff3399, #6666ff); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + animation: rainbow_animation 6s ease-in-out infinite; + background-size: 400% 100%; +} +.me .nick { + background: linear-gradient(to right, #6666ff, #0099ff , #00ff00, #ff3399, #6666ff); + -webkit-background-clip: text; + background-clip: text; + color: transparent; + animation: rainbow_animation 6s ease-in-out infinite; + background-size: 400% 100%; +} +.info .nick, +.info .text { + color: #60ac39; +} +.warn .nick, +.warn .text { + color: #cfb017; +} +#footer { + background: #111; +} +#sidebar { + background: #111; + border-color: #777; +} +#chatform { + border-color: #777; +} + diff --git a/client/schemes/retro.css b/client/schemes/retro.css new file mode 100644 index 0000000..ab04a9d --- /dev/null +++ b/client/schemes/retro.css @@ -0,0 +1,285 @@ +/** defaults **/ + +body { + background: #20201d; + color: #a6a28c; +} +input, +textarea { + color: #a6a28c; +} +.message { + border-left: 1px solid rgba(125, 122, 104, 0.5) !important; +} +.refmessage { + border-left: 1px solid rgba(125, 122, 104, 1) !important; +} +.nick { + color: #6684e1; +} +.trip { + color: #6e6b5e; +} +.text a { + color: #e8e4cf; +} +.admin .nick { + color: #d73737; +} +.mod .nick { + color: #1fad83; +} +.me .nick { + color: #b854d4; +} +.info .nick, +.info .text { + color: #60ac39; +} +.warn .nick, +.warn .text { + color: #cfb017; +} +#footer { + background: #20201d; +} +#sidebar { + background: #292824; + border-color: #7d7a68; +} +#chatform { + border-color: #7d7a68; +} + + +/** customizations **/ + +:root { + color-scheme: dark!important; + scrollbar-color: #8e8e8e #151515; +} + +html { + font-family: 'Courier New', 'Consolas', 'Lucida Console', 'Menlo', Courier, monospace; +} +body, #footer, #sidebar { + background: #050505; +} +article.container { + min-height: 100vh; + width: 100%; + max-width: calc(100% - 264px); + margin: 36px 36px 0em 36px; + overflow: hidden; + border: 2px solid gray; + border-top: 0; + border-bottom: 0; + padding-bottom: 2px; +} +.hidden { + display: inherit; +} +@keyframes changeColors { + 0%, 100% { + background-color: initial; + } + 0.1% { + background-color: #0d1b62; + } + 99.9% { + background-color: #0d1b62; + } +} +.message { + animation-name: changeColors; + animation-duration: 10s; + animation-timing-function: steps(1, start); + animation-iteration-count: 1; +} + +#pin-sidebar { + display: none; +} +label[for=pin-sidebar] { + display: none; +} +#messages { + padding: 0; + border-bottom: 0; +} +#messages::after { + width: 100%; + max-width: calc(100% - 270px); + position: absolute; + display: block; + top: 15px; + left: 36px; + height: 14px; + padding: 2px 3px; + content: "#programming [+ver 1.0] :: https://hack.chat - The Next Frontier of Unknown Pleasures"; + border: 2px solid gray; + border-bottom: 2px solid gray; + background: linear-gradient(to right, #000080, #1084d0); + color: white; + font-size: 12px; + text-overflow:ellipsis; + overflow: hidden; + white-space: nowrap; +} +#messages > :first-child { + background: #1f71a4!important; +} +#sidebar { + width: 195px; +} +#users li { + list-style-type: none!important; + margin-left: -1.3em; + margin-top: 0.5em; +} +#sidebar-content { + display: flex; + flex-direction: column-reverse; + justify-content:start; + align-items:start; +} +#sidebar-content hr { + display:none; +} +#sidebar-content select, #sidebar-content button { + border-radius: 0; + margin-bottom: 0.5em; +} +#sidebar-content > :nth-child(19) { + /* border: 1px solid red; */ + margin-top: 80vh; + margin-bottom: 2.5em; +} +#sidebar-content > :nth-child(22) { + display: none; +} +#sidebar-content > :nth-child(21) { + display: none; +} +#sidebar-content > :nth-child(1) { + display: none; +} + +/* chat form */ +#footer { + margin-bottom: 0px; +} +#footer .container { + margin: 0 0 0 3em; + border: 2px solid gray; + max-width: calc(100% - 22em); + overflow: hidden; +} +#chatform { + height: 4em; + overflow: hidden; + overflow-y: scroll; +} +#chatinput { + padding: 1px 5px; + overflow: hidden; +} + +/* chat room */ +pre { + margin-top: 0.3rem; + margin-bottom: 0.3rem; + margin-left: 0em; + overflow: hidden; + padding: 0.1rem; + font-weight: 400; + background: #1d1f21; + border: 0; + border-radius: 3px; + width: calc(100% - 17em); +} +.message { + position: relative; + border: 0 !important; + padding: 0.2em 0; +} +.message .nick { + display: inline-block; + text-align: right; + margin-left: 6.6em; + width: 226px; +} +.trip { + display: inline-block!important; + width: 6em; + text-align: right; + margin-right: 0.75em; +} +.nick > a { + font-weight: bold; + display: inline-block; +} +.nick > a::before { + display: inline; + content: attr(title); + font-weight: normal; + margin-left: -5.8em; + position: absolute; + left: 0; +} +/* Missing trip */ +.message .nick a:only-child { + margin-left: 5.5em; +} +.message .nick a::after { + content: "|"; + position: absolute; + font-weight: bolder; + color: #6e6b5e; + font-size: 10px; + margin-top: 1px; + margin-left: 0.6em; +} +/* system */ +.message.info { + background: #2a7550!important; +} +.message.info * { + color: black!important; +} +.message.warn { + background: #887221!important; +} +.message.warn * { + color: black!important; +} +.info > .nick { + margin-left: 6.6em; +} +.info > .nick > :only-child { + margin-left: 15em; +} +.message.info .nick a::after, .message.warn .nick a::after { + color: black; +} +/* misc */ +.text > p { + line-height: 1.2em !important; + width: calc(100% - 20px); + display: inline-block; + margin-left: 0.5em; +} +.text > pre, .text > blockquote:first-child { + display: block; + margin: 6px 0 5px 6px; + width: calc(100% - 2.3em); +} +.text > ol { + margin-left: 20px; +} +.message .text:not(:first-child) { + width: auto; + margin-left: 320px; +} + + diff --git a/client/schemes/tk-night.css b/client/schemes/tk-night.css new file mode 100644 index 0000000..7459c35 --- /dev/null +++ b/client/schemes/tk-night.css @@ -0,0 +1,54 @@ +body { + background: #1f2224; + color: #b9a8eb; +} +input, +textarea { + color: #b9a8eb; +} + +.message { + border-left: 1px solid #cf56ff57; +} +.refmessage { + border-left: 1px solid #cf56ff57; +} +.nick { + color: #55586d; +} +.trip { + color: #7b80a3; +} +.text a { + color: #97ff97ef; +} +.admin .nick { + color: #fd9652; +} +.mod .nick { + color: #ec8476; +} +.me .nick { + color: #55586d; +} +.info .nick, +.info .text { + color: #d179d4; +} +.warn .nick, +.warn .text { + color: #eba8a8; +} + +#footer { + background: #1f2224e7; +} + +#sidebar { + background: #0000008c; + border-color: #cf56ff57; +} + +#chatform { + border-color: #cf56ff67; +} diff --git a/client/vendor/hljs/styles/tk-night.min.css b/client/vendor/hljs/styles/tk-night.min.css new file mode 100644 index 0000000..c852f72 --- /dev/null +++ b/client/vendor/hljs/styles/tk-night.min.css @@ -0,0 +1 @@ +.hljs{display:block;overflow-x:auto;padding:0.5em;color:#7f8ba0;background:#282c34;}.hljs-comment,.hljs-quote{color:#f7297f;font-style:italic;}.hljs-doctag,.hljs-keyword,.hljs-formula{color:#ad6fe7;}.hljs-section,.hljs-name,.hljs-selector-tag,.hljs-deletion,.hljs-subst{color:#e44855;}.hljs-literal{color:#46c2d3;}.hljs-string,.hljs-regexp,.hljs-addition,.hljs-attribute,.hljs-meta-string{color:#797bf0;}.hljs-built_in,.hljs-class.hljs-title{color:#c0e068;}.hljs-attr,.hljs-variable,.hljs-template-variable,.hljs-type,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-number{color:#ffc760;}.hljs-symbol,.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-title{color:#59b4ff;}.hljs-emphasis{font-style:italic;}.hljs-strong{font-weight:bold;}.hljs-link{text-decoration:underline;} \ No newline at end of file From d72428df8eeb3c5fe579c956d13483e4cd8a3d5b Mon Sep 17 00:00:00 2001 From: marzavec Date: Fri, 29 Dec 2023 23:24:12 -0800 Subject: [PATCH 37/37] documentation update --- commands/core/changecolor.js | 2 +- commands/core/changenick.js | 2 +- commands/core/chat.js | 6 +- commands/core/emote.js | 2 +- commands/core/help.js | 2 +- commands/core/morestats.js | 2 +- commands/core/whisper.js | 2 +- commands/mod/dumb.js | 6 +- commands/mod/enablecaptcha.js | 4 +- commands/mod/forcecolor.js | 2 +- commands/mod/lockroom.js | 10 +- documentation/admin_addmod.js.html | 6 +- documentation/admin_listusers.js.html | 4 +- documentation/admin_reload.js.html | 7 +- documentation/admin_removemod.js.html | 8 +- documentation/admin_saveconfig.js.html | 8 +- documentation/admin_shout.js.html | 4 +- documentation/core_changecolor.js.html | 6 +- documentation/core_changenick.js.html | 20 +- documentation/core_chat.js.html | 92 +- documentation/core_emote.js.html | 6 +- documentation/core_help.js.html | 7 +- documentation/core_invite.js.html | 4 +- documentation/core_join.js.html | 37 +- documentation/core_morestats.js.html | 6 +- documentation/core_ping.js.html | 4 +- documentation/core_session.js.html | 39 +- documentation/core_stats.js.html | 4 +- documentation/core_updateMessage.js.html | 178 +++ documentation/core_whisper.js.html | 6 +- documentation/index.html | 4 +- documentation/internal_disconnect.js.html | 20 +- documentation/internal_socketreply.js.html | 4 +- documentation/mod_ban.js.html | 4 +- documentation/mod_disablecaptcha.js.html | 137 ++ documentation/mod_dumb.js.html | 10 +- documentation/mod_enablecaptcha.js.html | 330 ++++ documentation/mod_forcecolor.js.html | 6 +- documentation/mod_kick.js.html | 4 +- documentation/mod_lockroom.js.html | 382 +++++ documentation/mod_speak.js.html | 6 +- documentation/mod_unban.js.html | 4 +- documentation/mod_unbanall.js.html | 4 +- documentation/mod_unlockroom.js.html | 140 ++ documentation/module-addmod.html | 4 +- documentation/module-ban.html | 4 +- documentation/module-changecolor.html | 30 +- documentation/module-changenick.html | 38 +- documentation/module-chat.html | 645 +++++++- documentation/module-disablecaptcha.html | 687 ++++++++ documentation/module-disconnect.html | 10 +- documentation/module-dumb.html | 105 +- documentation/module-emote.html | 30 +- documentation/module-enablecaptcha.html | 1178 ++++++++++++++ documentation/module-forcecolor.html | 30 +- documentation/module-help.html | 36 +- documentation/module-invite.html | 4 +- documentation/module-join.html | 10 +- documentation/module-kick.html | 4 +- documentation/module-listusers.html | 4 +- documentation/module-lockroom.html | 1681 ++++++++++++++++++++ documentation/module-morestats.html | 30 +- documentation/module-ping.html | 4 +- documentation/module-reload.html | 6 +- documentation/module-removemod.html | 8 +- documentation/module-saveconfig.html | 6 +- documentation/module-session.html | 22 +- documentation/module-shout.html | 4 +- documentation/module-socketreply.html | 4 +- documentation/module-speak.html | 27 +- documentation/module-stats.html | 4 +- documentation/module-unban.html | 4 +- documentation/module-unbanall.html | 4 +- documentation/module-unlockroom.html | 686 ++++++++ documentation/module-updateMessage.html | 604 +++++++ documentation/module-whisper.html | 30 +- documentation/scripts/linenumber.js | 40 +- documentation/scripts/prettify/lang-css.js | 4 +- documentation/scripts/prettify/prettify.js | 153 +- 79 files changed, 7288 insertions(+), 393 deletions(-) create mode 100644 documentation/core_updateMessage.js.html create mode 100644 documentation/mod_disablecaptcha.js.html create mode 100644 documentation/mod_enablecaptcha.js.html create mode 100644 documentation/mod_lockroom.js.html create mode 100644 documentation/mod_unlockroom.js.html create mode 100644 documentation/module-disablecaptcha.html create mode 100644 documentation/module-enablecaptcha.html create mode 100644 documentation/module-lockroom.html create mode 100644 documentation/module-unlockroom.html create mode 100644 documentation/module-updateMessage.html diff --git a/commands/core/changecolor.js b/commands/core/changecolor.js index 8326b2a..bb75a14 100644 --- a/commands/core/changecolor.js +++ b/commands/core/changecolor.js @@ -89,7 +89,7 @@ export function initHooks(server) { * Executes every time an incoming chat command is invoked * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/core/changenick.js b/commands/core/changenick.js index 184e966..ceda5df 100644 --- a/commands/core/changenick.js +++ b/commands/core/changenick.js @@ -143,7 +143,7 @@ export function initHooks(server) { * Executes every time an incoming chat command is invoked * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/core/chat.js b/commands/core/chat.js index b8ed943..958ccbc 100644 --- a/commands/core/chat.js +++ b/commands/core/chat.js @@ -35,7 +35,7 @@ const TIMEOUT_CHECK_INTERVAL = 30 * 1000; /** * Stores active messages that can be edited. - * @type {{ customId: string, userid: number, sent: number }[]} + * @type {Array} */ export const ACTIVE_MESSAGES = []; @@ -161,7 +161,7 @@ export function initHooks(server) { * checks for miscellaneous '/' based commands * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -188,7 +188,7 @@ export function commandCheckIn({ server, socket, payload }) { * assumes a failed chat command invocation and will reject with notice * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/core/emote.js b/commands/core/emote.js index 0f00eda..3adfbbd 100644 --- a/commands/core/emote.js +++ b/commands/core/emote.js @@ -91,7 +91,7 @@ export function initHooks(server) { * hooks chat commands checking for /me * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/core/help.js b/commands/core/help.js index 8152896..7431217 100644 --- a/commands/core/help.js +++ b/commands/core/help.js @@ -86,7 +86,7 @@ export function initHooks(server) { * hooks chat commands checking for /help * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/core/morestats.js b/commands/core/morestats.js index 02ea8af..c2f4cfa 100644 --- a/commands/core/morestats.js +++ b/commands/core/morestats.js @@ -118,7 +118,7 @@ export function initHooks(server) { * hooks chat commands checking for /stats * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/core/whisper.js b/commands/core/whisper.js index 7a2ae17..3a96338 100644 --- a/commands/core/whisper.js +++ b/commands/core/whisper.js @@ -124,7 +124,7 @@ export function initHooks(server) { * hooks chat commands checking for /whisper * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/mod/dumb.js b/commands/mod/dumb.js index ea602ac..d36cc7c 100644 --- a/commands/mod/dumb.js +++ b/commands/mod/dumb.js @@ -155,7 +155,7 @@ export function initHooks(server) { * hook incoming chat commands, shadow-prevent chat if they are muzzled * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -218,7 +218,7 @@ export function chatCheck({ * shadow-prevent all invites from muzzled users * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -290,7 +290,7 @@ export function inviteCheck({ * shadow-prevent all whispers from muzzled users * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/mod/enablecaptcha.js b/commands/mod/enablecaptcha.js index 0992219..06bba46 100644 --- a/commands/mod/enablecaptcha.js +++ b/commands/mod/enablecaptcha.js @@ -101,7 +101,7 @@ export function initHooks(server) { * hook incoming chat commands, check if they are answering a captcha * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -156,7 +156,7 @@ export function chatCheck({ * hook incoming join commands, check if they are joining a captcha protected channel * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/mod/forcecolor.js b/commands/mod/forcecolor.js index 8c53caf..0f6bd23 100644 --- a/commands/mod/forcecolor.js +++ b/commands/mod/forcecolor.js @@ -118,7 +118,7 @@ export function initHooks(server) { * hooks chat commands checking for /forcecolor * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/commands/mod/lockroom.js b/commands/mod/lockroom.js index c27d612..9c28333 100644 --- a/commands/mod/lockroom.js +++ b/commands/mod/lockroom.js @@ -126,7 +126,7 @@ export function initHooks(server) { * hook incoming changenick commands, reject them if the channel is 'purgatory' * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -145,7 +145,7 @@ export function changeNickCheck({ * hook incoming whisper commands, reject them if the channel is 'purgatory' * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -164,7 +164,7 @@ export function whisperCheck({ * hook incoming chat commands, reject them if the channel is 'purgatory' * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -187,7 +187,7 @@ export function chatCheck({ * hook incoming invite commands, reject them if the channel is 'purgatory' * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -206,7 +206,7 @@ export function inviteCheck({ * hook incoming join commands, shunt them to purgatory if needed * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ diff --git a/documentation/admin_addmod.js.html b/documentation/admin_addmod.js.html index 94ee2a3..8f440eb 100644 --- a/documentation/admin_addmod.js.html +++ b/documentation/admin_addmod.js.html @@ -56,7 +56,7 @@ export async function run({ } // add new trip to config - core.config.mods.push({ trip: payload.trip }); + core.appConfig.data.globalMods.push({ trip: payload.trip }); // find targets current connections const newMod = server.findSockets({ trip: payload.trip }); @@ -144,13 +144,13 @@ export const info = {

- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/admin_listusers.js.html b/documentation/admin_listusers.js.html index c2d28a0..4d052f1 100644 --- a/documentation/admin_listusers.js.html +++ b/documentation/admin_listusers.js.html @@ -113,13 +113,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/admin_reload.js.html b/documentation/admin_reload.js.html index fa80ba2..3294c48 100644 --- a/documentation/admin_reload.js.html +++ b/documentation/admin_reload.js.html @@ -54,8 +54,7 @@ export async function run({ } // do command reload and store results - let loadResult = core.dynamicImports.reloadDirCache(); - loadResult += core.commands.loadCommands(); + let loadResult = await core.commands.reloadCommands(); // clear and rebuild all module hooks server.loadHooks(); @@ -108,13 +107,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/admin_removemod.js.html b/documentation/admin_removemod.js.html index 5c79041..cab6c34 100644 --- a/documentation/admin_removemod.js.html +++ b/documentation/admin_removemod.js.html @@ -57,7 +57,9 @@ export async function run({ // remove trip from config // eslint-disable-next-line no-param-reassign - core.config.mods = core.config.mods.filter((mod) => mod.trip !== payload.trip); + core.appConfig.data.globalMods = core.appConfig.data.globalMods.filter( + (mod) => mod.trip !== payload.trip, + ); // find targets current connections const targetMod = server.findSockets({ trip: payload.trip }); @@ -147,13 +149,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/admin_saveconfig.js.html b/documentation/admin_saveconfig.js.html index 336418e..2856e3e 100644 --- a/documentation/admin_saveconfig.js.html +++ b/documentation/admin_saveconfig.js.html @@ -52,7 +52,9 @@ export async function run({ core, server, socket }) { } // attempt save, notify of failure - if (!core.configManager.save()) { + try { + await core.appConfig.write(); + } catch (err) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` text: 'Failed to save config, check logs.', @@ -96,13 +98,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/admin_shout.js.html b/documentation/admin_shout.js.html index 68b9e61..e5cd885 100644 --- a/documentation/admin_shout.js.html +++ b/documentation/admin_shout.js.html @@ -94,13 +94,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_changecolor.js.html b/documentation/core_changecolor.js.html index e63a2c2..76804dd 100644 --- a/documentation/core_changecolor.js.html +++ b/documentation/core_changecolor.js.html @@ -117,7 +117,7 @@ export function initHooks(server) { * Executes every time an incoming chat command is invoked * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -194,13 +194,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_changenick.js.html b/documentation/core_changenick.js.html index 1715f7f..e70e4b2 100644 --- a/documentation/core_changenick.js.html +++ b/documentation/core_changenick.js.html @@ -48,7 +48,7 @@ import { * @return {void} */ export async function run({ - core, server, socket, payload, + server, socket, payload, }) { const { channel } = socket; @@ -77,18 +77,6 @@ export async function run({ }, socket); } - // prevent admin impersonation - // @todo prevent mod impersonation - if (newNick.toLowerCase() === core.config.adminName.toLowerCase()) { - server.police.frisk(socket, 4); - - return server.reply({ - cmd: 'warn', // @todo Add numeric error code as `id` - text: 'You are not the admin, liar!', - channel, // @todo Multichannel - }, socket); - } - if (newNick == previousNick) { return server.reply({ cmd: 'warn', // @todo Add numeric error code as `id` @@ -183,7 +171,7 @@ export function initHooks(server) { * Executes every time an incoming chat command is invoked * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -261,13 +249,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_chat.js.html b/documentation/core_chat.js.html index f41697e..5c8594a 100644 --- a/documentation/core_chat.js.html +++ b/documentation/core_chat.js.html @@ -34,33 +34,73 @@ * @module chat */ +import { + parseText, +} from '../utility/_Text.js'; import { isAdmin, isModerator, } from '../utility/_UAC.js'; /** - * Check and trim string provided by remote client - * @param {string} text - Subject string - * @private - * @todo Move into utility module - * @return {string|boolean} + * Maximum length of the customId property + * @type {number} */ -const parseText = (text) => { - // verifies user input is text - if (typeof text !== 'string') { - return false; +export const MAX_MESSAGE_ID_LENGTH = 6; + +/** + * The time in milliseconds before a message is considered stale, and thus no longer allowed + * to be edited. + * @type {number} + */ +const ACTIVE_TIMEOUT = 5 * 60 * 1000; + +/** + * The time in milliseconds that a check for stale messages should be performed. + * @type {number} + */ +const TIMEOUT_CHECK_INTERVAL = 30 * 1000; + +/** + * Stores active messages that can be edited. + * @type {Array} + */ +export const ACTIVE_MESSAGES = []; + +/** + * Cleans up stale messages. + * @public + * @return {void} + */ +export function cleanActiveMessages() { + const now = Date.now(); + for (let i = 0; i < ACTIVE_MESSAGES.length; i += 1) { + const message = ACTIVE_MESSAGES[i]; + if (now - message.sent > ACTIVE_TIMEOUT || message.toDelete) { + ACTIVE_MESSAGES.splice(i, 1); + i -= 1; + } } +} - let sanitizedText = text; +// TODO: This won't get cleared on module reload. +setInterval(cleanActiveMessages, TIMEOUT_CHECK_INTERVAL); - // strip newlines from beginning and end - sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, ''); - // replace 3+ newlines with just 2 newlines - sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n'); - - return sanitizedText; -}; +/** + * Adds a message to the active messages map. + * @public + * @param {string} id + * @param {number} userid + * @return {void} + */ +export function addActiveMessage(customId, userid) { + ACTIVE_MESSAGES.push({ + customId, + userid, + sent: Date.now(), + toDelete: false, + }); +} /** * Executes when invoked by a remote client @@ -89,6 +129,13 @@ export async function run({ }, socket); } + const { customId } = payload; + + if (typeof (customId) === 'string' && customId.length > MAX_MESSAGE_ID_LENGTH) { + // There's a limit on the custom id length. + return server.police.frisk(socket, 13); + } + // build chat payload const outgoingPayload = { cmd: 'chat', @@ -98,6 +145,7 @@ export async function run({ channel: socket.channel, text, level: socket.level, + customId, }; if (isAdmin(socket.level)) { @@ -114,6 +162,8 @@ export async function run({ outgoingPayload.color = socket.color; } + addActiveMessage(outgoingPayload.customId, socket.userid); + // broadcast to channel peers server.broadcast(outgoingPayload, { channel: socket.channel }); @@ -139,7 +189,7 @@ export function initHooks(server) { * checks for miscellaneous '/' based commands * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -166,7 +216,7 @@ export function commandCheckIn({ server, socket, payload }) { * assumes a failed chat command invocation and will reject with notice * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -231,13 +281,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_emote.js.html b/documentation/core_emote.js.html index f4392c3..9779ad6 100644 --- a/documentation/core_emote.js.html +++ b/documentation/core_emote.js.html @@ -119,7 +119,7 @@ export function initHooks(server) { * hooks chat commands checking for /me * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -198,13 +198,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_help.js.html b/documentation/core_help.js.html index a062853..dd69be4 100644 --- a/documentation/core_help.js.html +++ b/documentation/core_help.js.html @@ -79,6 +79,7 @@ export async function run({ } else { reply += `# ${command.info.name} command:\n| | |\n|---:|---|\n`; reply += `|**Name:**|${command.info.name}|\n`; + reply += `|**Hash:**|${command.info.srcHash}|\n`; reply += `|**Aliases:**|${typeof command.info.aliases !== 'undefined' ? command.info.aliases.join(', ') : 'None'}|\n`; reply += `|**Category:**|${command.info.category.replace('../src/commands/', '').replace(/^\w/, (c) => c.toUpperCase())}|\n`; reply += `|**Required Parameters:**|${command.requiredData || 'None'}|\n`; @@ -113,7 +114,7 @@ export function initHooks(server) { * hooks chat commands checking for /help * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -170,13 +171,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_invite.js.html b/documentation/core_invite.js.html index 0b8023b..51e7b23 100644 --- a/documentation/core_invite.js.html +++ b/documentation/core_invite.js.html @@ -159,13 +159,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_join.js.html b/documentation/core_join.js.html index 50a162d..bbb2f07 100644 --- a/documentation/core_join.js.html +++ b/documentation/core_join.js.html @@ -27,6 +27,7 @@
/* eslint no-param-reassign: 0 */
+/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
 
 /**
   * @author Marzavec ( https://github.com/marzavec )
@@ -36,6 +37,9 @@
   * @module join
   */
 
+import {
+  getSession,
+} from './session.js';
 import {
   canJoinChannel,
   socketInChannel,
@@ -51,6 +55,7 @@ import {
   verifyNickname,
   getUserPerms,
   getUserDetails,
+  isModerator,
 } from '../utility/_UAC.js';
 
 /**
@@ -73,7 +78,7 @@ export async function run({
   }
 
   // `join` is the legacy entry point, check if it needs to be upgraded
-  if (typeof socket.hcProtocol === 'undefined') {
+  if (typeof socket.hcProtocol === 'undefined' || socket.hcProtocol === 1) {
     payload = upgradeLegacyJoin(server, socket, payload);
   }
 
@@ -114,7 +119,7 @@ export async function run({
   }
 
   // get trip and level
-  const { trip, level } = getUserPerms(pass, core.config, channel);
+  const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel);
 
   // store the user values
   const userInfo = {
@@ -129,13 +134,6 @@ export async function run({
     channel,
   };
 
-  // prevent admin impersonation
-  if (nick.toLowerCase() === core.config.adminName.toLowerCase()) {
-    if (userInfo.trip !== 'Admin') {
-      userInfo.nick = `Fake${userInfo.nick}`;
-    }
-  }
-
   // check if the nickname already exists in the channel
   const userExists = server.findSockets({
     channel,
@@ -180,6 +178,12 @@ export async function run({
   socket.channel = channel; /* @legacy */
   // @todo multi-channel patch
   // socket.channels.push(channel);
+  socket.channels = [channel];
+
+  // global mod perks
+  if (isModerator(socket.level)) {
+    socket.ratelimitImmune = true;
+  }
 
   nicks.push(userInfo.nick); /* @legacy */
   users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo });
@@ -192,6 +196,14 @@ export async function run({
     channel, // @todo Multichannel (?)
   }, socket);
 
+  // update client with new session info
+  server.reply({
+    cmd: 'session',
+    restored: false,
+    token: getSession(socket, core),
+    channels: socket.channels,
+  }, socket);
+
   // stats are fun
   core.stats.increment('users-joined');
 
@@ -270,6 +282,9 @@ export function restoreJoin({
     channel, // @todo Multichannel (?)
   }, socket);
 
+  socket.channel = channel; /* @legacy */
+  socket.channels.push(channel);
+
   return true;
 }
 
@@ -299,13 +314,13 @@ export const info = {
 
 
 
 
 
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_morestats.js.html b/documentation/core_morestats.js.html index 4e37b5a..58e2351 100644 --- a/documentation/core_morestats.js.html +++ b/documentation/core_morestats.js.html @@ -146,7 +146,7 @@ export function initHooks(server) { * hooks chat commands checking for /stats * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -200,13 +200,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_ping.js.html b/documentation/core_ping.js.html index fd0cb6f..5c9bfbd 100644 --- a/documentation/core_ping.js.html +++ b/documentation/core_ping.js.html @@ -68,13 +68,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_session.js.html b/documentation/core_session.js.html index 78c58a0..3d04283 100644 --- a/documentation/core_session.js.html +++ b/documentation/core_session.js.html @@ -26,7 +26,7 @@
-
/* eslint no-param-reassign: 0 */
+            
/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
 
 /**
   * @author Marzavec ( https://github.com/marzavec )
@@ -40,6 +40,7 @@ import fs from 'fs';
 import jsonwebtoken from 'jsonwebtoken';
 
 import {
+  isModerator,
   verifyNickname,
 } from '../utility/_UAC.js';
 import {
@@ -49,10 +50,10 @@ import {
   restoreJoin,
 } from './join.js';
 
-const CertLocation = './cert.key';
+const SessionLocation = './session.key';
 
 /**
-  *
+  * Get a new json web token for the provided socket
   * @param {*} socket
   * @param {*} core
   * @returns {object}
@@ -68,15 +69,15 @@ export function getSession(socket, core) {
     trip: socket.trip,
     userid: socket.userid,
     uType: socket.uType,
-    muzzled: socket.muzzled,
-    banned: socket.banned,
-  }, core.cert, {
+    muzzled: socket.muzzled || false,
+    banned: socket.banned || false,
+  }, core.sessionKey, {
     expiresIn: '7 days',
   });
 }
 
 /**
-  *
+  * Reply to target socket with session failure notice
   * @param {*} server
   * @param {*} socket
   * @returns {boolean}
@@ -106,7 +107,7 @@ export async function run({
 
   let session = false;
   try {
-    session = jsonwebtoken.verify(payload.token, core.cert);
+    session = jsonwebtoken.verify(payload.token, core.sessionKey);
   } catch (err) {
     return notifyFailure(server, socket);
   }
@@ -120,7 +121,7 @@ export async function run({
     return notifyFailure(server, socket);
   }
 
-  if (typeof session.color !== 'string') {
+  if (typeof session.color !== 'string' && typeof session.color !== 'boolean') {
     return notifyFailure(server, socket);
   }
 
@@ -157,8 +158,7 @@ export async function run({
   }
 
   // populate socket info with validated session
-  socket.channel = session.channel;
-  socket.channels = session.channels;
+  socket.channels = [];
   socket.color = session.color;
   socket.isBot = session.isBot;
   socket.level = session.level;
@@ -169,6 +169,11 @@ export async function run({
   socket.muzzled = session.muzzled;
   socket.banned = session.banned;
 
+  // global mod perks
+  if (isModerator(socket.level)) {
+    socket.ratelimitImmune = true;
+  }
+
   socket.hash = server.getSocketHash(socket);
   socket.hcProtocol = 2;
 
@@ -180,12 +185,12 @@ export async function run({
     channels: socket.channels,
   }, socket);
 
-  for (let i = 0, j = socket.channels.length; i < j; i += 1) {
+  for (let i = 0, j = session.channels.length; i < j; i += 1) {
     restoreJoin({
       core,
       server,
       socket,
-      channel: socket.channels[i],
+      channel: session.channels[i],
     }, true);
   }
 
@@ -200,8 +205,8 @@ export async function run({
   */
 export function init(core) {
   // load the encryption key if required
-  if (typeof core.cert === 'undefined') {
-    core.cert = fs.readFileSync(CertLocation);
+  if (typeof core.sessionKey === 'undefined') {
+    core.sessionKey = fs.readFileSync(SessionLocation);
   }
 }
 
@@ -230,13 +235,13 @@ export const info = {
 
 
 
 
 
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_stats.js.html b/documentation/core_stats.js.html index b16c7b9..e25eb13 100644 --- a/documentation/core_stats.js.html +++ b/documentation/core_stats.js.html @@ -95,13 +95,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/core_updateMessage.js.html b/documentation/core_updateMessage.js.html new file mode 100644 index 0000000..3b19b89 --- /dev/null +++ b/documentation/core_updateMessage.js.html @@ -0,0 +1,178 @@ + + + + + JSDoc: Source: core/updateMessage.js + + + + + + + + + + +
+ +

Source: core/updateMessage.js

+ + + + + + +
+
+
/**
+  * @author MinusGix ( https://github.com/MinusGix )
+  * @summary Change target message
+  * @version v1.0.0
+  * @description Will alter a previously sent message using that message's customId
+  * @module updateMessage
+  */
+
+import {
+  parseText,
+} from '../utility/_Text.js';
+import {
+  isAdmin,
+  isModerator,
+} from '../utility/_UAC.js';
+import {
+  ACTIVE_MESSAGES,
+  MAX_MESSAGE_ID_LENGTH,
+} from './chat.js';
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  server, socket, payload,
+}) {
+  // undefined | "overwrite" | "append" | "prepend" | "complete"
+  const { customId } = payload;
+  let { mode, text } = payload;
+
+  if (!mode) {
+    mode = 'overwrite';
+  }
+
+  if (mode !== 'overwrite' && mode !== 'append' && mode !== 'prepend' && mode !== 'complete') {
+    return server.police.frisk(socket, 13);
+  }
+
+  if (!customId || typeof customId !== 'string' || customId.length > MAX_MESSAGE_ID_LENGTH) {
+    return server.police.frisk(socket, 13);
+  }
+
+  if (typeof (text) !== 'string') {
+    return server.police.frisk(socket, 13);
+  }
+
+  if (mode === 'overwrite') {
+    text = parseText(text);
+
+    if (text === '') {
+      text = '\u0000';
+    }
+  }
+
+  if (!text) {
+    return server.police.frisk(socket, 13);
+  }
+
+  // TODO: What score should we use for this? It isn't as space filling as chat messages.
+  // But we also don't want a massive growing message.
+  // Or flashing between huge and small. Etc.
+
+  let message;
+  for (let i = 0; i < ACTIVE_MESSAGES.length; i += 1) {
+    const msg = ACTIVE_MESSAGES[i];
+
+    if (msg.userid === socket.userid && msg.customId === customId) {
+      message = ACTIVE_MESSAGES[i];
+      if (mode === 'complete') {
+        ACTIVE_MESSAGES[i].toDelete = true;
+      }
+      break;
+    }
+  }
+
+  if (!message) {
+    return server.police.frisk(socket, 6);
+  }
+
+  const outgoingPayload = {
+    cmd: 'updateMessage',
+    userid: socket.userid,
+    channel: socket.channel,
+    level: socket.level,
+    mode,
+    text,
+    customId: message.customId,
+  };
+
+  if (isAdmin(socket.level)) {
+    outgoingPayload.admin = true;
+  } else if (isModerator(socket.level)) {
+    outgoingPayload.mod = true;
+  }
+
+  server.broadcast(outgoingPayload, { channel: socket.channel });
+
+  return true;
+}
+
+/**
+  * The following payload properties are required to invoke this module:
+  * "text", "customId"
+  * @public
+  * @typedef {Array} addmod/requiredData
+  */
+export const requiredData = ['text', 'customId'];
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} updateMessage/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'updateMessage',
+  category: 'core',
+  description: 'Update a message you have sent.',
+  usage: `
+    API: { cmd: 'updateMessage', mode: 'overwrite'|'append'|'prepend'|'complete', text: '<text to apply>', customId: '<customId sent with the chat message>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/documentation/core_whisper.js.html b/documentation/core_whisper.js.html index dcc81b9..bf1f995 100644 --- a/documentation/core_whisper.js.html +++ b/documentation/core_whisper.js.html @@ -152,7 +152,7 @@ export function initHooks(server) { * hooks chat commands checking for /whisper * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -267,13 +267,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/index.html b/documentation/index.html index 310280f..6fa26bb 100644 --- a/documentation/index.html +++ b/documentation/index.html @@ -90,13 +90,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/internal_disconnect.js.html b/documentation/internal_disconnect.js.html index 5379738..5ac0c97 100644 --- a/documentation/internal_disconnect.js.html +++ b/documentation/internal_disconnect.js.html @@ -34,6 +34,10 @@ * @module disconnect */ +import { + socketInChannel, +} from '../utility/_Channels.js'; + /** * Executes when invoked by a remote client * @param {Object} env - Enviroment object with references to core, server, socket & payload @@ -49,10 +53,14 @@ export async function run({ server, socket, payload }) { // send leave notice to client peers // @todo Multichannel update if (socket.channel) { - server.broadcast({ - cmd: 'onlineRemove', - nick: socket.nick, - }, { channel: socket.channel }); + const isDuplicate = socketInChannel(server, socket.channel, socket); + + if (isDuplicate === false) { + server.broadcast({ + cmd: 'onlineRemove', + nick: socket.nick, + }, { channel: socket.channel }); + } } // commit close just in case @@ -94,13 +102,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/internal_socketreply.js.html b/documentation/internal_socketreply.js.html index 1f233bd..6ac2255 100644 --- a/documentation/internal_socketreply.js.html +++ b/documentation/internal_socketreply.js.html @@ -87,13 +87,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/mod_ban.js.html b/documentation/mod_ban.js.html index d87bc9b..2dbe6da 100644 --- a/documentation/mod_ban.js.html +++ b/documentation/mod_ban.js.html @@ -151,13 +151,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/mod_disablecaptcha.js.html b/documentation/mod_disablecaptcha.js.html new file mode 100644 index 0000000..46eba22 --- /dev/null +++ b/documentation/mod_disablecaptcha.js.html @@ -0,0 +1,137 @@ + + + + + JSDoc: Source: mod/disablecaptcha.js + + + + + + + + + + +
+ +

Source: mod/disablecaptcha.js

+ + + + + + +
+
+
/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Disables the captcha
+  * @version 1.0.0
+  * @description Disables the captcha on the channel specified in the channel property,
+  *              default is current channel
+  * @module disablecaptcha
+  */
+
+import {
+  isModerator,
+} from '../utility/_UAC.js';
+
+/**
+  * Automatically executes once after server is ready
+  * @param {Object} core - Reference to core enviroment object
+  * @public
+  * @return {void}
+  */
+export async function init(core) {
+  if (typeof core.captchas === 'undefined') {
+    core.captchas = {};
+  }
+}
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket, 10);
+  }
+
+  let targetChannel;
+
+  if (typeof payload.channel !== 'string') {
+    if (typeof socket.channel !== 'string') { // @todo Multichannel
+      return false; // silently fail
+    }
+
+    targetChannel = socket.channel;
+  } else {
+    targetChannel = payload.channel;
+  }
+
+  if (!core.captchas[targetChannel]) {
+    return server.reply({
+      cmd: 'info',
+      text: 'Captcha is not enabled.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  core.captchas[targetChannel] = false;
+
+  server.broadcast({
+    cmd: 'info',
+    text: `Captcha disabled on: ${targetChannel}`,
+    channel: false, // @todo Multichannel, false for global info
+  }, { channel: targetChannel, level: isModerator });
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} disablecaptcha/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'disablecaptcha',
+  category: 'moderators',
+  description: 'Disables the captcha on the channel specified in the channel property, default is current channel',
+  usage: `
+    API: { cmd: 'disablecaptcha', channel: '<optional channel, defaults to your current channel' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/documentation/mod_dumb.js.html b/documentation/mod_dumb.js.html index 5227833..76e943d 100644 --- a/documentation/mod_dumb.js.html +++ b/documentation/mod_dumb.js.html @@ -183,7 +183,7 @@ export function initHooks(server) { * hook incoming chat commands, shadow-prevent chat if they are muzzled * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -246,7 +246,7 @@ export function chatCheck({ * shadow-prevent all invites from muzzled users * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -318,7 +318,7 @@ export function inviteCheck({ * shadow-prevent all whispers from muzzled users * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -410,13 +410,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/mod_enablecaptcha.js.html b/documentation/mod_enablecaptcha.js.html new file mode 100644 index 0000000..19b4f59 --- /dev/null +++ b/documentation/mod_enablecaptcha.js.html @@ -0,0 +1,330 @@ + + + + + JSDoc: Source: mod/enablecaptcha.js + + + + + + + + + + +
+ +

Source: mod/enablecaptcha.js

+ + + + + + +
+
+
/* eslint no-param-reassign: 0 */
+
+/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Enables the captcha
+  * @version 1.0.0
+  * @description Enables the captcha on the channel specified in the channel property,
+  *              default is current channel
+  * @module enablecaptcha
+  */
+
+import captcha from 'ascii-captcha';
+
+import {
+  isTrustedUser,
+  isModerator,
+  verifyNickname,
+  getUserPerms,
+} from '../utility/_UAC.js';
+import {
+  canJoinChannel,
+} from '../utility/_Channels.js';
+import {
+  upgradeLegacyJoin,
+  legacyLevelToLabel,
+} from '../utility/_LegacyFunctions.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+
+/**
+  * Automatically executes once after server is ready
+  * @param {Object} core - Reference to core enviroment object
+  * @public
+  * @return {void}
+  */
+export async function init(core) {
+  if (typeof core.captchas === 'undefined') {
+    core.captchas = {};
+  }
+}
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket, 10);
+  }
+
+  let targetChannel;
+
+  if (typeof payload.channel !== 'string') {
+    if (typeof socket.channel !== 'string') { // @todo Multichannel
+      return false; // silently fail
+    }
+
+    targetChannel = socket.channel;
+  } else {
+    targetChannel = payload.channel;
+  }
+
+  if (core.captchas[targetChannel]) {
+    return server.reply({
+      cmd: 'info',
+      text: 'Captcha is already enabled.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  core.captchas[targetChannel] = true;
+
+  server.broadcast({
+    cmd: 'info',
+    text: `Captcha enabled on: ${targetChannel}`,
+    channel: socket.channel, // @todo Multichannel, false for global info
+  }, { channel: socket.channel, level: isModerator });
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'chat', this.chatCheck.bind(this), 5);
+  server.registerHook('in', 'join', this.joinCheck.bind(this), 5);
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * hook incoming chat commands, check if they are answering a captcha
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {(Object|boolean|string)} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function chatCheck({
+  core, server, socket, payload,
+}) {
+  // always verifiy user input
+  if (typeof payload.text !== 'string') {
+    return false;
+  }
+
+  if (typeof socket.captcha !== 'undefined') {
+    if (socket.captcha.awaiting === true) {
+      if (payload.text === socket.captcha.solution) {
+        if (typeof socket.captcha.whitelist === 'undefined') {
+          socket.captcha.whitelist = [];
+        }
+
+        socket.captcha.whitelist.push(socket.captcha.origChannel);
+        socket.captcha.awaiting = false;
+
+        if (socket.hcProtocol === 1) {
+          core.commands.handleCommand(server, socket, {
+            cmd: 'join',
+            nick: `${socket.captcha.origNick}#${socket.captcha.origPass}`,
+            channel: socket.captcha.origChannel,
+          });
+        } else {
+          core.commands.handleCommand(server, socket, {
+            cmd: 'join',
+            nick: socket.captcha.origNick,
+            pass: socket.captcha.origPass,
+            channel: socket.captcha.origChannel,
+          });
+        }
+
+        return false;
+      }
+
+      server.police.frisk(socket, 7);
+      socket.terminate();
+
+      return false;
+    }
+  }
+
+  return payload;
+}
+
+/**
+  * Executes every time an incoming join command is invoked;
+  * hook incoming join commands, check if they are joining a captcha protected channel
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {(Object|boolean|string)} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function joinCheck({
+  core, server, socket, payload,
+}) {
+  // check if channel has captcha enabled
+  if (core.captchas[payload.channel] !== true) {
+    return payload;
+  }
+
+  // `join` is the legacy entry point, check if it needs to be upgraded
+  const origPayload = { ...payload };
+  if (typeof socket.hcProtocol === 'undefined') {
+    payload = upgradeLegacyJoin(server, socket, payload);
+  }
+
+  // store payload values
+  const { channel, nick, pass } = payload;
+
+  // check if a client is able to join target channel
+  const mayJoin = canJoinChannel(channel, socket);
+  if (mayJoin !== true) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'You may not join that channel.',
+      id: mayJoin,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // calling socket already in a channel
+  // @todo multichannel update, will remove
+  if (typeof socket.channel !== 'undefined') {
+    return server.reply({
+      cmd: 'warn', // @todo Remove this
+      text: 'Joining more than one channel is not currently supported',
+      id: Errors.Join.ALREADY_JOINED,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+  // end todo
+
+  // validates the user input for `nick`
+  if (verifyNickname(nick, socket) !== true) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Nickname must consist of up to 24 letters, numbers, and underscores',
+      id: Errors.Join.INVALID_NICK,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // get trip and level
+  const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel);
+
+  // store the user values
+  const userInfo = {
+    nick,
+    trip,
+    uType: legacyLevelToLabel(level),
+    hash: socket.hash,
+    level,
+    userid: socket.userid,
+    isBot: socket.isBot,
+    color: socket.color,
+    channel,
+  };
+
+  if (userInfo.uType === 'user') {
+    if (userInfo.trip == null || isTrustedUser(level) === false) {
+      if (typeof socket.captcha === 'undefined') {
+        socket.captcha = {
+          awaiting: true,
+          origChannel: payload.channel,
+          origNick: payload.nick,
+          origPass: pass,
+          solution: captcha.generateRandomText(6),
+        };
+
+        server.reply({
+          cmd: 'warn',
+          text: 'Enter the following to join (case-sensitive):',
+          channel: payload.channel, // @todo Multichannel
+        }, socket);
+
+        server.reply({
+          cmd: 'captcha',
+          text: captcha.word2Transformedstr(socket.captcha.solution),
+          channel: payload.channel, // @todo Multichannel
+        }, socket);
+
+        return false;
+      }
+
+      socket.terminate();
+
+      return false;
+    }
+  }
+
+  return origPayload;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} enablecaptcha/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'enablecaptcha',
+  category: 'moderators',
+  description: 'Enables a captcha in the current channel you are in',
+  usage: `
+    API: { cmd: 'enablecaptcha', channel: '<optional channel, defaults to your current channel>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/documentation/mod_forcecolor.js.html b/documentation/mod_forcecolor.js.html index 93c07ae..c92a4d6 100644 --- a/documentation/mod_forcecolor.js.html +++ b/documentation/mod_forcecolor.js.html @@ -146,7 +146,7 @@ export function initHooks(server) { * hooks chat commands checking for /forcecolor * @param {Object} env - Enviroment object with references to core, server, socket & payload * @public - * @return {{Object|boolean|string}} Object = same/altered payload, + * @return {(Object|boolean|string)} Object = same/altered payload, * false = suppress action, * string = error */ @@ -235,13 +235,13 @@ Text: /forcecolor <target nick> <color as hex>`,
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/mod_kick.js.html b/documentation/mod_kick.js.html index 9ca38e9..daddd47 100644 --- a/documentation/mod_kick.js.html +++ b/documentation/mod_kick.js.html @@ -188,13 +188,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/mod_lockroom.js.html b/documentation/mod_lockroom.js.html new file mode 100644 index 0000000..dc97d7b --- /dev/null +++ b/documentation/mod_lockroom.js.html @@ -0,0 +1,382 @@ + + + + + JSDoc: Source: mod/lockroom.js + + + + + + + + + + +
+ +

Source: mod/lockroom.js

+ + + + + + +
+
+
/* eslint no-param-reassign: 0 */
+
+/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Locks the channel
+  * @version 1.0.0
+  * @description Locks a channel preventing default levels from joining
+  * @module lockroom
+  */
+
+import {
+  isTrustedUser,
+  isModerator,
+  verifyNickname,
+  getUserPerms,
+} from '../utility/_UAC.js';
+import {
+  upgradeLegacyJoin,
+  legacyLevelToLabel,
+} from '../utility/_LegacyFunctions.js';
+import {
+  Errors,
+} from '../utility/_Constants.js';
+import {
+  canJoinChannel,
+} from '../utility/_Channels.js';
+
+const danteQuotes = [
+  'Do not be afraid; our fate cannot be taken from us; it is a gift.',
+  'In the middle of the journey of our life I found myself within a dark woods where the straight way was lost.',
+  'There is no greater sorrow then to recall our times of joy in wretchedness.',
+  'They yearn for what they fear for.',
+  'Through me you go into a city of weeping; through me you go into eternal pain; through me you go amongst the lost people',
+  'From there we came outside and saw the stars',
+  'But the stars that marked our starting fall away. We must go deeper into greater pain, for it is not permitted that we stay.',
+  'Hope not ever to see Heaven. I have come to lead you to the other shore; into eternal darkness; into fire and into ice.',
+  'As little flowers, which the chill of night has bent and huddled, when the white sun strikes, grow straight and open fully on their stems, so did I, too, with my exhausted force.',
+  'At grief so deep the tongue must wag in vain; the language of our sense and memory lacks the vocabulary of such pain.',
+  'Thence we came forth to rebehold the stars.',
+  'He is, most of all, l\'amor che move il sole e l\'altre stelle.',
+  'The poets leave hell and again behold the stars.',
+  'One ought to be afraid of nothing other then things possessed of power to do us harm, but things innoucuous need not be feared.',
+  'As phantoms frighten beasts when shadows fall.',
+  'We were men once, though we\'ve become trees',
+  'Here pity only lives when it is dead',
+  'Lasciate ogne speranza, voi ch\'intrate.',
+  'There is no greater sorrow than thinking back upon a happy time in misery',
+  'My thoughts were full of other things When I wandered off the path.',
+];
+
+/**
+  * Automatically executes once after server is ready
+  * @param {Object} core - Reference to core enviroment object
+  * @public
+  * @return {void}
+  */
+export async function init(core) {
+  if (typeof core.locked === 'undefined') {
+    core.locked = {};
+  }
+}
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket, 10);
+  }
+
+  let targetChannel;
+
+  if (typeof payload.channel !== 'string') {
+    if (typeof socket.channel !== 'string') { // @todo Multichannel
+      return false; // silently fail
+    }
+
+    targetChannel = socket.channel;
+  } else {
+    targetChannel = payload.channel;
+  }
+
+  if (core.locked[targetChannel]) {
+    return server.reply({
+      cmd: 'info',
+      text: 'Channel is already locked.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  // apply lock flag to channel list
+  core.locked[targetChannel] = true;
+
+  // inform mods
+  server.broadcast({
+    cmd: 'info',
+    text: `Channel: ?${targetChannel} lock enabled by [${socket.trip}]${socket.nick}`,
+    channel: false, // @todo Multichannel, false for global info
+  }, { level: isModerator });
+
+  return true;
+}
+
+/**
+  * Automatically executes once after server is ready to register this modules hooks
+  * @param {Object} server - Reference to server enviroment object
+  * @public
+  * @return {void}
+  */
+export function initHooks(server) {
+  server.registerHook('in', 'changenick', this.changeNickCheck.bind(this), 1);
+  server.registerHook('in', 'whisper', this.whisperCheck.bind(this), 1);
+  server.registerHook('in', 'chat', this.chatCheck.bind(this), 1);
+  server.registerHook('in', 'invite', this.inviteCheck.bind(this), 1);
+  server.registerHook('in', 'join', this.joinCheck.bind(this), 1);
+}
+
+/**
+  * Executes every time an incoming changenick command is invoked;
+  * hook incoming changenick commands, reject them if the channel is 'purgatory'
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {(Object|boolean|string)} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function changeNickCheck({
+  socket, payload,
+}) {
+  if (socket.channel === 'purgatory') { // @todo Multichannel update
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Executes every time an incoming whisper command is invoked;
+  * hook incoming whisper commands, reject them if the channel is 'purgatory'
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {(Object|boolean|string)} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function whisperCheck({
+  socket, payload,
+}) {
+  if (socket.channel === 'purgatory') { // @todo Multichannel update
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Executes every time an incoming chat command is invoked;
+  * hook incoming chat commands, reject them if the channel is 'purgatory'
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {(Object|boolean|string)} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function chatCheck({
+  socket, payload,
+}) {
+  if (socket.channel === 'purgatory') {
+    if (isModerator(socket.level)) {
+      return payload;
+    }
+
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Executes every time an incoming invite command is invoked;
+  * hook incoming invite commands, reject them if the channel is 'purgatory'
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {(Object|boolean|string)} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function inviteCheck({
+  socket, payload,
+}) {
+  if (socket.channel === 'purgatory') {
+    return false;
+  }
+
+  return payload;
+}
+
+/**
+  * Executes every time an incoming join command is invoked;
+  * hook incoming join commands, shunt them to purgatory if needed
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {(Object|boolean|string)} Object = same/altered payload,
+  * false = suppress action,
+  * string = error
+  */
+export function joinCheck({
+  core, server, socket, payload,
+}) {
+  // check if target channel is locked
+  if (typeof core.locked[payload.channel] === 'undefined' || core.locked[payload.channel] !== true) {
+    if (payload.channel !== 'purgatory') {
+      return payload;
+    }
+  }
+
+  // `join` is the legacy entry point, check if it needs to be upgraded
+  if (typeof socket.hcProtocol === 'undefined') {
+    payload = upgradeLegacyJoin(server, socket, payload);
+  }
+
+  // store payload values
+  const { channel, nick, pass } = payload;
+
+  // check if a client is able to join target channel
+  const mayJoin = canJoinChannel(channel, socket);
+  if (mayJoin !== true) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'You may not join that channel.',
+      id: mayJoin,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // calling socket already in a channel
+  // @todo multichannel update, will remove
+  if (typeof socket.channel !== 'undefined') {
+    return server.reply({
+      cmd: 'warn', // @todo Remove this
+      text: 'Joining more than one channel is not currently supported',
+      id: Errors.Join.ALREADY_JOINED,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+  // end todo
+
+  // validates the user input for `nick`
+  if (verifyNickname(nick, socket) !== true) {
+    return server.reply({
+      cmd: 'warn',
+      text: 'Nickname must consist of up to 24 letters, numbers, and underscores',
+      id: Errors.Join.INVALID_NICK,
+      channel: false, // @todo Multichannel, false for global event
+    }, socket);
+  }
+
+  // get trip and level
+  const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel);
+
+  // store the user values
+  const userInfo = {
+    nick,
+    trip,
+    uType: legacyLevelToLabel(level),
+    hash: socket.hash,
+    level,
+    userid: socket.userid,
+    isBot: socket.isBot,
+    color: socket.color,
+    channel,
+  };
+
+  // check if trip is allowed
+  if (userInfo.uType === 'user') {
+    if (userInfo.trip == null || isTrustedUser(level) === false) {
+      const origNick = userInfo.nick;
+      const origChannel = payload.channel;
+
+      // not allowed, shunt to purgatory
+      payload.channel = 'purgatory';
+
+      // lost souls have no names
+      if (origChannel === 'purgatory') {
+        // someone is pulling a Dante
+        payload.nick = `Dante_${Math.random().toString(36).substr(2, 8)}`;
+      } else {
+        payload.nick = `${Math.random().toString(36).substr(2, 8)}${Math.random().toString(36).substr(2, 8)}`;
+      }
+
+      setTimeout(() => {
+        server.reply({
+          cmd: 'info',
+          text: danteQuotes[Math.floor(Math.random() * danteQuotes.length)],
+          channel: 'purgatory', // @todo Multichannel
+        }, socket);
+      }, 100);
+
+      server.broadcast({
+        cmd: 'info',
+        text: `${payload.nick} is: ${origNick}\ntrip: ${userInfo.trip || 'none'}\ntried to join: ?${origChannel}\nhash: ${userInfo.hash}`,
+        channel: 'purgatory', // @todo Multichannel, false for global info
+      }, { channel: 'purgatory', level: isModerator });
+    }
+  }
+
+  return payload;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} kick/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'lockroom',
+  category: 'moderators',
+  description: 'Locks a channel preventing default levels from joining',
+  usage: `
+    API: { cmd: 'lockroom', channel: '<optional channel, defaults to your current channel>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/documentation/mod_speak.js.html b/documentation/mod_speak.js.html index 1e6fb78..1dc51d8 100644 --- a/documentation/mod_speak.js.html +++ b/documentation/mod_speak.js.html @@ -131,7 +131,7 @@ export const info = { description: 'Pardon a dumb user to be able to speak again', aliases: ['unmuzzle', 'unmute'], usage: ` - API: { cmd: 'speak', ip/hash: '<target ip or hash' }`, + API: { cmd: 'speak', ip/hash: '<target ip or hash>' }`, };
@@ -143,13 +143,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/mod_unban.js.html b/documentation/mod_unban.js.html index 45d2427..269bd23 100644 --- a/documentation/mod_unban.js.html +++ b/documentation/mod_unban.js.html @@ -127,13 +127,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/mod_unbanall.js.html b/documentation/mod_unbanall.js.html index d1ae5fe..76bcf94 100644 --- a/documentation/mod_unbanall.js.html +++ b/documentation/mod_unbanall.js.html @@ -100,13 +100,13 @@ export const info = {
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/mod_unlockroom.js.html b/documentation/mod_unlockroom.js.html new file mode 100644 index 0000000..f6e1894 --- /dev/null +++ b/documentation/mod_unlockroom.js.html @@ -0,0 +1,140 @@ + + + + + JSDoc: Source: mod/unlockroom.js + + + + + + + + + + +
+ +

Source: mod/unlockroom.js

+ + + + + + +
+
+
/* eslint no-console: 0 */
+
+/**
+  * @author Marzavec ( https://github.com/marzavec )
+  * @summary Unlock target channel
+  * @version 1.0.0
+  * @description Unlocks a channel allowing anyone to join
+  * @module unlockroom
+  */
+
+import {
+  isModerator,
+} from '../utility/_UAC.js';
+
+/**
+  * Automatically executes once after server is ready
+  * @param {Object} core - Reference to core enviroment object
+  * @public
+  * @return {void}
+  */
+export async function init(core) {
+  if (typeof core.locked === 'undefined') {
+    core.locked = {};
+  }
+}
+
+/**
+  * Executes when invoked by a remote client
+  * @param {Object} env - Enviroment object with references to core, server, socket & payload
+  * @public
+  * @return {void}
+  */
+export async function run({
+  core, server, socket, payload,
+}) {
+  // increase rate limit chance and ignore if not admin or mod
+  if (!isModerator(socket.level)) {
+    return server.police.frisk(socket, 10);
+  }
+
+  let targetChannel;
+
+  if (typeof payload.channel !== 'string') {
+    if (typeof socket.channel !== 'string') { // @todo Multichannel
+      return false; // silently fail
+    }
+
+    targetChannel = socket.channel;
+  } else {
+    targetChannel = payload.channel;
+  }
+
+  if (!core.locked[targetChannel]) {
+    return server.reply({
+      cmd: 'info',
+      text: 'Channel is not locked.',
+      channel: socket.channel, // @todo Multichannel
+    }, socket);
+  }
+
+  core.locked[targetChannel] = false;
+
+  server.broadcast({
+    cmd: 'info',
+    text: `Channel: ?${targetChannel} unlocked by [${socket.trip}]${socket.nick}`,
+    channel: targetChannel, // @todo Multichannel, false for global info
+  }, { channel: targetChannel, level: isModerator });
+
+  console.log(`Channel: ?${targetChannel} unlocked by [${socket.trip}]${socket.nick} in ${socket.channel}`);
+
+  return true;
+}
+
+/**
+  * Module meta information
+  * @public
+  * @typedef {Object} unlockroom/info
+  * @property {string} name - Module command name
+  * @property {string} category - Module category name
+  * @property {string} description - Information about module
+  * @property {string} usage - Information about module usage
+  */
+export const info = {
+  name: 'unlockroom',
+  category: 'moderators',
+  description: 'Unlock the current channel you are in or target channel as specified',
+  usage: `
+    API: { cmd: 'unlockroom', channel: '<optional target channel>' }`,
+};
+
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + diff --git a/documentation/module-addmod.html b/documentation/module-addmod.html index 3e7e7a5..510321b 100644 --- a/documentation/module-addmod.html +++ b/documentation/module-addmod.html @@ -589,13 +589,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-ban.html b/documentation/module-ban.html index 661f988..e4a3413 100644 --- a/documentation/module-ban.html +++ b/documentation/module-ban.html @@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-changecolor.html b/documentation/module-changecolor.html index f684538..348bc0a 100644 --- a/documentation/module-changecolor.html +++ b/documentation/module-changecolor.html @@ -154,7 +154,7 @@ -

(static) colorCheck(env)

+

(static) colorCheck(env) → {Object|boolean|string}

@@ -283,8 +283,32 @@
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -887,13 +911,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-changenick.html b/documentation/module-changenick.html index d74189c..5d5e65c 100644 --- a/documentation/module-changenick.html +++ b/documentation/module-changenick.html @@ -255,7 +255,7 @@
Source:
@@ -309,7 +309,7 @@ -

(static) nickCheck(env)

+

(static) nickCheck(env) → {Object|boolean|string}

@@ -410,7 +410,7 @@
Source:
@@ -438,8 +438,32 @@
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -784,7 +808,7 @@
Source:
@@ -857,7 +881,7 @@
Source:
@@ -887,13 +911,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-chat.html b/documentation/module-chat.html index bc4fba8..f068e08 100644 --- a/documentation/module-chat.html +++ b/documentation/module-chat.html @@ -144,6 +144,299 @@ +

Members

+ + + +

(static, constant) ACTIVE_MESSAGES :Array

+ + + + +
+ Stores active messages that can be edited. +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(static, constant) MAX_MESSAGE_ID_LENGTH :number

+ + + + +
+ Maximum length of the customId property +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(inner, constant) ACTIVE_TIMEOUT :number

+ + + + +
+ The time in milliseconds before a message is considered stale, and thus no longer allowed +to be edited. +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(inner, constant) TIMEOUT_CHECK_INTERVAL :number

+ + + + +
+ The time in milliseconds that a check for stale messages should be performed. +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + +

Methods

@@ -154,7 +447,291 @@ -

(static) commandCheckIn(env)

+

(static) addActiveMessage(id, userid) → {void}

+ + + + + + +
+ Adds a message to the active messages map. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
id + + +string + + + +
userid + + +number + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) cleanActiveMessages() → {void}

+ + + + + + +
+ Cleans up stale messages. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) commandCheckIn(env) → {Object|boolean|string}

@@ -256,7 +833,7 @@ checks for miscellaneous '/' based commands
Source:
@@ -284,8 +861,32 @@ checks for miscellaneous '/' based commands
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -298,7 +899,7 @@ checks for miscellaneous '/' based commands -

(static) finalCmdCheck(env)

+

(static) finalCmdCheck(env) → {Object|boolean|string}

@@ -400,7 +1001,7 @@ assumes a failed chat command invocation and will reject with notice
Source:
@@ -428,8 +1029,32 @@ assumes a failed chat command invocation and will reject with notice
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -543,7 +1168,7 @@ assumes a failed chat command invocation and will reject with notice
Source:
@@ -698,7 +1323,7 @@ assumes a failed chat command invocation and will reject with notice
Source:
@@ -929,7 +1554,7 @@ assumes a failed chat command invocation and will reject with notice
Source:
@@ -1002,7 +1627,7 @@ assumes a failed chat command invocation and will reject with notice
Source:
@@ -1032,13 +1657,13 @@ assumes a failed chat command invocation and will reject with notice
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-disablecaptcha.html b/documentation/module-disablecaptcha.html new file mode 100644 index 0000000..2cabf56 --- /dev/null +++ b/documentation/module-disablecaptcha.html @@ -0,0 +1,687 @@ + + + + + JSDoc: Module: disablecaptcha + + + + + + + + + + +
+ +

Module: disablecaptcha

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Disables the captcha on the channel specified in the channel property, + default is current channel
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) init(core) → {void}

+ + + + + + +
+ Automatically executes once after server is ready +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
core + + +Object + + + + Reference to core enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

disablecaptcha/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-disconnect.html b/documentation/module-disconnect.html index 47db03c..cf82807 100644 --- a/documentation/module-disconnect.html +++ b/documentation/module-disconnect.html @@ -255,7 +255,7 @@
Source:
@@ -486,7 +486,7 @@
Source:
@@ -559,7 +559,7 @@
Source:
@@ -589,13 +589,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-dumb.html b/documentation/module-dumb.html index 4c86f9f..a4e1909 100644 --- a/documentation/module-dumb.html +++ b/documentation/module-dumb.html @@ -154,7 +154,7 @@ -

(static) chatCheck(env)

+

(static) chatCheck(env) → {Object|boolean|string}

@@ -284,8 +284,32 @@ hook incoming chat commands, shadow-prevent chat if they are muzzled
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -608,7 +632,7 @@ hook incoming chat commands, shadow-prevent chat if they are muzzled -

(static) inviteCheck(env)

+

(static) inviteCheck(env) → {Object|boolean|string}

@@ -738,8 +762,32 @@ shadow-prevent all invites from muzzled users
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -907,7 +955,7 @@ shadow-prevent all invites from muzzled users -

(static) whisperCheck(env)

+

(static) whisperCheck(env) → {Object|boolean|string}

@@ -1037,8 +1085,32 @@ shadow-prevent all whispers from muzzled users
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -1171,6 +1243,29 @@ shadow-prevent all whispers from muzzled users + + + aliases + + + + + +Array + + + + + + + + + + An array of alternative cmd names + + + + usage @@ -1258,13 +1353,13 @@ shadow-prevent all whispers from muzzled users
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-emote.html b/documentation/module-emote.html index 229f5c4..b753cfc 100644 --- a/documentation/module-emote.html +++ b/documentation/module-emote.html @@ -154,7 +154,7 @@ -

(static) emoteCheck(env)

+

(static) emoteCheck(env) → {Object|boolean|string}

@@ -284,8 +284,32 @@ hooks chat commands checking for /me
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -888,13 +912,13 @@ hooks chat commands checking for /me
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-enablecaptcha.html b/documentation/module-enablecaptcha.html new file mode 100644 index 0000000..97de3d9 --- /dev/null +++ b/documentation/module-enablecaptcha.html @@ -0,0 +1,1178 @@ + + + + + JSDoc: Module: enablecaptcha + + + + + + + + + + +
+ +

Module: enablecaptcha

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Enables the captcha on the channel specified in the channel property, + default is current channel
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) chatCheck(env) → {Object|boolean|string}

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +hook incoming chat commands, check if they are answering a captcha +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object = same/altered payload, +false = suppress action, +string = error +
+ + + +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ + + + + + + + + + + + + +

(static) init(core) → {void}

+ + + + + + +
+ Automatically executes once after server is ready +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
core + + +Object + + + + Reference to core enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) joinCheck(env) → {Object|boolean|string}

+ + + + + + +
+ Executes every time an incoming join command is invoked; +hook incoming join commands, check if they are joining a captcha protected channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object = same/altered payload, +false = suppress action, +string = error +
+ + + +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

enablecaptcha/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-forcecolor.html b/documentation/module-forcecolor.html index 56be862..02efa9d 100644 --- a/documentation/module-forcecolor.html +++ b/documentation/module-forcecolor.html @@ -154,7 +154,7 @@ -

(static) colorCheck(env)

+

(static) colorCheck(env) → {Object|boolean|string}

@@ -284,8 +284,32 @@ hooks chat commands checking for /forcecolor
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -888,13 +912,13 @@ hooks chat commands checking for /forcecolor
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-help.html b/documentation/module-help.html index f43fd20..8f61eef 100644 --- a/documentation/module-help.html +++ b/documentation/module-help.html @@ -154,7 +154,7 @@ -

(static) helpCheck(env)

+

(static) helpCheck(env) → {Object|boolean|string}

@@ -256,7 +256,7 @@ hooks chat commands checking for /help
Source:
@@ -284,8 +284,32 @@ hooks chat commands checking for /help
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -399,7 +423,7 @@ hooks chat commands checking for /help
Source:
@@ -785,7 +809,7 @@ hooks chat commands checking for /help
Source:
@@ -815,13 +839,13 @@ hooks chat commands checking for /help
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-invite.html b/documentation/module-invite.html index d635329..d862e7a 100644 --- a/documentation/module-invite.html +++ b/documentation/module-invite.html @@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-join.html b/documentation/module-join.html index 6b8470b..74a9c99 100644 --- a/documentation/module-join.html +++ b/documentation/module-join.html @@ -97,7 +97,7 @@
Source:
@@ -255,7 +255,7 @@
Source:
@@ -486,7 +486,7 @@
Source:
@@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-kick.html b/documentation/module-kick.html index 1101b23..c7b82c3 100644 --- a/documentation/module-kick.html +++ b/documentation/module-kick.html @@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-listusers.html b/documentation/module-listusers.html index e4a23c2..d5caf86 100644 --- a/documentation/module-listusers.html +++ b/documentation/module-listusers.html @@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-lockroom.html b/documentation/module-lockroom.html new file mode 100644 index 0000000..0ff495a --- /dev/null +++ b/documentation/module-lockroom.html @@ -0,0 +1,1681 @@ + + + + + JSDoc: Module: lockroom + + + + + + + + + + +
+ +

Module: lockroom

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Locks a channel preventing default levels from joining
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) changeNickCheck(env) → {Object|boolean|string}

+ + + + + + +
+ Executes every time an incoming changenick command is invoked; +hook incoming changenick commands, reject them if the channel is 'purgatory' +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object = same/altered payload, +false = suppress action, +string = error +
+ + + +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ + + + + + + + + + + + + +

(static) chatCheck(env) → {Object|boolean|string}

+ + + + + + +
+ Executes every time an incoming chat command is invoked; +hook incoming chat commands, reject them if the channel is 'purgatory' +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object = same/altered payload, +false = suppress action, +string = error +
+ + + +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ + + + + + + + + + + + + +

(static) init(core) → {void}

+ + + + + + +
+ Automatically executes once after server is ready +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
core + + +Object + + + + Reference to core enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) initHooks(server) → {void}

+ + + + + + +
+ Automatically executes once after server is ready to register this modules hooks +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +Object + + + + Reference to server enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) inviteCheck(env) → {Object|boolean|string}

+ + + + + + +
+ Executes every time an incoming invite command is invoked; +hook incoming invite commands, reject them if the channel is 'purgatory' +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object = same/altered payload, +false = suppress action, +string = error +
+ + + +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ + + + + + + + + + + + + +

(static) joinCheck(env) → {Object|boolean|string}

+ + + + + + +
+ Executes every time an incoming join command is invoked; +hook incoming join commands, shunt them to purgatory if needed +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object = same/altered payload, +false = suppress action, +string = error +
+ + + +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) whisperCheck(env) → {Object|boolean|string}

+ + + + + + +
+ Executes every time an incoming whisper command is invoked; +hook incoming whisper commands, reject them if the channel is 'purgatory' +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object = same/altered payload, +false = suppress action, +string = error +
+ + + +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

kick/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-morestats.html b/documentation/module-morestats.html index a26cabd..192146b 100644 --- a/documentation/module-morestats.html +++ b/documentation/module-morestats.html @@ -464,7 +464,7 @@ -

(static) statsCheck(env)

+

(static) statsCheck(env) → {Object|boolean|string}

@@ -594,8 +594,32 @@ hooks chat commands checking for /stats
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -815,13 +839,13 @@ hooks chat commands checking for /stats
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-ping.html b/documentation/module-ping.html index eb93b1a..535a230 100644 --- a/documentation/module-ping.html +++ b/documentation/module-ping.html @@ -467,13 +467,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-reload.html b/documentation/module-reload.html index 7ebbebb..56fa67b 100644 --- a/documentation/module-reload.html +++ b/documentation/module-reload.html @@ -486,7 +486,7 @@
Source:
@@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-removemod.html b/documentation/module-removemod.html index 3611d20..1fd4f85 100644 --- a/documentation/module-removemod.html +++ b/documentation/module-removemod.html @@ -486,7 +486,7 @@
Source:
@@ -559,7 +559,7 @@
Source:
@@ -589,13 +589,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-saveconfig.html b/documentation/module-saveconfig.html index 00bfd34..eda4496 100644 --- a/documentation/module-saveconfig.html +++ b/documentation/module-saveconfig.html @@ -486,7 +486,7 @@
Source:
@@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-session.html b/documentation/module-session.html index 1ebaa0b..be1c462 100644 --- a/documentation/module-session.html +++ b/documentation/module-session.html @@ -161,6 +161,10 @@ +
+ Get a new json web token for the provided socket +
+ @@ -274,7 +278,7 @@
Source:
@@ -429,7 +433,7 @@
Source:
@@ -584,7 +588,7 @@
Source:
@@ -645,6 +649,10 @@ +
+ Reply to target socket with session failure notice +
+ @@ -758,7 +766,7 @@
Source:
@@ -989,7 +997,7 @@
Source:
@@ -1019,13 +1027,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-shout.html b/documentation/module-shout.html index 4cdbbfb..61ad2a9 100644 --- a/documentation/module-shout.html +++ b/documentation/module-shout.html @@ -589,13 +589,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-socketreply.html b/documentation/module-socketreply.html index 9cb906a..55fc9f4 100644 --- a/documentation/module-socketreply.html +++ b/documentation/module-socketreply.html @@ -590,13 +590,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-speak.html b/documentation/module-speak.html index 1db6710..833b986 100644 --- a/documentation/module-speak.html +++ b/documentation/module-speak.html @@ -584,6 +584,29 @@ + + + aliases + + + + + +Array + + + + + + + + + + An array of alternative cmd names + + + + usage @@ -671,13 +694,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-stats.html b/documentation/module-stats.html index 3a11bab..209eded 100644 --- a/documentation/module-stats.html +++ b/documentation/module-stats.html @@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-unban.html b/documentation/module-unban.html index e455524..ce37d42 100644 --- a/documentation/module-unban.html +++ b/documentation/module-unban.html @@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-unbanall.html b/documentation/module-unbanall.html index 408a449..fface1a 100644 --- a/documentation/module-unbanall.html +++ b/documentation/module-unbanall.html @@ -516,13 +516,13 @@
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/module-unlockroom.html b/documentation/module-unlockroom.html new file mode 100644 index 0000000..508ba70 --- /dev/null +++ b/documentation/module-unlockroom.html @@ -0,0 +1,686 @@ + + + + + JSDoc: Module: unlockroom + + + + + + + + + + +
+ +

Module: unlockroom

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Unlocks a channel allowing anyone to join
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • 1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • Marzavec ( https://github.com/marzavec )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) init(core) → {void}

+ + + + + + +
+ Automatically executes once after server is ready +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
core + + +Object + + + + Reference to core enviroment object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

unlockroom/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-updateMessage.html b/documentation/module-updateMessage.html new file mode 100644 index 0000000..6d87c8e --- /dev/null +++ b/documentation/module-updateMessage.html @@ -0,0 +1,604 @@ + + + + + JSDoc: Module: updateMessage + + + + + + + + + + +
+ +

Module: updateMessage

+ + + + + + +
+ +
+ + + + + +
+ +
+
+ + +
Will alter a previously sent message using that message's customId
+ + + + + + + + + + + + + + + + + + + +
+ + +
Version:
+
  • v1.0.0
+ + + + + + + + + + + + + + + + + +
Author:
+
+
    +
  • MinusGix ( https://github.com/MinusGix )
  • +
+
+ + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) run(env) → {void}

+ + + + + + +
+ Executes when invoked by a remote client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
env + + +Object + + + + Enviroment object with references to core, server, socket & payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +void + + +
+
+ + + + + + + + + + + +

Type Definitions

+ + + +

addmod/requiredData

+ + + + +
+ The following payload properties are required to invoke this module: +"text", "customId" +
+ + + +
Type:
+
    +
  • + +Array + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

updateMessage/info

+ + + + +
+ Module meta information +
+ + + +
Type:
+
    +
  • + +Object + + +
  • +
+ + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
name + + +string + + + + Module command name
category + + +string + + + + Module category name
description + + +string + + + + Information about module
usage + + +string + + + + Information about module usage
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time) +
+ + + + + \ No newline at end of file diff --git a/documentation/module-whisper.html b/documentation/module-whisper.html index dfaa035..3da3aa1 100644 --- a/documentation/module-whisper.html +++ b/documentation/module-whisper.html @@ -472,7 +472,7 @@ -

(static) whisperCheck(env)

+

(static) whisperCheck(env) → {Object|boolean|string}

@@ -602,8 +602,32 @@ hooks chat commands checking for /whisper
Returns:
+
+ Object = same/altered payload, +false = suppress action, +string = error +
+ +
+
+ Type +
+
+ +Object +| + +boolean +| + +string + + +
+
+ @@ -896,13 +920,13 @@ hooks chat commands checking for /whisper
- Documentation generated by JSDoc 3.6.10 on Thu May 05 2022 00:29:35 GMT-0700 (Pacific Daylight Time) + Documentation generated by JSDoc 3.6.10 on Fri Dec 29 2023 23:22:35 GMT-0800 (Pacific Standard Time)
diff --git a/documentation/scripts/linenumber.js b/documentation/scripts/linenumber.js index f355ce2..4354785 100644 --- a/documentation/scripts/linenumber.js +++ b/documentation/scripts/linenumber.js @@ -1,25 +1,25 @@ -/* global document */ +/*global document */ (() => { - const source = document.getElementsByClassName('prettyprint source linenums'); - let i = 0; - let lineNumber = 0; - let lineId; - let lines; - let totalLines; - let anchorHash; + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; - if (source && source[0]) { - anchorHash = document.location.hash.substring(1); - lines = source[0].getElementsByTagName('li'); - totalLines = lines.length; + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; - for (; i < totalLines; i++) { - lineNumber++; - lineId = `line${lineNumber}`; - lines[i].id = lineId; - if (lineId === anchorHash) { - lines[i].className += ' selected'; - } + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } } - } })(); diff --git a/documentation/scripts/prettify/lang-css.js b/documentation/scripts/prettify/lang-css.js index b258dc8..041e1f5 100644 --- a/documentation/scripts/prettify/lang-css.js +++ b/documentation/scripts/prettify/lang-css.js @@ -1,2 +1,2 @@ -PR.registerLangHandler(PR.createSimpleLexer([['pln', /^[\t\n\f\r ]+/, null, ' \t\r\n ']], [['str', /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], ['str', /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], ['lang-css-str', /^url\(([^"')]*)\)/i], ['kwd', /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, null], ['lang-css-kw', /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i], ['com', /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], ['com', - /^(?:<\!--|--\>)/], ['lit', /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], ['lit', /^#[\da-f]{3,6}/i], ['pln', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], ['pun', /^[^\s\w"']+/]]), ['css']); PR.registerLangHandler(PR.createSimpleLexer([], [['kwd', /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]), ['css-kw']); PR.registerLangHandler(PR.createSimpleLexer([], [['str', /^[^"')]+/]]), ['css-str']); +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/documentation/scripts/prettify/prettify.js b/documentation/scripts/prettify/prettify.js index bf2f003..eef5ad7 100644 --- a/documentation/scripts/prettify/prettify.js +++ b/documentation/scripts/prettify/prettify.js @@ -1,125 +1,28 @@ -const q = null; window.PR_SHOULD_USE_CONTINUATION = !0; -(function () { - function L(a) { - function m(a) { let f = a.charCodeAt(0); if (f !== 92) return f; const b = a.charAt(1); return (f = r[b]) ? f : b >= '0' && b <= '7' ? parseInt(a.substring(1), 8) : b === 'u' || b === 'x' ? parseInt(a.substring(2), 16) : a.charCodeAt(1); } function e(a) { if (a < 32) return (a < 16 ? '\\x0' : '\\x') + a.toString(16); a = String.fromCharCode(a); if (a === '\\' || a === '-' || a === '[' || a === ']')a = `\\${a}`; return a; } function h(a) { - for (var f = a.substring(1, a.length - 1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g), a = [], b = [], o = f[0] === '^', c = o ? 1 : 0, i = f.length; c < i; ++c) { var j = f[c]; if (/\\[bdsw]/i.test(j))a.push(j); else { var j = m(j); var d; c + 2 < i && f[c + 1] === '-' ? (d = m(f[c + 2]), c += 2) : d = j; b.push([j, d]); d < 65 || j > 122 || (d < 65 || j > 90 || b.push([Math.max(65, j) | 32, Math.min(d, 90) | 32]), d < 97 || j > 122 || b.push([Math.max(97, j) & -33, Math.min(d, 122) & -33])); } }b.sort((a, f) => a[0] - f[0] || f[1] - a[1]); f = []; j = [NaN, NaN]; for (c = 0; c < b.length; ++c)i = b[c], i[0] <= j[1] + 1 ? j[1] = Math.max(j[1], i[1]) : f.push(j = i); b = ['[']; o && b.push('^'); b.push.apply(b, a); for (c = 0; c -< f.length; ++c)i = f[c], b.push(e(i[0])), i[1] > i[0] && (i[1] + 1 > i[0] && b.push('-'), b.push(e(i[1]))); b.push(']'); return b.join(''); - } function y(a) { - for (var f = a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g), b = f.length, d = [], c = 0, i = 0; c < b; ++c) { var j = f[c]; j === '(' ? ++i : j.charAt(0) === '\\' && (j = +j.substring(1)) && j <= i && (d[j] = -1); } for (c = 1; c < d.length; ++c)d[c] === -1 && (d[c] = ++t); for (i = c = 0; c < b; ++c) { - j = f[c], j === '(' ? (++i, d[i] === void 0 && (f[c] = '(?:')) : j.charAt(0) === '\\' -&& (j = +j.substring(1)) && j <= i && (f[c] = `\\${d[i]}`); - } for (i = c = 0; c < b; ++c)f[c] === '^' && f[c + 1] !== '^' && (f[c] = ''); if (a.ignoreCase && s) for (c = 0; c < b; ++c)j = f[c], a = j.charAt(0), j.length >= 2 && a === '[' ? f[c] = h(j) : a !== '\\' && (f[c] = j.replace(/[A-Za-z]/g, (a) => { a = a.charCodeAt(0); return `[${String.fromCharCode(a & -33, a | 32)}]`; })); return f.join(''); - } for (var t = 0, s = !1, l = !1, p = 0, d = a.length; p < d; ++p) { var g = a[p]; if (g.ignoreCase)l = !0; else if (/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, ''))) { s = !0; l = !1; break; } } for (var r = { - b: 8, t: 9, n: 10, v: 11, f: 12, r: 13, - }, n = [], p = 0, d = a.length; p < d; ++p) { g = a[p]; if (g.global || g.multiline) throw Error(`${g}`); n.push(`(?:${y(g)})`); } return RegExp(n.join('|'), l ? 'gi' : 'g'); - } function M(a) { - function m(a) { - switch (a.nodeType) { - case 1: if (e.test(a.className)) break; for (var g = a.firstChild; g; g = g.nextSibling)m(g); g = a.nodeName; if (g === 'BR' || g === 'LI')h[s] = '\n', t[s << 1] = y++, t[s++ << 1 | 1] = a; break; case 3: case 4: g = a.nodeValue, g.length && (g = p ? g.replace(/\r\n?/g, '\n') : g.replace(/[\t\n\r ]+/g, ' '), h[s] = g, t[s << 1] = y, y += g.length, - t[s++ << 1 | 1] = a); - } - } var e = /(?:^|\s)nocode(?:\s|$)/; var h = []; var y = 0; var t = []; var s = 0; let l; a.currentStyle ? l = a.currentStyle.whiteSpace : window.getComputedStyle && (l = document.defaultView.getComputedStyle(a, q).getPropertyValue('white-space')); var p = l && l.substring(0, 3) === 'pre'; m(a); return { a: h.join('').replace(/\n$/, ''), c: t }; - } function B(a, m, e, h) { m && (a = { a: m, d: a }, e(a), h.push.apply(h, a.e)); } function x(a, m) { - function e(a) { - for (var l = a.d, p = [l, 'pln'], d = 0, g = a.a.match(y) || [], r = {}, n = 0, z = g.length; n < z; ++n) { - const f = g[n]; let b = r[f]; let o = void 0; var c; if (typeof b -=== 'string')c = !1; else { var i = h[f.charAt(0)]; if (i)o = f.match(i[1]), b = i[0]; else { for (c = 0; c < t; ++c) if (i = m[c], o = f.match(i[1])) { b = i[0]; break; }o || (b = 'pln'); } if ((c = b.length >= 5 && b.substring(0, 5) === 'lang-') && !(o && typeof o[1] === 'string'))c = !1, b = 'src'; c || (r[f] = b); }i = d; d += f.length; if (c) { c = o[1]; let j = f.indexOf(c); let k = j + c.length; o[2] && (k = f.length - o[2].length, j = k - c.length); b = b.substring(5); B(l + i, f.substring(0, j), e, p); B(l + i + j, c, C(b, c), p); B(l + i + k, f.substring(k), e, p); } else p.push(l + i, b); - }a.e = p; - } var h = {}; let y; (function () { - for (var e = a.concat(m), - l = [], p = {}, d = 0, g = e.length; d < g; ++d) { let r = e[d]; let n = r[3]; if (n) for (let k = n.length; --k >= 0;)h[n.charAt(k)] = r; r = r[1]; n = `${r}`; p.hasOwnProperty(n) || (l.push(r), p[n] = q); }l.push(/[\S\s]/); y = L(l); - }()); var t = m.length; return e; - } function u(a) { - const m = []; const e = []; a.tripleQuotedStrings ? m.push(['str', /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, q, "'\""]) : a.multiLineStrings ? m.push(['str', /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, - q, "'\"`"]) : m.push(['str', /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, q, "\"'"]); a.verbatimStrings && e.push(['str', /^@"(?:[^"]|"")*(?:"|$)/, q]); let h = a.hashComments; h && (a.cStyleComments ? (h > 1 ? m.push(['com', /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, '#']) : m.push(['com', /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/, q, '#']), e.push(['str', /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, q])) : m.push(['com', /^#[^\n\r]*/, - q, '#'])); a.cStyleComments && (e.push(['com', /^\/\/[^\n\r]*/, q]), e.push(['com', /^\/\*[\S\s]*?(?:\*\/|$)/, q])); a.regexLiterals && e.push(['lang-regex', /^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]); (h = a.types) && e.push(['typ', h]); a = (`${a.keywords}`).replace( - /^ | $/g, - '', - ); a.length && e.push(['kwd', RegExp(`^(?:${a.replace(/[\s,]+/g, '|')})\\b`), q]); m.push(['pln', /^\s+/, q, ' \r\n\t\xa0']); e.push(['lit', /^@[$_a-z][\w$@]*/i, q], ['typ', /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], ['pln', /^[$_a-z][\w$@]*/i, q], ['lit', /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, q, '0123456789'], ['pln', /^\\[\S\s]?/, q], ['pun', /^.[^\s\w"-$'./@\\`]*/, q]); return x(m, e); - } function D(a, m) { - function e(a) { - switch (a.nodeType) { - case 1: if (k.test(a.className)) break; if (a.nodeName === 'BR') { - h(a), - a.parentNode && a.parentNode.removeChild(a); - } else for (a = a.firstChild; a; a = a.nextSibling)e(a); break; case 3: case 4: if (p) { let b = a.nodeValue; const d = b.match(t); if (d) { const c = b.substring(0, d.index); a.nodeValue = c; (b = b.substring(d.index + d[0].length)) && a.parentNode.insertBefore(s.createTextNode(b), a.nextSibling); h(a); c || a.parentNode.removeChild(a); } } - } - } function h(a) { - function b(a, d) { const e = d ? a.cloneNode(!1) : a; var f = a.parentNode; if (f) { var f = b(f, 1); let g = a.nextSibling; f.appendChild(e); for (let h = g; h; h = g)g = h.nextSibling, f.appendChild(h); } return e; } - for (;!a.nextSibling;) if (a = a.parentNode, !a) return; for (var a = b(a.nextSibling, 0), e; (e = a.parentNode) && e.nodeType === 1;)a = e; d.push(a); - } var k = /(?:^|\s)nocode(?:\s|$)/; var t = /\r\n?|\n/; var s = a.ownerDocument; let l; a.currentStyle ? l = a.currentStyle.whiteSpace : window.getComputedStyle && (l = s.defaultView.getComputedStyle(a, q).getPropertyValue('white-space')); var p = l && l.substring(0, 3) === 'pre'; for (l = s.createElement('LI'); a.firstChild;)l.appendChild(a.firstChild); for (var d = [l], g = 0; g < d.length; ++g)e(d[g]); m === (m | 0) && d[0].setAttribute( - 'value', - m, - ); const r = s.createElement('OL'); r.className = 'linenums'; for (var n = Math.max(0, m - 1 | 0) || 0, g = 0, z = d.length; g < z; ++g)l = d[g], l.className = `L${(g + n) % 10}`, l.firstChild || l.appendChild(s.createTextNode('\xa0')), r.appendChild(l); a.appendChild(r); - } function k(a, m) { for (let e = m.length; --e >= 0;) { const h = m[e]; A.hasOwnProperty(h) ? window.console && console.warn('cannot override language handler %s', h) : A[h] = a; } } function C(a, m) { if (!a || !A.hasOwnProperty(a))a = /^\s*= o && (h += 2); e >= c && (a += 2); - } - } catch (w) { 'console' in window && console.log(w && w.stack ? w.stack : w); } - } var v = ['break,continue,do,else,for,if,return,while']; var w = [[v, 'auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile'], - 'catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof']; const F = [w, 'alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where']; const G = [w, 'abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient']; - const H = [G, 'as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var']; var w = [w, 'debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN']; const I = [v, 'and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None']; - const J = [v, 'alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END']; var v = [v, 'case,done,elif,esac,eval,fi,function,in,local,set,then,until']; const K = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/; const N = /\S/; const O = u({ - keywords: [F, H, w, `caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END${ - I}`, J, v], - hashComments: !0, - cStyleComments: !0, - multiLineStrings: !0, - regexLiterals: !0, - }); var A = {}; k(O, ['default-code']); k( - x([], [['pln', /^[^]*(?:>|$)/], ['com', /^<\!--[\S\s]*?(?:--\>|$)/], ['lang-', /^<\?([\S\s]+?)(?:\?>|$)/], ['lang-', /^<%([\S\s]+?)(?:%>|$)/], ['pun', /^(?:<[%?]|[%?]>)/], ['lang-', /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], ['lang-js', /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], ['lang-css', /^]*>([\S\s]*?)(<\/style\b[^>]*>)/i], ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i]]), - ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl'], - ); k(x([['pln', /^\s+/, q, ' \t\r\n'], ['atv', /^(?:"[^"]*"?|'[^']*'?)/, q, "\"'"]], [['tag', /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], ['atn', /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], ['lang-uq.val', /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], ['pun', /^[/<->]+/], ['lang-js', /^on\w+\s*=\s*"([^"]+)"/i], ['lang-js', /^on\w+\s*=\s*'([^']+)'/i], ['lang-js', /^on\w+\s*=\s*([^\s"'>]+)/i], ['lang-css', /^style\s*=\s*"([^"]+)"/i], ['lang-css', /^style\s*=\s*'([^']+)'/i], ['lang-css', - /^style\s*=\s*([^\s"'>]+)/i]]), ['in.tag']); k(x([], [['atv', /^[\S\s]+/]]), ['uq.val']); k(u({ - keywords: F, hashComments: !0, cStyleComments: !0, types: K, - }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']); k(u({ keywords: 'null,true,false' }), ['json']); k(u({ - keywords: H, hashComments: !0, cStyleComments: !0, verbatimStrings: !0, types: K, - }), ['cs']); k(u({ keywords: G, cStyleComments: !0 }), ['java']); k(u({ keywords: v, hashComments: !0, multiLineStrings: !0 }), ['bsh', 'csh', 'sh']); k( - u({ - keywords: I, hashComments: !0, multiLineStrings: !0, tripleQuotedStrings: !0, - }), - ['cv', 'py'], - ); k(u({ - keywords: 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END', hashComments: !0, multiLineStrings: !0, regexLiterals: !0, - }), ['perl', 'pl', 'pm']); k(u({ - keywords: J, hashComments: !0, multiLineStrings: !0, regexLiterals: !0, - }), ['rb']); k(u({ keywords: w, cStyleComments: !0, regexLiterals: !0 }), ['js']); k(u({ - keywords: 'all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes', - hashComments: 3, - cStyleComments: !0, - multilineStrings: !0, - tripleQuotedStrings: !0, - regexLiterals: !0, - }), ['coffee']); k(x([], [['str', /^[\S\s]+/]]), ['regex']); window.prettyPrintOne = function (a, m, e) { const h = document.createElement('PRE'); h.innerHTML = a; e && D(h, e); E({ g: m, i: e, h }); return h.innerHTML; }; window.prettyPrint = function (a) { - function m() { - for (let e = window.PR_SHOULD_USE_CONTINUATION ? l.now() + 250 : Infinity; p < h.length && l.now() < e; p++) { - const n = h[p]; var k = n.className; if (k.indexOf('prettyprint') >= 0) { - var k = k.match(g); var f; var b; if (b = !k) { b = n; for (var o = void 0, c = b.firstChild; c; c = c.nextSibling) var i = c.nodeType, o = i === 1 ? o ? b : c : i === 3 ? N.test(c.nodeValue) ? b : o : o; b = (f = o === b ? void 0 : o) && f.tagName === 'CODE'; }b && (k = f.className.match(g)); k && (k = k[1]); b = !1; for (o = n.parentNode; o; o = o.parentNode) if ((o.tagName === 'pre' || o.tagName === 'code' || o.tagName === 'xmp') && o.className && o.className.indexOf('prettyprint') >= 0) { b = !0; break; }b || ((b = (b = n.className.match(/\blinenums\b(?::(\d+))?/)) ? b[1] && b[1].length ? +b[1] : !0 : !1) && D(n, b), d = { g: k, h: n, i: b }, E(d)); - } - }p < h.length ? setTimeout( - m, - 250, - ) : a && a(); - } for (var e = [document.getElementsByTagName('pre'), document.getElementsByTagName('code'), document.getElementsByTagName('xmp')], h = [], k = 0; k < e.length; ++k) for (let t = 0, s = e[k].length; t < s; ++t)h.push(e[k][t]); var e = q; var l = Date; l.now || (l = { now() { return +new Date(); } }); var p = 0; let d; var g = /\blang(?:uage)?-([\w.]+)(?!\S)/; m(); - }; window.PR = { - createSimpleLexer: x, - registerLangHandler: k, - sourceDecorator: u, - PR_ATTRIB_NAME: 'atn', - PR_ATTRIB_VALUE: 'atv', - PR_COMMENT: 'com', - PR_DECLARATION: 'dec', - PR_KEYWORD: 'kwd', - PR_LITERAL: 'lit', - PR_NOCODE: 'nocode', - PR_PLAIN: 'pln', - PR_PUNCTUATION: 'pun', - PR_SOURCE: 'src', - PR_STRING: 'str', - PR_TAG: 'tag', - PR_TYPE: 'typ', - }; -}()); +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p

)CdQ3F!eKyF|9D2V!F-rhUpJ8J+l7g0OBBVM#THTI&O8)>EGR%u6Gd9D9pm5!S}%&6DxW}^f|7=Y zPoO3(pTZY#?(7(|!5}5Nn!D%DotZmlW)?smSMcEE<^aT$6gw#LlwubPI9BYTffL0! zyu-EPCnz{Y#ZR&1d{F!hr_NW!&#~mXis$jseXDo@U)-kR7sMBeUt-T&RQw9By@BF9 z3f?cpmw4m-R{RHncaC**(V--ipJ<~6LkW2fi6RVfh%vcYt9@z>&M0LBSf-Q|Et8wU zCt43_*JB)mHR71wb`K@~5Cizwp{`A2uuJ^_Bcl3k{7ree$8&@l?;^2nagS+NqCDBfkB?pJws=PbK~+A7|2 z{gCDJKI-i%m4LD$n{WIwWR|c+NRy`C1#)1sSBI7FiH6z-QkhY&Q_|%I3exQ zQ`X1M?cZH4^M&BSyr;2z$+^SZUMA*0001Z+HKHROw(}?!13=vX`$@Br+fGR zZ%e`5O6%Txi$Yrz0gF{}p>fY>OnlS0Uevf}oDXW;D{d2gcE<2)oFcV80@g$H)63L{HN*d{8kVzKVW(;E)$9N_%kx5Ku3R9WJbY?JW^G#k0Wdx>E$NBBVtKRLiL?sA*s%w`TdsNz1=+~FRNdB8&+@iBD0 zXFTC4C-8-Cwv(4U=LLQ~^Oa4^rG|OTr5?ItoaPMYxxh`%a*kVU z;HYGAjq6;IY{`*awo0DlOMw(hkrYdb(O28l;MYvSx*ChcQW4f^QL5UdE3HbqvbxB$pfSg`>Cj#;?~00;nMAg}==M6d%RaIhCe zARtS)01i=0um)3FSgr#ump{<1pq_<0a34Kp8x=7I1^|9 literal 0 HcmV?d00001 diff --git a/documentation/fonts/OpenSans-Regular-webfont.eot b/documentation/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..6bbc3cf58cb011a6b4bf3cb1612ce212608f7274 GIT binary patch literal 19836 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/fonts/OpenSans-Regular-webfont.woff b/documentation/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..e231183dce4c7b452afc9e7799586fd285e146f4 GIT binary patch literal 22660 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 ML;wL%uV=LY00kR;TmS$7 literal 0 HcmV?d00001 diff --git a/documentation/index.html b/documentation/index.html new file mode 100644 index 0000000..2c1c319 --- /dev/null +++ b/documentation/index.html @@ -0,0 +1,105 @@ + + + + + JSDoc: Home + + + + + + + + + + +