diff --git a/plugins/cloud/package-lock.json b/plugins/cloud/package-lock.json index 50e9e3a50..8831bad85 100644 --- a/plugins/cloud/package-lock.json +++ b/plugins/cloud/package-lock.json @@ -1,28 +1,23 @@ { "name": "@scrypted/cloud", - "version": "0.1.23", + "version": "0.1.24", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@scrypted/cloud", - "version": "0.1.23", + "version": "0.1.24", "dependencies": { "@eneris/push-receiver": "^3.1.4", "@scrypted/common": "file:../../common", "@scrypted/sdk": "file:../../sdk", "axios": "^1.4.0", "bpmux": "^8.2.1", - "debug": "^4.3.4", "http-proxy": "^1.18.1", - "lodash": "^4.17.21", - "nat-upnp": "file:./external/node-nat-upnp", - "query-string": "^6.14.1" + "nat-upnp": "file:./external/node-nat-upnp" }, "devDependencies": { - "@types/debug": "^4.1.8", "@types/http-proxy": "^1.17.11", - "@types/lodash": "^4.14.196", "@types/nat-upnp": "^1.1.2", "@types/node": "^20.4.5" } @@ -80,6 +75,7 @@ } }, "external/node-nat-upnp": { + "name": "nat-upnp", "version": "1.1.1", "dependencies": { "async": "^2.1.5", @@ -168,15 +164,6 @@ "resolved": "../../sdk", "link": true }, - "node_modules/@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", - "dev": true, - "dependencies": { - "@types/ms": "*" - } - }, "node_modules/@types/http-proxy": { "version": "1.17.11", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", @@ -186,18 +173,6 @@ "@types/node": "*" } }, - "node_modules/@types/lodash": { - "version": "4.14.196", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.196.tgz", - "integrity": "sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==", - "dev": true - }, - "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true - }, "node_modules/@types/nat-upnp": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/nat-upnp/-/nat-upnp-1.1.2.tgz", @@ -383,30 +358,6 @@ "node": ">=0.4.0" } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/deep-equal": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", @@ -551,14 +502,6 @@ "node": "> 0.1.90" } }, - "node_modules/filter-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", - "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -1379,11 +1322,6 @@ "node": ">=0.8.0" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -1532,23 +1470,6 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "node_modules/query-string": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", - "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", - "dependencies": { - "decode-uri-component": "^0.2.0", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -1655,14 +1576,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", - "engines": { - "node": ">=6" - } - }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -1684,14 +1597,6 @@ "node": ">= 0.4" } }, - "node_modules/strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/strip-ansi": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", @@ -2079,15 +1984,6 @@ "webpack-bundle-analyzer": "^4.5.0" } }, - "@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", - "dev": true, - "requires": { - "@types/ms": "*" - } - }, "@types/http-proxy": { "version": "1.17.11", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", @@ -2097,18 +1993,6 @@ "@types/node": "*" } }, - "@types/lodash": { - "version": "4.14.196", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.196.tgz", - "integrity": "sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ==", - "dev": true - }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true - }, "@types/nat-upnp": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/nat-upnp/-/nat-upnp-1.1.2.tgz", @@ -2258,19 +2142,6 @@ "integrity": "sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==", "dev": true }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" - }, "deep-equal": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", @@ -2375,11 +2246,6 @@ "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", "dev": true }, - "filter-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", - "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==" - }, "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -3005,11 +2871,6 @@ } } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -3131,17 +2992,6 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "query-string": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", - "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", - "requires": { - "decode-uri-component": "^0.2.0", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - } - }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -3223,11 +3073,6 @@ "object-inspect": "^1.9.0" } }, - "split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" - }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -3243,11 +3088,6 @@ "internal-slot": "^1.0.4" } }, - "strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==" - }, "strip-ansi": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", diff --git a/plugins/cloud/package.json b/plugins/cloud/package.json index 7f16f7429..fde77bb48 100644 --- a/plugins/cloud/package.json +++ b/plugins/cloud/package.json @@ -42,18 +42,13 @@ "@scrypted/sdk": "file:../../sdk", "axios": "^1.4.0", "bpmux": "^8.2.1", - "debug": "^4.3.4", "http-proxy": "^1.18.1", - "lodash": "^4.17.21", - "nat-upnp": "file:./external/node-nat-upnp", - "query-string": "^6.14.1" + "nat-upnp": "file:./external/node-nat-upnp" }, "devDependencies": { - "@types/debug": "^4.1.8", "@types/http-proxy": "^1.17.11", - "@types/lodash": "^4.14.196", "@types/nat-upnp": "^1.1.2", "@types/node": "^20.4.5" }, - "version": "0.1.23" + "version": "0.1.24" } diff --git a/plugins/cloud/src/main.ts b/plugins/cloud/src/main.ts index 5d23cd95a..9388ec2f6 100644 --- a/plugins/cloud/src/main.ts +++ b/plugins/cloud/src/main.ts @@ -11,13 +11,12 @@ import upnp from 'nat-upnp'; import net from 'net'; import os from 'os'; import path from 'path'; -import qs from 'query-string'; import { Duplex } from 'stream'; import tls from 'tls'; -import Url from 'url'; import { createSelfSignedCertificate } from '../../../server/src/cert'; import { PushManager } from './push'; import { readLine } from '../../../common/src/read-stream'; +import { qsparse, qsstringify } from "./qs"; const { deviceManager, endpointManager, systemManager } = sdk; @@ -343,21 +342,21 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings, } async whitelist(localUrl: string, ttl: number, baseUrl: string): Promise { - const local = Url.parse(localUrl); + const local = new URL(localUrl); if (this.storageSettings.values.forwardingMode === 'Custom Domain' && this.storageSettings.values.hostname) { - return Buffer.from(`${baseUrl}${local.path}`); + return Buffer.from(`${baseUrl}${local.pathname}`); } - if (this.whitelisted.has(local.path)) { - return Buffer.from(this.whitelisted.get(local.path)); + if (this.whitelisted.has(local.pathname)) { + return Buffer.from(this.whitelisted.get(local.pathname)); } const { token_info } = this.storageSettings.values; if (!token_info) throw new Error('@scrypted/cloud is not logged in.'); - const q = qs.stringify({ - scope: local.path, + const q = qsstringify({ + scope: local.pathname, ttl, }) const scope = await axios(`https://${this.getHostname()}/_punch/scope?${q}`, { @@ -367,13 +366,13 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings, }) const { userToken, userTokenSignature } = scope.data; - const tokens = qs.stringify({ + const tokens = qsstringify({ user_token: userToken, user_token_signature: userTokenSignature }) - const url = `${baseUrl}${local.path}?${tokens}`; - this.whitelisted.set(local.path, url); + const url = `${baseUrl}${local.pathname}?${tokens}`; + this.whitelisted.set(local.pathname, url); return Buffer.from(url); } @@ -415,7 +414,7 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings, const { upnp_port, hostname } = this.getAuthority(); const registration_secret = this.storageSettings.values.registrationSecret || crypto.randomBytes(8).toString('base64'); - const q = qs.stringify({ + const q = qsstringify({ upnp_port, registration_id, sender_id: DEFAULT_SENDER_ID, @@ -520,7 +519,7 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings, } async getOauthUrl(): Promise { - const args = qs.stringify({ + const args = qsstringify({ hostname: os.hostname(), registration_id: await this.manager.registrationId, sender_id: DEFAULT_SENDER_ID, @@ -555,9 +554,9 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings, const handler = async (req: http.IncomingMessage, res: http.ServerResponse) => { this.console.log(req.socket?.remoteAddress, req.url); - const url = Url.parse(req.url); - if (url.path.startsWith('/web/oauth/callback') && url.query) { - const query = qs.parse(url.query); + const url = new URL(req.url, 'https://localhost'); + if (url.pathname.startsWith('/web/oauth/callback') && url.search) { + const query = qsparse(url.searchParams); if (!query.callback_url && query.token_info && query.user_info) { this.storageSettings.values.token_info = query.token_info; this.storageSettings.values.lastPersistedRegistrationId = await this.manager.registrationId; @@ -571,7 +570,7 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings, return; } } - else if (url.path === '/web/') { + else if (url.pathname === '/web/') { if (this.storageSettings.values.forwardingMode === 'Custom Domain' && this.storageSettings.values.hostname) res.setHeader('Location', `https://${this.storageSettings.values.hostname}/endpoint/@scrypted/core/public/`); else @@ -580,7 +579,7 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings, res.end(); return; } - else if (url.path === '/web/component/home/endpoint') { + else if (url.pathname === '/web/component/home/endpoint') { this.proxy.web(req, res, { target: googleHomeTarget.toString(), ignorePath: true, @@ -588,7 +587,7 @@ class ScryptedCloud extends ScryptedDeviceBase implements OauthClient, Settings, }); return; } - else if (url.path === '/web/component/alexa/endpoint') { + else if (url.pathname === '/web/component/alexa/endpoint') { this.proxy.web(req, res, { target: alexaTarget.toString(), ignorePath: true, diff --git a/plugins/cloud/src/qs.ts b/plugins/cloud/src/qs.ts new file mode 100644 index 000000000..059991635 --- /dev/null +++ b/plugins/cloud/src/qs.ts @@ -0,0 +1,16 @@ +export function qsstringify(dict: any) { + const params = new URLSearchParams(); + for (const [k, v] of Object.entries(dict)) { + params.set(k, v?.toString()); + } + + return params.toString(); +} + +export function qsparse(search: URLSearchParams) { + const ret: any = {}; + for (const [k, v] of search.entries()) { + ret[k] = v; + } + return ret; +} \ No newline at end of file