mirror of
https://github.com/koush/scrypted.git
synced 2026-03-20 16:40:24 +00:00
191
plugins/synology-ss/package-lock.json
generated
191
plugins/synology-ss/package-lock.json
generated
@@ -1,30 +1,30 @@
|
||||
{
|
||||
"name": "@scrypted/synology-ss",
|
||||
"version": "0.0.16",
|
||||
"version": "0.0.17",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/synology-ss",
|
||||
"version": "0.0.16",
|
||||
"version": "0.0.17",
|
||||
"license": "Apache",
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0"
|
||||
"axios": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@types/node": "^16.6.1"
|
||||
"@types/node": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"../../sdk": {
|
||||
"name": "@scrypted/sdk",
|
||||
"version": "0.2.86",
|
||||
"version": "0.3.5",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"adm-zip": "^0.4.13",
|
||||
"axios": "^0.21.4",
|
||||
"axios": "^1.6.5",
|
||||
"babel-loader": "^9.1.0",
|
||||
"babel-plugin-const-enum": "^1.1.0",
|
||||
"esbuild": "^0.15.9",
|
||||
@@ -59,23 +59,52 @@
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.11.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
|
||||
"integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==",
|
||||
"dev": true
|
||||
"version": "18.19.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.10.tgz",
|
||||
"integrity": "sha512-IZD8kAM02AW1HRDTPOlz3npFava678pr8Ie9Vp8uRhBROXAv8MXT2pCnGZZAKYdromsNQLHQcfWQ6EOatVLtqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
||||
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.4"
|
||||
"follow-redirects": "^1.15.4",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -90,6 +119,49 @@
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -100,7 +172,7 @@
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/stringify-object": "^4.0.0",
|
||||
"adm-zip": "^0.4.13",
|
||||
"axios": "^0.21.4",
|
||||
"axios": "^1.6.5",
|
||||
"babel-loader": "^9.1.0",
|
||||
"babel-plugin-const-enum": "^1.1.0",
|
||||
"esbuild": "^0.15.9",
|
||||
@@ -118,23 +190,80 @@
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.11.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
|
||||
"integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==",
|
||||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"version": "18.19.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.10.tgz",
|
||||
"integrity": "sha512-IZD8kAM02AW1HRDTPOlz3npFava678pr8Ie9Vp8uRhBROXAv8MXT2pCnGZZAKYdromsNQLHQcfWQ6EOatVLtqA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.4"
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
||||
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.4",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw=="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"requires": {
|
||||
"mime-db": "1.52.0"
|
||||
}
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/synology-ss",
|
||||
"version": "0.0.16",
|
||||
"version": "0.0.17",
|
||||
"description": "A Synology Surveillance Station plugin for Scrypted",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache",
|
||||
@@ -36,10 +36,10 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0"
|
||||
"axios": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@types/node": "^16.6.1"
|
||||
"@types/node": "^18.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,11 +164,12 @@ export class SynologyApiClient {
|
||||
const response = await this.client.get<SynologyApiResponse<T>>(url ?? await this.getApiPath(params.api), { params });
|
||||
|
||||
if (!response.data?.success) {
|
||||
if (response.data?.error?.code) {
|
||||
const errorCode = response.data?.error?.code;
|
||||
if (errorCode) {
|
||||
const errorCodeLookup = { ...errorCodeDescriptions, ...extraErrorCodes }
|
||||
throw new Error(`${errorCodeLookup[response.data.error.code]} (error code ${response.data.error.code})`)
|
||||
throw new SynologyApiError(`${errorCodeLookup[errorCode]} (error code ${errorCode})`, errorCode)
|
||||
} else {
|
||||
throw new Error(`Synology API call failed with status code ${response.status}`);
|
||||
throw new SynologyApiError(`Synology API call failed with status code ${response.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +187,17 @@ export interface SynologyApiInfo {
|
||||
maxVersion: number;
|
||||
}
|
||||
|
||||
export interface SynologyApiError {
|
||||
export class SynologyApiError extends Error {
|
||||
code?: string;
|
||||
constructor(message: string, code?: string) {
|
||||
super(message);
|
||||
|
||||
this.name = 'SynologyApiError';
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
export interface SynologyApiErrorObject {
|
||||
code: string;
|
||||
}
|
||||
|
||||
@@ -198,7 +209,7 @@ interface SynologyApiRequestParams {
|
||||
|
||||
interface SynologyApiResponse<T> {
|
||||
data?: T;
|
||||
error?: SynologyApiError;
|
||||
error?: SynologyApiErrorObject;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import sdk, { Camera, Device, DeviceProvider, HttpRequest, HttpRequestHandler, HttpResponse, MediaObject, MediaStreamOptions, MediaStreamUrl, MotionSensor, PictureOptions, ResponseMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, VideoCamera } from "@scrypted/sdk";
|
||||
import { createInstanceableProviderPlugin, enableInstanceableProviderMode, isInstanceableProviderModeEnabled } from '../../../common/src/provider-plugin';
|
||||
import { SynologyApiClient, SynologyCamera, SynologyCameraStream } from "./api/synology-api-client";
|
||||
import { SynologyApiClient, SynologyApiError, SynologyCamera, SynologyCameraStream } from "./api/synology-api-client";
|
||||
|
||||
const { deviceManager } = sdk;
|
||||
|
||||
@@ -162,10 +162,11 @@ class SynologyCameraDevice extends ScryptedDeviceBase implements Camera, HttpReq
|
||||
}
|
||||
|
||||
class SynologySurveillanceStation extends ScryptedDeviceBase implements Settings, DeviceProvider {
|
||||
private cameras: SynologyCamera[];
|
||||
private cameras: SynologyCamera[] = [];
|
||||
private cameraDevices: Map<string, SynologyCameraDevice> = new Map();
|
||||
api: SynologyApiClient;
|
||||
private startup: Promise<void>;
|
||||
private discovering: boolean;
|
||||
|
||||
constructor(nativeId?: string) {
|
||||
super(nativeId);
|
||||
@@ -177,66 +178,23 @@ class SynologySurveillanceStation extends ScryptedDeviceBase implements Settings
|
||||
}
|
||||
|
||||
public async discoverDevices(duration: number): Promise<void> {
|
||||
const url = this.getSetting('url');
|
||||
const username = this.getSetting('username');
|
||||
const password = this.getSetting('password');
|
||||
const otpCode = this.getSetting('otpCode');
|
||||
const mfaDeviceId = this.getSetting('mfaDeviceId');
|
||||
if (this.discovering) return;
|
||||
this.discovering = true;
|
||||
|
||||
this.log.clearAlerts();
|
||||
|
||||
if (!url) {
|
||||
this.log.a('Must provide URL.');
|
||||
return
|
||||
}
|
||||
|
||||
if (!username) {
|
||||
this.log.a('Must provide username.');
|
||||
return
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
this.log.a('Must provide password.');
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.api || url !== this.api.url) {
|
||||
this.api = new SynologyApiClient(url);
|
||||
}
|
||||
this.console.info(`Fetching list of cameras from Synology server...`);
|
||||
|
||||
try {
|
||||
const newMfaDeviceId = await this.api.login(username, password, otpCode ? parseInt(otpCode) : undefined, !!otpCode, 'Scrypted', mfaDeviceId);
|
||||
|
||||
// If a OTP was present, store the device ID to allow us to skip the OTP requirement next login.
|
||||
if (otpCode) {
|
||||
this.storage.setItem('mfaDeviceId', newMfaDeviceId);
|
||||
if (!await this.tryLogin()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.log.a(`login error: ${e}`);
|
||||
this.console.error('login error', e);
|
||||
|
||||
// Clear device ID upon login failure, since it's likely useless now
|
||||
this.storage.removeItem('mfaDeviceId');
|
||||
|
||||
return;
|
||||
}
|
||||
finally {
|
||||
// Clear the OTP setting if provided since it's a temporary code
|
||||
if (otpCode) {
|
||||
this.storage.removeItem('otpCode');
|
||||
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.cameras = await this.api.listCameras();
|
||||
|
||||
if (!this.cameras) {
|
||||
this.console.error('Cameras failed to load. Retrying in 10 seconds.');
|
||||
setTimeout(() => {
|
||||
this.discoverDevices(0);
|
||||
}, 100000);
|
||||
}, 10000);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -285,6 +243,8 @@ class SynologySurveillanceStation extends ScryptedDeviceBase implements Settings
|
||||
catch (e) {
|
||||
this.log.a(`device discovery error: ${e}`);
|
||||
this.console.error('device discovery error', e);
|
||||
} finally {
|
||||
this.discovering = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +313,81 @@ class SynologySurveillanceStation extends ScryptedDeviceBase implements Settings
|
||||
return;
|
||||
}
|
||||
this.storage.setItem(key, value.toString());
|
||||
this.discoverDevices(0);
|
||||
|
||||
// Delaying discover in case user updated multiple settings, so that it doesn't run until all have been set
|
||||
setTimeout(() => this.discoverDevices(0), 200);
|
||||
}
|
||||
|
||||
private async tryLogin(): Promise<boolean> {
|
||||
this.console.info('Logging into Synology...');
|
||||
|
||||
const url = this.getSetting('url');
|
||||
const username = this.getSetting('username');
|
||||
const password = this.getSetting('password');
|
||||
const otpCode = this.getSetting('otpCode');
|
||||
const mfaDeviceId = this.getSetting('mfaDeviceId');
|
||||
|
||||
this.log.clearAlerts();
|
||||
|
||||
if (!url) {
|
||||
this.log.a('Must provide URL.');
|
||||
return
|
||||
}
|
||||
|
||||
if (!username) {
|
||||
this.log.a('Must provide username.');
|
||||
return
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
this.log.a('Must provide password.');
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.api || url !== this.api.url) {
|
||||
this.api = new SynologyApiClient(url);
|
||||
}
|
||||
|
||||
let successful = false;
|
||||
for (let attempt=1; attempt<=3; attempt++) {
|
||||
try {
|
||||
const newMfaDeviceId = await this.api.login(username, password, otpCode ? parseInt(otpCode) : undefined, !!otpCode, 'Scrypted', mfaDeviceId);
|
||||
|
||||
// If a OTP was present, store the device ID to allow us to skip the OTP requirement next login.
|
||||
if (otpCode) {
|
||||
this.storage.setItem('mfaDeviceId', newMfaDeviceId);
|
||||
}
|
||||
|
||||
successful = true;
|
||||
}
|
||||
catch (e) {
|
||||
this.log.a(`login error on attempt ${attempt}: ${e}`);
|
||||
this.console.error(`login error on attempt ${attempt}`, e);
|
||||
|
||||
if (e instanceof SynologyApiError) {
|
||||
break;
|
||||
} else {
|
||||
// Retry on failures that aren't Synology-specific, such as timeouts
|
||||
await new Promise((resolve) => setTimeout(resolve, attempt * 1000));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Clear the OTP setting if provided since it's a temporary code
|
||||
if (otpCode) {
|
||||
this.storage.removeItem('otpCode');
|
||||
this.onDeviceEvent(ScryptedInterface.Settings, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (successful) {
|
||||
this.console.info(`Successfully logged into Synology`);
|
||||
} else {
|
||||
this.console.info(`Failed to log into Synology`);
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"module": "Node16",
|
||||
"target": "ES2021",
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "Node16",
|
||||
|
||||
Reference in New Issue
Block a user