From 922cd1dc546cff53bea268c166f7f6349aa00e60 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 19 Jan 2022 10:45:14 -0500 Subject: [PATCH] serve command (#451) --- package-lock.json | 1412 +++++++++++++++++++++++++-- package.json | 4 + src/commands/completion.command.ts | 2 +- src/commands/confirm.command.ts | 31 +- src/commands/create.command.ts | 98 +- src/commands/delete.command.ts | 46 +- src/commands/download.command.ts | 8 +- src/commands/edit.command.ts | 53 +- src/commands/encode.command.ts | 2 - src/commands/generate.command.ts | 86 +- src/commands/get.command.ts | 43 +- src/commands/list.command.ts | 101 +- src/commands/lock.command.ts | 4 +- src/commands/restore.command.ts | 8 +- src/commands/send/create.command.ts | 64 +- src/commands/send/edit.command.ts | 37 +- src/commands/send/get.command.ts | 8 +- src/commands/send/list.command.ts | 17 +- src/commands/serve.command.ts | 294 ++++++ src/commands/share.command.ts | 29 +- src/commands/status.command.ts | 2 - src/commands/sync.command.ts | 21 +- src/commands/unlock.command.ts | 26 +- src/program.ts | 19 +- src/utils.ts | 4 + src/vault.program.ts | 4 +- 26 files changed, 2091 insertions(+), 332 deletions(-) create mode 100644 src/commands/serve.command.ts diff --git a/package-lock.json b/package-lock.json index 8d96bee7fa..c907e05d27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,14 @@ "browser-hrtime": "^1.1.8", "chalk": "^4.1.1", "commander": "7.2.0", + "express": "^4.17.1", "form-data": "4.0.0", "https-proxy-agent": "5.0.0", "inquirer": "8.0.0", "jsdom": "^16.5.3", "lowdb": "1.0.0", "lunr": "^2.3.9", + "multer": "^1.4.3", "node-fetch": "^2.6.1", "node-forge": "0.10.0", "open": "^8.0.8", @@ -31,10 +33,12 @@ "bw": "build/bw.js" }, "devDependencies": { + "@types/express": "^4.17.13", "@types/inquirer": "^7.3.1", "@types/jsdom": "^16.2.10", "@types/lowdb": "^1.0.10", "@types/lunr": "^2.3.3", + "@types/multer": "^1.4.7", "@types/node": "^16.11.12", "@types/node-fetch": "^2.5.10", "@types/node-forge": "^0.9.7", @@ -237,6 +241,25 @@ "node": ">= 6" } }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz", @@ -263,6 +286,29 @@ "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "dev": true }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "node_modules/@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -327,12 +373,27 @@ "integrity": "sha512-09sXZZVsB3Ib41U0fC+O1O+4UOZT1bl/e+/QubPxpqDWHNEchvx/DEb1KJMOwq6K3MTNzZFoNSzVdR++o1DVnw==", "dev": true }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "node_modules/@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", "dev": true }, + "node_modules/@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/node": { "version": "16.11.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", @@ -387,6 +448,28 @@ "integrity": "sha512-oPwPSj4a1wu9rsXTEGIJz91ISU725t0BmSnUhb57sI+M8XEmvUop84lzuiYdq0Y5M6xLY8DBPg0C2xEQKLyvBA==", "dev": true }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "node_modules/@types/through": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz", @@ -613,6 +696,18 @@ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -766,6 +861,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "node_modules/aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -821,6 +921,11 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -916,6 +1021,39 @@ "readable-stream": "^3.4.0" } }, + "node_modules/body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", + "dependencies": { + "bytes": "3.1.1", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -998,8 +1136,7 @@ "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==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/builtin-modules": { "version": "1.1.1", @@ -1010,6 +1147,47 @@ "node": ">=0.10.0" } }, + "node_modules/busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "dependencies": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/busboy/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/busboy/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/busboy/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/bytes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001292", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001292.tgz", @@ -1251,12 +1429,85 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/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==", + "dependencies": { + "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" + } + }, + "node_modules/concat-stream/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/concat-stream/node_modules/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==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, "node_modules/copy-webpack-plugin": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.0.tgz", @@ -1340,8 +1591,7 @@ "node_modules/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=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "node_modules/cross-env": { "version": "7.0.3", @@ -1554,6 +1804,19 @@ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -1566,6 +1829,39 @@ "node": ">=0.10" } }, + "node_modules/dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "dependencies": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/dicer/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/dicer/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/dicer/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/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -1606,6 +1902,11 @@ "node": ">=8" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "node_modules/electron-to-chromium": { "version": "1.4.28", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.28.tgz", @@ -1626,6 +1927,14 @@ "node": ">= 4" } }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -1688,6 +1997,11 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -1779,6 +2093,14 @@ "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -1820,6 +2142,59 @@ "node": ">=6" } }, + "node_modules/express": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -1907,6 +2282,36 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -1933,6 +2338,22 @@ "node": ">= 6" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -2196,6 +2617,21 @@ "node": ">=10" } }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -2323,8 +2759,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", @@ -2380,6 +2815,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-core-module": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", @@ -2522,8 +2965,7 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "node_modules/isexe": { "version": "2.0.0", @@ -2967,6 +3409,14 @@ "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/memory-fs": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", @@ -3010,6 +3460,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3025,6 +3480,14 @@ "node": ">= 8" } }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", @@ -3038,6 +3501,17 @@ "node": ">=8.6" } }, + "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/mime-db": { "version": "1.48.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", @@ -3092,8 +3566,18 @@ "node_modules/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "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/mkdirp-classic": { "version": "0.5.3", @@ -3106,6 +3590,24 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/multer": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz", + "integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/multistream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", @@ -3141,6 +3643,14 @@ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -3260,7 +3770,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3274,6 +3783,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3407,6 +3927,14 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3446,6 +3974,11 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3633,8 +4166,7 @@ "node_modules/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==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/progress": { "version": "2.0.3", @@ -3645,6 +4177,18 @@ "node": ">=0.4.0" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -3671,6 +4215,17 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, + "node_modules/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3700,6 +4255,28 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", + "dependencies": { + "bytes": "3.1.1", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -3887,7 +4464,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -3938,6 +4514,47 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/send/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==" + }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -3947,12 +4564,31 @@ "randombytes": "^2.1.0" } }, + "node_modules/serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + }, + "engines": { + "node": ">= 0.8.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/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -4096,6 +4732,14 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/steno": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz", @@ -4143,6 +4787,14 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4443,6 +5095,14 @@ "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/tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -4662,18 +5322,6 @@ "node": ">=4.0.0" } }, - "node_modules/tslint-loader/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==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/tslint-loader/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -4751,18 +5399,6 @@ "node": ">=4" } }, - "node_modules/tslint/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==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/tslint/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -4842,6 +5478,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "node_modules/typescript": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", @@ -4864,6 +5517,14 @@ "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", @@ -4885,8 +5546,23 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } }, "node_modules/w3c-hr-time": { "version": "1.0.2", @@ -5237,6 +5913,14 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -5426,6 +6110,25 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/eslint": { "version": "8.2.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz", @@ -5452,6 +6155,29 @@ "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", "dev": true }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -5516,12 +6242,27 @@ "integrity": "sha512-09sXZZVsB3Ib41U0fC+O1O+4UOZT1bl/e+/QubPxpqDWHNEchvx/DEb1KJMOwq6K3MTNzZFoNSzVdR++o1DVnw==", "dev": true }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", "dev": true }, + "@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/node": { "version": "16.11.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz", @@ -5575,6 +6316,28 @@ "integrity": "sha512-oPwPSj4a1wu9rsXTEGIJz91ISU725t0BmSnUhb57sI+M8XEmvUop84lzuiYdq0Y5M6xLY8DBPg0C2xEQKLyvBA==", "dev": true }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "@types/through": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz", @@ -5788,6 +6551,15 @@ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, "acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -5890,6 +6662,11 @@ "color-convert": "^2.0.1" } }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -5947,6 +6724,11 @@ "sprintf-js": "~1.0.2" } }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -6010,6 +6792,38 @@ "readable-stream": "^3.4.0" } }, + "body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", + "requires": { + "bytes": "3.1.1", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" + }, + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -6065,8 +6879,7 @@ "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==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "builtin-modules": { "version": "1.1.1", @@ -6074,6 +6887,43 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "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" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "bytes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" + }, "caniuse-lite": { "version": "1.0.30001292", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001292.tgz", @@ -6244,12 +7094,75 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "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==", + "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" + } + }, + "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==" + }, + "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" + } + } + } + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, "copy-webpack-plugin": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.0.tgz", @@ -6304,8 +7217,7 @@ "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=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cross-env": { "version": "7.0.3", @@ -6468,12 +7380,54 @@ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "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" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -6504,6 +7458,11 @@ } } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "electron-to-chromium": { "version": "1.4.28", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.28.tgz", @@ -6521,6 +7480,11 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -6568,6 +7532,11 @@ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -6627,6 +7596,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, "events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -6656,6 +7630,58 @@ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true }, + "express": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -6728,6 +7754,35 @@ "to-regex-range": "^5.0.1" } }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -6748,6 +7803,16 @@ "mime-types": "^2.1.12" } }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, "from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -6967,6 +8032,18 @@ "whatwg-encoding": "^1.0.5" } }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, "http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -7047,8 +8124,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.8", @@ -7092,6 +8168,11 @@ "p-is-promise": "^3.0.0" } }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, "is-core-module": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", @@ -7192,8 +8273,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -7532,6 +8612,11 @@ "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, "memory-fs": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", @@ -7574,6 +8659,11 @@ } } }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -7586,6 +8676,11 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", @@ -7596,6 +8691,11 @@ "picomatch": "^2.2.3" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, "mime-db": { "version": "1.48.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", @@ -7632,8 +8732,15 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "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" + } }, "mkdirp-classic": { "version": "0.5.3", @@ -7646,6 +8753,21 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "multer": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz", + "integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + }, "multistream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", @@ -7667,6 +8789,11 @@ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", "dev": true }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, "neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -7771,8 +8898,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { "version": "1.12.0", @@ -7780,6 +8906,14 @@ "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "dev": true }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -7876,6 +9010,11 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7906,6 +9045,11 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -8039,8 +9183,7 @@ "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==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "progress": { "version": "2.0.3", @@ -8048,6 +9191,15 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -8074,6 +9226,11 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, + "qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -8089,6 +9246,22 @@ "safe-buffer": "^5.1.0" } }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", + "requires": { + "bytes": "3.1.1", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -8220,8 +9393,7 @@ "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==", - "dev": true + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safer-buffer": { "version": "2.1.2", @@ -8248,6 +9420,48 @@ "ajv-keywords": "^5.0.0" } }, + "send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.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" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, "serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -8257,12 +9471,28 @@ "randombytes": "^2.1.0" } }, + "serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + } + }, "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.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -8361,6 +9591,11 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, "steno": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz", @@ -8410,6 +9645,11 @@ } } }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -8625,6 +9865,11 @@ "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==" + }, "tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -8812,15 +10057,6 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -8877,15 +10113,6 @@ "json5": "^1.0.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==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -8942,6 +10169,20 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "typescript": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", @@ -8954,6 +10195,11 @@ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, + "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", @@ -8974,8 +10220,17 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "w3c-hr-time": { "version": "1.0.2", @@ -9221,6 +10476,11 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 15abfffaec..04b25a6f86 100644 --- a/package.json +++ b/package.json @@ -51,10 +51,12 @@ "assets": "./build/**/*" }, "devDependencies": { + "@types/express": "^4.17.13", "@types/inquirer": "^7.3.1", "@types/jsdom": "^16.2.10", "@types/lowdb": "^1.0.10", "@types/lunr": "^2.3.3", + "@types/multer": "^1.4.7", "@types/node": "^16.11.12", "@types/node-fetch": "^2.5.10", "@types/node-forge": "^0.9.7", @@ -83,12 +85,14 @@ "browser-hrtime": "^1.1.8", "chalk": "^4.1.1", "commander": "7.2.0", + "express": "^4.17.1", "form-data": "4.0.0", "https-proxy-agent": "5.0.0", "inquirer": "8.0.0", "jsdom": "^16.5.3", "lowdb": "1.0.0", "lunr": "^2.3.9", + "multer": "^1.4.3", "node-fetch": "^2.6.1", "node-forge": "0.10.0", "open": "^8.0.8", diff --git a/src/commands/completion.command.ts b/src/commands/completion.command.ts index 63d8a169d3..2deaef4903 100644 --- a/src/commands/completion.command.ts +++ b/src/commands/completion.command.ts @@ -23,7 +23,7 @@ export class CompletionCommand { const shell: typeof validShells[number] = options.shell; if (!shell) { - return Response.badRequest("`shell` was not provided."); + return Response.badRequest("`shell` option was not provided."); } if (!validShells.includes(shell)) { diff --git a/src/commands/confirm.command.ts b/src/commands/confirm.command.ts index 9607839184..3dbe7da760 100644 --- a/src/commands/confirm.command.ts +++ b/src/commands/confirm.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { ApiService } from "jslib-common/abstractions/api.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service"; @@ -12,35 +10,36 @@ import { Utils } from "jslib-common/misc/utils"; export class ConfirmCommand { constructor(private apiService: ApiService, private cryptoService: CryptoService) {} - async run(object: string, id: string, cmd: program.Command): Promise { + async run(object: string, id: string, cmdOptions: Record): Promise { if (id != null) { id = id.toLowerCase(); } + const normalizedOptions = new Options(cmdOptions); switch (object.toLowerCase()) { case "org-member": - return await this.confirmOrganizationMember(id, cmd); + return await this.confirmOrganizationMember(id, normalizedOptions); default: return Response.badRequest("Unknown object."); } } - private async confirmOrganizationMember(id: string, options: program.OptionValues) { - if (options.organizationid == null || options.organizationid === "") { + private async confirmOrganizationMember(id: string, options: Options) { + if (options.organizationId == null || options.organizationId === "") { return Response.badRequest("--organizationid required."); } if (!Utils.isGuid(id)) { - return Response.error("`" + id + "` is not a GUID."); + return Response.badRequest("`" + id + "` is not a GUID."); } - if (!Utils.isGuid(options.organizationid)) { - return Response.error("`" + options.organizationid + "` is not a GUID."); + if (!Utils.isGuid(options.organizationId)) { + return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } try { - const orgKey = await this.cryptoService.getOrgKey(options.organizationid); + const orgKey = await this.cryptoService.getOrgKey(options.organizationId); if (orgKey == null) { throw new Error("No encryption key for this organization."); } - const orgUser = await this.apiService.getOrganizationUser(options.organizationid, id); + const orgUser = await this.apiService.getOrganizationUser(options.organizationId, id); if (orgUser == null) { throw new Error("Member id does not exist for this organization."); } @@ -49,10 +48,18 @@ export class ConfirmCommand { const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer); const req = new OrganizationUserConfirmRequest(); req.key = key.encryptedString; - await this.apiService.postOrganizationUserConfirm(options.organizationid, id, req); + await this.apiService.postOrganizationUserConfirm(options.organizationId, id, req); return Response.success(); } catch (e) { return Response.error(e); } } } + +class Options { + organizationId: string; + + constructor(passedOptions: Record) { + this.organizationId = passedOptions.organizationid || passedOptions.organizationId; + } +} diff --git a/src/commands/create.command.ts b/src/commands/create.command.ts index c2c5412633..0451620c67 100644 --- a/src/commands/create.command.ts +++ b/src/commands/create.command.ts @@ -1,4 +1,3 @@ -import * as program from "commander"; import * as fs from "fs"; import * as path from "path"; @@ -36,10 +35,15 @@ export class CreateCommand { private apiService: ApiService ) {} - async run(object: string, requestJson: string, cmd: program.Command): Promise { + async run( + object: string, + requestJson: string, + cmdOptions: Record, + additionalData: any = null + ): Promise { let req: any = null; if (object !== "attachment") { - if (requestJson == null || requestJson === "") { + if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) { requestJson = await CliUtils.readStdin(); } @@ -47,23 +51,28 @@ export class CreateCommand { return Response.badRequest("`requestJson` was not provided."); } - try { - const reqJson = Buffer.from(requestJson, "base64").toString(); - req = JSON.parse(reqJson); - } catch (e) { - return Response.badRequest("Error parsing the encoded request data."); + if (typeof requestJson !== "string") { + req = requestJson; + } else { + try { + const reqJson = Buffer.from(requestJson, "base64").toString(); + req = JSON.parse(reqJson); + } catch (e) { + return Response.badRequest("Error parsing the encoded request data."); + } } } + const normalizedOptions = new Options(cmdOptions); switch (object.toLowerCase()) { case "item": return await this.createCipher(req); case "attachment": - return await this.createAttachment(cmd); + return await this.createAttachment(normalizedOptions, additionalData); case "folder": return await this.createFolder(req); case "org-collection": - return await this.createOrganizationCollection(req, cmd); + return await this.createOrganizationCollection(req, normalizedOptions); default: return Response.badRequest("Unknown object."); } @@ -82,19 +91,35 @@ export class CreateCommand { } } - private async createAttachment(options: program.OptionValues) { - if (options.itemid == null || options.itemid === "") { - return Response.badRequest("--itemid required."); + private async createAttachment(options: Options, additionalData: any) { + if (options.itemId == null || options.itemId === "") { + return Response.badRequest("`itemid` option is required."); } - if (options.file == null || options.file === "") { - return Response.badRequest("--file required."); - } - const filePath = path.resolve(options.file); - if (!fs.existsSync(options.file)) { - return Response.badRequest("Cannot find file at " + filePath); + let fileBuf: Buffer = null; + let fileName: string = null; + if (process.env.BW_SERVE === "true") { + fileBuf = additionalData.fileBuffer; + fileName = additionalData.fileName; + } else { + if (options.file == null || options.file === "") { + return Response.badRequest("`file` option is required."); + } + const filePath = path.resolve(options.file); + if (!fs.existsSync(options.file)) { + return Response.badRequest("Cannot find file at " + filePath); + } + fileBuf = fs.readFileSync(filePath); + fileName = path.basename(filePath); } - const itemId = options.itemid.toLowerCase(); + if (fileBuf == null) { + return Response.badRequest("File not provided."); + } + if (fileName == null || fileName.trim() === "") { + return Response.badRequest("File name not provided."); + } + + const itemId = options.itemId.toLowerCase(); const cipher = await this.cipherService.get(itemId); if (cipher == null) { return Response.notFound(); @@ -113,16 +138,14 @@ export class CreateCommand { } try { - const fileBuf = fs.readFileSync(filePath); await this.cipherService.saveAttachmentRawWithServer( cipher, - path.basename(filePath), + fileName, new Uint8Array(fileBuf).buffer ); const updatedCipher = await this.cipherService.get(cipher.id); const decCipher = await updatedCipher.decrypt(); const res = new CipherResponse(decCipher); - return Response.success(res); } catch (e) { return Response.error(e); } @@ -141,18 +164,15 @@ export class CreateCommand { } } - private async createOrganizationCollection( - req: OrganizationCollectionRequest, - options: program.OptionValues - ) { - if (options.organizationid == null || options.organizationid === "") { - return Response.badRequest("--organizationid required."); + private async createOrganizationCollection(req: OrganizationCollectionRequest, options: Options) { + if (options.organizationId == null || options.organizationId === "") { + return Response.badRequest("`organizationid` option is required."); } - if (!Utils.isGuid(options.organizationid)) { - return Response.error("`" + options.organizationid + "` is not a GUID."); + if (!Utils.isGuid(options.organizationId)) { + return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } - if (options.organizationid !== req.organizationId) { - return Response.error("--organizationid does not match request object."); + if (options.organizationId !== req.organizationId) { + return Response.badRequest("`organizationid` option does not match request object."); } try { const orgKey = await this.cryptoService.getOrgKey(req.organizationId); @@ -178,3 +198,15 @@ export class CreateCommand { } } } + +class Options { + itemId: string; + organizationId: string; + file: string; + + constructor(passedOptions: Record) { + this.organizationId = passedOptions.organizationid || passedOptions.organizationId; + this.itemId = passedOptions.itemid || passedOptions.itemId; + this.file = passedOptions.file; + } +} diff --git a/src/commands/delete.command.ts b/src/commands/delete.command.ts index 1fe88a5ba9..a0354f9299 100644 --- a/src/commands/delete.command.ts +++ b/src/commands/delete.command.ts @@ -8,6 +8,7 @@ import { StateService } from "jslib-common/abstractions/state.service"; import { Response } from "jslib-node/cli/models/response"; import { Utils } from "jslib-common/misc/utils"; +import { CliUtils } from "src/utils"; export class DeleteCommand { constructor( @@ -17,26 +18,27 @@ export class DeleteCommand { private apiService: ApiService ) {} - async run(object: string, id: string, cmd: program.Command): Promise { + async run(object: string, id: string, cmdOptions: Record): Promise { if (id != null) { id = id.toLowerCase(); } + const normalizedOptions = new Options(cmdOptions); switch (object.toLowerCase()) { case "item": - return await this.deleteCipher(id, cmd); + return await this.deleteCipher(id, normalizedOptions); case "attachment": - return await this.deleteAttachment(id, cmd); + return await this.deleteAttachment(id, normalizedOptions); case "folder": return await this.deleteFolder(id); case "org-collection": - return await this.deleteOrganizationCollection(id, cmd); + return await this.deleteOrganizationCollection(id, normalizedOptions); default: return Response.badRequest("Unknown object."); } } - private async deleteCipher(id: string, options: program.OptionValues) { + private async deleteCipher(id: string, options: Options) { const cipher = await this.cipherService.get(id); if (cipher == null) { return Response.notFound(); @@ -54,12 +56,12 @@ export class DeleteCommand { } } - private async deleteAttachment(id: string, options: program.OptionValues) { - if (options.itemid == null || options.itemid === "") { - return Response.badRequest("--itemid required."); + private async deleteAttachment(id: string, options: Options) { + if (options.itemId == null || options.itemId === "") { + return Response.badRequest("`itemid` option is required."); } - const itemId = options.itemid.toLowerCase(); + const itemId = options.itemId.toLowerCase(); const cipher = await this.cipherService.get(itemId); if (cipher == null) { return Response.notFound(); @@ -100,21 +102,33 @@ export class DeleteCommand { } } - private async deleteOrganizationCollection(id: string, options: program.OptionValues) { - if (options.organizationid == null || options.organizationid === "") { - return Response.badRequest("--organizationid required."); + private async deleteOrganizationCollection(id: string, options: Options) { + if (options.organizationId == null || options.organizationId === "") { + return Response.badRequest("`organizationid` options is required."); } if (!Utils.isGuid(id)) { - return Response.error("`" + id + "` is not a GUID."); + return Response.badRequest("`" + id + "` is not a GUID."); } - if (!Utils.isGuid(options.organizationid)) { - return Response.error("`" + options.organizationid + "` is not a GUID."); + if (!Utils.isGuid(options.organizationId)) { + return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } try { - await this.apiService.deleteCollection(options.organizationid, id); + await this.apiService.deleteCollection(options.organizationId, id); return Response.success(); } catch (e) { return Response.error(e); } } } + +class Options { + itemId: string; + organizationId: string; + permanent: boolean; + + constructor(passedOptions: Record) { + this.organizationId = passedOptions.organizationid || passedOptions.organizationId; + this.itemId = passedOptions.itemid || passedOptions.itemId; + this.permanent = CliUtils.convertBooleanOption(passedOptions.permanent); + } +} diff --git a/src/commands/download.command.ts b/src/commands/download.command.ts index 78c2050d34..610c2e1749 100644 --- a/src/commands/download.command.ts +++ b/src/commands/download.command.ts @@ -5,6 +5,7 @@ import { CryptoService } from "jslib-common/abstractions/crypto.service"; import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey"; import { Response } from "jslib-node/cli/models/response"; +import { FileResponse } from "jslib-node/cli/models/response/fileResponse"; import { CliUtils } from "../utils"; @@ -27,7 +28,12 @@ export abstract class DownloadCommand { try { const buf = await response.arrayBuffer(); const decBuf = await this.cryptoService.decryptFromBytes(buf, key); - return await CliUtils.saveResultToFile(Buffer.from(decBuf), output, fileName); + if (process.env.BW_SERVE === "true") { + const res = new FileResponse(Buffer.from(decBuf), fileName); + return Response.success(res); + } else { + return await CliUtils.saveResultToFile(Buffer.from(decBuf), output, fileName); + } } catch (e) { if (typeof e === "string") { return Response.error(e); diff --git a/src/commands/edit.command.ts b/src/commands/edit.command.ts index 7e2ed4b391..fa20300055 100644 --- a/src/commands/edit.command.ts +++ b/src/commands/edit.command.ts @@ -35,10 +35,10 @@ export class EditCommand { async run( object: string, id: string, - requestJson: string, - cmd: program.Command + requestJson: any, + cmdOptions: Record ): Promise { - if (requestJson == null || requestJson === "") { + if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) { requestJson = await CliUtils.readStdin(); } @@ -47,17 +47,22 @@ export class EditCommand { } let req: any = null; - try { - const reqJson = Buffer.from(requestJson, "base64").toString(); - req = JSON.parse(reqJson); - } catch (e) { - return Response.badRequest("Error parsing the encoded request data."); + if (typeof requestJson !== "string") { + req = requestJson; + } else { + try { + const reqJson = Buffer.from(requestJson, "base64").toString(); + req = JSON.parse(reqJson); + } catch (e) { + return Response.badRequest("Error parsing the encoded request data."); + } } if (id != null) { id = id.toLowerCase(); } + const normalizedOptions = new Options(cmdOptions); switch (object.toLowerCase()) { case "item": return await this.editCipher(id, req); @@ -66,7 +71,7 @@ export class EditCommand { case "folder": return await this.editFolder(id, req); case "org-collection": - return await this.editOrganizationCollection(id, req, cmd); + return await this.editOrganizationCollection(id, req, normalizedOptions); default: return Response.badRequest("Unknown object."); } @@ -80,9 +85,7 @@ export class EditCommand { let cipherView = await cipher.decrypt(); if (cipherView.isDeleted) { - return Response.badRequest( - "You may not edit a deleted cipher. Use restore item command first." - ); + return Response.badRequest("You may not edit a deleted item. Use the restore command first."); } cipherView = Cipher.toView(req, cipherView); const encCipher = await this.cipherService.encrypt(cipherView); @@ -104,7 +107,7 @@ export class EditCommand { } if (cipher.organizationId == null) { return Response.badRequest( - "Item does not belong to an organization. Consider sharing it first." + "Item does not belong to an organization. Consider moving it first." ); } @@ -143,19 +146,19 @@ export class EditCommand { private async editOrganizationCollection( id: string, req: OrganizationCollectionRequest, - options: program.OptionValues + options: Options ) { - if (options.organizationid == null || options.organizationid === "") { - return Response.badRequest("--organizationid required."); + if (options.organizationId == null || options.organizationId === "") { + return Response.badRequest("`organizationid` option is required."); } if (!Utils.isGuid(id)) { - return Response.error("`" + id + "` is not a GUID."); + return Response.badRequest("`" + id + "` is not a GUID."); } - if (!Utils.isGuid(options.organizationid)) { - return Response.error("`" + options.organizationid + "` is not a GUID."); + if (!Utils.isGuid(options.organizationId)) { + return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } - if (options.organizationid !== req.organizationId) { - return Response.error("--organizationid does not match request object."); + if (options.organizationId !== req.organizationId) { + return Response.badRequest("`organizationid` option does not match request object."); } try { const orgKey = await this.cryptoService.getOrgKey(req.organizationId); @@ -181,3 +184,11 @@ export class EditCommand { } } } + +class Options { + organizationId: string; + + constructor(passedOptions: Record) { + this.organizationId = passedOptions.organizationid || passedOptions.organizationId; + } +} diff --git a/src/commands/encode.command.ts b/src/commands/encode.command.ts index 1aadf6495d..c7de9a11b3 100644 --- a/src/commands/encode.command.ts +++ b/src/commands/encode.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { Response } from "jslib-node/cli/models/response"; import { StringResponse } from "jslib-node/cli/models/response/stringResponse"; diff --git a/src/commands/generate.command.ts b/src/commands/generate.command.ts index 908f555dae..f1b3688747 100644 --- a/src/commands/generate.command.ts +++ b/src/commands/generate.command.ts @@ -1,42 +1,27 @@ -import * as program from "commander"; - import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { Response } from "jslib-node/cli/models/response"; import { StringResponse } from "jslib-node/cli/models/response/stringResponse"; +import { CliUtils } from "../utils"; + export class GenerateCommand { constructor(private passwordGenerationService: PasswordGenerationService) {} - async run(cmdOptions: program.OptionValues): Promise { + async run(cmdOptions: Record): Promise { + const normalizedOptions = new Options(cmdOptions); const options = { - uppercase: cmdOptions.uppercase || false, - lowercase: cmdOptions.lowercase || false, - number: cmdOptions.number || false, - special: cmdOptions.special || false, - length: cmdOptions.length || 14, - type: cmdOptions.passphrase ? "passphrase" : "password", - wordSeparator: cmdOptions.separator == null ? "-" : cmdOptions.separator, - numWords: cmdOptions.words || 3, - capitalize: cmdOptions.capitalize || false, - includeNumber: cmdOptions.includeNumber || false, + uppercase: normalizedOptions.uppercase, + lowercase: normalizedOptions.lowercase, + number: normalizedOptions.number, + special: normalizedOptions.special, + length: normalizedOptions.length, + type: normalizedOptions.type, + wordSeparator: normalizedOptions.separator, + numWords: normalizedOptions.words, + capitalize: normalizedOptions.capitalize, + includeNumber: normalizedOptions.includeNumber, }; - if (!options.uppercase && !options.lowercase && !options.special && !options.number) { - options.lowercase = true; - options.uppercase = true; - options.number = true; - } - if (options.length < 5) { - options.length = 5; - } - if (options.numWords < 3) { - options.numWords = 3; - } - if (options.wordSeparator === "space") { - options.wordSeparator = " "; - } else if (options.wordSeparator != null && options.wordSeparator.length > 1) { - options.wordSeparator = options.wordSeparator[0]; - } const enforcedOptions = await this.passwordGenerationService.enforcePasswordGeneratorPoliciesOnOptions(options); const password = await this.passwordGenerationService.generatePassword(enforcedOptions[0]); @@ -44,3 +29,46 @@ export class GenerateCommand { return Response.success(res); } } + +class Options { + uppercase: boolean; + lowercase: boolean; + number: boolean; + special: boolean; + length: number; + type: "passphrase" | "password"; + separator: string; + words: number; + capitalize: boolean; + includeNumber: boolean; + + constructor(passedOptions: Record) { + this.uppercase = CliUtils.convertBooleanOption(passedOptions.uppercase); + this.lowercase = CliUtils.convertBooleanOption(passedOptions.lowercase); + this.number = CliUtils.convertBooleanOption(passedOptions.number); + this.special = CliUtils.convertBooleanOption(passedOptions.special); + this.capitalize = CliUtils.convertBooleanOption(passedOptions.capitalize); + this.includeNumber = CliUtils.convertBooleanOption(passedOptions.includeNumber); + this.length = passedOptions.length != null ? parseInt(passedOptions.length, null) : 14; + this.type = passedOptions.passphrase ? "passphrase" : "password"; + this.separator = passedOptions.separator == null ? "-" : passedOptions.separator + ""; + this.words = passedOptions.words != null ? parseInt(passedOptions.words, null) : 3; + + if (!this.uppercase && !this.lowercase && !this.special && !this.number) { + this.lowercase = true; + this.uppercase = true; + this.number = true; + } + if (this.length < 5) { + this.length = 5; + } + if (this.words < 3) { + this.words = 3; + } + if (this.separator === "space") { + this.separator = " "; + } else if (this.separator != null && this.separator.length > 1) { + this.separator = this.separator[0]; + } + } +} diff --git a/src/commands/get.command.ts b/src/commands/get.command.ts index 3884323f09..453a9c94b8 100644 --- a/src/commands/get.command.ts +++ b/src/commands/get.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { CipherType } from "jslib-common/enums/cipherType"; import { ApiService } from "jslib-common/abstractions/api.service"; @@ -71,11 +69,12 @@ export class GetCommand extends DownloadCommand { super(cryptoService); } - async run(object: string, id: string, options: program.OptionValues): Promise { + async run(object: string, id: string, cmdOptions: Record): Promise { if (id != null) { id = id.toLowerCase(); } + const normalizedOptions = new Options(cmdOptions); switch (object.toLowerCase()) { case "item": return await this.getCipher(id); @@ -92,13 +91,13 @@ export class GetCommand extends DownloadCommand { case "exposed": return await this.getExposed(id); case "attachment": - return await this.getAttachment(id, options); + return await this.getAttachment(id, normalizedOptions); case "folder": return await this.getFolder(id); case "collection": return await this.getCollection(id); case "org-collection": - return await this.getOrganizationCollection(id, options); + return await this.getOrganizationCollection(id, normalizedOptions); case "organization": return await this.getOrganization(id); case "template": @@ -292,12 +291,12 @@ export class GetCommand extends DownloadCommand { return Response.success(res); } - private async getAttachment(id: string, options: program.OptionValues) { - if (options.itemid == null || options.itemid === "") { + private async getAttachment(id: string, options: Options) { + if (options.itemId == null || options.itemId === "") { return Response.badRequest("--itemid required."); } - const itemId = options.itemid.toLowerCase(); + const itemId = options.itemId.toLowerCase(); const cipherResponse = await this.getCipher(itemId); if (!cipherResponse.success) { return cipherResponse; @@ -412,23 +411,23 @@ export class GetCommand extends DownloadCommand { return Response.success(res); } - private async getOrganizationCollection(id: string, options: program.OptionValues) { - if (options.organizationid == null || options.organizationid === "") { - return Response.badRequest("--organizationid required."); + private async getOrganizationCollection(id: string, options: Options) { + if (options.organizationId == null || options.organizationId === "") { + return Response.badRequest("`organizationid` option is required."); } if (!Utils.isGuid(id)) { - return Response.error("`" + id + "` is not a GUID."); + return Response.badRequest("`" + id + "` is not a GUID."); } - if (!Utils.isGuid(options.organizationid)) { - return Response.error("`" + options.organizationid + "` is not a GUID."); + if (!Utils.isGuid(options.organizationId)) { + return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } try { - const orgKey = await this.cryptoService.getOrgKey(options.organizationid); + const orgKey = await this.cryptoService.getOrgKey(options.organizationId); if (orgKey == null) { throw new Error("No encryption key for this organization."); } - const response = await this.apiService.getCollectionDetails(options.organizationid, id); + const response = await this.apiService.getCollectionDetails(options.organizationId, id); const decCollection = new CollectionView(response); decCollection.name = await this.cryptoService.decryptToUtf8( new EncString(response.name), @@ -536,3 +535,15 @@ export class GetCommand extends DownloadCommand { return Response.success(res); } } + +class Options { + itemId: string; + organizationId: string; + output: string; + + constructor(passedOptions: Record) { + this.organizationId = passedOptions.organizationid || passedOptions.organizationId; + this.itemId = passedOptions.itemid || passedOptions.itemId; + this.output = passedOptions.output; + } +} diff --git a/src/commands/list.command.ts b/src/commands/list.command.ts index bf1a59d292..c4066bce98 100644 --- a/src/commands/list.command.ts +++ b/src/commands/list.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { CipherView } from "jslib-common/models/view/cipherView"; import { ApiService } from "jslib-common/abstractions/api.service"; @@ -42,26 +40,27 @@ export class ListCommand { private apiService: ApiService ) {} - async run(object: string, cmd: program.Command): Promise { + async run(object: string, cmdOptions: Record): Promise { + const normalizedOptions = new Options(cmdOptions); switch (object.toLowerCase()) { case "items": - return await this.listCiphers(cmd); + return await this.listCiphers(normalizedOptions); case "folders": - return await this.listFolders(cmd); + return await this.listFolders(normalizedOptions); case "collections": - return await this.listCollections(cmd); + return await this.listCollections(normalizedOptions); case "org-collections": - return await this.listOrganizationCollections(cmd); + return await this.listOrganizationCollections(normalizedOptions); case "org-members": - return await this.listOrganizationMembers(cmd); + return await this.listOrganizationMembers(normalizedOptions); case "organizations": - return await this.listOrganizations(cmd); + return await this.listOrganizations(normalizedOptions); default: return Response.badRequest("Unknown object."); } } - private async listCiphers(options: program.OptionValues) { + private async listCiphers(options: Options) { let ciphers: CipherView[]; options.trash = options.trash || false; if (options.url != null && options.url.trim() !== "") { @@ -71,43 +70,43 @@ export class ListCommand { } if ( - options.folderid != null || - options.collectionid != null || - options.organizationid != null + options.folderId != null || + options.collectionId != null || + options.organizationId != null ) { ciphers = ciphers.filter((c) => { if (options.trash !== c.isDeleted) { return false; } - if (options.folderid != null) { - if (options.folderid === "notnull" && c.folderId != null) { + if (options.folderId != null) { + if (options.folderId === "notnull" && c.folderId != null) { return true; } - const folderId = options.folderid === "null" ? null : options.folderid; + const folderId = options.folderId === "null" ? null : options.folderId; if (folderId === c.folderId) { return true; } } - if (options.organizationid != null) { - if (options.organizationid === "notnull" && c.organizationId != null) { + if (options.organizationId != null) { + if (options.organizationId === "notnull" && c.organizationId != null) { return true; } - const organizationId = options.organizationid === "null" ? null : options.organizationid; + const organizationId = options.organizationId === "null" ? null : options.organizationId; if (organizationId === c.organizationId) { return true; } } - if (options.collectionid != null) { + if (options.collectionId != null) { if ( - options.collectionid === "notnull" && + options.collectionId === "notnull" && c.collectionIds != null && c.collectionIds.length > 0 ) { return true; } - const collectionId = options.collectionid === "null" ? null : options.collectionid; + const collectionId = options.collectionId === "null" ? null : options.collectionId; if (collectionId == null && (c.collectionIds == null || c.collectionIds.length === 0)) { return true; } @@ -133,7 +132,7 @@ export class ListCommand { return Response.success(res); } - private async listFolders(options: program.OptionValues) { + private async listFolders(options: Options) { let folders = await this.folderService.getAllDecrypted(); if (options.search != null && options.search.trim() !== "") { @@ -144,12 +143,12 @@ export class ListCommand { return Response.success(res); } - private async listCollections(options: program.OptionValues) { + private async listCollections(options: Options) { let collections = await this.collectionService.getAllDecrypted(); - if (options.organizationid != null) { + if (options.organizationId != null) { collections = collections.filter((c) => { - if (options.organizationid === c.organizationId) { + if (options.organizationId === c.organizationId) { return true; } return false; @@ -164,14 +163,14 @@ export class ListCommand { return Response.success(res); } - private async listOrganizationCollections(options: program.OptionValues) { - if (options.organizationid == null || options.organizationid === "") { - return Response.badRequest("--organizationid required."); + private async listOrganizationCollections(options: Options) { + if (options.organizationId == null || options.organizationId === "") { + return Response.badRequest("`organizationid` option is required."); } - if (!Utils.isGuid(options.organizationid)) { - return Response.error("`" + options.organizationid + "` is not a GUID."); + if (!Utils.isGuid(options.organizationId)) { + return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } - const organization = await this.organizationService.get(options.organizationid); + const organization = await this.organizationService.get(options.organizationId); if (organization == null) { return Response.error("Organization not found."); } @@ -179,12 +178,12 @@ export class ListCommand { try { let response: ApiListResponse; if (organization.canViewAllCollections) { - response = await this.apiService.getCollections(options.organizationid); + response = await this.apiService.getCollections(options.organizationId); } else { response = await this.apiService.getUserCollections(); } const collections = response.data - .filter((c) => c.organizationId === options.organizationid) + .filter((c) => c.organizationId === options.organizationId) .map((r) => new Collection(new CollectionData(r as ApiCollectionDetailsResponse))); let decCollections = await this.collectionService.decryptMany(collections); if (options.search != null && options.search.trim() !== "") { @@ -197,20 +196,20 @@ export class ListCommand { } } - private async listOrganizationMembers(options: program.OptionValues) { - if (options.organizationid == null || options.organizationid === "") { - return Response.badRequest("--organizationid required."); + private async listOrganizationMembers(options: Options) { + if (options.organizationId == null || options.organizationId === "") { + return Response.badRequest("`organizationid` option is required."); } - if (!Utils.isGuid(options.organizationid)) { - return Response.error("`" + options.organizationid + "` is not a GUID."); + if (!Utils.isGuid(options.organizationId)) { + return Response.badRequest("`" + options.organizationId + "` is not a GUID."); } - const organization = await this.organizationService.get(options.organizationid); + const organization = await this.organizationService.get(options.organizationId); if (organization == null) { return Response.error("Organization not found."); } try { - const response = await this.apiService.getOrganizationUsers(options.organizationid); + const response = await this.apiService.getOrganizationUsers(options.organizationId); const res = new ListResponse( response.data.map((r) => { const u = new OrganizationUserResponse(); @@ -229,7 +228,7 @@ export class ListCommand { } } - private async listOrganizations(options: program.OptionValues) { + private async listOrganizations(options: Options) { let organizations = await this.organizationService.getAll(); if (options.search != null && options.search.trim() !== "") { @@ -240,3 +239,21 @@ export class ListCommand { return Response.success(res); } } + +class Options { + organizationId: string; + collectionId: string; + folderId: string; + search: string; + url: string; + trash: boolean; + + constructor(passedOptions: Record) { + this.organizationId = passedOptions.organizationid || passedOptions.organizationId; + this.collectionId = passedOptions.collectionid || passedOptions.collectionId; + this.folderId = passedOptions.folderid || passedOptions.folderId; + this.search = passedOptions.search; + this.url = passedOptions.url; + this.trash = CliUtils.convertBooleanOption(passedOptions.trash); + } +} diff --git a/src/commands/lock.command.ts b/src/commands/lock.command.ts index dac3950102..4fc12412f0 100644 --- a/src/commands/lock.command.ts +++ b/src/commands/lock.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; import { Response } from "jslib-node/cli/models/response"; @@ -8,7 +6,7 @@ import { MessageResponse } from "jslib-node/cli/models/response/messageResponse" export class LockCommand { constructor(private vaultTimeoutService: VaultTimeoutService) {} - async run(cmd: program.Command) { + async run() { await this.vaultTimeoutService.lock(); process.env.BW_SESSION = null; const res = new MessageResponse("Your vault is locked.", null); diff --git a/src/commands/restore.command.ts b/src/commands/restore.command.ts index e7397d2808..1942a477e7 100644 --- a/src/commands/restore.command.ts +++ b/src/commands/restore.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { CipherService } from "jslib-common/abstractions/cipher.service"; import { Response } from "jslib-node/cli/models/response"; @@ -7,20 +5,20 @@ import { Response } from "jslib-node/cli/models/response"; export class RestoreCommand { constructor(private cipherService: CipherService) {} - async run(object: string, id: string, cmd: program.Command): Promise { + async run(object: string, id: string): Promise { if (id != null) { id = id.toLowerCase(); } switch (object.toLowerCase()) { case "item": - return await this.restoreCipher(id, cmd); + return await this.restoreCipher(id); default: return Response.badRequest("Unknown object."); } } - private async restoreCipher(id: string, cmd: program.Command) { + private async restoreCipher(id: string) { const cipher = await this.cipherService.get(id); if (cipher == null) { return Response.notFound(); diff --git a/src/commands/send/create.command.ts b/src/commands/send/create.command.ts index 48573859f4..c69ae81fd2 100644 --- a/src/commands/send/create.command.ts +++ b/src/commands/send/create.command.ts @@ -1,4 +1,3 @@ -import * as program from "commander"; import * as fs from "fs"; import * as path from "path"; @@ -11,7 +10,6 @@ import { SendType } from "jslib-common/enums/sendType"; import { NodeUtils } from "jslib-common/misc/nodeUtils"; import { Response } from "jslib-node/cli/models/response"; -import { StringResponse } from "jslib-node/cli/models/response/stringResponse"; import { SendResponse } from "../../models/response/sendResponse"; import { SendTextResponse } from "../../models/response/sendTextResponse"; @@ -25,9 +23,9 @@ export class SendCreateCommand { private environmentService: EnvironmentService ) {} - async run(requestJson: string, options: program.OptionValues) { + async run(requestJson: any, cmdOptions: Record) { let req: any = null; - if (requestJson == null || requestJson === "") { + if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) { requestJson = await CliUtils.readStdin(); } @@ -35,15 +33,19 @@ export class SendCreateCommand { return Response.badRequest("`requestJson` was not provided."); } - try { - const reqJson = Buffer.from(requestJson, "base64").toString(); - req = SendResponse.fromJson(reqJson); + if (typeof requestJson !== "string") { + req = requestJson; + } else { + try { + const reqJson = Buffer.from(requestJson, "base64").toString(); + req = SendResponse.fromJson(reqJson); - if (req == null) { - throw new Error("Null request"); + if (req == null) { + throw new Error("Null request"); + } + } catch (e) { + return Response.badRequest("Error parsing the encoded request data."); } - } catch (e) { - return Response.badRequest("Error parsing the encoded request data."); } if ( @@ -58,10 +60,11 @@ export class SendCreateCommand { return Response.badRequest("Unable to parse expirationDate: " + req.expirationDate); } - return this.createSend(req, options); + const normalizedOptions = new Options(cmdOptions); + return this.createSend(req, normalizedOptions); } - private async createSend(req: SendResponse, options: program.OptionValues) { + private async createSend(req: SendResponse, options: Options) { const filePath = req.file?.fileName ?? options.file; const text = req.text?.text ?? options.text; const hidden = req.text?.hidden ?? options.hidden; @@ -73,13 +76,19 @@ export class SendCreateCommand { switch (req.type) { case SendType.File: + if (process.env.BW_SERVE === "true") { + return Response.error( + "Creating a file-based Send is unsupported through the `serve` command at this time." + ); + } + if (!(await this.stateService.getCanAccessPremium())) { return Response.error("Premium status is required to use this feature."); } if (filePath == null) { return Response.badRequest( - "Must specify a file to Send either with the --file option or in the encoded json" + "Must specify a file to Send either with the --file option or in the request JSON." ); } @@ -88,7 +97,7 @@ export class SendCreateCommand { case SendType.Text: if (text == null) { return Response.badRequest( - "Must specify text content to Send either with the --text option or in the encoded json" + "Must specify text content to Send either with the --text option or in the request JSON." ); } req.text = new SendTextResponse(); @@ -97,7 +106,7 @@ export class SendCreateCommand { break; default: return Response.badRequest( - "Unknown Send type " + SendType[req.type] + "valid types are: file, text" + "Unknown Send type " + SendType[req.type] + ". Valid types are: file, text" ); } @@ -117,13 +126,26 @@ export class SendCreateCommand { const newSend = await this.sendService.get(encSend.id); const decSend = await newSend.decrypt(); const res = new SendResponse(decSend, this.environmentService.getWebVaultUrl()); - return Response.success( - options.fullObject - ? res - : new StringResponse("Send created! It can be accessed at:\n" + res.accessUrl) - ); + return Response.success(res); } catch (e) { return Response.error(e); } } } + +class Options { + file: string; + text: string; + maxAccessCount: number; + password: string; + hidden: boolean; + + constructor(passedOptions: Record) { + this.file = passedOptions.file; + this.text = passedOptions.text; + this.password = passedOptions.password; + this.hidden = CliUtils.convertBooleanOption(passedOptions.hidden); + this.maxAccessCount = + passedOptions.maxAccessCount != null ? parseInt(passedOptions.maxAccessCount, null) : null; + } +} diff --git a/src/commands/send/edit.command.ts b/src/commands/send/edit.command.ts index 9cc5311c64..388e62fee9 100644 --- a/src/commands/send/edit.command.ts +++ b/src/commands/send/edit.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { SendService } from "jslib-common/abstractions/send.service"; import { StateService } from "jslib-common/abstractions/state.service"; @@ -18,24 +16,29 @@ export class SendEditCommand { private getCommand: SendGetCommand ) {} - async run(encodedJson: string, options: program.OptionValues): Promise { - if (encodedJson == null || encodedJson === "") { - encodedJson = await CliUtils.readStdin(); + async run(requestJson: string, cmdOptions: Record): Promise { + if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) { + requestJson = await CliUtils.readStdin(); } - if (encodedJson == null || encodedJson === "") { - return Response.badRequest("`encodedJson` was not provided."); + if (requestJson == null || requestJson === "") { + return Response.badRequest("`requestJson` was not provided."); } let req: SendResponse = null; - try { - const reqJson = Buffer.from(encodedJson, "base64").toString(); - req = SendResponse.fromJson(reqJson); - } catch (e) { - return Response.badRequest("Error parsing the encoded request data."); + if (typeof requestJson !== "string") { + req = requestJson; + } else { + try { + const reqJson = Buffer.from(requestJson, "base64").toString(); + req = SendResponse.fromJson(reqJson); + } catch (e) { + return Response.badRequest("Error parsing the encoded request data."); + } } - req.id = options.itemid || req.id; + const normalizedOptions = new Options(cmdOptions); + req.id = normalizedOptions.itemId || req.id; if (req.id != null) { req.id = req.id.toLowerCase(); @@ -76,3 +79,11 @@ export class SendEditCommand { return await this.getCommand.run(send.id, {}); } } + +class Options { + itemId: string; + + constructor(passedOptions: Record) { + this.itemId = passedOptions.itemId || passedOptions.itemid; + } +} diff --git a/src/commands/send/get.command.ts b/src/commands/send/get.command.ts index bad46e16fc..1688a2e560 100644 --- a/src/commands/send/get.command.ts +++ b/src/commands/send/get.command.ts @@ -1,6 +1,5 @@ import * as program from "commander"; -import { ApiService } from "jslib-common/abstractions/api.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { SearchService } from "jslib-common/abstractions/search.service"; @@ -27,6 +26,11 @@ export class SendGetCommand extends DownloadCommand { } async run(id: string, options: program.OptionValues) { + const serveCommand = process.env.BW_SERVE === "true"; + if (serveCommand && !Utils.isGuid(id)) { + return Response.badRequest("`" + id + "` is not a GUID."); + } + let sends = await this.getSendView(id); if (sends == null) { return Response.notFound(); @@ -36,7 +40,7 @@ export class SendGetCommand extends DownloadCommand { let filter = (s: SendView) => true; let selector = async (s: SendView): Promise => Response.success(new SendResponse(s, webVaultUrl)); - if (options.text != null) { + if (!serveCommand && options?.text != null) { filter = (s) => { return filter(s) && s.text != null; }; diff --git a/src/commands/send/list.command.ts b/src/commands/send/list.command.ts index 4d4623e188..97786d2682 100644 --- a/src/commands/send/list.command.ts +++ b/src/commands/send/list.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { SearchService } from "jslib-common/abstractions/search.service"; import { SendService } from "jslib-common/abstractions/send.service"; @@ -16,11 +14,12 @@ export class SendListCommand { private searchService: SearchService ) {} - async run(options: program.OptionValues): Promise { + async run(cmdOptions: Record): Promise { let sends = await this.sendService.getAllDecrypted(); - if (options.search != null && options.search.trim() !== "") { - sends = this.searchService.searchSends(sends, options.search); + const normalizedOptions = new Options(cmdOptions); + if (normalizedOptions.search != null && normalizedOptions.search.trim() !== "") { + sends = this.searchService.searchSends(sends, normalizedOptions.search); } const webVaultUrl = this.environmentService.getWebVaultUrl(); @@ -28,3 +27,11 @@ export class SendListCommand { return Response.success(res); } } + +class Options { + search: string; + + constructor(passedOptions: Record) { + this.search = passedOptions.search; + } +} diff --git a/src/commands/serve.command.ts b/src/commands/serve.command.ts new file mode 100644 index 0000000000..67d79d3d47 --- /dev/null +++ b/src/commands/serve.command.ts @@ -0,0 +1,294 @@ +import * as program from "commander"; +import * as express from "express"; +import * as multer from "multer"; + +import { Main } from "../bw"; + +import { ConfirmCommand } from "./confirm.command"; +import { CreateCommand } from "./create.command"; +import { DeleteCommand } from "./delete.command"; +import { EditCommand } from "./edit.command"; +import { GenerateCommand } from "./generate.command"; +import { GetCommand } from "./get.command"; +import { ListCommand } from "./list.command"; +import { LockCommand } from "./lock.command"; +import { RestoreCommand } from "./restore.command"; +import { ShareCommand } from "./share.command"; +import { StatusCommand } from "./status.command"; +import { SyncCommand } from "./sync.command"; +import { UnlockCommand } from "./unlock.command"; + +import { SendCreateCommand } from "./send/create.command"; +import { SendDeleteCommand } from "./send/delete.command"; +import { SendEditCommand } from "./send/edit.command"; +import { SendGetCommand } from "./send/get.command"; +import { SendListCommand } from "./send/list.command"; +import { SendRemovePasswordCommand } from "./send/removePassword.command"; + +import { Response } from "jslib-node/cli/models/response"; +import { FileResponse } from "jslib-node/cli/models/response/fileResponse"; + +export class ServeCommand { + private listCommand: ListCommand; + private getCommand: GetCommand; + private createCommand: CreateCommand; + private editCommand: EditCommand; + private generateCommand: GenerateCommand; + private shareCommand: ShareCommand; + private statusCommand: StatusCommand; + private syncCommand: SyncCommand; + private deleteCommand: DeleteCommand; + private confirmCommand: ConfirmCommand; + private restoreCommand: RestoreCommand; + private lockCommand: LockCommand; + private unlockCommand: UnlockCommand; + + private sendCreateCommand: SendCreateCommand; + private sendDeleteCommand: SendDeleteCommand; + private sendEditCommand: SendEditCommand; + private sendGetCommand: SendGetCommand; + private sendListCommand: SendListCommand; + private sendRemovePasswordCommand: SendRemovePasswordCommand; + + constructor(protected main: Main) { + this.getCommand = new GetCommand( + this.main.cipherService, + this.main.folderService, + this.main.collectionService, + this.main.totpService, + this.main.auditService, + this.main.cryptoService, + this.main.stateService, + this.main.searchService, + this.main.apiService, + this.main.organizationService + ); + this.listCommand = new ListCommand( + this.main.cipherService, + this.main.folderService, + this.main.collectionService, + this.main.organizationService, + this.main.searchService, + this.main.apiService + ); + this.createCommand = new CreateCommand( + this.main.cipherService, + this.main.folderService, + this.main.stateService, + this.main.cryptoService, + this.main.apiService + ); + this.editCommand = new EditCommand( + this.main.cipherService, + this.main.folderService, + this.main.cryptoService, + this.main.apiService + ); + this.generateCommand = new GenerateCommand(this.main.passwordGenerationService); + this.syncCommand = new SyncCommand(this.main.syncService); + this.statusCommand = new StatusCommand( + this.main.environmentService, + this.main.syncService, + this.main.stateService, + this.main.vaultTimeoutService + ); + this.deleteCommand = new DeleteCommand( + this.main.cipherService, + this.main.folderService, + this.main.stateService, + this.main.apiService + ); + this.confirmCommand = new ConfirmCommand(this.main.apiService, this.main.cryptoService); + this.restoreCommand = new RestoreCommand(this.main.cipherService); + this.shareCommand = new ShareCommand(this.main.cipherService); + this.lockCommand = new LockCommand(this.main.vaultTimeoutService); + this.unlockCommand = new UnlockCommand( + this.main.cryptoService, + this.main.stateService, + this.main.cryptoFunctionService, + this.main.apiService, + this.main.logService + ); + + this.sendCreateCommand = new SendCreateCommand( + this.main.sendService, + this.main.stateService, + this.main.environmentService + ); + this.sendDeleteCommand = new SendDeleteCommand(this.main.sendService); + this.sendGetCommand = new SendGetCommand( + this.main.sendService, + this.main.environmentService, + this.main.searchService, + this.main.cryptoService + ); + this.sendEditCommand = new SendEditCommand( + this.main.sendService, + this.main.stateService, + this.sendGetCommand + ); + this.sendListCommand = new SendListCommand( + this.main.sendService, + this.main.environmentService, + this.main.searchService + ); + this.sendRemovePasswordCommand = new SendRemovePasswordCommand(this.main.sendService); + } + + async run(options: program.OptionValues) { + const port = options.port || 8087; + const server = express(); + process.env.BW_SERVE = "true"; + process.env.BW_NOINTERACTION = "true"; + + server.use(express.json()); + server.use((req, res, next) => { + const sessionHeader = req.get("Session"); + if (sessionHeader != null && sessionHeader !== "") { + process.env.BW_SESSION = sessionHeader; + } + next(); + }); + + server.get("/generate", async (req, res) => { + const response = await this.generateCommand.run(req.query); + this.processResponse(res, response); + }); + + server.get("/status", async (req, res) => { + const response = await this.statusCommand.run(); + this.processResponse(res, response); + }); + + server.get("/list/:object", async (req, res) => { + let response: Response = null; + if (req.params.object === "send") { + response = await this.sendListCommand.run(req.query); + } else { + response = await this.listCommand.run(req.params.object, req.query); + } + this.processResponse(res, response); + }); + + server.get("/send/list", async (req, res) => { + const response = await this.sendListCommand.run(req.query); + this.processResponse(res, response); + }); + + server.post("/sync", async (req, res) => { + const response = await this.syncCommand.run(req.query); + this.processResponse(res, response); + }); + + server.post("/lock", async (req, res) => { + const response = await this.lockCommand.run(); + this.processResponse(res, response); + }); + + server.post("/unlock", async (req, res) => { + const response = await this.unlockCommand.run( + req.body == null ? null : (req.body.password as string), + req.query + ); + this.processResponse(res, response); + }); + + server.post("/confirm/:object/:id", async (req, res) => { + const response = await this.confirmCommand.run(req.params.object, req.params.id, req.query); + this.processResponse(res, response); + }); + + server.post("/restore/:object/:id", async (req, res) => { + const response = await this.restoreCommand.run(req.params.object, req.params.id); + this.processResponse(res, response); + }); + + server.post("/move/:id/:organizationId", async (req, res) => { + const response = await this.shareCommand.run( + req.params.id, + req.params.organizationId, + req.body + ); + this.processResponse(res, response); + }); + + server.post("/attachment", multer().single("file"), async (req, res) => { + const response = await this.createCommand.run("attachment", req.body, req.query, { + fileBuffer: req.file.buffer, + fileName: req.file.originalname, + }); + this.processResponse(res, response); + }); + + server.post("/send/:id/remove-password", async (req, res) => { + const response = await this.sendRemovePasswordCommand.run(req.params.id); + this.processResponse(res, response); + }); + + server.post("/:object", async (req, res) => { + let response: Response = null; + if (req.params.object === "send") { + response = await this.sendCreateCommand.run(req.body, req.query); + } else { + response = await this.createCommand.run(req.params.object, req.body, req.query); + } + this.processResponse(res, response); + }); + + server.put("/:object/:id", async (req, res) => { + let response: Response = null; + if (req.params.object === "send") { + req.body.id = req.params.id; + response = await this.sendEditCommand.run(req.body, req.query); + } else { + response = await this.editCommand.run( + req.params.object, + req.params.id, + req.body, + req.query + ); + } + this.processResponse(res, response); + }); + + server.get("/:object/:id", async (req, res) => { + let response: Response = null; + if (req.params.object === "send") { + response = await this.sendGetCommand.run(req.params.id, null); + } else { + response = await this.getCommand.run(req.params.object, req.params.id, req.query); + } + this.processResponse(res, response); + }); + + server.delete("/:object/:id", async (req, res) => { + let response: Response = null; + if (req.params.object === "send") { + response = await this.sendDeleteCommand.run(req.params.id); + } else { + response = await this.deleteCommand.run(req.params.object, req.params.id, req.query); + } + this.processResponse(res, response); + }); + + server.listen(port, () => { + this.main.logService.info("Listening on port " + port); + }); + } + + private processResponse(res: any, commandResponse: Response) { + if (!commandResponse.success) { + res.statusCode = 400; + } + if (commandResponse.data instanceof FileResponse) { + res.writeHead(200, { + "Content-Type": "application/octet-stream", + "Content-Disposition": "attachment;filename=" + commandResponse.data.fileName, + "Content-Length": commandResponse.data.data.length, + }); + res.end(commandResponse.data.data); + } else { + res.json(commandResponse); + } + } +} diff --git a/src/commands/share.command.ts b/src/commands/share.command.ts index 2a1b621ce7..d07893503d 100644 --- a/src/commands/share.command.ts +++ b/src/commands/share.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { CipherService } from "jslib-common/abstractions/cipher.service"; import { Response } from "jslib-node/cli/models/response"; @@ -11,13 +9,8 @@ import { CliUtils } from "../utils"; export class ShareCommand { constructor(private cipherService: CipherService) {} - async run( - id: string, - organizationId: string, - requestJson: string, - cmd: program.Command - ): Promise { - if (requestJson == null || requestJson === "") { + async run(id: string, organizationId: string, requestJson: string): Promise { + if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) { requestJson = await CliUtils.readStdin(); } @@ -26,14 +19,18 @@ export class ShareCommand { } let req: string[] = []; - try { - const reqJson = Buffer.from(requestJson, "base64").toString(); - req = JSON.parse(reqJson); - if (req == null || req.length === 0) { - return Response.badRequest("You must provide at least one collection id for this item."); + if (typeof requestJson !== "string") { + req = requestJson; + } else { + try { + const reqJson = Buffer.from(requestJson, "base64").toString(); + req = JSON.parse(reqJson); + if (req == null || req.length === 0) { + return Response.badRequest("You must provide at least one collection id for this item."); + } + } catch (e) { + return Response.badRequest("Error parsing the encoded request data."); } - } catch (e) { - return Response.badRequest("Error parsing the encoded request data."); } if (id != null) { diff --git a/src/commands/status.command.ts b/src/commands/status.command.ts index 36c9a74274..e594cfe26b 100644 --- a/src/commands/status.command.ts +++ b/src/commands/status.command.ts @@ -1,5 +1,3 @@ -import * as program from "commander"; - import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { StateService } from "jslib-common/abstractions/state.service"; import { SyncService } from "jslib-common/abstractions/sync.service"; diff --git a/src/commands/sync.command.ts b/src/commands/sync.command.ts index 6d40e7780f..1c20f629a4 100644 --- a/src/commands/sync.command.ts +++ b/src/commands/sync.command.ts @@ -1,21 +1,22 @@ -import * as program from "commander"; - import { SyncService } from "jslib-common/abstractions/sync.service"; import { Response } from "jslib-node/cli/models/response"; import { MessageResponse } from "jslib-node/cli/models/response/messageResponse"; import { StringResponse } from "jslib-node/cli/models/response/stringResponse"; +import { CliUtils } from "src/utils"; + export class SyncCommand { constructor(private syncService: SyncService) {} - async run(options: program.OptionValues): Promise { - if (options.last || false) { + async run(cmdOptions: Record): Promise { + const normalizedOptions = new Options(cmdOptions); + if (normalizedOptions.last) { return await this.getLastSync(); } try { - const result = await this.syncService.fullSync(options.force || false, true); + const result = await this.syncService.fullSync(normalizedOptions.force, true); const res = new MessageResponse("Syncing complete.", null); return Response.success(res); } catch (e) { @@ -29,3 +30,13 @@ export class SyncCommand { return Response.success(res); } } + +class Options { + last: boolean; + force: boolean; + + constructor(passedOptions: Record) { + this.last = CliUtils.convertBooleanOption(passedOptions.last); + this.force = CliUtils.convertBooleanOption(passedOptions.force); + } +} diff --git a/src/commands/unlock.command.ts b/src/commands/unlock.command.ts index 963153b5de..501855190d 100644 --- a/src/commands/unlock.command.ts +++ b/src/commands/unlock.command.ts @@ -1,4 +1,3 @@ -import * as program from "commander"; import * as inquirer from "inquirer"; import { ApiService } from "jslib-common/abstractions/api.service"; @@ -26,17 +25,18 @@ export class UnlockCommand { private logService: ConsoleLogService ) {} - async run(password: string, options: program.OptionValues) { + async run(password: string, cmdOptions: Record) { const canInteract = process.env.BW_NOINTERACTION !== "true"; + const normalizedOptions = new Options(cmdOptions); if (password == null || password === "") { - if (options?.passwordfile) { - password = await NodeUtils.readFirstLine(options.passwordfile); - } else if (options?.passwordenv) { - if (process.env[options.passwordenv]) { - password = process.env[options.passwordenv]; + if (normalizedOptions?.passwordFile) { + password = await NodeUtils.readFirstLine(normalizedOptions.passwordFile); + } else if (normalizedOptions?.passwordEnv) { + if (process.env[normalizedOptions.passwordEnv]) { + password = process.env[normalizedOptions.passwordEnv]; } else { this.logService.warning( - `Warning: Provided passwordenv ${options.passwordenv} is not set` + `Warning: Provided passwordenv ${normalizedOptions.passwordEnv} is not set` ); } } @@ -118,3 +118,13 @@ export class UnlockCommand { process.env.BW_SESSION = Utils.fromBufferToB64(key); } } + +class Options { + passwordEnv: string; + passwordFile: string; + + constructor(passedOptions: Record) { + this.passwordEnv = passedOptions.passwordenv || passedOptions.passwordEnv; + this.passwordFile = passedOptions.passwordfile || passedOptions.passwordFile; + } +} diff --git a/src/program.ts b/src/program.ts index d6eec6e2e9..8948fc3a28 100644 --- a/src/program.ts +++ b/src/program.ts @@ -8,6 +8,7 @@ import { EncodeCommand } from "./commands/encode.command"; import { GenerateCommand } from "./commands/generate.command"; import { LockCommand } from "./commands/lock.command"; import { LoginCommand } from "./commands/login.command"; +import { ServeCommand } from "./commands/serve.command"; import { StatusCommand } from "./commands/status.command"; import { SyncCommand } from "./commands/sync.command"; import { UnlockCommand } from "./commands/unlock.command"; @@ -214,7 +215,7 @@ export class Program extends BaseProgram { } const command = new LockCommand(this.main.vaultTimeoutService); - const response = await command.run(cmd); + const response = await command.run(); this.processResponse(response); }); @@ -462,6 +463,22 @@ export class Program extends BaseProgram { const response = await command.run(); this.processResponse(response); }); + + program + .command("serve") + .description("Start a RESTful API webserver.") + .option("--port ", "The port to run your API webserver on. Default port is 8087.") + .on("--help", () => { + writeLn("\n Examples:"); + writeLn(""); + writeLn(" bw serve"); + writeLn(" bw serve --port 8080"); + writeLn("", true); + }) + .action(async (cmd) => { + const command = new ServeCommand(this.main); + await command.run(cmd); + }); } protected processResponse(response: Response, exitImmediately = false) { diff --git a/src/utils.ts b/src/utils.ts index 3a7462e739..a3c5317725 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -170,4 +170,8 @@ export class CliUtils { return false; }); } + + static convertBooleanOption(optionValue: any) { + return optionValue || optionValue === "" ? true : false; + } } diff --git a/src/vault.program.ts b/src/vault.program.ts index f7cef1e631..54651e82ab 100644 --- a/src/vault.program.ts +++ b/src/vault.program.ts @@ -346,7 +346,7 @@ export class VaultProgram extends Program { await this.exitIfLocked(); const command = new RestoreCommand(this.main.cipherService); - const response = await command.run(object, id, cmd); + const response = await command.run(object, id); this.processResponse(response); }); } @@ -383,7 +383,7 @@ export class VaultProgram extends Program { .action(async (id, organizationId, encodedJson, cmd) => { await this.exitIfLocked(); const command = new ShareCommand(this.main.cipherService); - const response = await command.run(id, organizationId, encodedJson, cmd); + const response = await command.run(id, organizationId, encodedJson); this.processResponse(response); }); }