@scrypted/server 0.0.181 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @scrypted/server might be problematic. Click here for more details.
- package/dist/io.js +3 -0
- package/dist/io.js.map +1 -0
- package/dist/plugin/buffer-serializer.js +18 -1
- package/dist/plugin/buffer-serializer.js.map +1 -1
- package/dist/plugin/media.js +4 -3
- package/dist/plugin/media.js.map +1 -1
- package/dist/plugin/plugin-host-api.js +2 -0
- package/dist/plugin/plugin-host-api.js.map +1 -1
- package/dist/plugin/plugin-host.js +83 -14
- package/dist/plugin/plugin-host.js.map +1 -1
- package/dist/plugin/plugin-http.js +7 -5
- package/dist/plugin/plugin-http.js.map +1 -1
- package/dist/plugin/plugin-remote-websocket.js +0 -2
- package/dist/plugin/plugin-remote-websocket.js.map +1 -1
- package/dist/plugin/plugin-remote-worker.js +12 -10
- package/dist/plugin/plugin-remote-worker.js.map +1 -1
- package/dist/plugin/plugin-remote.js +4 -2
- package/dist/plugin/plugin-remote.js.map +1 -1
- package/dist/rpc.js +18 -27
- package/dist/rpc.js.map +1 -1
- package/dist/runtime.js +95 -2
- package/dist/runtime.js.map +1 -1
- package/dist/scrypted-server-main.js +20 -21
- package/dist/scrypted-server-main.js.map +1 -1
- package/dist/server-settings.js +67 -15
- package/dist/server-settings.js.map +1 -1
- package/dist/services/cors.js +17 -0
- package/dist/services/cors.js.map +1 -0
- package/package.json +6 -4
- package/python/plugin-remote.py +22 -17
- package/python/rpc.py +0 -6
- package/src/io.ts +25 -0
- package/src/plugin/buffer-serializer.ts +19 -0
- package/src/plugin/media.ts +5 -4
- package/src/plugin/plugin-host-api.ts +2 -0
- package/src/plugin/plugin-host.ts +70 -17
- package/src/plugin/plugin-http.ts +11 -8
- package/src/plugin/plugin-remote-websocket.ts +0 -2
- package/src/plugin/plugin-remote-worker.ts +12 -10
- package/src/plugin/plugin-remote.ts +4 -2
- package/src/rpc.ts +22 -36
- package/src/runtime.ts +86 -3
- package/src/scrypted-server-main.ts +24 -27
- package/src/server-settings.ts +54 -16
- package/src/services/cors.ts +19 -0
- package/dist/addresses.js +0 -12
- package/dist/addresses.js.map +0 -1
- package/src/addresses.ts +0 -5
@@ -8,7 +8,7 @@ import net from 'net';
|
|
8
8
|
import { ScryptedRuntime } from './runtime';
|
9
9
|
import level from './level';
|
10
10
|
import { Plugin, ScryptedUser, Settings } from './db-types';
|
11
|
-
import { SCRYPTED_DEBUG_PORT, SCRYPTED_INSECURE_PORT, SCRYPTED_SECURE_PORT } from './server-settings';
|
11
|
+
import { getHostAddresses, SCRYPTED_DEBUG_PORT, SCRYPTED_INSECURE_PORT, SCRYPTED_SECURE_PORT } from './server-settings';
|
12
12
|
import crypto from 'crypto';
|
13
13
|
import cookieParser from 'cookie-parser';
|
14
14
|
import axios from 'axios';
|
@@ -20,7 +20,6 @@ import { install as installSourceMapSupport } from 'source-map-support';
|
|
20
20
|
import httpAuth from 'http-auth';
|
21
21
|
import semver from 'semver';
|
22
22
|
import { Info } from './services/info';
|
23
|
-
import { getAddresses } from './addresses';
|
24
23
|
import { sleep } from './sleep';
|
25
24
|
import { createSelfSignedCertificate, CURRENT_SELF_SIGNED_CERTIFICATE_VERSION } from './cert';
|
26
25
|
import { PluginError } from './plugin/plugin-error';
|
@@ -123,7 +122,6 @@ async function start() {
|
|
123
122
|
certSetting = await db.upsert(certSetting);
|
124
123
|
}
|
125
124
|
|
126
|
-
|
127
125
|
const basicAuth = httpAuth.basic({
|
128
126
|
realm: 'Scrypted',
|
129
127
|
}, async (username, password, callback) => {
|
@@ -184,6 +182,7 @@ async function start() {
|
|
184
182
|
// }
|
185
183
|
|
186
184
|
res.locals.username = username;
|
185
|
+
(req as any).username = username;
|
187
186
|
}
|
188
187
|
next();
|
189
188
|
});
|
@@ -193,6 +192,7 @@ async function start() {
|
|
193
192
|
if (req.protocol === 'https' && req.headers.authorization && req.headers.authorization.toLowerCase()?.indexOf('basic') !== -1) {
|
194
193
|
const basicChecker = basicAuth.check((req) => {
|
195
194
|
res.locals.username = req.user;
|
195
|
+
(req as any).username = req.user;
|
196
196
|
next();
|
197
197
|
});
|
198
198
|
|
@@ -226,7 +226,7 @@ async function start() {
|
|
226
226
|
|
227
227
|
console.log('#######################################################');
|
228
228
|
console.log(`Scrypted Server (Local) : https://localhost:${SCRYPTED_SECURE_PORT}/`);
|
229
|
-
for (const address of
|
229
|
+
for (const address of getHostAddresses(true, true)) {
|
230
230
|
console.log(`Scrypted Server (Remote) : https://${address}:${SCRYPTED_SECURE_PORT}/`);
|
231
231
|
}
|
232
232
|
console.log(`Version: : ${await new Info().getVersion()}`);
|
@@ -360,10 +360,20 @@ async function start() {
|
|
360
360
|
|
361
361
|
let hasLogin = await db.getCount(ScryptedUser) > 0;
|
362
362
|
|
363
|
+
app.options('/login', (req, res) => {
|
364
|
+
scrypted.addAccessControlHeaders(req, res);
|
365
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
366
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
|
367
|
+
res.send(200);
|
368
|
+
});
|
369
|
+
|
363
370
|
app.post('/login', async (req, res) => {
|
371
|
+
scrypted.addAccessControlHeaders(req, res);
|
372
|
+
|
364
373
|
const { username, password, change_password } = req.body;
|
365
374
|
const timestamp = Date.now();
|
366
375
|
const maxAge = 86400000;
|
376
|
+
const addresses = getHostAddresses(true, true).map(address => `https://${address}:${SCRYPTED_SECURE_PORT}`);
|
367
377
|
|
368
378
|
if (hasLogin) {
|
369
379
|
const user = await db.tryGet(ScryptedUser, username);
|
@@ -393,6 +403,7 @@ async function start() {
|
|
393
403
|
secure: true,
|
394
404
|
signed: true,
|
395
405
|
httpOnly: true,
|
406
|
+
sameSite: 'none',
|
396
407
|
});
|
397
408
|
|
398
409
|
if (change_password) {
|
@@ -405,6 +416,7 @@ async function start() {
|
|
405
416
|
res.send({
|
406
417
|
username,
|
407
418
|
expiration: maxAge,
|
419
|
+
addresses,
|
408
420
|
});
|
409
421
|
|
410
422
|
return;
|
@@ -423,6 +435,7 @@ async function start() {
|
|
423
435
|
user.salt = crypto.randomBytes(64).toString('base64');
|
424
436
|
user.passwordHash = crypto.createHash('sha256').update(user.salt + password).digest().toString('hex');
|
425
437
|
user.passwordDate = timestamp;
|
438
|
+
user.token = crypto.randomBytes(16).toString('hex');
|
426
439
|
await db.upsert(user);
|
427
440
|
hasLogin = true;
|
428
441
|
|
@@ -432,16 +445,21 @@ async function start() {
|
|
432
445
|
secure: true,
|
433
446
|
signed: true,
|
434
447
|
httpOnly: true,
|
448
|
+
sameSite: 'none',
|
435
449
|
});
|
436
450
|
|
437
451
|
res.send({
|
438
452
|
username,
|
453
|
+
token: user.token,
|
439
454
|
expiration: maxAge,
|
455
|
+
addresses,
|
440
456
|
});
|
441
457
|
});
|
442
458
|
|
443
|
-
|
444
459
|
app.get('/login', async (req, res) => {
|
460
|
+
scrypted.addAccessControlHeaders(req, res);
|
461
|
+
|
462
|
+
const addresses = getHostAddresses(true, true).map(address => `https://${address}:${SCRYPTED_SECURE_PORT}`);
|
445
463
|
if (req.protocol === 'https' && req.headers.authorization) {
|
446
464
|
const username = await new Promise(resolve => {
|
447
465
|
const basicChecker = basicAuth.check((req) => {
|
@@ -484,31 +502,10 @@ async function start() {
|
|
484
502
|
return;
|
485
503
|
}
|
486
504
|
|
487
|
-
// this database lookup on every web request is not necessary, the cookie
|
488
|
-
// itself is the auth, and is signed. furthermore, this is currently
|
489
|
-
// a single user setup anywyas. revisit this at some point when
|
490
|
-
// multiple users are implemented.
|
491
|
-
|
492
|
-
// const user = await db.tryGet(ScryptedUser, username);
|
493
|
-
// if (!user) {
|
494
|
-
// res.send({
|
495
|
-
// error: 'User not found.',
|
496
|
-
// hasLogin,
|
497
|
-
// })
|
498
|
-
// return;
|
499
|
-
// }
|
500
|
-
|
501
|
-
// if (timestamp < user.passwordDate) {
|
502
|
-
// res.send({
|
503
|
-
// error: 'Login invalid. Password has changed.',
|
504
|
-
// hasLogin,
|
505
|
-
// })
|
506
|
-
// return;
|
507
|
-
// }
|
508
|
-
|
509
505
|
res.send({
|
510
506
|
expiration: 86400000 - (Date.now() - timestamp),
|
511
507
|
username,
|
508
|
+
addresses,
|
512
509
|
})
|
513
510
|
});
|
514
511
|
|
package/src/server-settings.ts
CHANGED
@@ -1,24 +1,62 @@
|
|
1
1
|
import os from 'os';
|
2
|
+
import * as nodeIp from 'ip';
|
2
3
|
|
3
4
|
export const SCRYPTED_INSECURE_PORT = parseInt(process.env.SCRYPTED_INSECURE_PORT) || 11080;
|
4
5
|
export const SCRYPTED_SECURE_PORT = parseInt(process.env.SCRYPTED_SECURE_PORT) || 10443;
|
5
6
|
export const SCRYPTED_DEBUG_PORT = parseInt(process.env.SCRYPTED_DEBUG_PORT) || 10081;
|
6
7
|
|
7
8
|
export function getIpAddress(): string {
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
9
|
+
return nodeIp.address();
|
10
|
+
}
|
11
|
+
|
12
|
+
function nodeIpAddress(family: string): string[] {
|
13
|
+
// https://chromium.googlesource.com/external/webrtc/+/master/rtc_base/network.cc#236
|
14
|
+
const costlyNetworks = ["ipsec", "tun", "utun", "tap"];
|
15
|
+
|
16
|
+
const ignoreNetworks = [
|
17
|
+
// seen these on macos
|
18
|
+
'llw',
|
19
|
+
'awdl',
|
20
|
+
|
21
|
+
...costlyNetworks,
|
22
|
+
];
|
23
|
+
|
24
|
+
const interfaces = os.networkInterfaces();
|
25
|
+
|
26
|
+
const all = Object.keys(interfaces)
|
27
|
+
.map((nic) => {
|
28
|
+
for (const costly of ignoreNetworks) {
|
29
|
+
if (nic.startsWith(costly)) {
|
30
|
+
return {
|
31
|
+
nic,
|
32
|
+
addresses: [],
|
33
|
+
};
|
34
|
+
}
|
35
|
+
}
|
36
|
+
const addresses = interfaces[nic]!.filter(
|
37
|
+
(details) =>
|
38
|
+
details.family.toLowerCase() === family
|
39
|
+
&& !nodeIp.isLoopback(details.address)
|
40
|
+
);
|
41
|
+
return {
|
42
|
+
nic,
|
43
|
+
addresses: addresses.map((address) => address.address),
|
44
|
+
};
|
45
|
+
})
|
46
|
+
.filter((address) => !!address);
|
47
|
+
|
48
|
+
// os.networkInterfaces doesn't actually return addresses in a good order.
|
49
|
+
// have seen instances where en0 (ethernet) is after en1 (wlan), etc.
|
50
|
+
// eth0 > eth1
|
51
|
+
all.sort((a, b) => a.nic.localeCompare(b.nic));
|
52
|
+
return Object.values(all)
|
53
|
+
.map((entry) => entry.addresses)
|
54
|
+
.flat();
|
55
|
+
}
|
56
|
+
|
57
|
+
export function getHostAddresses(useIpv4: boolean, useIpv6: boolean) {
|
58
|
+
const address: string[] = [];
|
59
|
+
if (useIpv4) address.push(...nodeIpAddress("ipv4"));
|
60
|
+
if (useIpv6) address.push(...nodeIpAddress("ipv6"));
|
61
|
+
return address;
|
24
62
|
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { ScryptedRuntime } from "../runtime";
|
2
|
+
|
3
|
+
export interface CORSServer {
|
4
|
+
tag: string;
|
5
|
+
server: string;
|
6
|
+
}
|
7
|
+
|
8
|
+
export class CORSControl {
|
9
|
+
constructor(public runtime: ScryptedRuntime) {
|
10
|
+
}
|
11
|
+
|
12
|
+
async getCORS(): Promise<CORSServer[]> {
|
13
|
+
return this.runtime.cors;
|
14
|
+
}
|
15
|
+
|
16
|
+
async setCORS(servers: CORSServer[]) {
|
17
|
+
this.runtime.cors = servers;
|
18
|
+
}
|
19
|
+
}
|
package/dist/addresses.js
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
-
};
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.getAddresses = void 0;
|
7
|
-
const os_1 = __importDefault(require("os"));
|
8
|
-
function getAddresses() {
|
9
|
-
return Object.entries(os_1.default.networkInterfaces()).filter(([iface]) => iface.startsWith('en') || iface.startsWith('eth') || iface.startsWith('wlan')).map(([_, addr]) => addr).flat().map(info => info.address).filter(address => address);
|
10
|
-
}
|
11
|
-
exports.getAddresses = getAddresses;
|
12
|
-
//# sourceMappingURL=addresses.js.map
|
package/dist/addresses.js.map
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"addresses.js","sourceRoot":"","sources":["../src/addresses.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AAEpB,SAAgB,YAAY;IACxB,OAAO,MAAM,CAAC,OAAO,CAAC,YAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;AAC1O,CAAC;AAFD,oCAEC"}
|
package/src/addresses.ts
DELETED
@@ -1,5 +0,0 @@
|
|
1
|
-
import os from 'os';
|
2
|
-
|
3
|
-
export function getAddresses() {
|
4
|
-
return Object.entries(os.networkInterfaces()).filter(([iface]) => iface.startsWith('en') || iface.startsWith('eth') || iface.startsWith('wlan')).map(([_, addr]) => addr).flat().map(info => info.address).filter(address => address);
|
5
|
-
}
|