eufy-security-client 2.4.2 → 2.4.4
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.
- package/README.md +12 -0
- package/build/error.d.ts +57 -57
- package/build/error.js +155 -155
- package/build/eufysecurity.d.ts +162 -161
- package/build/eufysecurity.js +2104 -2091
- package/build/eufysecurity.js.map +1 -1
- package/build/http/api.d.ts +90 -90
- package/build/http/api.js +1407 -1407
- package/build/http/api.js.map +1 -1
- package/build/http/cache.d.ts +8 -8
- package/build/http/cache.js +33 -33
- package/build/http/const.d.ts +3 -3
- package/build/http/const.js +8545 -8545
- package/build/http/device.d.ts +360 -360
- package/build/http/device.js +2793 -2793
- package/build/http/device.js.map +1 -1
- package/build/http/error.d.ts +28 -28
- package/build/http/error.js +76 -76
- package/build/http/index.d.ts +10 -10
- package/build/http/index.js +29 -29
- package/build/http/interfaces.d.ts +202 -202
- package/build/http/interfaces.js +2 -2
- package/build/http/models.d.ts +561 -561
- package/build/http/models.js +2 -2
- package/build/http/parameter.d.ts +5 -5
- package/build/http/parameter.js +75 -75
- package/build/http/station.d.ts +292 -292
- package/build/http/station.js +6780 -6780
- package/build/http/station.js.map +1 -1
- package/build/http/types.d.ts +945 -945
- package/build/http/types.js +6070 -6070
- package/build/http/utils.d.ts +37 -37
- package/build/http/utils.js +370 -370
- package/build/index.d.ts +7 -7
- package/build/index.js +25 -25
- package/build/interfaces.d.ts +113 -113
- package/build/interfaces.js +2 -2
- package/build/mqtt/interface.d.ts +6 -6
- package/build/mqtt/interface.js +2 -2
- package/build/mqtt/model.d.ts +24 -24
- package/build/mqtt/model.js +2 -2
- package/build/mqtt/service.d.ts +30 -30
- package/build/mqtt/service.js +168 -168
- package/build/mqtt/service.js.map +1 -1
- package/build/p2p/ble.d.ts +47 -47
- package/build/p2p/ble.js +188 -188
- package/build/p2p/ble.js.map +1 -1
- package/build/p2p/error.d.ts +24 -24
- package/build/p2p/error.js +67 -67
- package/build/p2p/index.d.ts +8 -8
- package/build/p2p/index.js +27 -27
- package/build/p2p/interfaces.d.ts +162 -162
- package/build/p2p/interfaces.js +2 -2
- package/build/p2p/models.d.ts +146 -146
- package/build/p2p/models.js +2 -2
- package/build/p2p/session.d.ts +168 -168
- package/build/p2p/session.js +2087 -2087
- package/build/p2p/session.js.map +1 -1
- package/build/p2p/talkback.d.ts +10 -10
- package/build/p2p/talkback.js +22 -22
- package/build/p2p/types.d.ts +923 -923
- package/build/p2p/types.js +957 -957
- package/build/p2p/utils.d.ts +56 -56
- package/build/p2p/utils.js +653 -653
- package/build/push/client.d.ts +51 -51
- package/build/push/client.js +311 -311
- package/build/push/client.js.map +1 -1
- package/build/push/index.d.ts +5 -5
- package/build/push/index.js +24 -24
- package/build/push/interfaces.d.ts +19 -19
- package/build/push/interfaces.js +2 -2
- package/build/push/models.d.ts +292 -292
- package/build/push/models.js +30 -30
- package/build/push/parser.d.ts +28 -28
- package/build/push/parser.js +215 -215
- package/build/push/parser.js.map +1 -1
- package/build/push/service.d.ts +45 -45
- package/build/push/service.js +643 -643
- package/build/push/service.js.map +1 -1
- package/build/push/types.d.ts +176 -176
- package/build/push/types.js +192 -192
- package/build/push/utils.d.ts +7 -7
- package/build/push/utils.js +102 -102
- package/build/utils.d.ts +16 -13
- package/build/utils.js +207 -191
- package/build/utils.js.map +1 -1
- package/package.json +10 -10
package/build/http/api.js
CHANGED
|
@@ -1,1408 +1,1408 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.HTTPApi = void 0;
|
|
30
|
-
const got_1 = __importStar(require("got"));
|
|
31
|
-
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
|
|
32
|
-
const ts_log_1 = require("ts-log");
|
|
33
|
-
const i18n_iso_countries_1 = require("i18n-iso-countries");
|
|
34
|
-
const i18n_iso_languages_1 = require("@cospired/i18n-iso-languages");
|
|
35
|
-
const crypto_1 = require("crypto");
|
|
36
|
-
const schedule = __importStar(require("node-schedule"));
|
|
37
|
-
const p_throttle_1 = __importDefault(require("p-throttle"));
|
|
38
|
-
const types_1 = require("./types");
|
|
39
|
-
const parameter_1 = require("./parameter");
|
|
40
|
-
const utils_1 = require("./utils");
|
|
41
|
-
const error_1 = require("./../error");
|
|
42
|
-
const utils_2 = require("./../utils");
|
|
43
|
-
const error_2 = require("./error");
|
|
44
|
-
class HTTPApi extends tiny_typed_emitter_1.TypedEmitter {
|
|
45
|
-
constructor(apiBase, country, username, password, log = ts_log_1.dummyLogger, persistentData) {
|
|
46
|
-
super();
|
|
47
|
-
this.SERVER_PUBLIC_KEY = "04c5c00c4f8d1197cc7c3167c52bf7acb054d722f0ef08dcd7e0883236e0d72a3868d9750cb47fa4619248f3d83f0f662671dadc6e2d31c2f41db0161651c7c076";
|
|
48
|
-
this.ecdh = (0, crypto_1.createECDH)("prime256v1");
|
|
49
|
-
this.token = null;
|
|
50
|
-
this.tokenExpiration = null;
|
|
51
|
-
this.connected = false;
|
|
52
|
-
this.throttle = (0, p_throttle_1.default)({
|
|
53
|
-
limit: 6,
|
|
54
|
-
interval: 10000,
|
|
55
|
-
});
|
|
56
|
-
this.devices = {};
|
|
57
|
-
this.hubs = {};
|
|
58
|
-
this.houses = {};
|
|
59
|
-
this.persistentData = {
|
|
60
|
-
user_id: "",
|
|
61
|
-
email: "",
|
|
62
|
-
nick_name: "",
|
|
63
|
-
device_public_keys: {},
|
|
64
|
-
clientPrivateKey: "",
|
|
65
|
-
serverPublicKey: this.SERVER_PUBLIC_KEY
|
|
66
|
-
};
|
|
67
|
-
this.headers = {
|
|
68
|
-
App_version: "v4.5.1_1523",
|
|
69
|
-
Os_type: "android",
|
|
70
|
-
Os_version: "31",
|
|
71
|
-
Phone_model: "ONEPLUS A3003",
|
|
72
|
-
Country: "DE",
|
|
73
|
-
Language: "en",
|
|
74
|
-
Openudid: "5e4621b0152c0d00",
|
|
75
|
-
//uid: "",
|
|
76
|
-
Net_type: "wifi",
|
|
77
|
-
Mnc: "02",
|
|
78
|
-
Mcc: "262",
|
|
79
|
-
Sn: "75814221ee75",
|
|
80
|
-
Model_type: "PHONE",
|
|
81
|
-
Timezone: "GMT+01:00",
|
|
82
|
-
"Cache-Control": "no-cache",
|
|
83
|
-
};
|
|
84
|
-
this.username = username;
|
|
85
|
-
this.password = password;
|
|
86
|
-
this.log = log;
|
|
87
|
-
this.apiBase = apiBase;
|
|
88
|
-
this.log.debug(`Loaded API_BASE: ${apiBase}`);
|
|
89
|
-
this.headers.timezone = (0, utils_1.getTimezoneGMTString)();
|
|
90
|
-
this.headers.country = country.toUpperCase();
|
|
91
|
-
if (persistentData) {
|
|
92
|
-
this.persistentData = persistentData;
|
|
93
|
-
}
|
|
94
|
-
if (this.persistentData.clientPrivateKey === undefined || this.persistentData.clientPrivateKey === "") {
|
|
95
|
-
this.ecdh.generateKeys();
|
|
96
|
-
this.persistentData.clientPrivateKey = this.ecdh.getPrivateKey().toString("hex");
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
try {
|
|
100
|
-
this.ecdh.setPrivateKey(Buffer.from(this.persistentData.clientPrivateKey, "hex"));
|
|
101
|
-
}
|
|
102
|
-
catch (error) {
|
|
103
|
-
this.log.debug(`Invalid client private key, generate new client private key...`, error);
|
|
104
|
-
this.ecdh.generateKeys();
|
|
105
|
-
this.persistentData.clientPrivateKey = this.ecdh.getPrivateKey().toString("hex");
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (this.persistentData.serverPublicKey === undefined || this.persistentData.serverPublicKey === "") {
|
|
109
|
-
this.persistentData.serverPublicKey = this.SERVER_PUBLIC_KEY;
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
try {
|
|
113
|
-
this.ecdh.computeSecret(Buffer.from(this.persistentData.serverPublicKey, "hex"));
|
|
114
|
-
}
|
|
115
|
-
catch (error) {
|
|
116
|
-
this.log.debug(`Invalid server public key, fallback to default server public key...`, error);
|
|
117
|
-
this.persistentData.serverPublicKey = this.SERVER_PUBLIC_KEY;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
this.requestEufyCloud = got_1.default.extend({
|
|
121
|
-
prefixUrl: this.apiBase,
|
|
122
|
-
headers: this.headers,
|
|
123
|
-
responseType: "json",
|
|
124
|
-
//throwHttpErrors: false,
|
|
125
|
-
retry: {
|
|
126
|
-
limit: 3,
|
|
127
|
-
methods: ["GET", "POST"],
|
|
128
|
-
statusCodes: [
|
|
129
|
-
408,
|
|
130
|
-
413,
|
|
131
|
-
423,
|
|
132
|
-
429,
|
|
133
|
-
500,
|
|
134
|
-
502,
|
|
135
|
-
503,
|
|
136
|
-
504,
|
|
137
|
-
521,
|
|
138
|
-
522,
|
|
139
|
-
524
|
|
140
|
-
],
|
|
141
|
-
calculateDelay: ({ computedValue }) => {
|
|
142
|
-
return computedValue * 3;
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
hooks: {
|
|
146
|
-
afterResponse: [
|
|
147
|
-
async (response, retryWithMergedOptions) => {
|
|
148
|
-
// Unauthorized
|
|
149
|
-
if (response.statusCode === 401) {
|
|
150
|
-
const oldToken = this.token;
|
|
151
|
-
this.log.debug("Invalidate token an get a new one...", { requestUrl: response.requestUrl, statusCode: response.statusCode, statusMessage: response.statusMessage });
|
|
152
|
-
this.invalidateToken();
|
|
153
|
-
await this.login({ force: true });
|
|
154
|
-
if (oldToken !== this.token && this.token) {
|
|
155
|
-
// Refresh the access token
|
|
156
|
-
const updatedOptions = {
|
|
157
|
-
headers: {
|
|
158
|
-
"X-Auth-Token": this.token
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
// Update the defaults
|
|
162
|
-
this.requestEufyCloud.defaults.options = this.requestEufyCloud.mergeOptions(this.requestEufyCloud.defaults.options, updatedOptions);
|
|
163
|
-
// Make a new retry
|
|
164
|
-
return retryWithMergedOptions(updatedOptions);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
// No changes otherwise
|
|
168
|
-
return response;
|
|
169
|
-
}
|
|
170
|
-
],
|
|
171
|
-
beforeRetry: [
|
|
172
|
-
(options, error, retryCount) => {
|
|
173
|
-
var _a;
|
|
174
|
-
// This will be called on `retryWithMergedOptions(...)`
|
|
175
|
-
this.log.debug(`Retrying [${retryCount}]: ${error === null || error === void 0 ? void 0 : error.code} (${(_a = error === null || error === void 0 ? void 0 : error.request) === null || _a === void 0 ? void 0 : _a.requestUrl})`, { options: options });
|
|
176
|
-
// Retrying [1]: ERR_NON_2XX_3XX_RESPONSE
|
|
177
|
-
}
|
|
178
|
-
],
|
|
179
|
-
beforeError: [
|
|
180
|
-
error => {
|
|
181
|
-
var _a;
|
|
182
|
-
const { response } = error;
|
|
183
|
-
if (response && response.body) {
|
|
184
|
-
const result = response.body;
|
|
185
|
-
error.name = "EufyError";
|
|
186
|
-
error.message = `Code: ${result.code} Message: ${result.msg} (HTTP Code: ${response.statusCode})`;
|
|
187
|
-
this.log.error(`${error.name} - ${error.message} - requestUrl: ${(_a = error.request) === null || _a === void 0 ? void 0 : _a.requestUrl}`);
|
|
188
|
-
}
|
|
189
|
-
return error;
|
|
190
|
-
}
|
|
191
|
-
],
|
|
192
|
-
beforeRequest: [
|
|
193
|
-
async (_options) => {
|
|
194
|
-
await this.throttle(async () => { return; })();
|
|
195
|
-
}
|
|
196
|
-
]
|
|
197
|
-
},
|
|
198
|
-
mutableDefaults: true
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
static async getApiBaseFromCloud(country) {
|
|
202
|
-
const response = await (0, got_1.default)(`domain/${country}`, {
|
|
203
|
-
prefixUrl: this.apiDomainBase,
|
|
204
|
-
method: "GET",
|
|
205
|
-
responseType: "json",
|
|
206
|
-
retry: {
|
|
207
|
-
limit: 1,
|
|
208
|
-
methods: ["GET"]
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
const result = response.body;
|
|
212
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
213
|
-
return `https://${result.data.domain}`;
|
|
214
|
-
}
|
|
215
|
-
throw new error_2.ApiBaseLoadError(result.code, result.msg);
|
|
216
|
-
}
|
|
217
|
-
static async initialize(country, username, password, log = ts_log_1.dummyLogger, persistentData) {
|
|
218
|
-
if ((0, i18n_iso_countries_1.isValid)(country) && country.length === 2) {
|
|
219
|
-
const apiBase = await this.getApiBaseFromCloud(country);
|
|
220
|
-
return new HTTPApi(apiBase, country, username, password, log, persistentData);
|
|
221
|
-
}
|
|
222
|
-
throw new error_1.InvalidCountryCodeError("Invalid ISO 3166-1 Alpha-2 country code");
|
|
223
|
-
}
|
|
224
|
-
clearScheduleRenewAuthToken() {
|
|
225
|
-
if (this.renewAuthTokenJob !== undefined) {
|
|
226
|
-
this.renewAuthTokenJob.cancel();
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
scheduleRenewAuthToken() {
|
|
230
|
-
this.clearScheduleRenewAuthToken();
|
|
231
|
-
if (this.tokenExpiration !== null) {
|
|
232
|
-
const scheduleDate = new Date(this.tokenExpiration.getTime() - (1000 * 60 * 60 * 24));
|
|
233
|
-
if (this.renewAuthTokenJob === undefined) {
|
|
234
|
-
this.renewAuthTokenJob = schedule.scheduleJob("renewAuthToken", scheduleDate, async () => {
|
|
235
|
-
this.log.info("Authentication token is soon expiring, fetching a new one...");
|
|
236
|
-
await this.login({ force: true });
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
this.renewAuthTokenJob.schedule(scheduleDate);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
invalidateToken() {
|
|
245
|
-
this.token = null;
|
|
246
|
-
this.requestEufyCloud.defaults.options.headers["X-Auth-Token"] = undefined;
|
|
247
|
-
this.tokenExpiration = null;
|
|
248
|
-
this.clearScheduleRenewAuthToken();
|
|
249
|
-
this.emit("auth token invalidated");
|
|
250
|
-
}
|
|
251
|
-
setPhoneModel(model) {
|
|
252
|
-
this.headers.phone_model = model.toUpperCase();
|
|
253
|
-
this.requestEufyCloud.defaults.options.headers = this.headers;
|
|
254
|
-
}
|
|
255
|
-
getPhoneModel() {
|
|
256
|
-
return this.headers.phone_model;
|
|
257
|
-
}
|
|
258
|
-
getCountry() {
|
|
259
|
-
return this.headers.country;
|
|
260
|
-
}
|
|
261
|
-
setLanguage(language) {
|
|
262
|
-
if ((0, i18n_iso_languages_1.isValid)(language) && language.length === 2) {
|
|
263
|
-
this.headers.language = language;
|
|
264
|
-
this.requestEufyCloud.defaults.options.headers = this.headers;
|
|
265
|
-
}
|
|
266
|
-
else
|
|
267
|
-
throw new error_1.InvalidLanguageCodeError("Invalid ISO 639 language code");
|
|
268
|
-
}
|
|
269
|
-
getLanguage() {
|
|
270
|
-
return this.headers.language;
|
|
271
|
-
}
|
|
272
|
-
async login(options) {
|
|
273
|
-
var _a;
|
|
274
|
-
options = (0, utils_2.mergeDeep)(options, {
|
|
275
|
-
force: false
|
|
276
|
-
});
|
|
277
|
-
this.log.debug("Login and get an access token", { token: this.token, tokenExpiration: this.tokenExpiration });
|
|
278
|
-
if (!this.token || (this.tokenExpiration && (new Date()).getTime() >= this.tokenExpiration.getTime()) || options.verifyCode || options.captcha || options.force) {
|
|
279
|
-
try {
|
|
280
|
-
const data = {
|
|
281
|
-
ab: this.headers.country,
|
|
282
|
-
client_secret_info: {
|
|
283
|
-
public_key: this.ecdh.getPublicKey("hex")
|
|
284
|
-
},
|
|
285
|
-
enc: 0,
|
|
286
|
-
email: this.username,
|
|
287
|
-
password: (0, utils_1.encryptAPIData)(this.password, this.ecdh.computeSecret(Buffer.from(this.SERVER_PUBLIC_KEY, "hex"))),
|
|
288
|
-
time_zone: new Date().getTimezoneOffset() !== 0 ? -new Date().getTimezoneOffset() * 60 * 1000 : 0,
|
|
289
|
-
transaction: `${new Date().getTime()}`
|
|
290
|
-
};
|
|
291
|
-
if (options.verifyCode) {
|
|
292
|
-
data.verify_code = options.verifyCode;
|
|
293
|
-
}
|
|
294
|
-
else if (options.captcha) {
|
|
295
|
-
data.captcha_id = options.captcha.captchaId;
|
|
296
|
-
data.answer = options.captcha.captchaCode;
|
|
297
|
-
}
|
|
298
|
-
const response = await this.request({
|
|
299
|
-
method: "post",
|
|
300
|
-
endpoint: "v2/passport/login_sec",
|
|
301
|
-
data: data
|
|
302
|
-
});
|
|
303
|
-
if (response.status == 200) {
|
|
304
|
-
const result = response.data;
|
|
305
|
-
if (result.data !== undefined) {
|
|
306
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
307
|
-
const dataresult = result.data;
|
|
308
|
-
if ((_a = dataresult.server_secret_info) === null || _a === void 0 ? void 0 : _a.public_key)
|
|
309
|
-
this.persistentData.serverPublicKey = dataresult.server_secret_info.public_key;
|
|
310
|
-
this.persistentData.user_id = dataresult.user_id;
|
|
311
|
-
this.persistentData.email = this.decryptAPIData(dataresult.email, false);
|
|
312
|
-
this.persistentData.nick_name = dataresult.nick_name;
|
|
313
|
-
this.setToken(dataresult.auth_token);
|
|
314
|
-
this.tokenExpiration = new Date(dataresult.token_expires_at * 1000);
|
|
315
|
-
this.headers = {
|
|
316
|
-
...this.headers,
|
|
317
|
-
gtoken: (0, utils_2.md5)(dataresult.user_id)
|
|
318
|
-
};
|
|
319
|
-
this.log.debug("Token data", { token: this.token, tokenExpiration: this.tokenExpiration, serverPublicKey: this.persistentData.serverPublicKey });
|
|
320
|
-
if (!this.connected) {
|
|
321
|
-
this.connected = true;
|
|
322
|
-
this.emit("connect");
|
|
323
|
-
}
|
|
324
|
-
this.scheduleRenewAuthToken();
|
|
325
|
-
}
|
|
326
|
-
else if (result.code == types_1.ResponseErrorCode.CODE_NEED_VERIFY_CODE) {
|
|
327
|
-
this.log.debug(`Send verification code...`);
|
|
328
|
-
const dataresult = result.data;
|
|
329
|
-
this.setToken(dataresult.auth_token);
|
|
330
|
-
this.tokenExpiration = new Date(dataresult.token_expires_at * 1000);
|
|
331
|
-
this.log.debug("Token data", { token: this.token, tokenExpiration: this.tokenExpiration });
|
|
332
|
-
await this.sendVerifyCode(types_1.VerfyCodeTypes.TYPE_EMAIL);
|
|
333
|
-
this.emit("tfa request");
|
|
334
|
-
}
|
|
335
|
-
else if (result.code == types_1.ResponseErrorCode.LOGIN_NEED_CAPTCHA || result.code == types_1.ResponseErrorCode.LOGIN_CAPTCHA_ERROR) {
|
|
336
|
-
const dataresult = result.data;
|
|
337
|
-
this.log.debug("Captcha verification received", { captchaId: dataresult.captcha_id, item: dataresult.item });
|
|
338
|
-
this.emit("captcha request", dataresult.captcha_id, dataresult.item);
|
|
339
|
-
}
|
|
340
|
-
else {
|
|
341
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
342
|
-
this.emit("connection error", new error_2.ApiResponseCodeError(`Response code not ok (${result.code}).`));
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
else {
|
|
346
|
-
this.log.error("Response data is missing", { code: result.code, msg: result.msg, data: result.data });
|
|
347
|
-
this.emit("connection error", new error_2.ApiInvalidResponseError("Response data is missing"));
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
else {
|
|
351
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
352
|
-
this.emit("connection error", new error_2.ApiHTTPResponseCodeError(`HTTP response code not ok (${response.status}).`));
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
catch (error) {
|
|
356
|
-
this.log.error("Generic Error:", error);
|
|
357
|
-
this.emit("connection error", new error_2.ApiGenericError(`Generic error: ${error}`));
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
else if (!this.connected) {
|
|
361
|
-
try {
|
|
362
|
-
const profile = await this.getPassportProfile();
|
|
363
|
-
if (profile !== null) {
|
|
364
|
-
this.connected = true;
|
|
365
|
-
this.emit("connect");
|
|
366
|
-
this.scheduleRenewAuthToken();
|
|
367
|
-
}
|
|
368
|
-
else {
|
|
369
|
-
this.emit("connection error", new error_2.ApiInvalidResponseError(`Invalid passport profile response`));
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
this.log.error("getPassportProfile Error", error);
|
|
374
|
-
this.emit("connection error", new error_2.ApiGenericError(`Get passport profile error: ${error}`));
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
async sendVerifyCode(type) {
|
|
379
|
-
try {
|
|
380
|
-
if (!type)
|
|
381
|
-
type = types_1.VerfyCodeTypes.TYPE_EMAIL;
|
|
382
|
-
const response = await this.request({
|
|
383
|
-
method: "post",
|
|
384
|
-
endpoint: "v1/sms/send/verify_code",
|
|
385
|
-
data: {
|
|
386
|
-
message_type: type,
|
|
387
|
-
transaction: `${new Date().getTime()}`
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
if (response.status == 200) {
|
|
391
|
-
const result = response.data;
|
|
392
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
393
|
-
this.log.info(`Requested verification code for 2FA`);
|
|
394
|
-
return true;
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
catch (error) {
|
|
405
|
-
this.log.error("Generic Error:", error);
|
|
406
|
-
}
|
|
407
|
-
return false;
|
|
408
|
-
}
|
|
409
|
-
async listTrustDevice() {
|
|
410
|
-
if (this.connected) {
|
|
411
|
-
try {
|
|
412
|
-
const response = await this.request({
|
|
413
|
-
method: "get",
|
|
414
|
-
endpoint: "v1/app/trust_device/list"
|
|
415
|
-
});
|
|
416
|
-
if (response.status == 200) {
|
|
417
|
-
const result = response.data;
|
|
418
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
419
|
-
if (result.data && result.data.list) {
|
|
420
|
-
return result.data.list;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
catch (error) {
|
|
432
|
-
this.log.error("Generic Error:", error);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
return [];
|
|
436
|
-
}
|
|
437
|
-
async addTrustDevice(verifyCode) {
|
|
438
|
-
if (this.connected) {
|
|
439
|
-
try {
|
|
440
|
-
const response = await this.request({
|
|
441
|
-
method: "post",
|
|
442
|
-
endpoint: "v1/app/trust_device/add",
|
|
443
|
-
data: {
|
|
444
|
-
verify_code: verifyCode,
|
|
445
|
-
transaction: `${new Date().getTime()}`
|
|
446
|
-
}
|
|
447
|
-
});
|
|
448
|
-
this.log.debug("Response trust device:", response.data);
|
|
449
|
-
if (response.status == 200) {
|
|
450
|
-
const result = response.data;
|
|
451
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
452
|
-
this.log.info(`2FA authentication successfully done. Device trusted.`);
|
|
453
|
-
const trusted_devices = await this.listTrustDevice();
|
|
454
|
-
trusted_devices.forEach((trusted_device) => {
|
|
455
|
-
if (trusted_device.is_current_device === 1) {
|
|
456
|
-
this.log.debug("This device is trusted. Token expiration extended:", { tokenExpiration: this.tokenExpiration });
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
return true;
|
|
460
|
-
}
|
|
461
|
-
else {
|
|
462
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
else {
|
|
466
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
catch (error) {
|
|
470
|
-
this.log.error("Generic Error:", error);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return false;
|
|
474
|
-
}
|
|
475
|
-
async getStationList() {
|
|
476
|
-
if (this.connected) {
|
|
477
|
-
try {
|
|
478
|
-
const response = await this.request({
|
|
479
|
-
method: "post",
|
|
480
|
-
endpoint: "v2/house/station_list",
|
|
481
|
-
data: {
|
|
482
|
-
device_sn: "",
|
|
483
|
-
num: 1000,
|
|
484
|
-
orderby: "",
|
|
485
|
-
page: 0,
|
|
486
|
-
station_sn: "",
|
|
487
|
-
time_zone: new Date().getTimezoneOffset() !== 0 ? -new Date().getTimezoneOffset() * 60 * 1000 : 0,
|
|
488
|
-
transaction: `${new Date().getTime()}`
|
|
489
|
-
}
|
|
490
|
-
});
|
|
491
|
-
if (response.status == 200) {
|
|
492
|
-
const result = response.data;
|
|
493
|
-
if (result.code == 0) {
|
|
494
|
-
if (result.data) {
|
|
495
|
-
const stationList = this.decryptAPIData(result.data);
|
|
496
|
-
this.log.debug("Decrypted station list data", stationList);
|
|
497
|
-
return stationList;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
else {
|
|
501
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
else {
|
|
505
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
catch (error) {
|
|
509
|
-
this.log.error("Stations - Generic Error:", error);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
return [];
|
|
513
|
-
}
|
|
514
|
-
async getDeviceList() {
|
|
515
|
-
if (this.connected) {
|
|
516
|
-
try {
|
|
517
|
-
const response = await this.request({
|
|
518
|
-
method: "post",
|
|
519
|
-
endpoint: "v2/house/device_list",
|
|
520
|
-
data: {
|
|
521
|
-
device_sn: "",
|
|
522
|
-
num: 1000,
|
|
523
|
-
orderby: "",
|
|
524
|
-
page: 0,
|
|
525
|
-
station_sn: "",
|
|
526
|
-
time_zone: new Date().getTimezoneOffset() !== 0 ? -new Date().getTimezoneOffset() * 60 * 1000 : 0,
|
|
527
|
-
transaction: `${new Date().getTime()}`
|
|
528
|
-
}
|
|
529
|
-
});
|
|
530
|
-
if (response.status == 200) {
|
|
531
|
-
const result = response.data;
|
|
532
|
-
if (result.code == 0) {
|
|
533
|
-
if (result.data) {
|
|
534
|
-
const deviceList = this.decryptAPIData(result.data);
|
|
535
|
-
this.log.debug("Decrypted device list data", deviceList);
|
|
536
|
-
return deviceList;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
else {
|
|
540
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
else {
|
|
544
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
catch (error) {
|
|
548
|
-
this.log.error("Devices - Generic Error:", error);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
return [];
|
|
552
|
-
}
|
|
553
|
-
async refreshHouseData() {
|
|
554
|
-
//Get Houses
|
|
555
|
-
const houses = await this.getHouseList();
|
|
556
|
-
if (houses && houses.length > 0) {
|
|
557
|
-
houses.forEach(element => {
|
|
558
|
-
this.houses[element.house_id] = element;
|
|
559
|
-
});
|
|
560
|
-
if (Object.keys(this.houses).length > 0)
|
|
561
|
-
this.emit("houses", this.houses);
|
|
562
|
-
}
|
|
563
|
-
else {
|
|
564
|
-
this.log.info("No houses found.");
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
async refreshStationData() {
|
|
568
|
-
//Get Stations
|
|
569
|
-
const stations = await this.getStationList();
|
|
570
|
-
if (stations && stations.length > 0) {
|
|
571
|
-
stations.forEach(element => {
|
|
572
|
-
this.hubs[element.station_sn] = element;
|
|
573
|
-
});
|
|
574
|
-
if (Object.keys(this.hubs).length > 0)
|
|
575
|
-
this.emit("hubs", this.hubs);
|
|
576
|
-
}
|
|
577
|
-
else {
|
|
578
|
-
this.log.info("No stations found.");
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
async refreshDeviceData() {
|
|
582
|
-
//Get Devices
|
|
583
|
-
const devices = await this.getDeviceList();
|
|
584
|
-
if (devices && devices.length > 0) {
|
|
585
|
-
devices.forEach(element => {
|
|
586
|
-
this.devices[element.device_sn] = element;
|
|
587
|
-
});
|
|
588
|
-
if (Object.keys(this.devices).length > 0)
|
|
589
|
-
this.emit("devices", this.devices);
|
|
590
|
-
}
|
|
591
|
-
else {
|
|
592
|
-
this.log.info("No devices found.");
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
async refreshAllData() {
|
|
596
|
-
//Get the latest info
|
|
597
|
-
//Get Houses
|
|
598
|
-
await this.refreshHouseData();
|
|
599
|
-
//Get Stations
|
|
600
|
-
await this.refreshStationData();
|
|
601
|
-
//Get Devices
|
|
602
|
-
await this.refreshDeviceData();
|
|
603
|
-
}
|
|
604
|
-
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
605
|
-
async request(request) {
|
|
606
|
-
this.log.debug("Request:", { method: request.method, endpoint: request.endpoint, token: this.token, data: request.data });
|
|
607
|
-
try {
|
|
608
|
-
const internalResponse = await this.requestEufyCloud(request.endpoint, {
|
|
609
|
-
method: request.method,
|
|
610
|
-
json: request.data,
|
|
611
|
-
});
|
|
612
|
-
const response = {
|
|
613
|
-
status: internalResponse.statusCode,
|
|
614
|
-
statusText: internalResponse.statusMessage ? internalResponse.statusMessage : "",
|
|
615
|
-
headers: internalResponse.headers,
|
|
616
|
-
data: internalResponse.body,
|
|
617
|
-
};
|
|
618
|
-
this.log.debug("Response:", { token: this.token, request: request, response: response.data });
|
|
619
|
-
return response;
|
|
620
|
-
}
|
|
621
|
-
catch (error) {
|
|
622
|
-
if (error instanceof got_1.HTTPError) {
|
|
623
|
-
if (error.response.statusCode === 401) {
|
|
624
|
-
this.invalidateToken();
|
|
625
|
-
this.log.error("Status return code 401, invalidate token", { status: error.response.statusCode, statusText: error.response.statusMessage });
|
|
626
|
-
this.connected = false;
|
|
627
|
-
this.emit("close");
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
throw error;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
async checkPushToken() {
|
|
634
|
-
//Check push notification token
|
|
635
|
-
if (this.connected) {
|
|
636
|
-
try {
|
|
637
|
-
const response = await this.request({
|
|
638
|
-
method: "post",
|
|
639
|
-
endpoint: "v1/app/review/app_push_check",
|
|
640
|
-
data: {
|
|
641
|
-
app_type: "eufySecurity",
|
|
642
|
-
transaction: `${new Date().getTime()}`
|
|
643
|
-
}
|
|
644
|
-
});
|
|
645
|
-
if (response.status == 200) {
|
|
646
|
-
const result = response.data;
|
|
647
|
-
if (result.code == 0) {
|
|
648
|
-
this.log.debug(`Push token OK`);
|
|
649
|
-
return true;
|
|
650
|
-
}
|
|
651
|
-
else {
|
|
652
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
else {
|
|
656
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
catch (error) {
|
|
660
|
-
this.log.error("Generic Error:", error);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return false;
|
|
664
|
-
}
|
|
665
|
-
async registerPushToken(token) {
|
|
666
|
-
//Register push notification token
|
|
667
|
-
if (this.connected) {
|
|
668
|
-
try {
|
|
669
|
-
const response = await this.request({
|
|
670
|
-
method: "post",
|
|
671
|
-
endpoint: "v1/apppush/register_push_token",
|
|
672
|
-
data: {
|
|
673
|
-
is_notification_enable: true,
|
|
674
|
-
token: token,
|
|
675
|
-
transaction: `${new Date().getTime().toString()}`
|
|
676
|
-
}
|
|
677
|
-
});
|
|
678
|
-
if (response.status == 200) {
|
|
679
|
-
const result = response.data;
|
|
680
|
-
if (result.code == 0) {
|
|
681
|
-
this.log.debug(`Push token registered successfully`);
|
|
682
|
-
return true;
|
|
683
|
-
}
|
|
684
|
-
else {
|
|
685
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
else {
|
|
689
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
catch (error) {
|
|
693
|
-
this.log.error("Generic Error:", error);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
return false;
|
|
697
|
-
}
|
|
698
|
-
async setParameters(stationSN, deviceSN, params) {
|
|
699
|
-
if (this.connected) {
|
|
700
|
-
const tmp_params = [];
|
|
701
|
-
params.forEach(param => {
|
|
702
|
-
tmp_params.push({ param_type: param.paramType, param_value: parameter_1.ParameterHelper.writeValue(param.paramType, param.paramValue) });
|
|
703
|
-
});
|
|
704
|
-
try {
|
|
705
|
-
const response = await this.request({
|
|
706
|
-
method: "post",
|
|
707
|
-
endpoint: "v1/app/upload_devs_params",
|
|
708
|
-
data: {
|
|
709
|
-
device_sn: deviceSN,
|
|
710
|
-
station_sn: stationSN,
|
|
711
|
-
params: tmp_params
|
|
712
|
-
}
|
|
713
|
-
});
|
|
714
|
-
this.log.debug("Response:", { stationSN: stationSN, deviceSN: deviceSN, params: tmp_params, response: response.data });
|
|
715
|
-
if (response.status == 200) {
|
|
716
|
-
const result = response.data;
|
|
717
|
-
if (result.code == 0) {
|
|
718
|
-
const dataresult = result.data;
|
|
719
|
-
this.log.debug("New parameters set", { params: tmp_params, response: dataresult });
|
|
720
|
-
return true;
|
|
721
|
-
}
|
|
722
|
-
else {
|
|
723
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
else {
|
|
727
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
catch (error) {
|
|
731
|
-
this.log.error("Generic Error:", error);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
return false;
|
|
735
|
-
}
|
|
736
|
-
async getCiphers(cipherIDs, userID) {
|
|
737
|
-
if (this.connected) {
|
|
738
|
-
try {
|
|
739
|
-
const response = await this.request({
|
|
740
|
-
method: "post",
|
|
741
|
-
endpoint: "v1/app/cipher/get_ciphers",
|
|
742
|
-
data: {
|
|
743
|
-
cipher_ids: cipherIDs,
|
|
744
|
-
user_id: userID,
|
|
745
|
-
transaction: `${new Date().getTime().toString()}`
|
|
746
|
-
}
|
|
747
|
-
});
|
|
748
|
-
if (response.status == 200) {
|
|
749
|
-
const result = response.data;
|
|
750
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
751
|
-
if (result.data) {
|
|
752
|
-
const ciphers = {};
|
|
753
|
-
result.data.forEach((cipher) => {
|
|
754
|
-
ciphers[cipher.cipher_id] = cipher;
|
|
755
|
-
});
|
|
756
|
-
return ciphers;
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
else {
|
|
760
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
else {
|
|
764
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
catch (error) {
|
|
768
|
-
this.log.error("Generic Error:", error);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
return {};
|
|
772
|
-
}
|
|
773
|
-
async getVoices(deviceSN) {
|
|
774
|
-
if (this.connected) {
|
|
775
|
-
try {
|
|
776
|
-
const response = await this.request({
|
|
777
|
-
method: "get",
|
|
778
|
-
endpoint: `v1/voice/response/lists/${deviceSN}`
|
|
779
|
-
});
|
|
780
|
-
if (response.status == 200) {
|
|
781
|
-
const result = response.data;
|
|
782
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
783
|
-
if (result.data) {
|
|
784
|
-
const voices = {};
|
|
785
|
-
result.data.forEach((voice) => {
|
|
786
|
-
voices[voice.voice_id] = voice;
|
|
787
|
-
});
|
|
788
|
-
return voices;
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
else {
|
|
792
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
else {
|
|
796
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
catch (error) {
|
|
800
|
-
this.log.error("Generic Error:", error);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
return {};
|
|
804
|
-
}
|
|
805
|
-
async getCipher(cipherID, userID) {
|
|
806
|
-
return (await this.getCiphers([cipherID], userID))[cipherID];
|
|
807
|
-
}
|
|
808
|
-
getLog() {
|
|
809
|
-
return this.log;
|
|
810
|
-
}
|
|
811
|
-
getDevices() {
|
|
812
|
-
return this.devices;
|
|
813
|
-
}
|
|
814
|
-
getHubs() {
|
|
815
|
-
return this.hubs;
|
|
816
|
-
}
|
|
817
|
-
getToken() {
|
|
818
|
-
return this.token;
|
|
819
|
-
}
|
|
820
|
-
getTokenExpiration() {
|
|
821
|
-
return this.tokenExpiration;
|
|
822
|
-
}
|
|
823
|
-
setToken(token) {
|
|
824
|
-
this.token = token;
|
|
825
|
-
this.requestEufyCloud.defaults.options.headers["X-Auth-Token"] = token;
|
|
826
|
-
}
|
|
827
|
-
setTokenExpiration(tokenExpiration) {
|
|
828
|
-
this.tokenExpiration = tokenExpiration;
|
|
829
|
-
}
|
|
830
|
-
getAPIBase() {
|
|
831
|
-
return this.requestEufyCloud.defaults.options.prefixUrl;
|
|
832
|
-
}
|
|
833
|
-
setOpenUDID(openudid) {
|
|
834
|
-
this.headers.openudid = openudid;
|
|
835
|
-
this.requestEufyCloud.defaults.options.headers = this.headers;
|
|
836
|
-
}
|
|
837
|
-
setSerialNumber(serialnumber) {
|
|
838
|
-
this.headers.sn = serialnumber;
|
|
839
|
-
this.requestEufyCloud.defaults.options.headers = this.headers;
|
|
840
|
-
}
|
|
841
|
-
async _getEvents(functionName, endpoint, startTime, endTime, filter, maxResults) {
|
|
842
|
-
const records = [];
|
|
843
|
-
if (this.connected) {
|
|
844
|
-
try {
|
|
845
|
-
if (filter === undefined)
|
|
846
|
-
filter = { deviceSN: "", stationSN: "", storageType: types_1.StorageType.NONE };
|
|
847
|
-
if (maxResults === undefined)
|
|
848
|
-
maxResults = 1000;
|
|
849
|
-
const response = await this.request({
|
|
850
|
-
method: "post",
|
|
851
|
-
endpoint: endpoint,
|
|
852
|
-
data: {
|
|
853
|
-
device_sn: filter.deviceSN !== undefined ? filter.deviceSN : "",
|
|
854
|
-
end_time: Math.trunc(endTime.getTime() / 1000),
|
|
855
|
-
exclude_guest: false,
|
|
856
|
-
house_id: "HOUSEID_ALL_DEVICE",
|
|
857
|
-
id: 0,
|
|
858
|
-
id_type: 1,
|
|
859
|
-
is_favorite: false,
|
|
860
|
-
num: maxResults,
|
|
861
|
-
pullup: true,
|
|
862
|
-
shared: true,
|
|
863
|
-
start_time: Math.trunc(startTime.getTime() / 1000),
|
|
864
|
-
station_sn: filter.stationSN !== undefined ? filter.stationSN : "",
|
|
865
|
-
storage: filter.storageType !== undefined ? filter.storageType : types_1.StorageType.NONE,
|
|
866
|
-
transaction: `${new Date().getTime().toString()}`
|
|
867
|
-
}
|
|
868
|
-
});
|
|
869
|
-
this.log.debug(`${functionName} - Response:`, response.data);
|
|
870
|
-
if (response.status == 200) {
|
|
871
|
-
const result = response.data;
|
|
872
|
-
if (result.code == 0) {
|
|
873
|
-
if (result.data) {
|
|
874
|
-
const dataresult = this.decryptAPIData(result.data);
|
|
875
|
-
if (dataresult) {
|
|
876
|
-
dataresult.forEach(record => {
|
|
877
|
-
this.log.debug(`${functionName} - Record:`, record);
|
|
878
|
-
records.push(record);
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
else {
|
|
883
|
-
this.log.error("Response data is missing", { code: result.code, msg: result.msg, data: result.data });
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
else {
|
|
887
|
-
this.log.error(`${functionName} - Response code not ok`, { code: result.code, msg: result.msg });
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
else {
|
|
891
|
-
this.log.error(`${functionName} - Status return code not 200`, { status: response.status, statusText: response.statusText });
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
catch (error) {
|
|
895
|
-
this.log.error(`${functionName} - Generic Error:`, error);
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
return records;
|
|
899
|
-
}
|
|
900
|
-
async getVideoEvents(startTime, endTime, filter, maxResults) {
|
|
901
|
-
return this._getEvents("getVideoEvents", "v2/event/app/get_all_video_record", startTime, endTime, filter, maxResults);
|
|
902
|
-
}
|
|
903
|
-
async getAlarmEvents(startTime, endTime, filter, maxResults) {
|
|
904
|
-
return this._getEvents("getAlarmEvents", "v2/event/app/get_all_alarm_record", startTime, endTime, filter, maxResults);
|
|
905
|
-
}
|
|
906
|
-
async getHistoryEvents(startTime, endTime, filter, maxResults) {
|
|
907
|
-
return this._getEvents("getHistoryEvents", "v2/event/app/get_all_history_record", startTime, endTime, filter, maxResults);
|
|
908
|
-
}
|
|
909
|
-
async getAllVideoEvents(filter, maxResults) {
|
|
910
|
-
const fifteenYearsInMilliseconds = 15 * 365 * 24 * 60 * 60 * 1000;
|
|
911
|
-
return this.getVideoEvents(new Date(new Date().getTime() - fifteenYearsInMilliseconds), new Date(), filter, maxResults);
|
|
912
|
-
}
|
|
913
|
-
async getAllAlarmEvents(filter, maxResults) {
|
|
914
|
-
const fifteenYearsInMilliseconds = 15 * 365 * 24 * 60 * 60 * 1000;
|
|
915
|
-
return this.getAlarmEvents(new Date(new Date().getTime() - fifteenYearsInMilliseconds), new Date(), filter, maxResults);
|
|
916
|
-
}
|
|
917
|
-
async getAllHistoryEvents(filter, maxResults) {
|
|
918
|
-
const fifteenYearsInMilliseconds = 15 * 365 * 24 * 60 * 60 * 1000;
|
|
919
|
-
return this.getHistoryEvents(new Date(new Date().getTime() - fifteenYearsInMilliseconds), new Date(), filter, maxResults);
|
|
920
|
-
}
|
|
921
|
-
isConnected() {
|
|
922
|
-
return this.connected;
|
|
923
|
-
}
|
|
924
|
-
async getInvites() {
|
|
925
|
-
if (this.connected) {
|
|
926
|
-
try {
|
|
927
|
-
const response = await this.request({
|
|
928
|
-
method: "post",
|
|
929
|
-
endpoint: "v1/family/get_invites",
|
|
930
|
-
data: {
|
|
931
|
-
num: 100,
|
|
932
|
-
orderby: "",
|
|
933
|
-
own: false,
|
|
934
|
-
page: 0,
|
|
935
|
-
transaction: `${new Date().getTime().toString()}`
|
|
936
|
-
}
|
|
937
|
-
});
|
|
938
|
-
if (response.status == 200) {
|
|
939
|
-
const result = response.data;
|
|
940
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
941
|
-
if (result.data) {
|
|
942
|
-
const invites = {};
|
|
943
|
-
result.data.forEach((invite) => {
|
|
944
|
-
invites[invite.invite_id] = invite;
|
|
945
|
-
let data = (0, utils_2.parseJSON)(invites[invite.invite_id].devices, this.log);
|
|
946
|
-
if (data === undefined)
|
|
947
|
-
data = [];
|
|
948
|
-
invites[invite.invite_id].devices = data;
|
|
949
|
-
});
|
|
950
|
-
return invites;
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
else {
|
|
954
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
else {
|
|
958
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
catch (error) {
|
|
962
|
-
this.log.error("Generic Error:", error);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
return {};
|
|
966
|
-
}
|
|
967
|
-
async confirmInvites(confirmInvites) {
|
|
968
|
-
if (this.connected) {
|
|
969
|
-
try {
|
|
970
|
-
const response = await this.request({
|
|
971
|
-
method: "post",
|
|
972
|
-
endpoint: "v1/family/confirm_invite",
|
|
973
|
-
data: {
|
|
974
|
-
invites: confirmInvites,
|
|
975
|
-
transaction: `${new Date().getTime().toString()}`
|
|
976
|
-
}
|
|
977
|
-
});
|
|
978
|
-
if (response.status == 200) {
|
|
979
|
-
const result = response.data;
|
|
980
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
981
|
-
return true;
|
|
982
|
-
}
|
|
983
|
-
else {
|
|
984
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
else {
|
|
988
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
catch (error) {
|
|
992
|
-
this.log.error("Generic Error:", error);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
return false;
|
|
996
|
-
}
|
|
997
|
-
async getPublicKey(deviceSN, type) {
|
|
998
|
-
if (this.connected) {
|
|
999
|
-
try {
|
|
1000
|
-
if (this.persistentData.device_public_keys[deviceSN] !== undefined && type === types_1.PublicKeyType.LOCK) {
|
|
1001
|
-
this.log.debug("return cached public key", this.persistentData.device_public_keys[deviceSN]);
|
|
1002
|
-
return this.persistentData.device_public_keys[deviceSN];
|
|
1003
|
-
}
|
|
1004
|
-
else {
|
|
1005
|
-
const response = await this.request({
|
|
1006
|
-
method: "get",
|
|
1007
|
-
endpoint: `v1/app/public_key/query?device_sn=${deviceSN}&type=${type}`
|
|
1008
|
-
});
|
|
1009
|
-
if (response.status == 200) {
|
|
1010
|
-
const result = response.data;
|
|
1011
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1012
|
-
if (result.data) {
|
|
1013
|
-
if (type === types_1.PublicKeyType.LOCK)
|
|
1014
|
-
this.persistentData.device_public_keys[deviceSN] = result.data.public_key;
|
|
1015
|
-
return result.data.public_key;
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
else {
|
|
1019
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
else {
|
|
1023
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
catch (error) {
|
|
1028
|
-
this.log.error("Generic Error:", error);
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
return "";
|
|
1032
|
-
}
|
|
1033
|
-
decryptAPIData(data, json = true) {
|
|
1034
|
-
if (data) {
|
|
1035
|
-
let decryptedData;
|
|
1036
|
-
try {
|
|
1037
|
-
decryptedData = (0, utils_1.decryptAPIData)(data, this.ecdh.computeSecret(Buffer.from(this.persistentData.serverPublicKey, "hex")));
|
|
1038
|
-
}
|
|
1039
|
-
catch (error) {
|
|
1040
|
-
this.log.error("Data decryption error, invalidating session data and reconnecting...", error);
|
|
1041
|
-
this.persistentData.serverPublicKey = this.SERVER_PUBLIC_KEY;
|
|
1042
|
-
this.invalidateToken();
|
|
1043
|
-
this.emit("close");
|
|
1044
|
-
}
|
|
1045
|
-
if (decryptedData) {
|
|
1046
|
-
if (json)
|
|
1047
|
-
return (0, utils_2.parseJSON)(decryptedData.toString("utf-8"), this.log);
|
|
1048
|
-
return decryptedData.toString();
|
|
1049
|
-
}
|
|
1050
|
-
if (json)
|
|
1051
|
-
return {};
|
|
1052
|
-
}
|
|
1053
|
-
return undefined;
|
|
1054
|
-
}
|
|
1055
|
-
async getSensorHistory(stationSN, deviceSN) {
|
|
1056
|
-
if (this.connected) {
|
|
1057
|
-
try {
|
|
1058
|
-
const response = await this.request({
|
|
1059
|
-
method: "post",
|
|
1060
|
-
endpoint: "v1/app/get_sensor_history",
|
|
1061
|
-
data: {
|
|
1062
|
-
devicse_sn: deviceSN,
|
|
1063
|
-
max_time: 0,
|
|
1064
|
-
num: 500,
|
|
1065
|
-
page: 0,
|
|
1066
|
-
station_sn: stationSN,
|
|
1067
|
-
transaction: `${new Date().getTime().toString()}`
|
|
1068
|
-
}
|
|
1069
|
-
});
|
|
1070
|
-
if (response.status == 200) {
|
|
1071
|
-
const result = response.data;
|
|
1072
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1073
|
-
if (result.data) {
|
|
1074
|
-
const entries = result.data;
|
|
1075
|
-
return entries;
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
else {
|
|
1079
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
else {
|
|
1083
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
catch (error) {
|
|
1087
|
-
this.log.error("Generic Error:", error);
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
return [];
|
|
1091
|
-
}
|
|
1092
|
-
async getHouseDetail(houseID) {
|
|
1093
|
-
if (this.connected) {
|
|
1094
|
-
try {
|
|
1095
|
-
const response = await this.request({
|
|
1096
|
-
method: "post",
|
|
1097
|
-
endpoint: "v2/house/detail",
|
|
1098
|
-
data: {
|
|
1099
|
-
house_id: houseID,
|
|
1100
|
-
transaction: `${new Date().getTime().toString()}`
|
|
1101
|
-
}
|
|
1102
|
-
});
|
|
1103
|
-
if (response.status == 200) {
|
|
1104
|
-
const result = response.data;
|
|
1105
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1106
|
-
if (result.data) {
|
|
1107
|
-
const houseDetail = this.decryptAPIData(result.data);
|
|
1108
|
-
this.log.debug("Decrypted house detail data", houseDetail);
|
|
1109
|
-
return houseDetail;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
else {
|
|
1113
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
else {
|
|
1117
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
catch (error) {
|
|
1121
|
-
this.log.error("Generic Error:", error);
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
return null;
|
|
1125
|
-
}
|
|
1126
|
-
async getHouseList() {
|
|
1127
|
-
if (this.connected) {
|
|
1128
|
-
try {
|
|
1129
|
-
const response = await this.request({
|
|
1130
|
-
method: "post",
|
|
1131
|
-
endpoint: "v1/house/list",
|
|
1132
|
-
data: {
|
|
1133
|
-
transaction: `${new Date().getTime().toString()}`
|
|
1134
|
-
}
|
|
1135
|
-
});
|
|
1136
|
-
if (response.status == 200) {
|
|
1137
|
-
const result = response.data;
|
|
1138
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1139
|
-
if (result.data) {
|
|
1140
|
-
return result.data;
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
else {
|
|
1144
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
else {
|
|
1148
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
catch (error) {
|
|
1152
|
-
this.log.error("Generic Error:", error);
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
return [];
|
|
1156
|
-
}
|
|
1157
|
-
async getHouseInviteList(isInviter = 1) {
|
|
1158
|
-
//TODO: Understand the other values of isInviter and document it
|
|
1159
|
-
if (this.connected) {
|
|
1160
|
-
try {
|
|
1161
|
-
const response = await this.request({
|
|
1162
|
-
method: "post",
|
|
1163
|
-
endpoint: "v1/house/invite_list",
|
|
1164
|
-
data: {
|
|
1165
|
-
is_inviter: isInviter,
|
|
1166
|
-
transaction: `${new Date().getTime().toString()}`
|
|
1167
|
-
}
|
|
1168
|
-
});
|
|
1169
|
-
if (response.status == 200) {
|
|
1170
|
-
const result = response.data;
|
|
1171
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1172
|
-
if (result.data) {
|
|
1173
|
-
const houseInviteList = this.decryptAPIData(result.data);
|
|
1174
|
-
this.log.debug("Decrypted house invite list data", houseInviteList);
|
|
1175
|
-
return houseInviteList;
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
else {
|
|
1179
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
else {
|
|
1183
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
catch (error) {
|
|
1187
|
-
this.log.error("Generic Error:", error);
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
return [];
|
|
1191
|
-
}
|
|
1192
|
-
async confirmHouseInvite(houseID, inviteID) {
|
|
1193
|
-
if (this.connected) {
|
|
1194
|
-
try {
|
|
1195
|
-
const response = await this.request({
|
|
1196
|
-
method: "post",
|
|
1197
|
-
endpoint: "v1/house/confirm_invite",
|
|
1198
|
-
data: {
|
|
1199
|
-
house_id: houseID,
|
|
1200
|
-
invite_id: inviteID,
|
|
1201
|
-
is_inviter: 1,
|
|
1202
|
-
//user_id: "",
|
|
1203
|
-
transaction: `${new Date().getTime().toString()}`
|
|
1204
|
-
}
|
|
1205
|
-
});
|
|
1206
|
-
if (response.status == 200) {
|
|
1207
|
-
const result = response.data;
|
|
1208
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1209
|
-
return true;
|
|
1210
|
-
}
|
|
1211
|
-
else {
|
|
1212
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
else {
|
|
1216
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
catch (error) {
|
|
1220
|
-
this.log.error("Generic Error:", error);
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
return false;
|
|
1224
|
-
}
|
|
1225
|
-
getPersistentData() {
|
|
1226
|
-
return this.persistentData;
|
|
1227
|
-
}
|
|
1228
|
-
async getPassportProfile() {
|
|
1229
|
-
try {
|
|
1230
|
-
const response = await this.request({
|
|
1231
|
-
method: "get",
|
|
1232
|
-
endpoint: "v2/passport/profile"
|
|
1233
|
-
});
|
|
1234
|
-
if (response.status == 200) {
|
|
1235
|
-
const result = response.data;
|
|
1236
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1237
|
-
if (result.data) {
|
|
1238
|
-
const profile = this.decryptAPIData(result.data);
|
|
1239
|
-
this.log.debug("Decrypted passport profile data", profile);
|
|
1240
|
-
this.persistentData.user_id = profile.user_id;
|
|
1241
|
-
this.persistentData.nick_name = profile.nick_name;
|
|
1242
|
-
this.persistentData.email = profile.email;
|
|
1243
|
-
return profile;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
else {
|
|
1247
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1248
|
-
}
|
|
1249
|
-
}
|
|
1250
|
-
else {
|
|
1251
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
catch (error) {
|
|
1255
|
-
this.log.error("Generic Error:", error);
|
|
1256
|
-
}
|
|
1257
|
-
return null;
|
|
1258
|
-
}
|
|
1259
|
-
async addUser(deviceSN, nickname, stationSN = "") {
|
|
1260
|
-
if (this.connected) {
|
|
1261
|
-
try {
|
|
1262
|
-
const response = await this.request({
|
|
1263
|
-
method: "post",
|
|
1264
|
-
endpoint: "v1/app/device/local_user/add",
|
|
1265
|
-
data: {
|
|
1266
|
-
device_sn: deviceSN,
|
|
1267
|
-
nick_name: nickname,
|
|
1268
|
-
station_sn: stationSN === deviceSN ? "" : stationSN,
|
|
1269
|
-
transaction: `${new Date().getTime().toString()}`
|
|
1270
|
-
}
|
|
1271
|
-
});
|
|
1272
|
-
if (response.status == 200) {
|
|
1273
|
-
const result = response.data;
|
|
1274
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1275
|
-
if (result.data)
|
|
1276
|
-
return result.data;
|
|
1277
|
-
}
|
|
1278
|
-
else {
|
|
1279
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
else {
|
|
1283
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
catch (error) {
|
|
1287
|
-
this.log.error("Generic Error:", error);
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
return null;
|
|
1291
|
-
}
|
|
1292
|
-
async deleteUser(deviceSN, shortUserId, stationSN = "") {
|
|
1293
|
-
if (this.connected) {
|
|
1294
|
-
try {
|
|
1295
|
-
const response = await this.request({
|
|
1296
|
-
method: "post",
|
|
1297
|
-
endpoint: "v1/app/device/user/delete",
|
|
1298
|
-
data: {
|
|
1299
|
-
device_sn: deviceSN,
|
|
1300
|
-
short_user_ids: [shortUserId],
|
|
1301
|
-
station_sn: stationSN === deviceSN ? "" : stationSN,
|
|
1302
|
-
transaction: `${new Date().getTime().toString()}`
|
|
1303
|
-
}
|
|
1304
|
-
});
|
|
1305
|
-
if (response.status == 200) {
|
|
1306
|
-
const result = response.data;
|
|
1307
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1308
|
-
return true;
|
|
1309
|
-
}
|
|
1310
|
-
else {
|
|
1311
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
else {
|
|
1315
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
catch (error) {
|
|
1319
|
-
this.log.error("Generic Error:", error);
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
return false;
|
|
1323
|
-
}
|
|
1324
|
-
async getUsers(deviceSN, stationSN) {
|
|
1325
|
-
try {
|
|
1326
|
-
const response = await this.request({
|
|
1327
|
-
method: "get",
|
|
1328
|
-
endpoint: `v1/app/device/user/list?device_sn=${deviceSN}&station_sn=${stationSN}`
|
|
1329
|
-
});
|
|
1330
|
-
if (response.status == 200) {
|
|
1331
|
-
const result = response.data;
|
|
1332
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1333
|
-
if (result.data) {
|
|
1334
|
-
const usersResponse = result.data;
|
|
1335
|
-
return usersResponse.user_list;
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
else {
|
|
1339
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
else {
|
|
1343
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
catch (error) {
|
|
1347
|
-
this.log.error("Generic Error:", error);
|
|
1348
|
-
}
|
|
1349
|
-
return null;
|
|
1350
|
-
}
|
|
1351
|
-
async getUser(deviceSN, stationSN, shortUserId) {
|
|
1352
|
-
try {
|
|
1353
|
-
const users = await this.getUsers(deviceSN, stationSN);
|
|
1354
|
-
if (users !== null) {
|
|
1355
|
-
for (const user of users) {
|
|
1356
|
-
if (user.short_user_id === shortUserId) {
|
|
1357
|
-
return user;
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
catch (error) {
|
|
1363
|
-
this.log.error("Generic Error:", error);
|
|
1364
|
-
}
|
|
1365
|
-
return null;
|
|
1366
|
-
}
|
|
1367
|
-
async updateUser(deviceSN, stationSN, shortUserId, nickname) {
|
|
1368
|
-
if (this.connected) {
|
|
1369
|
-
try {
|
|
1370
|
-
const user = await this.getUser(deviceSN, stationSN, shortUserId);
|
|
1371
|
-
if (user !== null) {
|
|
1372
|
-
const response = await this.request({
|
|
1373
|
-
method: "post",
|
|
1374
|
-
endpoint: "v1/app/device/local_user/update",
|
|
1375
|
-
data: {
|
|
1376
|
-
device_sn: deviceSN,
|
|
1377
|
-
nick_name: nickname,
|
|
1378
|
-
password_list: user.password_list,
|
|
1379
|
-
short_user_id: shortUserId,
|
|
1380
|
-
station_sn: stationSN === deviceSN ? "" : stationSN,
|
|
1381
|
-
user_type: user.user_type,
|
|
1382
|
-
transaction: `${new Date().getTime().toString()}`
|
|
1383
|
-
}
|
|
1384
|
-
});
|
|
1385
|
-
if (response.status == 200) {
|
|
1386
|
-
const result = response.data;
|
|
1387
|
-
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1388
|
-
return true;
|
|
1389
|
-
}
|
|
1390
|
-
else {
|
|
1391
|
-
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
else {
|
|
1395
|
-
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
catch (error) {
|
|
1400
|
-
this.log.error("Generic Error:", error);
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
return false;
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
HTTPApi
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.HTTPApi = void 0;
|
|
30
|
+
const got_1 = __importStar(require("got"));
|
|
31
|
+
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
|
|
32
|
+
const ts_log_1 = require("ts-log");
|
|
33
|
+
const i18n_iso_countries_1 = require("i18n-iso-countries");
|
|
34
|
+
const i18n_iso_languages_1 = require("@cospired/i18n-iso-languages");
|
|
35
|
+
const crypto_1 = require("crypto");
|
|
36
|
+
const schedule = __importStar(require("node-schedule"));
|
|
37
|
+
const p_throttle_1 = __importDefault(require("p-throttle"));
|
|
38
|
+
const types_1 = require("./types");
|
|
39
|
+
const parameter_1 = require("./parameter");
|
|
40
|
+
const utils_1 = require("./utils");
|
|
41
|
+
const error_1 = require("./../error");
|
|
42
|
+
const utils_2 = require("./../utils");
|
|
43
|
+
const error_2 = require("./error");
|
|
44
|
+
class HTTPApi extends tiny_typed_emitter_1.TypedEmitter {
|
|
45
|
+
constructor(apiBase, country, username, password, log = ts_log_1.dummyLogger, persistentData) {
|
|
46
|
+
super();
|
|
47
|
+
this.SERVER_PUBLIC_KEY = "04c5c00c4f8d1197cc7c3167c52bf7acb054d722f0ef08dcd7e0883236e0d72a3868d9750cb47fa4619248f3d83f0f662671dadc6e2d31c2f41db0161651c7c076";
|
|
48
|
+
this.ecdh = (0, crypto_1.createECDH)("prime256v1");
|
|
49
|
+
this.token = null;
|
|
50
|
+
this.tokenExpiration = null;
|
|
51
|
+
this.connected = false;
|
|
52
|
+
this.throttle = (0, p_throttle_1.default)({
|
|
53
|
+
limit: 6,
|
|
54
|
+
interval: 10000,
|
|
55
|
+
});
|
|
56
|
+
this.devices = {};
|
|
57
|
+
this.hubs = {};
|
|
58
|
+
this.houses = {};
|
|
59
|
+
this.persistentData = {
|
|
60
|
+
user_id: "",
|
|
61
|
+
email: "",
|
|
62
|
+
nick_name: "",
|
|
63
|
+
device_public_keys: {},
|
|
64
|
+
clientPrivateKey: "",
|
|
65
|
+
serverPublicKey: this.SERVER_PUBLIC_KEY
|
|
66
|
+
};
|
|
67
|
+
this.headers = {
|
|
68
|
+
App_version: "v4.5.1_1523",
|
|
69
|
+
Os_type: "android",
|
|
70
|
+
Os_version: "31",
|
|
71
|
+
Phone_model: "ONEPLUS A3003",
|
|
72
|
+
Country: "DE",
|
|
73
|
+
Language: "en",
|
|
74
|
+
Openudid: "5e4621b0152c0d00",
|
|
75
|
+
//uid: "",
|
|
76
|
+
Net_type: "wifi",
|
|
77
|
+
Mnc: "02",
|
|
78
|
+
Mcc: "262",
|
|
79
|
+
Sn: "75814221ee75",
|
|
80
|
+
Model_type: "PHONE",
|
|
81
|
+
Timezone: "GMT+01:00",
|
|
82
|
+
"Cache-Control": "no-cache",
|
|
83
|
+
};
|
|
84
|
+
this.username = username;
|
|
85
|
+
this.password = password;
|
|
86
|
+
this.log = log;
|
|
87
|
+
this.apiBase = apiBase;
|
|
88
|
+
this.log.debug(`Loaded API_BASE: ${apiBase}`);
|
|
89
|
+
this.headers.timezone = (0, utils_1.getTimezoneGMTString)();
|
|
90
|
+
this.headers.country = country.toUpperCase();
|
|
91
|
+
if (persistentData) {
|
|
92
|
+
this.persistentData = persistentData;
|
|
93
|
+
}
|
|
94
|
+
if (this.persistentData.clientPrivateKey === undefined || this.persistentData.clientPrivateKey === "") {
|
|
95
|
+
this.ecdh.generateKeys();
|
|
96
|
+
this.persistentData.clientPrivateKey = this.ecdh.getPrivateKey().toString("hex");
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
try {
|
|
100
|
+
this.ecdh.setPrivateKey(Buffer.from(this.persistentData.clientPrivateKey, "hex"));
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.log.debug(`Invalid client private key, generate new client private key...`, error);
|
|
104
|
+
this.ecdh.generateKeys();
|
|
105
|
+
this.persistentData.clientPrivateKey = this.ecdh.getPrivateKey().toString("hex");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (this.persistentData.serverPublicKey === undefined || this.persistentData.serverPublicKey === "") {
|
|
109
|
+
this.persistentData.serverPublicKey = this.SERVER_PUBLIC_KEY;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
try {
|
|
113
|
+
this.ecdh.computeSecret(Buffer.from(this.persistentData.serverPublicKey, "hex"));
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
this.log.debug(`Invalid server public key, fallback to default server public key...`, error);
|
|
117
|
+
this.persistentData.serverPublicKey = this.SERVER_PUBLIC_KEY;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
this.requestEufyCloud = got_1.default.extend({
|
|
121
|
+
prefixUrl: this.apiBase,
|
|
122
|
+
headers: this.headers,
|
|
123
|
+
responseType: "json",
|
|
124
|
+
//throwHttpErrors: false,
|
|
125
|
+
retry: {
|
|
126
|
+
limit: 3,
|
|
127
|
+
methods: ["GET", "POST"],
|
|
128
|
+
statusCodes: [
|
|
129
|
+
408,
|
|
130
|
+
413,
|
|
131
|
+
423,
|
|
132
|
+
429,
|
|
133
|
+
500,
|
|
134
|
+
502,
|
|
135
|
+
503,
|
|
136
|
+
504,
|
|
137
|
+
521,
|
|
138
|
+
522,
|
|
139
|
+
524
|
|
140
|
+
],
|
|
141
|
+
calculateDelay: ({ computedValue }) => {
|
|
142
|
+
return computedValue * 3;
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
hooks: {
|
|
146
|
+
afterResponse: [
|
|
147
|
+
async (response, retryWithMergedOptions) => {
|
|
148
|
+
// Unauthorized
|
|
149
|
+
if (response.statusCode === 401) {
|
|
150
|
+
const oldToken = this.token;
|
|
151
|
+
this.log.debug("Invalidate token an get a new one...", { requestUrl: response.requestUrl, statusCode: response.statusCode, statusMessage: response.statusMessage });
|
|
152
|
+
this.invalidateToken();
|
|
153
|
+
await this.login({ force: true });
|
|
154
|
+
if (oldToken !== this.token && this.token) {
|
|
155
|
+
// Refresh the access token
|
|
156
|
+
const updatedOptions = {
|
|
157
|
+
headers: {
|
|
158
|
+
"X-Auth-Token": this.token
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
// Update the defaults
|
|
162
|
+
this.requestEufyCloud.defaults.options = this.requestEufyCloud.mergeOptions(this.requestEufyCloud.defaults.options, updatedOptions);
|
|
163
|
+
// Make a new retry
|
|
164
|
+
return retryWithMergedOptions(updatedOptions);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// No changes otherwise
|
|
168
|
+
return response;
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
beforeRetry: [
|
|
172
|
+
(options, error, retryCount) => {
|
|
173
|
+
var _a;
|
|
174
|
+
// This will be called on `retryWithMergedOptions(...)`
|
|
175
|
+
this.log.debug(`Retrying [${retryCount}]: ${error === null || error === void 0 ? void 0 : error.code} (${(_a = error === null || error === void 0 ? void 0 : error.request) === null || _a === void 0 ? void 0 : _a.requestUrl})`, { options: options });
|
|
176
|
+
// Retrying [1]: ERR_NON_2XX_3XX_RESPONSE
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
beforeError: [
|
|
180
|
+
error => {
|
|
181
|
+
var _a;
|
|
182
|
+
const { response } = error;
|
|
183
|
+
if (response && response.body) {
|
|
184
|
+
const result = response.body;
|
|
185
|
+
error.name = "EufyError";
|
|
186
|
+
error.message = `Code: ${result.code} Message: ${result.msg} (HTTP Code: ${response.statusCode})`;
|
|
187
|
+
this.log.error(`${error.name} - ${error.message} - requestUrl: ${(_a = error.request) === null || _a === void 0 ? void 0 : _a.requestUrl}`);
|
|
188
|
+
}
|
|
189
|
+
return error;
|
|
190
|
+
}
|
|
191
|
+
],
|
|
192
|
+
beforeRequest: [
|
|
193
|
+
async (_options) => {
|
|
194
|
+
await this.throttle(async () => { return; })();
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
mutableDefaults: true
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
static async getApiBaseFromCloud(country) {
|
|
202
|
+
const response = await (0, got_1.default)(`domain/${country}`, {
|
|
203
|
+
prefixUrl: this.apiDomainBase,
|
|
204
|
+
method: "GET",
|
|
205
|
+
responseType: "json",
|
|
206
|
+
retry: {
|
|
207
|
+
limit: 1,
|
|
208
|
+
methods: ["GET"]
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
const result = response.body;
|
|
212
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
213
|
+
return `https://${result.data.domain}`;
|
|
214
|
+
}
|
|
215
|
+
throw new error_2.ApiBaseLoadError(result.code, result.msg);
|
|
216
|
+
}
|
|
217
|
+
static async initialize(country, username, password, log = ts_log_1.dummyLogger, persistentData) {
|
|
218
|
+
if ((0, i18n_iso_countries_1.isValid)(country) && country.length === 2) {
|
|
219
|
+
const apiBase = await this.getApiBaseFromCloud(country);
|
|
220
|
+
return new HTTPApi(apiBase, country, username, password, log, persistentData);
|
|
221
|
+
}
|
|
222
|
+
throw new error_1.InvalidCountryCodeError("Invalid ISO 3166-1 Alpha-2 country code");
|
|
223
|
+
}
|
|
224
|
+
clearScheduleRenewAuthToken() {
|
|
225
|
+
if (this.renewAuthTokenJob !== undefined) {
|
|
226
|
+
this.renewAuthTokenJob.cancel();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
scheduleRenewAuthToken() {
|
|
230
|
+
this.clearScheduleRenewAuthToken();
|
|
231
|
+
if (this.tokenExpiration !== null) {
|
|
232
|
+
const scheduleDate = new Date(this.tokenExpiration.getTime() - (1000 * 60 * 60 * 24));
|
|
233
|
+
if (this.renewAuthTokenJob === undefined) {
|
|
234
|
+
this.renewAuthTokenJob = schedule.scheduleJob("renewAuthToken", scheduleDate, async () => {
|
|
235
|
+
this.log.info("Authentication token is soon expiring, fetching a new one...");
|
|
236
|
+
await this.login({ force: true });
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
this.renewAuthTokenJob.schedule(scheduleDate);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
invalidateToken() {
|
|
245
|
+
this.token = null;
|
|
246
|
+
this.requestEufyCloud.defaults.options.headers["X-Auth-Token"] = undefined;
|
|
247
|
+
this.tokenExpiration = null;
|
|
248
|
+
this.clearScheduleRenewAuthToken();
|
|
249
|
+
this.emit("auth token invalidated");
|
|
250
|
+
}
|
|
251
|
+
setPhoneModel(model) {
|
|
252
|
+
this.headers.phone_model = model.toUpperCase();
|
|
253
|
+
this.requestEufyCloud.defaults.options.headers = this.headers;
|
|
254
|
+
}
|
|
255
|
+
getPhoneModel() {
|
|
256
|
+
return this.headers.phone_model;
|
|
257
|
+
}
|
|
258
|
+
getCountry() {
|
|
259
|
+
return this.headers.country;
|
|
260
|
+
}
|
|
261
|
+
setLanguage(language) {
|
|
262
|
+
if ((0, i18n_iso_languages_1.isValid)(language) && language.length === 2) {
|
|
263
|
+
this.headers.language = language;
|
|
264
|
+
this.requestEufyCloud.defaults.options.headers = this.headers;
|
|
265
|
+
}
|
|
266
|
+
else
|
|
267
|
+
throw new error_1.InvalidLanguageCodeError("Invalid ISO 639 language code");
|
|
268
|
+
}
|
|
269
|
+
getLanguage() {
|
|
270
|
+
return this.headers.language;
|
|
271
|
+
}
|
|
272
|
+
async login(options) {
|
|
273
|
+
var _a;
|
|
274
|
+
options = (0, utils_2.mergeDeep)(options, {
|
|
275
|
+
force: false
|
|
276
|
+
});
|
|
277
|
+
this.log.debug("Login and get an access token", { token: this.token, tokenExpiration: this.tokenExpiration });
|
|
278
|
+
if (!this.token || (this.tokenExpiration && (new Date()).getTime() >= this.tokenExpiration.getTime()) || options.verifyCode || options.captcha || options.force) {
|
|
279
|
+
try {
|
|
280
|
+
const data = {
|
|
281
|
+
ab: this.headers.country,
|
|
282
|
+
client_secret_info: {
|
|
283
|
+
public_key: this.ecdh.getPublicKey("hex")
|
|
284
|
+
},
|
|
285
|
+
enc: 0,
|
|
286
|
+
email: this.username,
|
|
287
|
+
password: (0, utils_1.encryptAPIData)(this.password, this.ecdh.computeSecret(Buffer.from(this.SERVER_PUBLIC_KEY, "hex"))),
|
|
288
|
+
time_zone: new Date().getTimezoneOffset() !== 0 ? -new Date().getTimezoneOffset() * 60 * 1000 : 0,
|
|
289
|
+
transaction: `${new Date().getTime()}`
|
|
290
|
+
};
|
|
291
|
+
if (options.verifyCode) {
|
|
292
|
+
data.verify_code = options.verifyCode;
|
|
293
|
+
}
|
|
294
|
+
else if (options.captcha) {
|
|
295
|
+
data.captcha_id = options.captcha.captchaId;
|
|
296
|
+
data.answer = options.captcha.captchaCode;
|
|
297
|
+
}
|
|
298
|
+
const response = await this.request({
|
|
299
|
+
method: "post",
|
|
300
|
+
endpoint: "v2/passport/login_sec",
|
|
301
|
+
data: data
|
|
302
|
+
});
|
|
303
|
+
if (response.status == 200) {
|
|
304
|
+
const result = response.data;
|
|
305
|
+
if (result.data !== undefined) {
|
|
306
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
307
|
+
const dataresult = result.data;
|
|
308
|
+
if ((_a = dataresult.server_secret_info) === null || _a === void 0 ? void 0 : _a.public_key)
|
|
309
|
+
this.persistentData.serverPublicKey = dataresult.server_secret_info.public_key;
|
|
310
|
+
this.persistentData.user_id = dataresult.user_id;
|
|
311
|
+
this.persistentData.email = this.decryptAPIData(dataresult.email, false);
|
|
312
|
+
this.persistentData.nick_name = dataresult.nick_name;
|
|
313
|
+
this.setToken(dataresult.auth_token);
|
|
314
|
+
this.tokenExpiration = new Date(dataresult.token_expires_at * 1000);
|
|
315
|
+
this.headers = {
|
|
316
|
+
...this.headers,
|
|
317
|
+
gtoken: (0, utils_2.md5)(dataresult.user_id)
|
|
318
|
+
};
|
|
319
|
+
this.log.debug("Token data", { token: this.token, tokenExpiration: this.tokenExpiration, serverPublicKey: this.persistentData.serverPublicKey });
|
|
320
|
+
if (!this.connected) {
|
|
321
|
+
this.connected = true;
|
|
322
|
+
this.emit("connect");
|
|
323
|
+
}
|
|
324
|
+
this.scheduleRenewAuthToken();
|
|
325
|
+
}
|
|
326
|
+
else if (result.code == types_1.ResponseErrorCode.CODE_NEED_VERIFY_CODE) {
|
|
327
|
+
this.log.debug(`Send verification code...`);
|
|
328
|
+
const dataresult = result.data;
|
|
329
|
+
this.setToken(dataresult.auth_token);
|
|
330
|
+
this.tokenExpiration = new Date(dataresult.token_expires_at * 1000);
|
|
331
|
+
this.log.debug("Token data", { token: this.token, tokenExpiration: this.tokenExpiration });
|
|
332
|
+
await this.sendVerifyCode(types_1.VerfyCodeTypes.TYPE_EMAIL);
|
|
333
|
+
this.emit("tfa request");
|
|
334
|
+
}
|
|
335
|
+
else if (result.code == types_1.ResponseErrorCode.LOGIN_NEED_CAPTCHA || result.code == types_1.ResponseErrorCode.LOGIN_CAPTCHA_ERROR) {
|
|
336
|
+
const dataresult = result.data;
|
|
337
|
+
this.log.debug("Captcha verification received", { captchaId: dataresult.captcha_id, item: dataresult.item });
|
|
338
|
+
this.emit("captcha request", dataresult.captcha_id, dataresult.item);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
342
|
+
this.emit("connection error", new error_2.ApiResponseCodeError(`Response code not ok (${result.code}).`));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
this.log.error("Response data is missing", { code: result.code, msg: result.msg, data: result.data });
|
|
347
|
+
this.emit("connection error", new error_2.ApiInvalidResponseError("Response data is missing"));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
352
|
+
this.emit("connection error", new error_2.ApiHTTPResponseCodeError(`HTTP response code not ok (${response.status}).`));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
this.log.error("Generic Error:", error);
|
|
357
|
+
this.emit("connection error", new error_2.ApiGenericError(`Generic error: ${error}`));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
else if (!this.connected) {
|
|
361
|
+
try {
|
|
362
|
+
const profile = await this.getPassportProfile();
|
|
363
|
+
if (profile !== null) {
|
|
364
|
+
this.connected = true;
|
|
365
|
+
this.emit("connect");
|
|
366
|
+
this.scheduleRenewAuthToken();
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
this.emit("connection error", new error_2.ApiInvalidResponseError(`Invalid passport profile response`));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch (error) {
|
|
373
|
+
this.log.error("getPassportProfile Error", error);
|
|
374
|
+
this.emit("connection error", new error_2.ApiGenericError(`Get passport profile error: ${error}`));
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async sendVerifyCode(type) {
|
|
379
|
+
try {
|
|
380
|
+
if (!type)
|
|
381
|
+
type = types_1.VerfyCodeTypes.TYPE_EMAIL;
|
|
382
|
+
const response = await this.request({
|
|
383
|
+
method: "post",
|
|
384
|
+
endpoint: "v1/sms/send/verify_code",
|
|
385
|
+
data: {
|
|
386
|
+
message_type: type,
|
|
387
|
+
transaction: `${new Date().getTime()}`
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
if (response.status == 200) {
|
|
391
|
+
const result = response.data;
|
|
392
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
393
|
+
this.log.info(`Requested verification code for 2FA`);
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
this.log.error("Generic Error:", error);
|
|
406
|
+
}
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
async listTrustDevice() {
|
|
410
|
+
if (this.connected) {
|
|
411
|
+
try {
|
|
412
|
+
const response = await this.request({
|
|
413
|
+
method: "get",
|
|
414
|
+
endpoint: "v1/app/trust_device/list"
|
|
415
|
+
});
|
|
416
|
+
if (response.status == 200) {
|
|
417
|
+
const result = response.data;
|
|
418
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
419
|
+
if (result.data && result.data.list) {
|
|
420
|
+
return result.data.list;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
this.log.error("Generic Error:", error);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return [];
|
|
436
|
+
}
|
|
437
|
+
async addTrustDevice(verifyCode) {
|
|
438
|
+
if (this.connected) {
|
|
439
|
+
try {
|
|
440
|
+
const response = await this.request({
|
|
441
|
+
method: "post",
|
|
442
|
+
endpoint: "v1/app/trust_device/add",
|
|
443
|
+
data: {
|
|
444
|
+
verify_code: verifyCode,
|
|
445
|
+
transaction: `${new Date().getTime()}`
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
this.log.debug("Response trust device:", response.data);
|
|
449
|
+
if (response.status == 200) {
|
|
450
|
+
const result = response.data;
|
|
451
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
452
|
+
this.log.info(`2FA authentication successfully done. Device trusted.`);
|
|
453
|
+
const trusted_devices = await this.listTrustDevice();
|
|
454
|
+
trusted_devices.forEach((trusted_device) => {
|
|
455
|
+
if (trusted_device.is_current_device === 1) {
|
|
456
|
+
this.log.debug("This device is trusted. Token expiration extended:", { tokenExpiration: this.tokenExpiration });
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
this.log.error("Generic Error:", error);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
async getStationList() {
|
|
476
|
+
if (this.connected) {
|
|
477
|
+
try {
|
|
478
|
+
const response = await this.request({
|
|
479
|
+
method: "post",
|
|
480
|
+
endpoint: "v2/house/station_list",
|
|
481
|
+
data: {
|
|
482
|
+
device_sn: "",
|
|
483
|
+
num: 1000,
|
|
484
|
+
orderby: "",
|
|
485
|
+
page: 0,
|
|
486
|
+
station_sn: "",
|
|
487
|
+
time_zone: new Date().getTimezoneOffset() !== 0 ? -new Date().getTimezoneOffset() * 60 * 1000 : 0,
|
|
488
|
+
transaction: `${new Date().getTime()}`
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
if (response.status == 200) {
|
|
492
|
+
const result = response.data;
|
|
493
|
+
if (result.code == 0) {
|
|
494
|
+
if (result.data) {
|
|
495
|
+
const stationList = this.decryptAPIData(result.data);
|
|
496
|
+
this.log.debug("Decrypted station list data", stationList);
|
|
497
|
+
return stationList;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
this.log.error("Stations - Generic Error:", error);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return [];
|
|
513
|
+
}
|
|
514
|
+
async getDeviceList() {
|
|
515
|
+
if (this.connected) {
|
|
516
|
+
try {
|
|
517
|
+
const response = await this.request({
|
|
518
|
+
method: "post",
|
|
519
|
+
endpoint: "v2/house/device_list",
|
|
520
|
+
data: {
|
|
521
|
+
device_sn: "",
|
|
522
|
+
num: 1000,
|
|
523
|
+
orderby: "",
|
|
524
|
+
page: 0,
|
|
525
|
+
station_sn: "",
|
|
526
|
+
time_zone: new Date().getTimezoneOffset() !== 0 ? -new Date().getTimezoneOffset() * 60 * 1000 : 0,
|
|
527
|
+
transaction: `${new Date().getTime()}`
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
if (response.status == 200) {
|
|
531
|
+
const result = response.data;
|
|
532
|
+
if (result.code == 0) {
|
|
533
|
+
if (result.data) {
|
|
534
|
+
const deviceList = this.decryptAPIData(result.data);
|
|
535
|
+
this.log.debug("Decrypted device list data", deviceList);
|
|
536
|
+
return deviceList;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
catch (error) {
|
|
548
|
+
this.log.error("Devices - Generic Error:", error);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return [];
|
|
552
|
+
}
|
|
553
|
+
async refreshHouseData() {
|
|
554
|
+
//Get Houses
|
|
555
|
+
const houses = await this.getHouseList();
|
|
556
|
+
if (houses && houses.length > 0) {
|
|
557
|
+
houses.forEach(element => {
|
|
558
|
+
this.houses[element.house_id] = element;
|
|
559
|
+
});
|
|
560
|
+
if (Object.keys(this.houses).length > 0)
|
|
561
|
+
this.emit("houses", this.houses);
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
this.log.info("No houses found.");
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
async refreshStationData() {
|
|
568
|
+
//Get Stations
|
|
569
|
+
const stations = await this.getStationList();
|
|
570
|
+
if (stations && stations.length > 0) {
|
|
571
|
+
stations.forEach(element => {
|
|
572
|
+
this.hubs[element.station_sn] = element;
|
|
573
|
+
});
|
|
574
|
+
if (Object.keys(this.hubs).length > 0)
|
|
575
|
+
this.emit("hubs", this.hubs);
|
|
576
|
+
}
|
|
577
|
+
else {
|
|
578
|
+
this.log.info("No stations found.");
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
async refreshDeviceData() {
|
|
582
|
+
//Get Devices
|
|
583
|
+
const devices = await this.getDeviceList();
|
|
584
|
+
if (devices && devices.length > 0) {
|
|
585
|
+
devices.forEach(element => {
|
|
586
|
+
this.devices[element.device_sn] = element;
|
|
587
|
+
});
|
|
588
|
+
if (Object.keys(this.devices).length > 0)
|
|
589
|
+
this.emit("devices", this.devices);
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
this.log.info("No devices found.");
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
async refreshAllData() {
|
|
596
|
+
//Get the latest info
|
|
597
|
+
//Get Houses
|
|
598
|
+
await this.refreshHouseData();
|
|
599
|
+
//Get Stations
|
|
600
|
+
await this.refreshStationData();
|
|
601
|
+
//Get Devices
|
|
602
|
+
await this.refreshDeviceData();
|
|
603
|
+
}
|
|
604
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
605
|
+
async request(request) {
|
|
606
|
+
this.log.debug("Request:", { method: request.method, endpoint: request.endpoint, token: this.token, data: request.data });
|
|
607
|
+
try {
|
|
608
|
+
const internalResponse = await this.requestEufyCloud(request.endpoint, {
|
|
609
|
+
method: request.method,
|
|
610
|
+
json: request.data,
|
|
611
|
+
});
|
|
612
|
+
const response = {
|
|
613
|
+
status: internalResponse.statusCode,
|
|
614
|
+
statusText: internalResponse.statusMessage ? internalResponse.statusMessage : "",
|
|
615
|
+
headers: internalResponse.headers,
|
|
616
|
+
data: internalResponse.body,
|
|
617
|
+
};
|
|
618
|
+
this.log.debug("Response:", { token: this.token, request: request, response: response.data });
|
|
619
|
+
return response;
|
|
620
|
+
}
|
|
621
|
+
catch (error) {
|
|
622
|
+
if (error instanceof got_1.HTTPError) {
|
|
623
|
+
if (error.response.statusCode === 401) {
|
|
624
|
+
this.invalidateToken();
|
|
625
|
+
this.log.error("Status return code 401, invalidate token", { status: error.response.statusCode, statusText: error.response.statusMessage });
|
|
626
|
+
this.connected = false;
|
|
627
|
+
this.emit("close");
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
throw error;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
async checkPushToken() {
|
|
634
|
+
//Check push notification token
|
|
635
|
+
if (this.connected) {
|
|
636
|
+
try {
|
|
637
|
+
const response = await this.request({
|
|
638
|
+
method: "post",
|
|
639
|
+
endpoint: "v1/app/review/app_push_check",
|
|
640
|
+
data: {
|
|
641
|
+
app_type: "eufySecurity",
|
|
642
|
+
transaction: `${new Date().getTime()}`
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
if (response.status == 200) {
|
|
646
|
+
const result = response.data;
|
|
647
|
+
if (result.code == 0) {
|
|
648
|
+
this.log.debug(`Push token OK`);
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
catch (error) {
|
|
660
|
+
this.log.error("Generic Error:", error);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
async registerPushToken(token) {
|
|
666
|
+
//Register push notification token
|
|
667
|
+
if (this.connected) {
|
|
668
|
+
try {
|
|
669
|
+
const response = await this.request({
|
|
670
|
+
method: "post",
|
|
671
|
+
endpoint: "v1/apppush/register_push_token",
|
|
672
|
+
data: {
|
|
673
|
+
is_notification_enable: true,
|
|
674
|
+
token: token,
|
|
675
|
+
transaction: `${new Date().getTime().toString()}`
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
if (response.status == 200) {
|
|
679
|
+
const result = response.data;
|
|
680
|
+
if (result.code == 0) {
|
|
681
|
+
this.log.debug(`Push token registered successfully`);
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
catch (error) {
|
|
693
|
+
this.log.error("Generic Error:", error);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
async setParameters(stationSN, deviceSN, params) {
|
|
699
|
+
if (this.connected) {
|
|
700
|
+
const tmp_params = [];
|
|
701
|
+
params.forEach(param => {
|
|
702
|
+
tmp_params.push({ param_type: param.paramType, param_value: parameter_1.ParameterHelper.writeValue(param.paramType, param.paramValue) });
|
|
703
|
+
});
|
|
704
|
+
try {
|
|
705
|
+
const response = await this.request({
|
|
706
|
+
method: "post",
|
|
707
|
+
endpoint: "v1/app/upload_devs_params",
|
|
708
|
+
data: {
|
|
709
|
+
device_sn: deviceSN,
|
|
710
|
+
station_sn: stationSN,
|
|
711
|
+
params: tmp_params
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
this.log.debug("Response:", { stationSN: stationSN, deviceSN: deviceSN, params: tmp_params, response: response.data });
|
|
715
|
+
if (response.status == 200) {
|
|
716
|
+
const result = response.data;
|
|
717
|
+
if (result.code == 0) {
|
|
718
|
+
const dataresult = result.data;
|
|
719
|
+
this.log.debug("New parameters set", { params: tmp_params, response: dataresult });
|
|
720
|
+
return true;
|
|
721
|
+
}
|
|
722
|
+
else {
|
|
723
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
catch (error) {
|
|
731
|
+
this.log.error("Generic Error:", error);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
async getCiphers(cipherIDs, userID) {
|
|
737
|
+
if (this.connected) {
|
|
738
|
+
try {
|
|
739
|
+
const response = await this.request({
|
|
740
|
+
method: "post",
|
|
741
|
+
endpoint: "v1/app/cipher/get_ciphers",
|
|
742
|
+
data: {
|
|
743
|
+
cipher_ids: cipherIDs,
|
|
744
|
+
user_id: userID,
|
|
745
|
+
transaction: `${new Date().getTime().toString()}`
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
if (response.status == 200) {
|
|
749
|
+
const result = response.data;
|
|
750
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
751
|
+
if (result.data) {
|
|
752
|
+
const ciphers = {};
|
|
753
|
+
result.data.forEach((cipher) => {
|
|
754
|
+
ciphers[cipher.cipher_id] = cipher;
|
|
755
|
+
});
|
|
756
|
+
return ciphers;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
catch (error) {
|
|
768
|
+
this.log.error("Generic Error:", error);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return {};
|
|
772
|
+
}
|
|
773
|
+
async getVoices(deviceSN) {
|
|
774
|
+
if (this.connected) {
|
|
775
|
+
try {
|
|
776
|
+
const response = await this.request({
|
|
777
|
+
method: "get",
|
|
778
|
+
endpoint: `v1/voice/response/lists/${deviceSN}`
|
|
779
|
+
});
|
|
780
|
+
if (response.status == 200) {
|
|
781
|
+
const result = response.data;
|
|
782
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
783
|
+
if (result.data) {
|
|
784
|
+
const voices = {};
|
|
785
|
+
result.data.forEach((voice) => {
|
|
786
|
+
voices[voice.voice_id] = voice;
|
|
787
|
+
});
|
|
788
|
+
return voices;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
else {
|
|
792
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
catch (error) {
|
|
800
|
+
this.log.error("Generic Error:", error);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return {};
|
|
804
|
+
}
|
|
805
|
+
async getCipher(cipherID, userID) {
|
|
806
|
+
return (await this.getCiphers([cipherID], userID))[cipherID];
|
|
807
|
+
}
|
|
808
|
+
getLog() {
|
|
809
|
+
return this.log;
|
|
810
|
+
}
|
|
811
|
+
getDevices() {
|
|
812
|
+
return this.devices;
|
|
813
|
+
}
|
|
814
|
+
getHubs() {
|
|
815
|
+
return this.hubs;
|
|
816
|
+
}
|
|
817
|
+
getToken() {
|
|
818
|
+
return this.token;
|
|
819
|
+
}
|
|
820
|
+
getTokenExpiration() {
|
|
821
|
+
return this.tokenExpiration;
|
|
822
|
+
}
|
|
823
|
+
setToken(token) {
|
|
824
|
+
this.token = token;
|
|
825
|
+
this.requestEufyCloud.defaults.options.headers["X-Auth-Token"] = token;
|
|
826
|
+
}
|
|
827
|
+
setTokenExpiration(tokenExpiration) {
|
|
828
|
+
this.tokenExpiration = tokenExpiration;
|
|
829
|
+
}
|
|
830
|
+
getAPIBase() {
|
|
831
|
+
return this.requestEufyCloud.defaults.options.prefixUrl;
|
|
832
|
+
}
|
|
833
|
+
setOpenUDID(openudid) {
|
|
834
|
+
this.headers.openudid = openudid;
|
|
835
|
+
this.requestEufyCloud.defaults.options.headers = this.headers;
|
|
836
|
+
}
|
|
837
|
+
setSerialNumber(serialnumber) {
|
|
838
|
+
this.headers.sn = serialnumber;
|
|
839
|
+
this.requestEufyCloud.defaults.options.headers = this.headers;
|
|
840
|
+
}
|
|
841
|
+
async _getEvents(functionName, endpoint, startTime, endTime, filter, maxResults) {
|
|
842
|
+
const records = [];
|
|
843
|
+
if (this.connected) {
|
|
844
|
+
try {
|
|
845
|
+
if (filter === undefined)
|
|
846
|
+
filter = { deviceSN: "", stationSN: "", storageType: types_1.StorageType.NONE };
|
|
847
|
+
if (maxResults === undefined)
|
|
848
|
+
maxResults = 1000;
|
|
849
|
+
const response = await this.request({
|
|
850
|
+
method: "post",
|
|
851
|
+
endpoint: endpoint,
|
|
852
|
+
data: {
|
|
853
|
+
device_sn: filter.deviceSN !== undefined ? filter.deviceSN : "",
|
|
854
|
+
end_time: Math.trunc(endTime.getTime() / 1000),
|
|
855
|
+
exclude_guest: false,
|
|
856
|
+
house_id: "HOUSEID_ALL_DEVICE",
|
|
857
|
+
id: 0,
|
|
858
|
+
id_type: 1,
|
|
859
|
+
is_favorite: false,
|
|
860
|
+
num: maxResults,
|
|
861
|
+
pullup: true,
|
|
862
|
+
shared: true,
|
|
863
|
+
start_time: Math.trunc(startTime.getTime() / 1000),
|
|
864
|
+
station_sn: filter.stationSN !== undefined ? filter.stationSN : "",
|
|
865
|
+
storage: filter.storageType !== undefined ? filter.storageType : types_1.StorageType.NONE,
|
|
866
|
+
transaction: `${new Date().getTime().toString()}`
|
|
867
|
+
}
|
|
868
|
+
});
|
|
869
|
+
this.log.debug(`${functionName} - Response:`, response.data);
|
|
870
|
+
if (response.status == 200) {
|
|
871
|
+
const result = response.data;
|
|
872
|
+
if (result.code == 0) {
|
|
873
|
+
if (result.data) {
|
|
874
|
+
const dataresult = this.decryptAPIData(result.data);
|
|
875
|
+
if (dataresult) {
|
|
876
|
+
dataresult.forEach(record => {
|
|
877
|
+
this.log.debug(`${functionName} - Record:`, record);
|
|
878
|
+
records.push(record);
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
this.log.error("Response data is missing", { code: result.code, msg: result.msg, data: result.data });
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
this.log.error(`${functionName} - Response code not ok`, { code: result.code, msg: result.msg });
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
else {
|
|
891
|
+
this.log.error(`${functionName} - Status return code not 200`, { status: response.status, statusText: response.statusText });
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
catch (error) {
|
|
895
|
+
this.log.error(`${functionName} - Generic Error:`, error);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return records;
|
|
899
|
+
}
|
|
900
|
+
async getVideoEvents(startTime, endTime, filter, maxResults) {
|
|
901
|
+
return this._getEvents("getVideoEvents", "v2/event/app/get_all_video_record", startTime, endTime, filter, maxResults);
|
|
902
|
+
}
|
|
903
|
+
async getAlarmEvents(startTime, endTime, filter, maxResults) {
|
|
904
|
+
return this._getEvents("getAlarmEvents", "v2/event/app/get_all_alarm_record", startTime, endTime, filter, maxResults);
|
|
905
|
+
}
|
|
906
|
+
async getHistoryEvents(startTime, endTime, filter, maxResults) {
|
|
907
|
+
return this._getEvents("getHistoryEvents", "v2/event/app/get_all_history_record", startTime, endTime, filter, maxResults);
|
|
908
|
+
}
|
|
909
|
+
async getAllVideoEvents(filter, maxResults) {
|
|
910
|
+
const fifteenYearsInMilliseconds = 15 * 365 * 24 * 60 * 60 * 1000;
|
|
911
|
+
return this.getVideoEvents(new Date(new Date().getTime() - fifteenYearsInMilliseconds), new Date(), filter, maxResults);
|
|
912
|
+
}
|
|
913
|
+
async getAllAlarmEvents(filter, maxResults) {
|
|
914
|
+
const fifteenYearsInMilliseconds = 15 * 365 * 24 * 60 * 60 * 1000;
|
|
915
|
+
return this.getAlarmEvents(new Date(new Date().getTime() - fifteenYearsInMilliseconds), new Date(), filter, maxResults);
|
|
916
|
+
}
|
|
917
|
+
async getAllHistoryEvents(filter, maxResults) {
|
|
918
|
+
const fifteenYearsInMilliseconds = 15 * 365 * 24 * 60 * 60 * 1000;
|
|
919
|
+
return this.getHistoryEvents(new Date(new Date().getTime() - fifteenYearsInMilliseconds), new Date(), filter, maxResults);
|
|
920
|
+
}
|
|
921
|
+
isConnected() {
|
|
922
|
+
return this.connected;
|
|
923
|
+
}
|
|
924
|
+
async getInvites() {
|
|
925
|
+
if (this.connected) {
|
|
926
|
+
try {
|
|
927
|
+
const response = await this.request({
|
|
928
|
+
method: "post",
|
|
929
|
+
endpoint: "v1/family/get_invites",
|
|
930
|
+
data: {
|
|
931
|
+
num: 100,
|
|
932
|
+
orderby: "",
|
|
933
|
+
own: false,
|
|
934
|
+
page: 0,
|
|
935
|
+
transaction: `${new Date().getTime().toString()}`
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
if (response.status == 200) {
|
|
939
|
+
const result = response.data;
|
|
940
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
941
|
+
if (result.data) {
|
|
942
|
+
const invites = {};
|
|
943
|
+
result.data.forEach((invite) => {
|
|
944
|
+
invites[invite.invite_id] = invite;
|
|
945
|
+
let data = (0, utils_2.parseJSON)(invites[invite.invite_id].devices, this.log);
|
|
946
|
+
if (data === undefined)
|
|
947
|
+
data = [];
|
|
948
|
+
invites[invite.invite_id].devices = data;
|
|
949
|
+
});
|
|
950
|
+
return invites;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
catch (error) {
|
|
962
|
+
this.log.error("Generic Error:", error);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return {};
|
|
966
|
+
}
|
|
967
|
+
async confirmInvites(confirmInvites) {
|
|
968
|
+
if (this.connected) {
|
|
969
|
+
try {
|
|
970
|
+
const response = await this.request({
|
|
971
|
+
method: "post",
|
|
972
|
+
endpoint: "v1/family/confirm_invite",
|
|
973
|
+
data: {
|
|
974
|
+
invites: confirmInvites,
|
|
975
|
+
transaction: `${new Date().getTime().toString()}`
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
if (response.status == 200) {
|
|
979
|
+
const result = response.data;
|
|
980
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
981
|
+
return true;
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
catch (error) {
|
|
992
|
+
this.log.error("Generic Error:", error);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
async getPublicKey(deviceSN, type) {
|
|
998
|
+
if (this.connected) {
|
|
999
|
+
try {
|
|
1000
|
+
if (this.persistentData.device_public_keys[deviceSN] !== undefined && type === types_1.PublicKeyType.LOCK) {
|
|
1001
|
+
this.log.debug("return cached public key", this.persistentData.device_public_keys[deviceSN]);
|
|
1002
|
+
return this.persistentData.device_public_keys[deviceSN];
|
|
1003
|
+
}
|
|
1004
|
+
else {
|
|
1005
|
+
const response = await this.request({
|
|
1006
|
+
method: "get",
|
|
1007
|
+
endpoint: `v1/app/public_key/query?device_sn=${deviceSN}&type=${type}`
|
|
1008
|
+
});
|
|
1009
|
+
if (response.status == 200) {
|
|
1010
|
+
const result = response.data;
|
|
1011
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1012
|
+
if (result.data) {
|
|
1013
|
+
if (type === types_1.PublicKeyType.LOCK)
|
|
1014
|
+
this.persistentData.device_public_keys[deviceSN] = result.data.public_key;
|
|
1015
|
+
return result.data.public_key;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
else {
|
|
1023
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
catch (error) {
|
|
1028
|
+
this.log.error("Generic Error:", error);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return "";
|
|
1032
|
+
}
|
|
1033
|
+
decryptAPIData(data, json = true) {
|
|
1034
|
+
if (data) {
|
|
1035
|
+
let decryptedData;
|
|
1036
|
+
try {
|
|
1037
|
+
decryptedData = (0, utils_1.decryptAPIData)(data, this.ecdh.computeSecret(Buffer.from(this.persistentData.serverPublicKey, "hex")));
|
|
1038
|
+
}
|
|
1039
|
+
catch (error) {
|
|
1040
|
+
this.log.error("Data decryption error, invalidating session data and reconnecting...", error);
|
|
1041
|
+
this.persistentData.serverPublicKey = this.SERVER_PUBLIC_KEY;
|
|
1042
|
+
this.invalidateToken();
|
|
1043
|
+
this.emit("close");
|
|
1044
|
+
}
|
|
1045
|
+
if (decryptedData) {
|
|
1046
|
+
if (json)
|
|
1047
|
+
return (0, utils_2.parseJSON)(decryptedData.toString("utf-8"), this.log);
|
|
1048
|
+
return decryptedData.toString();
|
|
1049
|
+
}
|
|
1050
|
+
if (json)
|
|
1051
|
+
return {};
|
|
1052
|
+
}
|
|
1053
|
+
return undefined;
|
|
1054
|
+
}
|
|
1055
|
+
async getSensorHistory(stationSN, deviceSN) {
|
|
1056
|
+
if (this.connected) {
|
|
1057
|
+
try {
|
|
1058
|
+
const response = await this.request({
|
|
1059
|
+
method: "post",
|
|
1060
|
+
endpoint: "v1/app/get_sensor_history",
|
|
1061
|
+
data: {
|
|
1062
|
+
devicse_sn: deviceSN,
|
|
1063
|
+
max_time: 0,
|
|
1064
|
+
num: 500,
|
|
1065
|
+
page: 0,
|
|
1066
|
+
station_sn: stationSN,
|
|
1067
|
+
transaction: `${new Date().getTime().toString()}`
|
|
1068
|
+
}
|
|
1069
|
+
});
|
|
1070
|
+
if (response.status == 200) {
|
|
1071
|
+
const result = response.data;
|
|
1072
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1073
|
+
if (result.data) {
|
|
1074
|
+
const entries = result.data;
|
|
1075
|
+
return entries;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
else {
|
|
1079
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
else {
|
|
1083
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
catch (error) {
|
|
1087
|
+
this.log.error("Generic Error:", error);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
return [];
|
|
1091
|
+
}
|
|
1092
|
+
async getHouseDetail(houseID) {
|
|
1093
|
+
if (this.connected) {
|
|
1094
|
+
try {
|
|
1095
|
+
const response = await this.request({
|
|
1096
|
+
method: "post",
|
|
1097
|
+
endpoint: "v2/house/detail",
|
|
1098
|
+
data: {
|
|
1099
|
+
house_id: houseID,
|
|
1100
|
+
transaction: `${new Date().getTime().toString()}`
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
if (response.status == 200) {
|
|
1104
|
+
const result = response.data;
|
|
1105
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1106
|
+
if (result.data) {
|
|
1107
|
+
const houseDetail = this.decryptAPIData(result.data);
|
|
1108
|
+
this.log.debug("Decrypted house detail data", houseDetail);
|
|
1109
|
+
return houseDetail;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
else {
|
|
1113
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
catch (error) {
|
|
1121
|
+
this.log.error("Generic Error:", error);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
return null;
|
|
1125
|
+
}
|
|
1126
|
+
async getHouseList() {
|
|
1127
|
+
if (this.connected) {
|
|
1128
|
+
try {
|
|
1129
|
+
const response = await this.request({
|
|
1130
|
+
method: "post",
|
|
1131
|
+
endpoint: "v1/house/list",
|
|
1132
|
+
data: {
|
|
1133
|
+
transaction: `${new Date().getTime().toString()}`
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
if (response.status == 200) {
|
|
1137
|
+
const result = response.data;
|
|
1138
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1139
|
+
if (result.data) {
|
|
1140
|
+
return result.data;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
else {
|
|
1144
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
else {
|
|
1148
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
catch (error) {
|
|
1152
|
+
this.log.error("Generic Error:", error);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return [];
|
|
1156
|
+
}
|
|
1157
|
+
async getHouseInviteList(isInviter = 1) {
|
|
1158
|
+
//TODO: Understand the other values of isInviter and document it
|
|
1159
|
+
if (this.connected) {
|
|
1160
|
+
try {
|
|
1161
|
+
const response = await this.request({
|
|
1162
|
+
method: "post",
|
|
1163
|
+
endpoint: "v1/house/invite_list",
|
|
1164
|
+
data: {
|
|
1165
|
+
is_inviter: isInviter,
|
|
1166
|
+
transaction: `${new Date().getTime().toString()}`
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
if (response.status == 200) {
|
|
1170
|
+
const result = response.data;
|
|
1171
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1172
|
+
if (result.data) {
|
|
1173
|
+
const houseInviteList = this.decryptAPIData(result.data);
|
|
1174
|
+
this.log.debug("Decrypted house invite list data", houseInviteList);
|
|
1175
|
+
return houseInviteList;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
else {
|
|
1179
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
catch (error) {
|
|
1187
|
+
this.log.error("Generic Error:", error);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return [];
|
|
1191
|
+
}
|
|
1192
|
+
async confirmHouseInvite(houseID, inviteID) {
|
|
1193
|
+
if (this.connected) {
|
|
1194
|
+
try {
|
|
1195
|
+
const response = await this.request({
|
|
1196
|
+
method: "post",
|
|
1197
|
+
endpoint: "v1/house/confirm_invite",
|
|
1198
|
+
data: {
|
|
1199
|
+
house_id: houseID,
|
|
1200
|
+
invite_id: inviteID,
|
|
1201
|
+
is_inviter: 1,
|
|
1202
|
+
//user_id: "",
|
|
1203
|
+
transaction: `${new Date().getTime().toString()}`
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
if (response.status == 200) {
|
|
1207
|
+
const result = response.data;
|
|
1208
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1209
|
+
return true;
|
|
1210
|
+
}
|
|
1211
|
+
else {
|
|
1212
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
else {
|
|
1216
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
catch (error) {
|
|
1220
|
+
this.log.error("Generic Error:", error);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
return false;
|
|
1224
|
+
}
|
|
1225
|
+
getPersistentData() {
|
|
1226
|
+
return this.persistentData;
|
|
1227
|
+
}
|
|
1228
|
+
async getPassportProfile() {
|
|
1229
|
+
try {
|
|
1230
|
+
const response = await this.request({
|
|
1231
|
+
method: "get",
|
|
1232
|
+
endpoint: "v2/passport/profile"
|
|
1233
|
+
});
|
|
1234
|
+
if (response.status == 200) {
|
|
1235
|
+
const result = response.data;
|
|
1236
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1237
|
+
if (result.data) {
|
|
1238
|
+
const profile = this.decryptAPIData(result.data);
|
|
1239
|
+
this.log.debug("Decrypted passport profile data", profile);
|
|
1240
|
+
this.persistentData.user_id = profile.user_id;
|
|
1241
|
+
this.persistentData.nick_name = profile.nick_name;
|
|
1242
|
+
this.persistentData.email = profile.email;
|
|
1243
|
+
return profile;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
else {
|
|
1247
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
else {
|
|
1251
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
catch (error) {
|
|
1255
|
+
this.log.error("Generic Error:", error);
|
|
1256
|
+
}
|
|
1257
|
+
return null;
|
|
1258
|
+
}
|
|
1259
|
+
async addUser(deviceSN, nickname, stationSN = "") {
|
|
1260
|
+
if (this.connected) {
|
|
1261
|
+
try {
|
|
1262
|
+
const response = await this.request({
|
|
1263
|
+
method: "post",
|
|
1264
|
+
endpoint: "v1/app/device/local_user/add",
|
|
1265
|
+
data: {
|
|
1266
|
+
device_sn: deviceSN,
|
|
1267
|
+
nick_name: nickname,
|
|
1268
|
+
station_sn: stationSN === deviceSN ? "" : stationSN,
|
|
1269
|
+
transaction: `${new Date().getTime().toString()}`
|
|
1270
|
+
}
|
|
1271
|
+
});
|
|
1272
|
+
if (response.status == 200) {
|
|
1273
|
+
const result = response.data;
|
|
1274
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1275
|
+
if (result.data)
|
|
1276
|
+
return result.data;
|
|
1277
|
+
}
|
|
1278
|
+
else {
|
|
1279
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
else {
|
|
1283
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
catch (error) {
|
|
1287
|
+
this.log.error("Generic Error:", error);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
return null;
|
|
1291
|
+
}
|
|
1292
|
+
async deleteUser(deviceSN, shortUserId, stationSN = "") {
|
|
1293
|
+
if (this.connected) {
|
|
1294
|
+
try {
|
|
1295
|
+
const response = await this.request({
|
|
1296
|
+
method: "post",
|
|
1297
|
+
endpoint: "v1/app/device/user/delete",
|
|
1298
|
+
data: {
|
|
1299
|
+
device_sn: deviceSN,
|
|
1300
|
+
short_user_ids: [shortUserId],
|
|
1301
|
+
station_sn: stationSN === deviceSN ? "" : stationSN,
|
|
1302
|
+
transaction: `${new Date().getTime().toString()}`
|
|
1303
|
+
}
|
|
1304
|
+
});
|
|
1305
|
+
if (response.status == 200) {
|
|
1306
|
+
const result = response.data;
|
|
1307
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1308
|
+
return true;
|
|
1309
|
+
}
|
|
1310
|
+
else {
|
|
1311
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
else {
|
|
1315
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
catch (error) {
|
|
1319
|
+
this.log.error("Generic Error:", error);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
return false;
|
|
1323
|
+
}
|
|
1324
|
+
async getUsers(deviceSN, stationSN) {
|
|
1325
|
+
try {
|
|
1326
|
+
const response = await this.request({
|
|
1327
|
+
method: "get",
|
|
1328
|
+
endpoint: `v1/app/device/user/list?device_sn=${deviceSN}&station_sn=${stationSN}`
|
|
1329
|
+
});
|
|
1330
|
+
if (response.status == 200) {
|
|
1331
|
+
const result = response.data;
|
|
1332
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1333
|
+
if (result.data) {
|
|
1334
|
+
const usersResponse = result.data;
|
|
1335
|
+
return usersResponse.user_list;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
else {
|
|
1339
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
else {
|
|
1343
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
catch (error) {
|
|
1347
|
+
this.log.error("Generic Error:", error);
|
|
1348
|
+
}
|
|
1349
|
+
return null;
|
|
1350
|
+
}
|
|
1351
|
+
async getUser(deviceSN, stationSN, shortUserId) {
|
|
1352
|
+
try {
|
|
1353
|
+
const users = await this.getUsers(deviceSN, stationSN);
|
|
1354
|
+
if (users !== null) {
|
|
1355
|
+
for (const user of users) {
|
|
1356
|
+
if (user.short_user_id === shortUserId) {
|
|
1357
|
+
return user;
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
catch (error) {
|
|
1363
|
+
this.log.error("Generic Error:", error);
|
|
1364
|
+
}
|
|
1365
|
+
return null;
|
|
1366
|
+
}
|
|
1367
|
+
async updateUser(deviceSN, stationSN, shortUserId, nickname) {
|
|
1368
|
+
if (this.connected) {
|
|
1369
|
+
try {
|
|
1370
|
+
const user = await this.getUser(deviceSN, stationSN, shortUserId);
|
|
1371
|
+
if (user !== null) {
|
|
1372
|
+
const response = await this.request({
|
|
1373
|
+
method: "post",
|
|
1374
|
+
endpoint: "v1/app/device/local_user/update",
|
|
1375
|
+
data: {
|
|
1376
|
+
device_sn: deviceSN,
|
|
1377
|
+
nick_name: nickname,
|
|
1378
|
+
password_list: user.password_list,
|
|
1379
|
+
short_user_id: shortUserId,
|
|
1380
|
+
station_sn: stationSN === deviceSN ? "" : stationSN,
|
|
1381
|
+
user_type: user.user_type,
|
|
1382
|
+
transaction: `${new Date().getTime().toString()}`
|
|
1383
|
+
}
|
|
1384
|
+
});
|
|
1385
|
+
if (response.status == 200) {
|
|
1386
|
+
const result = response.data;
|
|
1387
|
+
if (result.code == types_1.ResponseErrorCode.CODE_WHATEVER_ERROR) {
|
|
1388
|
+
return true;
|
|
1389
|
+
}
|
|
1390
|
+
else {
|
|
1391
|
+
this.log.error("Response code not ok", { code: result.code, msg: result.msg });
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
else {
|
|
1395
|
+
this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText });
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
catch (error) {
|
|
1400
|
+
this.log.error("Generic Error:", error);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
return false;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
HTTPApi.apiDomainBase = "https://extend.eufylife.com";
|
|
1407
|
+
exports.HTTPApi = HTTPApi;
|
|
1408
1408
|
//# sourceMappingURL=api.js.map
|