mirror of
https://github.com/koush/scrypted.git
synced 2026-02-13 10:22:57 +00:00
Merge branch 'main' of github.com:koush/scrypted
This commit is contained in:
120
server/package-lock.json
generated
120
server/package-lock.json
generated
@@ -17,7 +17,7 @@
|
||||
"body-parser": "^1.19.0",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"debug": "^4.3.1",
|
||||
"engine.io": "^5.2.0",
|
||||
"engine.io": "^6.2.0",
|
||||
"express": "^4.17.2",
|
||||
"http-auth": "^4.1.9",
|
||||
"level": "^6.0.1",
|
||||
@@ -50,7 +50,6 @@
|
||||
"@types/adm-zip": "^0.4.33",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/engine.io": "^3.1.5",
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/http-auth": "^4.1.1",
|
||||
"@types/lodash": "^4.14.168",
|
||||
@@ -177,6 +176,11 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
|
||||
},
|
||||
"node_modules/@types/cookie-parser": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz",
|
||||
@@ -186,6 +190,11 @@
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
|
||||
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw=="
|
||||
},
|
||||
"node_modules/@types/debug": {
|
||||
"version": "4.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
|
||||
@@ -195,15 +204,6 @@
|
||||
"@types/ms": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/engine.io": {
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.7.tgz",
|
||||
"integrity": "sha512-qNjVXcrp+1sS8YpRUa714r0pgzOwESdW5UjHL7D/2ZFdBX0BXUXtg1LUrp+ylvqbvMcMWUy73YpRoxPN2VoKAQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express": {
|
||||
"version": "4.17.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
|
||||
@@ -291,8 +291,7 @@
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz",
|
||||
"integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA=="
|
||||
},
|
||||
"node_modules/@types/node-dijkstra": {
|
||||
"version": "2.5.2",
|
||||
@@ -534,14 +533,6 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base64-arraybuffer": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
|
||||
"integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@@ -895,39 +886,39 @@
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-5.2.1.tgz",
|
||||
"integrity": "sha512-hyNxjVgWp619QMfqi/+/6/LQF+ueOIWeVOza3TeyvxUGjeT9U/xPkkHW/NJNuhbStrxMujEoMadoc2EY7DDEnw==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz",
|
||||
"integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~4.0.0",
|
||||
"ws": "~7.4.2"
|
||||
"engine.io-parser": "~5.0.3",
|
||||
"ws": "~8.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.3.tgz",
|
||||
"integrity": "sha512-xEAAY0msNnESNPc00e19y5heTPX4y/TJ36gr8t1voOaNmTojP9b3oK3BbJLFufW2XFPQaaijpFewm2g2Um3uqA==",
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "0.1.4"
|
||||
},
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
|
||||
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/ws": {
|
||||
"version": "7.4.6",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
|
||||
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
|
||||
"version": "8.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
@@ -2630,6 +2621,11 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
|
||||
},
|
||||
"@types/cookie-parser": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz",
|
||||
@@ -2639,6 +2635,11 @@
|
||||
"@types/express": "*"
|
||||
}
|
||||
},
|
||||
"@types/cors": {
|
||||
"version": "2.8.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
|
||||
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw=="
|
||||
},
|
||||
"@types/debug": {
|
||||
"version": "4.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz",
|
||||
@@ -2648,15 +2649,6 @@
|
||||
"@types/ms": "*"
|
||||
}
|
||||
},
|
||||
"@types/engine.io": {
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.7.tgz",
|
||||
"integrity": "sha512-qNjVXcrp+1sS8YpRUa714r0pgzOwESdW5UjHL7D/2ZFdBX0BXUXtg1LUrp+ylvqbvMcMWUy73YpRoxPN2VoKAQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.17.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
|
||||
@@ -2744,8 +2736,7 @@
|
||||
"@types/node": {
|
||||
"version": "17.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz",
|
||||
"integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA=="
|
||||
},
|
||||
"@types/node-dijkstra": {
|
||||
"version": "2.5.2",
|
||||
@@ -2957,11 +2948,6 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"base64-arraybuffer": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz",
|
||||
"integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
@@ -3223,34 +3209,34 @@
|
||||
}
|
||||
},
|
||||
"engine.io": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-5.2.1.tgz",
|
||||
"integrity": "sha512-hyNxjVgWp619QMfqi/+/6/LQF+ueOIWeVOza3TeyvxUGjeT9U/xPkkHW/NJNuhbStrxMujEoMadoc2EY7DDEnw==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz",
|
||||
"integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==",
|
||||
"requires": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~4.0.0",
|
||||
"ws": "~7.4.2"
|
||||
"engine.io-parser": "~5.0.3",
|
||||
"ws": "~8.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": {
|
||||
"version": "7.4.6",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
|
||||
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
|
||||
"version": "8.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.3.tgz",
|
||||
"integrity": "sha512-xEAAY0msNnESNPc00e19y5heTPX4y/TJ36gr8t1voOaNmTojP9b3oK3BbJLFufW2XFPQaaijpFewm2g2Um3uqA==",
|
||||
"requires": {
|
||||
"base64-arraybuffer": "0.1.4"
|
||||
}
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
|
||||
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg=="
|
||||
},
|
||||
"env-paths": {
|
||||
"version": "2.2.1",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"body-parser": "^1.19.0",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"debug": "^4.3.1",
|
||||
"engine.io": "^5.2.0",
|
||||
"engine.io": "^6.2.0",
|
||||
"express": "^4.17.2",
|
||||
"http-auth": "^4.1.9",
|
||||
"level": "^6.0.1",
|
||||
@@ -44,7 +44,6 @@
|
||||
"@types/adm-zip": "^0.4.33",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/engine.io": "^3.1.5",
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/http-auth": "^4.1.1",
|
||||
"@types/lodash": "^4.14.168",
|
||||
|
||||
@@ -103,11 +103,13 @@ export class PluginHostAPI extends PluginAPIManagedListeners implements PluginAP
|
||||
}
|
||||
|
||||
async ioClose(id: string) {
|
||||
// @ts-ignore
|
||||
this.pluginHost.io.clients[id]?.close();
|
||||
this.pluginHost.ws[id]?.close();
|
||||
}
|
||||
|
||||
async ioSend(id: string, message: string) {
|
||||
// @ts-ignore
|
||||
this.pluginHost.io.clients[id]?.send(message);
|
||||
this.pluginHost.ws[id]?.send(message);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { Device, EngineIOHandler } from '@scrypted/types';
|
||||
import AdmZip from 'adm-zip';
|
||||
import crypto from 'crypto';
|
||||
import io, { Socket } from 'engine.io';
|
||||
import * as io from 'engine.io';
|
||||
import fs from 'fs';
|
||||
import mkdirp from 'mkdirp';
|
||||
import path from 'path';
|
||||
import rimraf from 'rimraf';
|
||||
import WebSocket from 'ws';
|
||||
import { Plugin } from '../db-types';
|
||||
import { IOServer, IOSocket } from '../io';
|
||||
import { Logger } from '../logger';
|
||||
import { RpcPeer } from '../rpc';
|
||||
import { ScryptedRuntime } from '../runtime';
|
||||
@@ -34,8 +35,15 @@ export class PluginHost {
|
||||
module: Promise<any>;
|
||||
scrypted: ScryptedRuntime;
|
||||
remote: PluginRemote;
|
||||
io = io(undefined, {
|
||||
io: IOServer<io.Socket> = new io.Server({
|
||||
pingTimeout: 120000,
|
||||
cors: (req, callback) => {
|
||||
const header = this.scrypted.getAccessControlAllowOrigin(req.headers);
|
||||
callback(undefined, {
|
||||
origin: header,
|
||||
credentials: true,
|
||||
})
|
||||
},
|
||||
});
|
||||
ws: { [id: string]: WebSocket } = {};
|
||||
api: PluginHostAPI;
|
||||
@@ -140,13 +148,13 @@ export class PluginHost {
|
||||
const handler = this.scrypted.getDevice<EngineIOHandler>(pluginDevice._id);
|
||||
|
||||
socket.on('message', message => {
|
||||
this.remote.ioEvent(socket.id, 'message', message)
|
||||
this.remote.ioEvent(socket.transport.sid, 'message', message)
|
||||
});
|
||||
socket.on('close', reason => {
|
||||
this.remote.ioEvent(socket.id, 'close');
|
||||
this.remote.ioEvent(socket.transport.sid, 'close');
|
||||
});
|
||||
|
||||
await handler.onConnection(endpointRequest, `io://${socket.id}`);
|
||||
await handler.onConnection(endpointRequest, `io://${socket.transport.sid}`);
|
||||
}
|
||||
catch (e) {
|
||||
console.error('engine.io plugin error', e);
|
||||
@@ -318,7 +326,7 @@ export class PluginHost {
|
||||
};
|
||||
}
|
||||
|
||||
async createRpcIoPeer(socket: Socket) {
|
||||
async createRpcIoPeer(socket: IOSocket) {
|
||||
let connected = true;
|
||||
const rpcPeer = new RpcPeer(`api/${this.pluginId}`, 'web', (message, reject) => {
|
||||
if (!connected)
|
||||
|
||||
@@ -8,22 +8,25 @@ export abstract class PluginHttp<T> {
|
||||
wss = new WebSocketServer({ noServer: true });
|
||||
|
||||
constructor(public app: Router) {
|
||||
app.all(['/endpoint/@:owner/:pkg/public/engine.io/*', '/endpoint/:pkg/public/engine.io/*'], (req, res) => {
|
||||
}
|
||||
|
||||
addMiddleware() {
|
||||
this.app.all(['/endpoint/@:owner/:pkg/public/engine.io/*', '/endpoint/:pkg/public/engine.io/*'], (req, res) => {
|
||||
this.endpointHandler(req, res, true, true, this.handleEngineIOEndpoint.bind(this))
|
||||
});
|
||||
|
||||
app.all(['/endpoint/@:owner/:pkg/engine.io/*', '/endpoint/@:owner/:pkg/engine.io/*'], (req, res) => {
|
||||
this.app.all(['/endpoint/@:owner/:pkg/engine.io/*', '/endpoint/@:owner/:pkg/engine.io/*'], (req, res) => {
|
||||
this.endpointHandler(req, res, false, true, this.handleEngineIOEndpoint.bind(this))
|
||||
});
|
||||
|
||||
// stringify all http endpoints
|
||||
app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], bodyParser.text() as any);
|
||||
this.app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], bodyParser.text() as any);
|
||||
|
||||
app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg/public', '/endpoint/:pkg/public/*'], (req, res) => {
|
||||
this.app.all(['/endpoint/@:owner/:pkg/public', '/endpoint/@:owner/:pkg/public/*', '/endpoint/:pkg/public', '/endpoint/:pkg/public/*'], (req, res) => {
|
||||
this.endpointHandler(req, res, true, false, this.handleRequestEndpoint.bind(this))
|
||||
});
|
||||
|
||||
app.all(['/endpoint/@:owner/:pkg', '/endpoint/@:owner/:pkg/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], (req, res) => {
|
||||
this.app.all(['/endpoint/@:owner/:pkg', '/endpoint/@:owner/:pkg/*', '/endpoint/:pkg', '/endpoint/:pkg/*'], (req, res) => {
|
||||
this.endpointHandler(req, res, false, false, this.handleRequestEndpoint.bind(this))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Plugin, PluginDevice, ScryptedAlert } from './db-types';
|
||||
import { getState, ScryptedStateManager, setState } from './state';
|
||||
import { Request, Response } from 'express';
|
||||
import { createResponseInterface } from './http-interfaces';
|
||||
import http, { ServerResponse } from 'http';
|
||||
import http, { ServerResponse, IncomingHttpHeaders } from 'http';
|
||||
import https from 'https';
|
||||
import express from 'express';
|
||||
import { LogEntry, Logger, makeAlertId } from './logger';
|
||||
@@ -25,13 +25,15 @@ import semver from 'semver';
|
||||
import { ServiceControl } from './services/service-control';
|
||||
import { Alerts } from './services/alerts';
|
||||
import { Info } from './services/info';
|
||||
import io from 'engine.io';
|
||||
import * as io from 'engine.io';
|
||||
import { spawn as ptySpawn } from 'node-pty';
|
||||
import rimraf from 'rimraf';
|
||||
import { getPluginVolume } from './plugin/plugin-volume';
|
||||
import { PluginHttp } from './plugin/plugin-http';
|
||||
import AdmZip from 'adm-zip';
|
||||
import path from 'path';
|
||||
import { CORSControl, CORSServer } from './services/cors';
|
||||
import { IOServer } from './io';
|
||||
|
||||
interface DeviceProxyPair {
|
||||
handler: PluginDeviceProxyHandler;
|
||||
@@ -56,9 +58,17 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
|
||||
devicesLogger = this.logger.getLogger('device', 'Devices');
|
||||
wss = new WebSocketServer({ noServer: true });
|
||||
wsAtomic = 0;
|
||||
shellio = io(undefined, {
|
||||
shellio: IOServer<io.Socket> = new io.Server({
|
||||
pingTimeout: 120000,
|
||||
cors: (req, callback) => {
|
||||
const header = this.getAccessControlAllowOrigin(req.headers);
|
||||
callback(undefined, {
|
||||
origin: header,
|
||||
credentials: true,
|
||||
})
|
||||
},
|
||||
});
|
||||
cors: CORSServer[] = [];
|
||||
|
||||
constructor(datastore: Level, insecure: http.Server, secure: https.Server, app: express.Application) {
|
||||
super(app);
|
||||
@@ -67,6 +77,8 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
|
||||
|
||||
app.disable('x-powered-by');
|
||||
|
||||
this.addMiddleware();
|
||||
|
||||
app.get('/web/oauth/callback', (req, res) => {
|
||||
this.oauthCallback(req, res);
|
||||
});
|
||||
@@ -122,6 +134,27 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
|
||||
}, 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
getAccessControlAllowOrigin(headers: IncomingHttpHeaders) {
|
||||
let { origin, referer } = headers;
|
||||
if (!origin && referer) {
|
||||
try {
|
||||
const u = new URL(headers.referer)
|
||||
origin = u.origin;
|
||||
}
|
||||
catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!origin)
|
||||
return;
|
||||
const servers: string[] = process.env.SCRYPTED_ACCESS_CONTROL_ALLOW_ORIGINS?.split(',') || [];
|
||||
servers.push(...Object.values(this.cors).map(entry => entry.server));
|
||||
if (!servers.includes(origin))
|
||||
return;
|
||||
|
||||
return origin;
|
||||
}
|
||||
|
||||
getDeviceLogger(device: PluginDevice): Logger {
|
||||
return this.devicesLogger.getLogger(device._id, getState(device, ScryptedInterfaceProperty.name));
|
||||
}
|
||||
@@ -311,6 +344,8 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
|
||||
return this.logger;
|
||||
case 'alerts':
|
||||
return new Alerts(this);
|
||||
case 'cors':
|
||||
return new CORSControl(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -360,6 +360,19 @@ async function start() {
|
||||
|
||||
let hasLogin = await db.getCount(ScryptedUser) > 0;
|
||||
|
||||
app.options('/login', (req, res) => {
|
||||
res.setHeader('Vary', 'Origin,Referer');
|
||||
res.set('Access-Control-Allow-Credentials', 'true');
|
||||
|
||||
const header = scrypted.getAccessControlAllowOrigin(req.headers);
|
||||
if (header)
|
||||
res.setHeader('Access-Control-Allow-Origin', header);
|
||||
|
||||
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
|
||||
res.set('Access-Control-Allow-Credentials', 'true');
|
||||
res.send(200);
|
||||
});
|
||||
app.post('/login', async (req, res) => {
|
||||
const { username, password, change_password } = req.body;
|
||||
const timestamp = Date.now();
|
||||
@@ -393,6 +406,7 @@ async function start() {
|
||||
secure: true,
|
||||
signed: true,
|
||||
httpOnly: true,
|
||||
sameSite: 'none',
|
||||
});
|
||||
|
||||
if (change_password) {
|
||||
@@ -432,6 +446,7 @@ async function start() {
|
||||
secure: true,
|
||||
signed: true,
|
||||
httpOnly: true,
|
||||
sameSite: 'none',
|
||||
});
|
||||
|
||||
res.send({
|
||||
@@ -442,6 +457,13 @@ async function start() {
|
||||
|
||||
|
||||
app.get('/login', async (req, res) => {
|
||||
res.setHeader('Vary', 'Origin,Referer');
|
||||
res.set('Access-Control-Allow-Credentials', 'true');
|
||||
|
||||
const header = scrypted.getAccessControlAllowOrigin(req.headers);
|
||||
if (header)
|
||||
res.setHeader('Access-Control-Allow-Origin', header);
|
||||
|
||||
if (req.protocol === 'https' && req.headers.authorization) {
|
||||
const username = await new Promise(resolve => {
|
||||
const basicChecker = basicAuth.check((req) => {
|
||||
|
||||
19
server/src/services/cors.ts
Normal file
19
server/src/services/cors.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { ScryptedRuntime } from "../runtime";
|
||||
|
||||
export interface CORSServer {
|
||||
tag: string;
|
||||
server: string;
|
||||
}
|
||||
|
||||
export class CORSControl {
|
||||
constructor(public runtime: ScryptedRuntime) {
|
||||
}
|
||||
|
||||
async getCORS(): Promise<CORSServer[]> {
|
||||
return this.runtime.cors;
|
||||
}
|
||||
|
||||
async setCORS(servers: CORSServer[]) {
|
||||
this.runtime.cors = servers;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user