diff --git a/config/env/common.js b/config/env/common.js index ba64d4b..b1d17d7 100644 --- a/config/env/common.js +++ b/config/env/common.js @@ -153,7 +153,13 @@ export default { // v2 Circuit Relay server (FullStack.cash) // '/ip4/78.46.129.7/tcp/4001/p2p/12D3KooWFQ11GQ5NubsJGhYZ4X3wrAGimLevxfm6HPExCrMYhpSL' - ] + ], // END IPFS CONFIGURATION + + // Account Configuration + disableNewAccounts: process.env.DISABLE_NEW_ACCOUNTS ? true : false, + + // Admin password + adminPassword: process.env.ADMIN_PASSWORD } diff --git a/package-lock.json b/package-lock.json index d0bd9cd..5c33c2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "@libp2p/tcp": "10.1.2", "@libp2p/webrtc": "5.2.2", "@libp2p/websockets": "9.2.2", - "@multiformats/multiaddr": "13.0.1", + "@multiformats/multiaddr": "12.5.1", "axios": "0.27.2", "bcryptjs": "2.4.3", "blockstore-fs": "2.0.2", @@ -164,9 +164,9 @@ "license": "Apache-2.0" }, "node_modules/@babel/code-frame": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", - "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -178,9 +178,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", - "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "license": "MIT", "peer": true, "engines": { @@ -188,21 +188,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", - "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -229,14 +229,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", - "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", "license": "MIT", "peer": true, "dependencies": { - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -368,13 +368,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "license": "MIT", "peer": true, "dependencies": { - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -616,18 +616,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", - "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -636,18 +636,18 @@ }, "node_modules/@babel/traverse--for-generate-function-map": { "name": "@babel/traverse", - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", - "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -655,9 +655,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "peer": true, "dependencies": { @@ -718,21 +718,6 @@ "npm": ">=8.7.0" } }, - "node_modules/@chainsafe/libp2p-gossipsub/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@chainsafe/libp2p-noise": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-16.0.1.tgz", @@ -1402,21 +1387,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@helia/bitswap/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@helia/bitswap/node_modules/it-length-prefixed": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-10.0.1.tgz", @@ -1455,30 +1425,6 @@ "uint8arraylist": "^2.4.8" } }, - "node_modules/@helia/block-brokers/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, - "node_modules/@helia/block-brokers/node_modules/@multiformats/multiaddr-matcher": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-2.0.2.tgz", - "integrity": "sha512-si7EZCI93mfBJKKRkh+u2bB9W6W5APVN3XfdwuseEJ0OS7ysg0Jno9SuAi0bRzsl5OEFESoF71SjsRqgp8PXAA==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.0.0" - } - }, "node_modules/@helia/delegated-routing-v1-http-api-client": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/@helia/delegated-routing-v1-http-api-client/-/delegated-routing-v1-http-api-client-4.2.5.tgz", @@ -1501,21 +1447,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@helia/delegated-routing-v1-http-api-client/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@helia/interface": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@helia/interface/-/interface-5.4.0.tgz", @@ -1532,21 +1463,6 @@ "progress-events": "^1.0.1" } }, - "node_modules/@helia/interface/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@helia/routers": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/@helia/routers/-/routers-3.1.3.tgz", @@ -1643,121 +1559,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@helia/utils/node_modules/@libp2p/logger": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-5.2.0.tgz", - "integrity": "sha512-OEFS529CnIKfbWEHmuCNESw9q0D0hL8cQ8klQfjIVPur15RcgAEgc1buQ7Y6l0B6tCYg120bp55+e9tGvn8c0g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/interface": "^2.11.0", - "@multiformats/multiaddr": "^12.4.4", - "interface-datastore": "^8.3.1", - "multiformats": "^13.3.6", - "weald": "^1.0.4" - } - }, - "node_modules/@helia/utils/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, - "node_modules/@helia/utils/node_modules/@multiformats/multiaddr-matcher": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-2.0.2.tgz", - "integrity": "sha512-si7EZCI93mfBJKKRkh+u2bB9W6W5APVN3XfdwuseEJ0OS7ysg0Jno9SuAi0bRzsl5OEFESoF71SjsRqgp8PXAA==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.0.0" - } - }, - "node_modules/@helia/utils/node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "license": "MIT" - }, - "node_modules/@helia/utils/node_modules/it-byte-stream": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/it-byte-stream/-/it-byte-stream-2.0.4.tgz", - "integrity": "sha512-8pS0OvkBYwQ206pRLgoLDAiHP6c8wYZJ1ig8KDmP5NOrzMxeH2Wv2ktXIjYHwdu7RPOsnxQb0vKo+O784L/m5g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "abort-error": "^1.0.1", - "it-queueless-pushable": "^2.0.0", - "it-stream-types": "^2.0.2", - "race-signal": "^2.0.0", - "uint8arraylist": "^2.4.8" - } - }, - "node_modules/@helia/utils/node_modules/it-byte-stream/node_modules/race-signal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/race-signal/-/race-signal-2.0.0.tgz", - "integrity": "sha512-P31bLhE4ByBX/70QDXMutxnqgwrF1WUXea1O8DXuviAgkdbQ1iQMQotNgzJIBC9yUSn08u/acZrMUhgw7w6GpA==", - "license": "Apache-2.0 OR MIT" - }, - "node_modules/@helia/utils/node_modules/libp2p": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/libp2p/-/libp2p-2.10.0.tgz", - "integrity": "sha512-tgDz7YuGg1XX7UfxebCUii+IGsly/8V0ZRZdFJSDySY2i3UuqpCTsEbRApH3cBKFhcAf00nx9xj8GL9zfo+XWw==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.1.0", - "@chainsafe/netmask": "^2.0.0", - "@libp2p/crypto": "^5.1.8", - "@libp2p/interface": "^2.11.0", - "@libp2p/interface-internal": "^2.3.19", - "@libp2p/logger": "^5.2.0", - "@libp2p/multistream-select": "^6.0.29", - "@libp2p/peer-collections": "^6.0.35", - "@libp2p/peer-id": "^5.1.9", - "@libp2p/peer-store": "^11.2.7", - "@libp2p/utils": "^6.7.2", - "@multiformats/dns": "^1.0.6", - "@multiformats/multiaddr": "^12.4.4", - "@multiformats/multiaddr-matcher": "^2.0.0", - "any-signal": "^4.1.1", - "datastore-core": "^10.0.2", - "interface-datastore": "^8.3.1", - "it-byte-stream": "^2.0.2", - "it-merge": "^3.0.11", - "it-parallel": "^3.0.11", - "main-event": "^1.0.1", - "multiformats": "^13.3.6", - "p-defer": "^4.0.1", - "p-retry": "^6.2.1", - "progress-events": "^1.0.1", - "race-event": "^1.3.0", - "race-signal": "^1.1.3", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@helia/utils/node_modules/p-retry": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", - "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", - "license": "MIT", - "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -1861,21 +1662,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@ipshipyard/libp2p-auto-tls/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@ipshipyard/node-datachannel": { "version": "0.26.6", "resolved": "https://registry.npmjs.org/@ipshipyard/node-datachannel/-/node-datachannel-0.26.6.tgz", @@ -2178,21 +1964,6 @@ "uint8arraylist": "^2.4.8" } }, - "node_modules/@libp2p/autonat/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/autonat/node_modules/it-byte-stream": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/it-byte-stream/-/it-byte-stream-2.0.4.tgz", @@ -2250,21 +2021,6 @@ "@multiformats/multiaddr": "^12.3.3" } }, - "node_modules/@libp2p/bootstrap/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/circuit-relay-v2": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@libp2p/circuit-relay-v2/-/circuit-relay-v2-3.2.2.tgz", @@ -2292,21 +2048,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/circuit-relay-v2/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@libp2p/config/-/config-1.1.0.tgz", @@ -2350,21 +2091,6 @@ "weald": "^1.0.4" } }, - "node_modules/@libp2p/config/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/crypto": { "version": "5.1.13", "resolved": "https://registry.npmjs.org/@libp2p/crypto/-/crypto-5.1.13.tgz", @@ -2438,30 +2164,6 @@ "uint8arraylist": "^2.4.8" } }, - "node_modules/@libp2p/dcutr/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, - "node_modules/@libp2p/dcutr/node_modules/@multiformats/multiaddr-matcher": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-2.0.2.tgz", - "integrity": "sha512-si7EZCI93mfBJKKRkh+u2bB9W6W5APVN3XfdwuseEJ0OS7ysg0Jno9SuAi0bRzsl5OEFESoF71SjsRqgp8PXAA==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.0.0" - } - }, "node_modules/@libp2p/dcutr/node_modules/it-byte-stream": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/it-byte-stream/-/it-byte-stream-2.0.4.tgz", @@ -2528,21 +2230,6 @@ "undici": "^6.21.0" } }, - "node_modules/@libp2p/http-fetch/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/identify": { "version": "3.0.22", "resolved": "https://registry.npmjs.org/@libp2p/identify/-/identify-3.0.22.tgz", @@ -2565,21 +2252,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/identify/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/interface": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.11.0.tgz", @@ -2608,36 +2280,6 @@ "progress-events": "^1.0.1" } }, - "node_modules/@libp2p/interface-internal/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, - "node_modules/@libp2p/interface/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/kad-dht": { "version": "14.2.15", "resolved": "https://registry.npmjs.org/@libp2p/kad-dht/-/kad-dht-14.2.15.tgz", @@ -2676,21 +2318,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/kad-dht/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/kad-dht/node_modules/it-length-prefixed": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-10.0.1.tgz", @@ -2738,21 +2365,6 @@ "weald": "^1.0.4" } }, - "node_modules/@libp2p/logger/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/mdns": { "version": "11.0.47", "resolved": "https://registry.npmjs.org/@libp2p/mdns/-/mdns-11.0.47.tgz", @@ -2770,21 +2382,6 @@ "multicast-dns": "^7.2.5" } }, - "node_modules/@libp2p/mdns/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/mplex": { "version": "11.0.47", "resolved": "https://registry.npmjs.org/@libp2p/mplex/-/mplex-11.0.47.tgz", @@ -2909,21 +2506,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/peer-record/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/peer-store": { "version": "11.2.7", "resolved": "https://registry.npmjs.org/@libp2p/peer-store/-/peer-store-11.2.7.tgz", @@ -2946,21 +2528,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/peer-store/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/ping": { "version": "2.0.22", "resolved": "https://registry.npmjs.org/@libp2p/ping/-/ping-2.0.22.tgz", @@ -2975,21 +2542,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/ping/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/pubsub": { "version": "10.1.18", "resolved": "https://registry.npmjs.org/@libp2p/pubsub/-/pubsub-10.1.18.tgz", @@ -3058,21 +2610,6 @@ "stream-to-it": "^1.0.1" } }, - "node_modules/@libp2p/tcp/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/tls": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/@libp2p/tls/-/tls-2.2.7.tgz", @@ -3095,45 +2632,20 @@ } }, "node_modules/@libp2p/upnp-nat": { - "version": "3.1.22", - "resolved": "https://registry.npmjs.org/@libp2p/upnp-nat/-/upnp-nat-3.1.22.tgz", - "integrity": "sha512-+Hm78LtgJzEEFrQDqnL8A2tkiQVAwEEe8aAE1niyBmujNLu1KYmqmmjsH6F5F4wacBOetU0QGXmBNMx6eq42CA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@libp2p/upnp-nat/-/upnp-nat-3.0.0.tgz", + "integrity": "sha512-0mq49KFo8vtLUIra7+NYjYC6Q9R4Mc6ODJDto0Y9FX6901vWWJ0wvNUPPB0bT/gdEY+VjVxK+VqnNV5gPdbR3w==", "license": "Apache-2.0 OR MIT", "dependencies": { - "@achingbrain/nat-port-mapper": "^4.0.2", - "@chainsafe/is-ip": "^2.1.0", - "@libp2p/interface": "^2.11.0", - "@libp2p/interface-internal": "^2.3.19", - "@libp2p/utils": "^6.7.2", - "@multiformats/multiaddr": "^12.4.4", - "@multiformats/multiaddr-matcher": "^2.0.0", - "main-event": "^1.0.1", + "@achingbrain/nat-port-mapper": "^4.0.0", + "@chainsafe/is-ip": "^2.0.2", + "@libp2p/interface": "^2.3.0", + "@libp2p/interface-internal": "^2.2.0", + "@libp2p/utils": "^6.3.0", + "@multiformats/multiaddr": "^12.3.3", + "@multiformats/multiaddr-matcher": "^1.6.0", "p-defer": "^4.0.1", - "race-signal": "^1.1.3" - } - }, - "node_modules/@libp2p/upnp-nat/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, - "node_modules/@libp2p/upnp-nat/node_modules/@multiformats/multiaddr-matcher": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-2.0.2.tgz", - "integrity": "sha512-si7EZCI93mfBJKKRkh+u2bB9W6W5APVN3XfdwuseEJ0OS7ysg0Jno9SuAi0bRzsl5OEFESoF71SjsRqgp8PXAA==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.0.0" + "race-signal": "^1.1.0" } }, "node_modules/@libp2p/utils": { @@ -3180,21 +2692,6 @@ "weald": "^1.0.4" } }, - "node_modules/@libp2p/utils/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/webrtc": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/@libp2p/webrtc/-/webrtc-5.2.2.tgz", @@ -3233,21 +2730,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/webrtc/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@libp2p/webrtc/node_modules/it-length-prefixed": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-10.0.1.tgz", @@ -3285,21 +2767,6 @@ "ws": "^8.18.0" } }, - "node_modules/@libp2p/websockets/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@ljharb/resumer": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@ljharb/resumer/-/resumer-0.1.3.tgz", @@ -3390,7 +2857,7 @@ "@multiformats/multiaddr": "^12.0.0" } }, - "node_modules/@multiformats/mafmt/node_modules/@multiformats/multiaddr": { + "node_modules/@multiformats/multiaddr": { "version": "12.5.1", "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", @@ -3405,22 +2872,10 @@ "uint8arrays": "^5.0.0" } }, - "node_modules/@multiformats/multiaddr": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-13.0.1.tgz", - "integrity": "sha512-XToN915cnfr6Lr9EdGWakGJbPT0ghpg/850HvdC+zFX8XvpLZElwa8synCiwa8TuvKNnny6m8j8NVBNCxhIO3g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@multiformats/multiaddr-matcher": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.8.0.tgz", - "integrity": "sha512-tR/HFhDucXjvwCef5lfXT7kikqR2ffUjliuYlg/RKYGPySVKVlvrDufz86cIuHNc+i/fNR16FWWgD/pMJ6RW4w==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.6.0.tgz", + "integrity": "sha512-E77lLvQR+50kTAfvjV3g4wr9qCu77Z+6yT0s1hgfh8B4sAXZ8u/YdQJGhjgstgW1kmGy7BXPppROKYijqQsesQ==", "license": "Apache-2.0 OR MIT", "dependencies": { "@chainsafe/is-ip": "^2.0.1", @@ -3428,45 +2883,15 @@ "multiformats": "^13.0.0" } }, - "node_modules/@multiformats/multiaddr-matcher/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@multiformats/multiaddr-to-uri": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-to-uri/-/multiaddr-to-uri-11.0.2.tgz", - "integrity": "sha512-SiLFD54zeOJ0qMgo9xv1Tl9O5YktDKAVDP4q4hL16mSq4O4sfFNagNADz8eAofxd6TfQUzGQ3TkRRG9IY2uHRg==", + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-to-uri/-/multiaddr-to-uri-10.1.2.tgz", + "integrity": "sha512-6sicfYRjJlHJn4bwsQancs8kXncWU4dDN/+V9sMVTYp9hi8ovWgVkK75AbAv4SfhztmmI+oufVUncQ1n+SukKQ==", "license": "Apache-2.0 OR MIT", "dependencies": { "@multiformats/multiaddr": "^12.3.0" } }, - "node_modules/@multiformats/multiaddr-to-uri/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@multiformats/murmur3": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@multiformats/murmur3/-/murmur3-2.2.0.tgz", @@ -3490,21 +2915,6 @@ "is-ip": "^5.0.0" } }, - "node_modules/@multiformats/uri-to-multiaddr/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/@noble/ciphers": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.6.0.tgz", @@ -4888,9 +4298,9 @@ } }, "node_modules/@types/node": { - "version": "25.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.1.0.tgz", - "integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==", + "version": "25.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", + "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -6592,21 +6002,6 @@ "weald": "^1.0.4" } }, - "node_modules/blockstore-core/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/blockstore-fs": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/blockstore-fs/-/blockstore-fs-2.0.2.tgz", @@ -7010,9 +6405,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001766", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", - "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", + "version": "1.0.30001767", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", + "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", "funding": [ { "type": "opencollective", @@ -7869,21 +7264,6 @@ "weald": "^1.0.4" } }, - "node_modules/datastore-core/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/datastore-fs": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/datastore-fs/-/datastore-fs-10.0.2.tgz", @@ -8473,9 +7853,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.279", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.279.tgz", - "integrity": "sha512-0bblUU5UNdOt5G7XqGiJtpZMONma6WAfq9vsFmtn9x1+joAObr6x1chfqyxFSDCAFwFhCQDrqeAr6MYdpwJ9Hg==", + "version": "1.5.283", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.283.tgz", + "integrity": "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==", "license": "ISC" }, "node_modules/elliptic": { @@ -13548,21 +12928,6 @@ "weald": "^1.0.4" } }, - "node_modules/libp2p/node_modules/@multiformats/multiaddr": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", - "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "abort-error": "^1.0.1", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, "node_modules/libp2p/node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", diff --git a/package.json b/package.json index 5f83428..ca76cea 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,11 @@ "type": "module", "scripts": { "start": "node index.js", - "test": "npm run test:all", + "test": "npm run test:unit", "test:all": "export SVC_ENV=test && c8 --reporter=text mocha --exit --timeout 15000 --recursive test/unit test/e2e/automated/", - "test:unit": "export SVC_ENV=test && mocha --exit --timeout 15000 --recursive test/unit/", - "test:e2e:auto": "export SVC_ENV=test && mocha --exit --timeout 30000 test/e2e/automated/", - "test:integration": "export SVC_ENV=test && mocha --timeout 30000 --recursive test/integration/", + "test:unit": "export SVC_ENV=test && c8 --reporter=text mocha --exit --timeout 15000 --recursive test/unit/", + "test:e2e:auto": "export SVC_ENV=test && mocha --exit --timeout 15000 test/e2e/automated/", + "start:e2e:server": "export SVC_ENV=test && node index.js", "test:temp": "export SVC_ENV=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/", "lint": "standard --env mocha --fix", "docs": "./node_modules/.bin/apidoc -i src/ -o docs", @@ -39,7 +39,7 @@ "@libp2p/tcp": "10.1.2", "@libp2p/webrtc": "5.2.2", "@libp2p/websockets": "9.2.2", - "@multiformats/multiaddr": "13.0.1", + "@multiformats/multiaddr": "12.5.1", "axios": "0.27.2", "bcryptjs": "2.4.3", "blockstore-fs": "2.0.2", @@ -102,5 +102,17 @@ "ignore": [ "/test/unit/mocks/**/*.js" ] + }, + "overrides": { + "@multiformats/multiaddr-to-uri": "10.1.2", + "@multiformats/multiaddr-matcher": "1.6.0", + "@multiformats/multiaddr": "12.5.1", + "helia": { + "libp2p": "2.7.2", + "@libp2p/upnp-nat": "3.0.0" + }, + "libp2p": { + "@multiformats/multiaddr": "12.5.1" + } } } diff --git a/src/adapters/admin.js b/src/adapters/admin.js index 8974b82..399e1ce 100644 --- a/src/adapters/admin.js +++ b/src/adapters/admin.js @@ -51,70 +51,37 @@ class Admin { // used by the Listing Manager and test scripts, in order access private API // functions. async createSystemUser () { - // Create the system user. try { - context.password = _this._randomString(20) - - const options = { - method: 'POST', - url: `${LOCALHOST}/users`, - data: { - user: { - email: 'system@system.com', - password: context.password, - name: 'admin' - } - } + const context = { + email: 'system@system.com', + name: 'admin', + password: _this.config.adminPassword || _this._randomString(20), + type: 'admin' } - const result = await _this.axios.request(options) - // console.log('admin.data: ', result.data) + // Check if the user already exists + let adminUser = await _this.User.findOne({ email: context.email }) - context.email = result.data.user.email - context.id = result.data.user._id - context.token = result.data.token + if (adminUser) { + // Update the password + adminUser.password = context.password + } else { + // Create a new admin user + adminUser = new _this.User(context) + } + // Update context with the new user id and token + context.id = adminUser._id + context.token = await adminUser.generateToken() - // Get the mongoDB entry - const user = await _this.User.findById(context.id) + // Save the user + await adminUser.save() - // Change the user type to admin - user.type = 'admin' - // console.log(`user created: ${JSON.stringify(user, null, 2)}`) - - // Save the user model. - await user.save() - - // console.log(`admin user created: ${JSON.stringify(result.body, null, 2)}`) - // console.log(`with password: ${context.password}`) - - // Write out the system user information to a JSON file that external - // applications like the Task Manager and the test scripts can access. - - await jsonFiles.writeJSON(context, JSON_PATH) - // console.log('context: ', context) - // console.log('JSON_PATH: ', JSON_PATH) + // Write the user data to the JSON file + await _this.jsonFiles.writeJSON(context, JSON_PATH) return context - } catch (err) { - // Handle existing system user. - if (err.response.status === 422) { - try { - // Delete the existing user - await _this.deleteExistingSystemUser() - - // Call this function again. - return _this.createSystemUser() - } catch (err2) { - console.error( - 'Error in admin.js/createSystemUser() while trying generate new system user.' - ) - // process.end(1) - throw err2 - } - } else { - console.log('Error in admin.js/createSystemUser: ') - // process.end(1) - throw err - } + } catch (error) { + console.log('Error in admin.js/createSystemUser()') + throw error } } @@ -129,6 +96,7 @@ class Admin { }) await _this.User.deleteOne({ email: 'system@system.com' }) + return true } catch (err) { console.log('Error in admin.js/deleteExistingSystemUser()') throw err @@ -152,7 +120,7 @@ class Admin { Accept: 'application/json' }, data: { - email: 'system@system.com', + email: existingUser.email, password: existingUser.password } } diff --git a/src/adapters/localdb/index.js b/src/adapters/localdb/index.js index be6b2cf..7fd6ead 100644 --- a/src/adapters/localdb/index.js +++ b/src/adapters/localdb/index.js @@ -4,11 +4,13 @@ // Load Mongoose models. import Users from './models/users.js' +import Usage from './models/usage.js' class LocalDB { constructor () { // Encapsulate dependencies this.Users = Users + this.Usage = Usage } } diff --git a/src/adapters/localdb/models/usage.js b/src/adapters/localdb/models/usage.js new file mode 100644 index 0000000..9dec059 --- /dev/null +++ b/src/adapters/localdb/models/usage.js @@ -0,0 +1,15 @@ +/* + Usage data model +*/ + +// Global npm libraries +import mongoose from 'mongoose' + +const Usage = new mongoose.Schema({ + ip: { type: String }, + url: { type: String }, + method: { type: String }, + timestamp: { type: Date } +}) + +export default mongoose.model('usage', Usage) diff --git a/src/adapters/wallet.adapter.js b/src/adapters/wallet.adapter.js index d00541e..6a3e1a1 100644 --- a/src/adapters/wallet.adapter.js +++ b/src/adapters/wallet.adapter.js @@ -20,6 +20,13 @@ class Wallet { // Bind 'this' object to all subfunctions this.instanceWalletWithoutInitialization = this.instanceWalletWithoutInitialization.bind(this) + this._instanceWallet = this._instanceWallet.bind(this) + this.openWallet = this.openWallet.bind(this) + this.instanceWallet = this.instanceWallet.bind(this) + this.incrementNextAddress = this.incrementNextAddress.bind(this) + this.getKeyPair = this.getKeyPair.bind(this) + this.optimize = this.optimize.bind(this) + this.getBalance = this.getBalance.bind(this) } // This is used for initializing the wallet, without waiting to update the wallet diff --git a/src/controllers/rest-api/ipfs/controller.js b/src/controllers/rest-api/ipfs/controller.js index d883288..204f68a 100644 --- a/src/controllers/rest-api/ipfs/controller.js +++ b/src/controllers/rest-api/ipfs/controller.js @@ -58,7 +58,26 @@ class IpfsRESTControllerLib { } } - // Return information on IPFS peers this node is connected to. + /** + * @api {post} /ipfs/peers Get information on IPFS peers this node is connected to + * @apiPermission public + * @apiName GetIpfsPeers + * @apiGroup REST IPFS + * + * @apiParam {Boolean} [showAll=false] Whether to include detailed peer data + * + * @apiExample Example usage: + * curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/peers \ + * -d '{"showAll": false}' + * + * @apiSuccess {Object[]} peers Array of peer objects + * @apiSuccess {String} peers[].peer Peer ID + * @apiSuccess {String} peers[].name Peer name + * @apiSuccess {String} peers[].protocol Protocol used by the peer + * @apiSuccess {String} peers[].version Peer version + * @apiSuccess {String} peers[].connectionAddr Connection address + * @apiSuccess {Object} [peers[].peerData] Detailed peer data (when showAll=true) + */ async getPeers (ctx) { try { const showAll = ctx.request.body.showAll @@ -73,6 +92,24 @@ class IpfsRESTControllerLib { } } + /** + * @api {post} /ipfs/relays Get data about the known Circuit Relays + * @apiPermission public + * @apiName GetIpfsRelays + * @apiGroup REST IPFS + * + * @apiDescription Returns information about Circuit Relays, both v1 and v2, that this node knows about. V2 relays are hydrated with peer data from the connected peers list. + * + * @apiExample Example usage: + * curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/relays + * + * @apiSuccess {Object} relays Object containing relay information + * @apiSuccess {Object[]} relays.v2Relays Array of v2 Circuit Relay objects + * @apiSuccess {String} relays.v2Relays[].ipfsId IPFS ID of the relay + * @apiSuccess {String} relays.v2Relays[].name Name of the relay (hydrated from peer data) + * @apiSuccess {String} relays.v2Relays[].description Description of the relay (hydrated from peer data) + * @apiSuccess {Object[]} relays.v1Relays Array of v1 Circuit Relay configurations + */ // Get data about the known Circuit Relays. Hydrate with data from peers list. async getRelays (ctx) { try { @@ -86,6 +123,24 @@ class IpfsRESTControllerLib { } } + /** + * @api {post} /ipfs/connect Connect to a specific IPFS peer + * @apiPermission public + * @apiName ConnectToIpfsPeer + * @apiGroup REST IPFS + * + * @apiDescription Attempts to establish a connection to a specific IPFS peer using the provided multiaddr. Optionally returns detailed information about the connection. + * + * @apiParam {String} multiaddr Multiaddress of the peer to connect to (required) + * @apiParam {Boolean} [getDetails=false] Whether to return detailed connection information + * + * @apiExample Example usage: + * curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/connect \ + * -d '{"multiaddr": "/ip4/161.35.99.207/tcp/4001/p2p/12D3KooWDtj9cfj1SKuLbDNKvKRKSsGN8qivq9M8CYpLPDpcD5pu", "getDetails": false}' + * + * @apiSuccess {Boolean} success Indicates whether the connection attempt was successful + * @apiSuccess {Object} [details] Additional connection details (when getDetails=true) + */ async connect (ctx) { try { const multiaddr = ctx.request.body.multiaddr diff --git a/src/controllers/rest-api/users/index.js b/src/controllers/rest-api/users/index.js index 0001861..e97717c 100644 --- a/src/controllers/rest-api/users/index.js +++ b/src/controllers/rest-api/users/index.js @@ -10,6 +10,8 @@ import UserRESTControllerLib from './controller.js' import Validators from '../middleware/validators.js' +import config from '../../../../config/index.js' + let _this class UserRouter { @@ -34,6 +36,7 @@ class UserRouter { } // Encapsulate dependencies. + this.config = config this.userRESTController = new UserRESTControllerLib(dependencies) this.validators = new Validators() @@ -52,7 +55,7 @@ class UserRouter { } // Define the routes and attach the controller. - this.router.post('/', this.userRESTController.createUser) + this.router.post('/', this.createUser) this.router.get('/', this.getAll) this.router.get('/:id', this.getById) this.router.put('/:id', this.updateUser) @@ -63,6 +66,14 @@ class UserRouter { app.use(this.router.allowedMethods()) } + async createUser (ctx, next) { + if (process.env.DISABLE_NEW_ACCOUNTS) { + await _this.validators.ensureAdmin(ctx, next) + } + await _this.userRESTController.createUser(ctx, next) + return true + } + async getAll (ctx, next) { await _this.validators.ensureUser(ctx, next) await _this.userRESTController.getUsers(ctx, next) diff --git a/src/controllers/timer-controllers.js b/src/controllers/timer-controllers.js index 62f95b6..320292f 100644 --- a/src/controllers/timer-controllers.js +++ b/src/controllers/timer-controllers.js @@ -1,6 +1,6 @@ /* This Controller library is concerned with timer-based functions that are - kicked off periodicially. + kicked off periodically. */ import config from '../../config/index.js' @@ -23,55 +23,76 @@ class TimerControllers { this.debugLevel = localConfig.debugLevel + // Constants + this.cleanUsageInterval = 60000 * 60 // 1 hour + this.backupUsageInterval = 60000 * 10 // 10 minutes + // Encapsulate dependencies this.config = config // Bind 'this' object to all subfunctions. - this.exampleTimerFunc = this.exampleTimerFunc.bind(this) this.cleanUsage = this.cleanUsage.bind(this) - - // this.startTimers() + this.backupUsage = this.backupUsage.bind(this) } // Start all the time-based controllers. startTimers () { // Any new timer control functions can be added here. They will be started // when the server starts. - this.optimizeWalletHandle = setInterval(this.exampleTimerFunc, 60000 * 60) - this.cleanUsageHandle = setInterval(this.cleanUsage, 60000 * 60) // 1 hour + this.cleanUsageHandle = setInterval(this.cleanUsage, this.cleanUsageInterval) + this.backupUsageHandle = setInterval(this.backupUsage, this.backupUsageInterval) return true } stopTimers () { - clearInterval(this.optimizeWalletHandle) - clearInterval(this.cleanusageHandle) + clearInterval(this.cleanUsageHandle) + clearInterval(this.backupUsageHandle) } - // Replace this example function with your own timer handler. - exampleTimerFunc (negativeTest) { + // Clean the usage state so that stats reflect the last 24 hours. + cleanUsage () { try { - console.log('Example timer controller executed.') + clearInterval(this.cleanUsageHandle) - if (negativeTest) throw new Error('test error') + const now = new Date() + console.log(`cleanUsage() Timer Controller executing at ${now.toLocaleString()}`) + + this.useCases.usage.cleanUsage() + + this.cleanUsageHandle = setInterval(this.cleanUsage, this.cleanUsageInterval) return true } catch (err) { - console.error('Error in exampleTimerFunc(): ', err) + console.error('Error in time-controller.js/cleanUsage(): ', err) + + this.cleanUsageHandle = setInterval(this.cleanUsage, this.cleanUsageInterval) // Note: Do not throw an error. This is a top-level function. return false } } - // Clean the usage state so that stats reflect the last 24 hours. - cleanUsage () { + // Backup the usage stats to the database + async backupUsage () { try { - this.useCases.usage.cleanUsage() + clearInterval(this.backupUsageHandle) + + console.log('backupUsage() Timer Controller executing at ', new Date().toLocaleString()) + + // Clear the database of old usage data. + await this.useCases.usage.clearUsage() + + // Save the current usage snapshot to the database. + await this.useCases.usage.saveUsage() + + this.backupUsageHandle = setInterval(this.backupUsage, this.backupUsageInterval) return true } catch (err) { - console.error('Error in time-controller.js/cleanUsage(): ', err) + console.error('Error in time-controller.js/backupUsage(): ', err) + + this.backupUsageHandle = setInterval(this.backupUsage, this.backupUsageInterval) // Note: Do not throw an error. This is a top-level function. return false diff --git a/src/use-cases/index.js b/src/use-cases/index.js index e8b6aec..20cf7f7 100644 --- a/src/use-cases/index.js +++ b/src/use-cases/index.js @@ -26,6 +26,9 @@ class UseCases { // Run any startup Use Cases at the start of the app. async start () { + // Load the usage stats from the database + await this.usage.loadUsage() + console.log('Async Use Cases have been started.') return true diff --git a/src/use-cases/usage-use-cases.js b/src/use-cases/usage-use-cases.js index 5880f58..77e952d 100644 --- a/src/use-cases/usage-use-cases.js +++ b/src/use-cases/usage-use-cases.js @@ -3,6 +3,10 @@ for tracking the usage of REST API and JSON RPC calls. This library is used by admins to keep an eye on how many API calls were made in a 24-hour and 1-hour time period. + + Usage stats are held in memory. But they are periodically backed up to the + Mongo database. On startup, the usage stats are loaded from the database. + This allows the usage stats to be persisted across restarts. */ // This global variable is used to share data between the REST middleware and @@ -19,11 +23,17 @@ class UsageUseCases { ) } + // Encapsulate dependencies + this.UsageModel = this.adapters.localdb.Usage + // Bind 'this' object to all subfunctions this.cleanUsage = this.cleanUsage.bind(this) this.getRestSummary = this.getRestSummary.bind(this) this.getTopIps = this.getTopIps.bind(this) this.getTopEndpoints = this.getTopEndpoints.bind(this) + this.clearUsage = this.clearUsage.bind(this) + this.saveUsage = this.saveUsage.bind(this) + this.loadUsage = this.loadUsage.bind(this) // State } @@ -36,7 +46,11 @@ class UsageUseCases { const now = new Date() const twentyFourHoursAgo = now.getTime() - (60000 * 60 * 24) + console.log('cleanUsage() now: ', now) + console.log('cleanUsage() restCalls.length before filtering: ', restCalls.length) restCalls = restCalls.filter(x => x.timestamp > twentyFourHoursAgo) + console.log('cleanUsage() restCalls.length after filtering: ', restCalls.length) + return restCalls } catch (err) { console.error('Error in usage-use-cases.js/cleanUsage()') @@ -104,6 +118,70 @@ class UsageUseCases { throw err } } + + // Clear the usage database data + async clearUsage () { + try { + await this.UsageModel.deleteMany({}) + + // Debugging: verify the database is empty + // Delete this code after debugging + const usage = await this.UsageModel.find({}) + console.log('clearUsage() usage: ', usage) + return true + } catch (err) { + console.error('Error in usage-use-cases.js/clearUsage()') + throw err + } + } + + // Save the usage data to the database + async saveUsage (inObj = {}) { + try { + for (let i = 0; i < restCalls.length; i++) { + const thisRestCall = restCalls[i] + + // Debugging: delete this code after debugging + // if (i === 5) { + // console.log('saveUsage() thisRestCall: ', thisRestCall) + // } + + const usageData = { + ip: thisRestCall.ip, + url: thisRestCall.url, + method: thisRestCall.method, + timestamp: thisRestCall.timestamp + } + + const usage = new this.UsageModel(usageData) + await usage.save() + } + return true + } catch (err) { + console.error('Error in usage-use-cases.js/saveUsage()') + throw err + } + } + + // Load usage data from the database + async loadUsage () { + try { + const usage = await this.UsageModel.find({}) + // console.log('usage: ', usage) + + // Debugging: delete this code after debugging + if (usage[5]) { + console.log('loadUsage() usage[5]: ', usage[5]) + } + + restCalls = usage + return usage + } catch (err) { + console.error('Error in usage-use-cases.js/loadUsage(): ', err) + return false + // throw err + } + } } // This Koa middleware is called any time there is a REST API. It logs the diff --git a/test/e2e/automated/a00-liveness.rest-e2e.js b/test/e2e/automated/a00-liveness.rest-e2e.js new file mode 100644 index 0000000..6401503 --- /dev/null +++ b/test/e2e/automated/a00-liveness.rest-e2e.js @@ -0,0 +1,45 @@ +/* + Liveness test runs before all other tests to ensure the server is running. +*/ + +// Public npm libraries +import { assert } from 'chai' +import axios from 'axios' +import testUtils from '../../utils/test-utils.js' + +// const sinon = require('sinon') + +// Local support libraries +import config from '../../../config/index.js' +// import Server from '../../../bin/server.js' +// import testUtils from '../../utils/test-utils.js' +// const adminLib = new AdminLib() + +const LOCALHOST = `http://localhost:${config.port}` + +describe('#Check Server Liveness', () => { + // before(async () => { + it('should confirm the server is running', async () => { + try { + const response = await axios.get(`${LOCALHOST}/`) + assert(response.status === 200, 'Server is running, continuing with E2E tests.') + } catch (err) { + console.log('\nServer is not running, exiting tests.') + console.log('Start the server with `npm run start:e2e:server` before running E2E tests.\n') + console.log('Ensure running npm run docs before running the test server') + process.exit(1) + } + }) + it('should confirm the server is running over test enviroment', async () => { + try { + const res = await testUtils.loginAdminUser() + assert.property(res, 'user') + assert.property(res, 'token') + assert.property(res, 'id') + } catch (err) { + console.log('\nServer is not running over test enviroment, exiting tests.') + console.log('Start the server with `npm run start:e2e:server` before running E2E tests.\n') + process.exit(1) + } + }) +}) diff --git a/test/e2e/automated/a01-auth.rest-e2e.js b/test/e2e/automated/a01-auth.rest-e2e.js index d6d21d0..88f3f22 100644 --- a/test/e2e/automated/a01-auth.rest-e2e.js +++ b/test/e2e/automated/a01-auth.rest-e2e.js @@ -13,10 +13,8 @@ import axios from 'axios' // Local support libraries import config from '../../../config/index.js' -import Server from '../../../bin/server.js' +// import Server from '../../../bin/server.js' import testUtils from '../../utils/test-utils.js' -import AdminLib from '../../../src/adapters/admin.js' -const adminLib = new AdminLib() // const request = supertest.agent(app.listen()) const context = {} @@ -26,10 +24,12 @@ const LOCALHOST = `http://localhost:${config.port}` if (!config.noMongo) { describe('Auth', () => { before(async () => { - const app = new Server() + // const app = new Server() // This should be the first instruction. It starts the REST API server. - await app.startServer() + // await app.startServer() + + // TODO: // Stop the IPFS node for the rest of the e2e tests. // await app.controllers.adapters.ipfs.stop() @@ -37,9 +37,6 @@ if (!config.noMongo) { // Delete all previous users in the database. await testUtils.deleteAllUsers() - // Create a new admin user. - await adminLib.createSystemUser() - const userObj = { email: 'test@test.com', password: 'pass', diff --git a/test/e2e/automated/a02-users.rest-e2e.js b/test/e2e/automated/a02-users.rest-e2e.js index 1d9a992..7ce8ac5 100644 --- a/test/e2e/automated/a02-users.rest-e2e.js +++ b/test/e2e/automated/a02-users.rest-e2e.js @@ -5,16 +5,11 @@ import axios from 'axios' import sinon from 'sinon' import util from 'util' -import UserController from '../../../src/controllers/rest-api/users/controller.js' -import Adapters from '../../../src/adapters/index.js' -import UseCases from '../../../src/use-cases/index.js' util.inspect.defaultOptions = { depth: 1 } const LOCALHOST = `http://localhost:${config.port}` const context = {} -const adapters = new Adapters() -let uut let sandbox // const mockContext = require('../../unit/mocks/ctx-mock').context @@ -50,9 +45,6 @@ if (!config.noMongo) { }) beforeEach(() => { - const useCases = new UseCases({ adapters }) - uut = new UserController({ adapters, useCases }) - sandbox = sinon.createSandbox() }) @@ -268,33 +260,6 @@ if (!config.noMongo) { assert.hasAnyKeys(users[0], ['type', '_id', 'email']) assert.isNumber(users.length) }) - - it('should return a 422 http status if biz-logic throws an error', async () => { - try { - const { token } = context - - // Force an error - sandbox - .stub(uut.useCases.user, 'getAllUsers') - .rejects(new Error('test error')) - - const options = { - method: 'GET', - url: `${LOCALHOST}/users`, - headers: { - Accept: 'application/json', - Authorization: `Bearer ${token}` - } - } - await axios(options) - - assert.fail('Unexpected code path!') - } catch (err) { - // console.log(err) - assert.equal(err.response.status, 422) - assert.equal(err.response.data, 'test error') - } - }) }) describe('GET /users/:id', () => { diff --git a/test/unit/adapters/adapters-index-unit.js b/test/unit/adapters/adapters-index-unit.js index ee382e4..328f2bb 100644 --- a/test/unit/adapters/adapters-index-unit.js +++ b/test/unit/adapters/adapters-index-unit.js @@ -37,6 +37,21 @@ describe('#adapters', () => { assert.equal(result, true) }) + it('should not start ipfs on test enviroment', async () => { + // Mock dependencies + uut.config.getJwtAtStartup = true + uut.config.useIpfs = true + uut.config.env = 'test' + + sandbox.stub(uut.fullStackJwt, 'getJWT').resolves() + sandbox.stub(uut.fullStackJwt, 'instanceBchjs').resolves() + const ipfsSpy = sandbox.stub(uut.ipfs, 'start').resolves(null) + + const result = await uut.start() + + assert.isTrue(ipfsSpy.notCalled) + assert.equal(result, true) + }) it('should catch and throw an error', async () => { try { diff --git a/test/e2e/automated/a09-admin.rest-e2e.js b/test/unit/adapters/admin.adapter.unit.js similarity index 50% rename from test/e2e/automated/a09-admin.rest-e2e.js rename to test/unit/adapters/admin.adapter.unit.js index 62901b0..6b59261 100644 --- a/test/e2e/automated/a09-admin.rest-e2e.js +++ b/test/unit/adapters/admin.adapter.unit.js @@ -19,26 +19,13 @@ describe('Admin', () => { if (!config.noMongo) { describe('loginAdmin()', () => { - it('should logind admin', async () => { + it('should login admin', async () => { try { - const error = new Error('test error') - error.response = { - status: 422 - } - // sandbox.stub(uut.axios, 'request').onFirstCall().throws(error) + sandbox.stub(uut.jsonFiles, 'readJSON').resolves({ password: 'pass' }) + sandbox.stub(uut.axios, 'request').resolves(true) const result = await uut.loginAdmin() - const user = result.data.user - - assert.property(user, '_id') - assert.property(user, 'email') - assert.property(user, 'type') - - assert.isString(user._id) - assert.isString(user.email) - assert.isString(user.type) - - assert.equal(user.type, 'admin') + assert.isTrue(result) } catch (err) { assert(false, 'Unexpected result') } @@ -48,13 +35,13 @@ describe('Admin', () => { try { // Returns an erroneous password to force // an auth error + sandbox.stub(uut.axios, 'request').throws(new Error('test error')) sandbox.stub(uut.jsonFiles, 'readJSON').resolves({ password: 'wrong' }) await uut.loginAdmin() assert(false, 'Unexpected result') } catch (err) { - assert.equal(err.response.status, 401) - assert.include(err.response.data, 'Unauthorized') + assert.include(err.message, 'test error') } }) }) @@ -62,6 +49,7 @@ describe('Admin', () => { describe('createSystemUser()', () => { it('should create admin', async () => { try { + await uut.deleteExistingSystemUser() const result = await uut.createSystemUser() assert.property(result, 'email') @@ -72,44 +60,59 @@ describe('Admin', () => { assert(false, 'Unexpected result') } }) - - it('should handle axios error', async () => { + it('should update admin password', async () => { try { - const error1 = new Error('test error') - error1.response = { - status: 422 - } - const error2 = new Error('test error') - error1.response = { - status: 500 - } - // The loginAdmin() function in some use cases is recursive - // after handling the 422 error, it gets called again - sandbox - .stub(uut.axios, 'request') - .onFirstCall() - .throws(error1) - .onSecondCall() - .throws(error2) + uut.config.adminPassword = 'newpassword' - await uut.createSystemUser() + const fakeUser = { + password: 'oldpassword', + save: () => { return 'token' }, + generateToken: () => { return 'token' } + } + + sandbox.stub(uut.User, 'findOne').resolves(fakeUser) + sandbox.stub(uut.jsonFiles, 'writeJSON').resolves(true) + const result = await uut.createSystemUser() + + assert.property(result, 'email') + assert.property(result, 'password') + assert.property(result, 'id') + assert.property(result, 'token') + + assert.equal(fakeUser.password, 'newpassword', 'password should be updated') + } catch (err) { + console.log(err) assert(false, 'Unexpected result') + } + }) + + it('should handle error', async () => { + try { + sandbox.stub(uut.User, 'findOne').throws(new Error('test error')) + await uut.createSystemUser() + assert.fail('Unexpected result') } catch (err) { assert.include(err.message, 'test error') } }) + }) - it('should handle errors when remove user', async () => { + describe('deleteExistingSystemUser()', () => { + it('should delete admin', async () => { try { - const error1 = new Error('test error') - error1.response = { - status: 422 - } - sandbox.stub(uut.axios, 'request').throws(error1) - sandbox.stub(uut.User, 'deleteOne').throws(new Error('test error')) - - await uut.createSystemUser() + sandbox.stub(uut.User, 'deleteOne').resolves(true) + const result = await uut.deleteExistingSystemUser() + assert.isTrue(result) + } catch (err) { assert(false, 'Unexpected result') + } + }) + + it('should handle error when deleting admin', async () => { + try { + sandbox.stub(uut.User, 'deleteOne').throws(new Error('test error')) + await uut.deleteExistingSystemUser() + assert.fail('Unexpected result') } catch (err) { assert.include(err.message, 'test error') } diff --git a/test/unit/adapters/passport.adapter.unit.js b/test/unit/adapters/passport.adapter.unit.js index 536fe54..2372a19 100644 --- a/test/unit/adapters/passport.adapter.unit.js +++ b/test/unit/adapters/passport.adapter.unit.js @@ -41,5 +41,17 @@ describe('#passport.js', () => { assert.include(err.message, 'cant auth user') } }) + it('should authenticate user', async () => { + const ctx = {} + const errMock = null + const userMock = { + _id: '123', + email: 'test@test.com' + } + sandbox.stub(uut.passport, 'authenticate').yields(errMock, userMock) + const user = await uut.authUser(ctx) + assert.equal(user._id, userMock._id) + assert.equal(user.email, userMock.email) + }) }) }) diff --git a/test/unit/adapters/users.adapter.unit.js b/test/unit/adapters/users.adapter.unit.js index 286d1eb..0205d55 100644 --- a/test/unit/adapters/users.adapter.unit.js +++ b/test/unit/adapters/users.adapter.unit.js @@ -54,6 +54,13 @@ describe('#User-Adapter', () => { assert.notEqual(testuser.password, 'password') }) + it('should ignore password encrption if password property is not provided', async () => { + const lastPassword = testuser.password + await testuser.save() + // console.log('testuser: ', testuser) + + assert.equal(testuser.password, lastPassword) + }) }) describe('#validatePassword', () => { diff --git a/test/unit/controllers/controllers.unit.js b/test/unit/controllers/controllers.unit.js index d574dee..445ed72 100644 --- a/test/unit/controllers/controllers.unit.js +++ b/test/unit/controllers/controllers.unit.js @@ -63,4 +63,25 @@ describe('#Controllers', () => { } }) }) + describe('#attachRESTControllers', () => { + it('should attach the controllers', async () => { + const app = { + use: () => {} + } + + await uut.attachRESTControllers(app) + }) + }) + describe('#initAdapters', () => { + it('should attach the controllers', async () => { + sandbox.stub(uut.adapters, 'start').resolves({}) + await uut.initAdapters() + }) + }) + describe('#initUseCases', () => { + it('should attach the controllers', async () => { + sandbox.stub(uut.useCases, 'start').resolves({}) + await uut.initUseCases() + }) + }) }) diff --git a/test/unit/controllers/rest-api/auth/auth.rest.controller.unit.js b/test/unit/controllers/rest-api/auth/auth.rest.controller.unit.js index 9c53d05..90a7726 100644 --- a/test/unit/controllers/rest-api/auth/auth.rest.controller.unit.js +++ b/test/unit/controllers/rest-api/auth/auth.rest.controller.unit.js @@ -79,11 +79,22 @@ describe('#Auth-REST-Router', () => { await uut.authUser(ctx) }) - it('should catch and throw an error', async () => { + it('should catch and throw passport error', async () => { try { // Force an error sandbox.stub(uut.passport, 'authUser').rejects('test error') + await uut.authUser(ctx) + } catch (err) { + // console.log('err: ', err) + assert.include(err.message, 'Unauthorized') + } + }) + it('should handle error if user is not found!', async () => { + try { + // Force an error + sandbox.stub(uut.passport, 'authUser').resolves(null) + await uut.authUser(ctx) } catch (err) { // console.log('err: ', err) diff --git a/test/unit/controllers/rest-api/rest.controller.unit.js b/test/unit/controllers/rest-api/rest.controller.unit.js index 0e46689..ae70c6e 100644 --- a/test/unit/controllers/rest-api/rest.controller.unit.js +++ b/test/unit/controllers/rest-api/rest.controller.unit.js @@ -20,7 +20,7 @@ describe('#RESTControllers', () => { let sandbox // let ctx - before(async () => {}) + before(async () => { }) beforeEach(() => { const useCases = new UseCasesMock() @@ -64,4 +64,19 @@ describe('#RESTControllers', () => { } }) }) + + describe('#attachRESTControllers', () => { + it('should attach controllers without mongo service', () => { + uut.config.noMongo = true + + const app = { use: () => {} } + uut.attachRESTControllers(app) + }) + it('should attach controllers with mongo service', () => { + uut.config.noMongo = false + + const app = { use: () => {} } + uut.attachRESTControllers(app) + }) + }) }) diff --git a/test/unit/controllers/rest-api/users/users.rest.controller.unit.js b/test/unit/controllers/rest-api/users/users.rest.controller.unit.js index 45b1b81..47c0a82 100644 --- a/test/unit/controllers/rest-api/users/users.rest.controller.unit.js +++ b/test/unit/controllers/rest-api/users/users.rest.controller.unit.js @@ -153,6 +153,20 @@ describe('#Users-REST-Controller', () => { // Assert that expected properties exist in the returned data. assert.property(ctx.response.body, 'user') }) + it('should run next function if it exists', async () => { + // Mock dependencies + const nextSpy = sandbox.spy() + sandbox.stub(uut.useCases.user, 'getUser').resolves({ _id: '123' }) + + await uut.getUser(ctx, nextSpy) + + // Assert the expected HTTP response + assert.equal(ctx.status, 200) + + // Assert that expected properties exist in the returned data. + assert.property(ctx.response.body, 'user') + assert.isTrue(nextSpy.calledOnce) + }) it('should return other error status passed by biz logic', async () => { try { diff --git a/test/unit/controllers/rest-api/users/users.rest.router.unit.js b/test/unit/controllers/rest-api/users/users.rest.router.unit.js index 798264f..126e5ae 100644 --- a/test/unit/controllers/rest-api/users/users.rest.router.unit.js +++ b/test/unit/controllers/rest-api/users/users.rest.router.unit.js @@ -79,4 +79,70 @@ describe('#Users-REST-Router', () => { } }) }) + + describe('#createUser', () => { + it('should ignore admin validator when DISABLE_NEW_ACCOUNTS is not defined', async () => { + // Stub functions + const validationSpy = sandbox.stub(uut.validators, 'ensureAdmin').resolves(true) + sandbox.stub(uut.userRESTController, 'createUser').resolves(true) + + // Call function + await uut.createUser() + + // Assertions + assert.isTrue(validationSpy.notCalled, 'Admin validator should not be called') + }) + it('should ensure admin when DISABLE_NEW_ACCOUNTS is defined', async () => { + // Set environment variable + process.env.DISABLE_NEW_ACCOUNTS = true + + // Stub functions + const validationSpy = sandbox.stub(uut.validators, 'ensureAdmin').resolves(true) + sandbox.stub(uut.userRESTController, 'createUser').resolves(true) + + // Call function + await uut.createUser() + + // Assertions + assert.isTrue(validationSpy.calledOnce, 'Admin validator should be called') + }) + }) + describe('#getAll', () => { + it('should route to controller', async () => { + sandbox.stub(uut.validators, 'ensureUser').resolves(true) + const spy = sandbox.stub(uut.userRESTController, 'getUsers').resolves(true) + + await uut.getAll() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#getById', () => { + it('should route to controller', async () => { + sandbox.stub(uut.validators, 'ensureUser').resolves(true) + const spy = sandbox.stub(uut.userRESTController, 'getUser').resolves(true) + + await uut.getById() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#updateUser', () => { + it('should route to controller', async () => { + sandbox.stub(uut.validators, 'ensureTargetUserOrAdmin').resolves(true) + sandbox.stub(uut.userRESTController, 'getUser').resolves(true) + const spy = sandbox.stub(uut.userRESTController, 'updateUser').resolves(true) + + await uut.updateUser() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#deleteUser', () => { + it('should route to controller', async () => { + sandbox.stub(uut.validators, 'ensureTargetUserOrAdmin').resolves(true) + sandbox.stub(uut.userRESTController, 'getUser').resolves(true) + const spy = sandbox.stub(uut.userRESTController, 'deleteUser').resolves(true) + + await uut.deleteUser() + assert.isTrue(spy.calledOnce) + }) + }) }) diff --git a/test/unit/controllers/timer-controllers.unit.js b/test/unit/controllers/timer-controllers.unit.js index fda1b72..3daacdc 100644 --- a/test/unit/controllers/timer-controllers.unit.js +++ b/test/unit/controllers/timer-controllers.unit.js @@ -66,19 +66,19 @@ describe('#Timer-Controllers', () => { }) }) - describe('#exampleTimerFunc', () => { - it('should kick off the Use Case', async () => { - const result = await uut.exampleTimerFunc() + // describe('#exampleTimerFunc', () => { + // it('should kick off the Use Case', async () => { + // const result = await uut.exampleTimerFunc() - assert.equal(result, true) - }) + // assert.equal(result, true) + // }) - it('should return false on error', async () => { - const result = await uut.exampleTimerFunc(true) + // it('should return false on error', async () => { + // const result = await uut.exampleTimerFunc(true) - assert.equal(result, false) - }) - }) + // assert.equal(result, false) + // }) + // }) describe('#cleanUsage', () => { it('should kick off the Use Case', async () => { @@ -94,4 +94,21 @@ describe('#Timer-Controllers', () => { assert.equal(result, false) }) }) + + describe('#backupUsage', () => { + it('should kick off the Use Case', async () => { + const result = await uut.backupUsage() + + assert.equal(result, true) + }) + + it('should return false on error', async () => { + sandbox.stub(uut.useCases.usage, 'clearUsage').throws(new Error('test error')) + // sandbox.stub(uut.useCases.usage, 'saveUsage').throws(new Error('test error')) + + const result = await uut.backupUsage() + + assert.equal(result, false) + }) + }) }) diff --git a/test/unit/misc/passport.unit.js b/test/unit/misc/passport.unit.js index 6cd1705..b646e45 100644 --- a/test/unit/misc/passport.unit.js +++ b/test/unit/misc/passport.unit.js @@ -34,6 +34,12 @@ describe('#passport', () => { passportCallback(id, 'password', done) }) + it('should handle not found user', () => { + // Mock Users model. + sandbox.stub(User, 'findOne').resolves(null) + + passportCallback(id, 'password', done) + }) it('should return if password is validated', () => { // Mock Users model. @@ -41,6 +47,15 @@ describe('#passport', () => { passportCallback(id, 'password', done) }) + it('should handle error on password validation', () => { + // Mock Users model. + const userMock = { + validatePassword: () => false + } + sandbox.stub(User, 'findOne').resolves(userMock) + + passportCallback(id, 'password', done) + }) it('should catch a high-level error', () => { // Force an error diff --git a/test/unit/misc/server-unit.js b/test/unit/misc/server-unit.js index 828d6b8..138bf3b 100644 --- a/test/unit/misc/server-unit.js +++ b/test/unit/misc/server-unit.js @@ -30,7 +30,7 @@ describe('#server', () => { sandbox.stub(uut.adminLib, 'createSystemUser').resolves(true) sandbox.stub(uut.controllers, 'attachControllers').resolves() uut.config.env = 'dev' - + uut.config.port = 5040 const result = await uut.startServer() // console.log('result: ', result) diff --git a/test/unit/mocks/adapters/index.js b/test/unit/mocks/adapters/index.js index 1ce1420..86a63ba 100644 --- a/test/unit/mocks/adapters/index.js +++ b/test/unit/mocks/adapters/index.js @@ -70,6 +70,39 @@ const localdb = { } }, + Usage: class Usage { + static findById () {} + static find () {} + static findOne () { + return { + validatePassword: localdb.validatePassword + } + } + + async save () { + return {} + } + + generateToken () { + return '123' + } + + toJSON () { + return {} + } + + async remove () { + return true + } + + async validatePassword () { + return true + } + static async deleteMany(){ + return true + } + }, + validatePassword: () => { return true } diff --git a/test/unit/mocks/use-cases/index.js b/test/unit/mocks/use-cases/index.js index f3aafb3..721216e 100644 --- a/test/unit/mocks/use-cases/index.js +++ b/test/unit/mocks/use-cases/index.js @@ -63,6 +63,14 @@ class UsageUseCaseMock { async getTopEndpoints(existingUser, newData) { return true } + + async clearUsage() { + return true + } + + async saveUsage() { + return true + } } class UseCasesMock { diff --git a/test/unit/use-cases/usage.use-case.unit.js b/test/unit/use-cases/usage.use-case.unit.js index 5dac264..b29900f 100644 --- a/test/unit/use-cases/usage.use-case.unit.js +++ b/test/unit/use-cases/usage.use-case.unit.js @@ -1,6 +1,5 @@ /* -Unit tests for the use-cases/usage-use-cases.js business logic library. - + Unit tests for the use-cases/usage-use-cases.js business logic library. */ // Public npm libraries @@ -58,7 +57,7 @@ describe('#usage-use-case', () => { // set older mock data restCalls.push({ - timestamp: now.getTime() - (60000 * 60 * 24), + timestamp: now.getTime() - (60000 * 60 * 48), // 48 hours ago ip: '127.0.0.1' }) @@ -88,6 +87,7 @@ describe('#usage-use-case', () => { } }) }) + describe('#getRestSummary', () => { it('should get the number of rest calls', () => { // Set mock data @@ -137,6 +137,7 @@ describe('#usage-use-case', () => { assert.equal(result[0].ip, 'localhost') assert.equal(result[0].cnt, '2') }) + it('should return a maximum of 20 values', () => { // Fill Array with 21 values for (let i = 0; i < 21; i++) { @@ -154,6 +155,7 @@ describe('#usage-use-case', () => { assert.equal(result.length, 20) }) + it('should handle error', () => { try { // Set mock data @@ -194,6 +196,7 @@ describe('#usage-use-case', () => { assert.equal(result[0].endpoint, 'GET /api/v1/users') assert.equal(result[0].cnt, '2') }) + it('should return a maximum of 20 values', () => { // Fill Array with 21 values for (let i = 0; i < 21; i++) { @@ -252,4 +255,67 @@ describe('#usage-use-case', () => { } }) }) + describe('#clearUsage', () => { + it('should clear the usage database data', async () => { + const res = await uut.clearUsage() + assert.isTrue(res) + }) + + it('should handle error', async () => { + try { + sandbox.stub(uut.UsageModel, 'deleteMany').throws(new Error('uut error')) + await uut.clearUsage() + assert.fail('Unexpected code path') + } catch (error) { + assert.equal(error.message, 'uut error') + } + }) + }) + + describe('#saveUsage', () => { + it('should save usage', async () => { + // Set mock data + restCalls.push({ + timestamp: new Date().getTime(), + ip: 'localhost', + url: 'fakeUrl', + method: 'unit test' + }) + const res = await uut.saveUsage() + assert.isTrue(res) + }) + + it('should handle error', async () => { + try { + restCalls.push(null) + await uut.saveUsage() + assert.fail('Unexpected code path') + } catch (error) { + console.log(error) + assert.include(error.message, 'Cannot read properties') + } + }) + }) + + describe('#loadUsage', () => { + it('should load usage', async () => { + // Set mock data + const mockObj = { + timestamp: new Date().getTime(), + ip: 'localhost', + url: 'fakeUrl', + method: 'unit test' + } + sandbox.stub(uut.UsageModel, 'find').returns(new Array(10).fill(null).map((_, i) => (mockObj))) + const res = await uut.loadUsage() + assert.equal(restCalls.length, 10) + assert.equal(res.length, 10) + }) + + it('should skip error', async () => { + sandbox.stub(uut.UsageModel, 'find').throws(new Error('uut error')) + const res = await uut.loadUsage() + assert.isFalse(res) + }) + }) }) diff --git a/test/utils/test-utils.js b/test/utils/test-utils.js index 5758dbc..6ee0e45 100644 --- a/test/utils/test-utils.js +++ b/test/utils/test-utils.js @@ -8,7 +8,6 @@ import axios from 'axios' // Local libraries import config from '../../config/index.js' -import User from '../../src/adapters/localdb/models/users.js' import JsonFiles from '../../src/adapters/json-files.js' // Hack to get __dirname back. @@ -33,24 +32,6 @@ async function cleanDb () { } } -// Delete all users in the database. This ensures there is no previous state -// to confuse tests. -async function deleteAllUsers () { - try { - // Get all the users in the DB. - const users = await User.find({}, '-password') - // console.log(`users: ${JSON.stringify(users, null, 2)}`) - - // Delete each user. - for (let i = 0; i < users.length; i++) { - const thisUser = users[i] - await thisUser.remove() - } - } catch (err) { - console.error('Error in test-utils.js/deleteAllUsers()') - } -} - // This function is used to create new users. // userObj = { // username, @@ -170,12 +151,56 @@ async function getAdminJWT () { throw err } } +// Fetches all users from the database. +async function getAllUsers () { + try { + const adminJWT = await getAdminJWT() + const options = { + method: 'GET', + url: `${LOCALHOST}/users`, + headers: { + Authorization: `Bearer ${adminJWT}` + } + } + const result = await axios(options) + return result.data.users + } catch (err) { + console.error('Error in test/utils.js/getAllUsers()', err) + throw err + } +} +// Deletes all users from the database. +async function deleteAllUsers () { + try { + const allUsers = await getAllUsers() + const adminJWT = await getAdminJWT() + for (let i = 0; i < allUsers.length; i++) { + const user = allUsers[i] + // Skip the admin user. + if (user.type === 'admin') { + continue + } + const options = { + method: 'DELETE', + url: `${LOCALHOST}/users/${user._id}`, + headers: { + Authorization: `Bearer ${adminJWT}` + } + } + await axios(options) + } + } catch (err) { + console.error('Error in test/utils.js/deleteAllUsers()', err) + throw err + } +} export default { cleanDb, createUser, loginTestUser, loginAdminUser, getAdminJWT, - deleteAllUsers + deleteAllUsers, + getAllUsers } diff --git a/util/users/createUsers.js b/util/users/createUsers.js index 3fc75e4..894eb2d 100644 --- a/util/users/createUsers.js +++ b/util/users/createUsers.js @@ -1,8 +1,9 @@ import mongoose from 'mongoose' import config from '../../config/index.js' +import User from '../../src/adapters/localdb/models/users.js' -const EMAIL = 'test@test.com' -const PASSWORD = 'pass' +const EMAIL = process.env.EMAIL || 'test@test3.com' +const PASSWORD = process.env.PASSWORD || 'pass' async function addUser () { // Connect to the Mongo Database. @@ -13,8 +14,6 @@ async function addUser () { { useNewUrlParser: true, useUnifiedTopology: true } ) - const User = require('../../src/models/users') - const userData = { email: EMAIL, password: PASSWORD diff --git a/util/users/getUsers.js b/util/users/getUsers.js index 56e1109..80b8681 100644 --- a/util/users/getUsers.js +++ b/util/users/getUsers.js @@ -1,6 +1,6 @@ import mongoose from 'mongoose' import config from '../../config/index.js' -import User from '../../src/models/users.js' +import User from '../../src/adapters/localdb/models/users.js' async function getUsers () { // Connect to the Mongo Database. diff --git a/util/users/updateUser.js b/util/users/updateUser.js new file mode 100644 index 0000000..28fa83d --- /dev/null +++ b/util/users/updateUser.js @@ -0,0 +1,30 @@ +import mongoose from 'mongoose' +import config from '../../config/index.js' +import User from '../../src/adapters/localdb/models/users.js' + +async function getUsers () { + // Connect to the Mongo Database. + mongoose.Promise = global.Promise + mongoose.set('useCreateIndex', true) // Stop deprecation warning. + await mongoose.connect( + config.database, + { useNewUrlParser: true, useUnifiedTopology: true } + ) + + // Find the user by email. + const user = await User.findOne({ + email: 'test@test.com' + }, '-password') + + // Update the users password + // user.password = 'newpassword' + + // Change the user to an admin + // user.type = 'admin' + + // Save the changes to the database. + await user.save() + + mongoose.connection.close() +} +getUsers()