@mega-yfue/eufy-sdk 0.4.0-beta.10 → 0.4.0-beta.12
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/dist/index.js
CHANGED
|
@@ -1070,6 +1070,401 @@ function normalizePushImage(data, p2pDid) {
|
|
|
1070
1070
|
return decodeImageV1(data, p2pDid) ?? data;
|
|
1071
1071
|
}
|
|
1072
1072
|
|
|
1073
|
+
// dist/core/types.js
|
|
1074
|
+
var PRINTER_CATEGORY_RE = /ankermake|eufymake|fdm|3d_?print/i;
|
|
1075
|
+
function classifyDevice(raw) {
|
|
1076
|
+
const category = raw.category ?? "";
|
|
1077
|
+
const hasP2p = typeof raw.p2p_did === "string" && raw.p2p_did.length > 0;
|
|
1078
|
+
if (category === "eufy_security" || hasP2p)
|
|
1079
|
+
return { category, api: "mega", realtime: "p2p" };
|
|
1080
|
+
if (PRINTER_CATEGORY_RE.test(category))
|
|
1081
|
+
return { category, api: "ankermake", realtime: "ankermake-mqtt" };
|
|
1082
|
+
return { category, api: "mega", realtime: "smqtt" };
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// dist/core/contracts.js
|
|
1086
|
+
var StoredSnapshotUnavailableError = class extends Error {
|
|
1087
|
+
reason;
|
|
1088
|
+
constructor(reason, message, options) {
|
|
1089
|
+
super(message, options);
|
|
1090
|
+
this.reason = reason;
|
|
1091
|
+
this.name = "StoredSnapshotUnavailableError";
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
var RETRYABLE_LIVE_SNAPSHOT_REASONS = [
|
|
1095
|
+
"no-keyframe",
|
|
1096
|
+
"source-failed",
|
|
1097
|
+
"undecodable-burst"
|
|
1098
|
+
];
|
|
1099
|
+
var LiveSnapshotUnavailableError = class extends Error {
|
|
1100
|
+
reason;
|
|
1101
|
+
/** Whether another attempt could plausibly succeed without the host changing anything. */
|
|
1102
|
+
retryable;
|
|
1103
|
+
constructor(reason, message, options) {
|
|
1104
|
+
super(message, options);
|
|
1105
|
+
this.reason = reason;
|
|
1106
|
+
this.name = "LiveSnapshotUnavailableError";
|
|
1107
|
+
this.retryable = RETRYABLE_LIVE_SNAPSHOT_REASONS.includes(reason);
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
var CameraDisabledError = class extends Error {
|
|
1111
|
+
camera;
|
|
1112
|
+
constructor(camera, options) {
|
|
1113
|
+
super(`camera${camera ? ` ${camera}` : ""} is disabled \u2014 no live stream possible`, options);
|
|
1114
|
+
this.camera = camera;
|
|
1115
|
+
this.name = "CameraDisabledError";
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
var StationKeyUnavailableError = class extends Error {
|
|
1119
|
+
stationSn;
|
|
1120
|
+
/** Always true: the negotiation is per connection, so a later one may still produce a key. */
|
|
1121
|
+
retryable = true;
|
|
1122
|
+
constructor(stationSn, options) {
|
|
1123
|
+
super(`station ${stationSn} did not provide its session key, so nothing that requires one could be sent`, options);
|
|
1124
|
+
this.stationSn = stationSn;
|
|
1125
|
+
this.name = "StationKeyUnavailableError";
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
var StationUnreachableError = class extends Error {
|
|
1129
|
+
stationSn;
|
|
1130
|
+
waitedMs;
|
|
1131
|
+
/** Always true: a station unreachable now may answer on a later attempt. */
|
|
1132
|
+
retryable = true;
|
|
1133
|
+
constructor(stationSn, waitedMs, options) {
|
|
1134
|
+
super(`station ${stationSn}'s P2P session did not connect within ${waitedMs}ms, so nothing could be sent to it`, options);
|
|
1135
|
+
this.stationSn = stationSn;
|
|
1136
|
+
this.waitedMs = waitedMs;
|
|
1137
|
+
this.name = "StationUnreachableError";
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
var DeviceChannelUnresolvedError = class extends Error {
|
|
1141
|
+
sn;
|
|
1142
|
+
stationSn;
|
|
1143
|
+
constructor(sn, stationSn, options) {
|
|
1144
|
+
super(`${sn} has no usable channel on station ${stationSn}, so nothing was sent to it`, options);
|
|
1145
|
+
this.sn = sn;
|
|
1146
|
+
this.stationSn = stationSn;
|
|
1147
|
+
this.name = "DeviceChannelUnresolvedError";
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
var LiveStreamStartError = class extends Error {
|
|
1151
|
+
reason;
|
|
1152
|
+
stage;
|
|
1153
|
+
timeoutMs;
|
|
1154
|
+
attempts;
|
|
1155
|
+
constructor(failure) {
|
|
1156
|
+
super(`live stream failed to start (${failure.reason} at ${failure.stage} after ${failure.attempts} attempts; ${failure.timeoutMs}ms deadline)`, failure.cause === void 0 ? void 0 : { cause: failure.cause });
|
|
1157
|
+
this.name = "LiveStreamStartError";
|
|
1158
|
+
this.reason = failure.reason;
|
|
1159
|
+
this.stage = failure.stage;
|
|
1160
|
+
this.timeoutMs = failure.timeoutMs;
|
|
1161
|
+
this.attempts = failure.attempts;
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
var StateConvergenceError = class extends Error {
|
|
1165
|
+
sn;
|
|
1166
|
+
property;
|
|
1167
|
+
param;
|
|
1168
|
+
expected;
|
|
1169
|
+
observed;
|
|
1170
|
+
timeoutMs;
|
|
1171
|
+
constructor(failure) {
|
|
1172
|
+
super(`device ${failure.sn} did not report ${failure.property} as ${String(failure.expected)} within ${failure.timeoutMs}ms (param ${failure.param} read ${String(failure.observed)})`);
|
|
1173
|
+
this.name = "StateConvergenceError";
|
|
1174
|
+
this.sn = failure.sn;
|
|
1175
|
+
this.property = failure.property;
|
|
1176
|
+
this.param = failure.param;
|
|
1177
|
+
this.expected = failure.expected;
|
|
1178
|
+
this.observed = failure.observed;
|
|
1179
|
+
this.timeoutMs = failure.timeoutMs;
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1182
|
+
var COMMAND_OBSERVATION = /* @__PURE__ */ Symbol("command-observation");
|
|
1183
|
+
function observeCommand(command, observation) {
|
|
1184
|
+
return Object.defineProperty(command, COMMAND_OBSERVATION, { configurable: true, value: observation });
|
|
1185
|
+
}
|
|
1186
|
+
function commandObservation(command) {
|
|
1187
|
+
return command[COMMAND_OBSERVATION];
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// dist/core/raw-dp-writer.js
|
|
1191
|
+
var WIRE = { VARINT: 0, LENGTH_DELIMITED: 2 };
|
|
1192
|
+
function encodeVarint(value) {
|
|
1193
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
1194
|
+
throw new Error(`varint: ${value} is not a non-negative safe integer`);
|
|
1195
|
+
}
|
|
1196
|
+
const out = [];
|
|
1197
|
+
let v = value;
|
|
1198
|
+
while (v > 127) {
|
|
1199
|
+
out.push(v % 128 + 128);
|
|
1200
|
+
v = Math.floor(v / 128);
|
|
1201
|
+
}
|
|
1202
|
+
out.push(v);
|
|
1203
|
+
return out;
|
|
1204
|
+
}
|
|
1205
|
+
function zigzag(value) {
|
|
1206
|
+
if (!Number.isSafeInteger(value))
|
|
1207
|
+
throw new Error(`zigzag: ${value} is not a safe integer`);
|
|
1208
|
+
return value < 0 ? -2 * value - 1 : 2 * value;
|
|
1209
|
+
}
|
|
1210
|
+
var RawDpWriter = class _RawDpWriter {
|
|
1211
|
+
body = [];
|
|
1212
|
+
/** A varint-valued field (`int32`, `uint32`, `bool`, an enum member). */
|
|
1213
|
+
int(field, value) {
|
|
1214
|
+
this.body.push(...encodeVarint(tag(field, WIRE.VARINT)), ...encodeVarint(value));
|
|
1215
|
+
return this;
|
|
1216
|
+
}
|
|
1217
|
+
/** A signed varint field (`sint32`, `sint64`), ZigZag-encoded — see {@link zigzag}. */
|
|
1218
|
+
sint(field, value) {
|
|
1219
|
+
return this.int(field, zigzag(value));
|
|
1220
|
+
}
|
|
1221
|
+
/** A boolean field, on protobuf's own terms: `1` or `0` in a varint. */
|
|
1222
|
+
bool(field, value) {
|
|
1223
|
+
return this.int(field, value ? 1 : 0);
|
|
1224
|
+
}
|
|
1225
|
+
/** A length-delimited field carrying raw bytes — a string, a blob, or a message built elsewhere. */
|
|
1226
|
+
bytes(field, value) {
|
|
1227
|
+
const bytes2 = value instanceof Uint8Array ? Array.from(value) : [...value];
|
|
1228
|
+
this.body.push(...encodeVarint(tag(field, WIRE.LENGTH_DELIMITED)), ...encodeVarint(bytes2.length), ...bytes2);
|
|
1229
|
+
return this;
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* A nested sub-message, built by `build` into a writer of its own.
|
|
1233
|
+
*
|
|
1234
|
+
* The sub-message is emitted even when `build` writes nothing into it. That is not an oversight: an
|
|
1235
|
+
* EMPTY sub-message is how these protocols say "this subsystem exists and is in its zero state", as
|
|
1236
|
+
* opposed to saying nothing about it, and the readers on the other side of this file depend on the
|
|
1237
|
+
* distinction. Omitting the call is what says nothing about it.
|
|
1238
|
+
*/
|
|
1239
|
+
sub(field, build) {
|
|
1240
|
+
const inner = new _RawDpWriter();
|
|
1241
|
+
build(inner);
|
|
1242
|
+
return this.bytes(field, inner.toBytes());
|
|
1243
|
+
}
|
|
1244
|
+
/** The message body on its own, unframed — for nesting into another writer. */
|
|
1245
|
+
toBytes() {
|
|
1246
|
+
return [...this.body];
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* The finished DP value: `varint(bodyLength) ++ body`, base64-encoded.
|
|
1250
|
+
*
|
|
1251
|
+
* This is the envelope `RawDpCodec.decode` unwraps, so a value produced here and read back through the
|
|
1252
|
+
* codec is a genuine round-trip rather than two implementations of the same guess.
|
|
1253
|
+
*/
|
|
1254
|
+
finish() {
|
|
1255
|
+
return Buffer.from([...encodeVarint(this.body.length), ...this.body]).toString("base64");
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
function tag(field, wire) {
|
|
1259
|
+
if (!Number.isSafeInteger(field) || field < 1)
|
|
1260
|
+
throw new Error(`field number: ${field} is not a positive integer`);
|
|
1261
|
+
return field * 8 + wire;
|
|
1262
|
+
}
|
|
1263
|
+
function rawDp(build) {
|
|
1264
|
+
const w = new RawDpWriter();
|
|
1265
|
+
build(w);
|
|
1266
|
+
return w.finish();
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
// dist/core/raw-dp-hex.js
|
|
1270
|
+
function hexToRawDp(hex) {
|
|
1271
|
+
if (hex.length === 0 || hex.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex))
|
|
1272
|
+
return void 0;
|
|
1273
|
+
return Buffer.from(hex, "hex").toString("base64");
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// dist/core/util.js
|
|
1277
|
+
var Timer = class {
|
|
1278
|
+
handle;
|
|
1279
|
+
/** (Re)arm to run `fn` after `ms`, cancelling any already-pending fire. */
|
|
1280
|
+
arm(ms, fn) {
|
|
1281
|
+
this.cancel();
|
|
1282
|
+
this.handle = setTimeout(() => {
|
|
1283
|
+
this.handle = void 0;
|
|
1284
|
+
fn();
|
|
1285
|
+
}, ms);
|
|
1286
|
+
this.handle.unref?.();
|
|
1287
|
+
}
|
|
1288
|
+
/** Cancel a pending fire. No-op if not armed. */
|
|
1289
|
+
cancel() {
|
|
1290
|
+
if (this.handle) {
|
|
1291
|
+
clearTimeout(this.handle);
|
|
1292
|
+
this.handle = void 0;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
/** Whether a fire is currently scheduled. */
|
|
1296
|
+
get pending() {
|
|
1297
|
+
return this.handle !== void 0;
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
function assertNever(value) {
|
|
1301
|
+
throw new Error(`unhandled variant: ${JSON.stringify(value)}`);
|
|
1302
|
+
}
|
|
1303
|
+
function asBool(value) {
|
|
1304
|
+
if (typeof value === "string")
|
|
1305
|
+
return value === "1" || value.toLowerCase() === "true";
|
|
1306
|
+
return value === true || value === 1;
|
|
1307
|
+
}
|
|
1308
|
+
function clamp(value, min, max) {
|
|
1309
|
+
if (Number.isNaN(value))
|
|
1310
|
+
return min;
|
|
1311
|
+
return Math.max(min, Math.min(max, Math.round(value)));
|
|
1312
|
+
}
|
|
1313
|
+
function structuralEqual(a, b) {
|
|
1314
|
+
if (Object.is(a, b))
|
|
1315
|
+
return true;
|
|
1316
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null)
|
|
1317
|
+
return false;
|
|
1318
|
+
const aArr = Array.isArray(a);
|
|
1319
|
+
const bArr = Array.isArray(b);
|
|
1320
|
+
if (aArr !== bArr)
|
|
1321
|
+
return false;
|
|
1322
|
+
if (aArr && bArr) {
|
|
1323
|
+
if (a.length !== b.length)
|
|
1324
|
+
return false;
|
|
1325
|
+
for (let i = 0; i < a.length; i++)
|
|
1326
|
+
if (!structuralEqual(a[i], b[i]))
|
|
1327
|
+
return false;
|
|
1328
|
+
return true;
|
|
1329
|
+
}
|
|
1330
|
+
const aObj = a;
|
|
1331
|
+
const bObj = b;
|
|
1332
|
+
const aKeys = Object.keys(aObj);
|
|
1333
|
+
const bKeys = Object.keys(bObj);
|
|
1334
|
+
if (aKeys.length !== bKeys.length)
|
|
1335
|
+
return false;
|
|
1336
|
+
for (const k of aKeys) {
|
|
1337
|
+
if (!Object.prototype.hasOwnProperty.call(bObj, k))
|
|
1338
|
+
return false;
|
|
1339
|
+
if (!structuralEqual(aObj[k], bObj[k]))
|
|
1340
|
+
return false;
|
|
1341
|
+
}
|
|
1342
|
+
return true;
|
|
1343
|
+
}
|
|
1344
|
+
function coerceEnumValue(enumObj, value) {
|
|
1345
|
+
const n = Number(value);
|
|
1346
|
+
return Number.isInteger(n) && Object.values(enumObj).includes(n) ? n : void 0;
|
|
1347
|
+
}
|
|
1348
|
+
function enumValues(enumObj) {
|
|
1349
|
+
return Object.values(enumObj).join("/");
|
|
1350
|
+
}
|
|
1351
|
+
function enumLabels(enumObj) {
|
|
1352
|
+
return Object.fromEntries(Object.entries(enumObj).map(([name, value]) => [value, name]));
|
|
1353
|
+
}
|
|
1354
|
+
function jsonObject(text2) {
|
|
1355
|
+
if (typeof text2 !== "string")
|
|
1356
|
+
return void 0;
|
|
1357
|
+
try {
|
|
1358
|
+
const v = JSON.parse(text2);
|
|
1359
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
1360
|
+
} catch {
|
|
1361
|
+
return void 0;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
function u16le(n) {
|
|
1365
|
+
const b = Buffer.alloc(2);
|
|
1366
|
+
b.writeUInt16LE(n & 65535);
|
|
1367
|
+
return b;
|
|
1368
|
+
}
|
|
1369
|
+
function u16be(n) {
|
|
1370
|
+
const b = Buffer.alloc(2);
|
|
1371
|
+
b.writeUInt16BE(n & 65535);
|
|
1372
|
+
return b;
|
|
1373
|
+
}
|
|
1374
|
+
function u32le(n) {
|
|
1375
|
+
const b = Buffer.alloc(4);
|
|
1376
|
+
b.writeUInt32LE(n >>> 0);
|
|
1377
|
+
return b;
|
|
1378
|
+
}
|
|
1379
|
+
function u32be(n) {
|
|
1380
|
+
const b = Buffer.alloc(4);
|
|
1381
|
+
b.writeUInt32BE(n >>> 0);
|
|
1382
|
+
return b;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
// dist/core/lz4-block.js
|
|
1386
|
+
var MAX_OUTPUT = 64 * 1024 * 1024;
|
|
1387
|
+
function lz4BlockDecompress(block, size) {
|
|
1388
|
+
if (!Number.isSafeInteger(size) || size < 0 || size > MAX_OUTPUT)
|
|
1389
|
+
return void 0;
|
|
1390
|
+
const out = Buffer.alloc(size);
|
|
1391
|
+
const end = block.length;
|
|
1392
|
+
let pos = 0;
|
|
1393
|
+
let written = 0;
|
|
1394
|
+
const extend2 = (base) => {
|
|
1395
|
+
let len = base;
|
|
1396
|
+
if (base !== 15)
|
|
1397
|
+
return len;
|
|
1398
|
+
for (; ; ) {
|
|
1399
|
+
if (pos >= end)
|
|
1400
|
+
return void 0;
|
|
1401
|
+
const extra = block[pos++];
|
|
1402
|
+
len += extra;
|
|
1403
|
+
if (extra !== 255)
|
|
1404
|
+
return len;
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
1407
|
+
while (pos < end) {
|
|
1408
|
+
const token = block[pos++];
|
|
1409
|
+
const literals = extend2(token >> 4);
|
|
1410
|
+
if (literals === void 0)
|
|
1411
|
+
return void 0;
|
|
1412
|
+
if (pos + literals > end || written + literals > size)
|
|
1413
|
+
return void 0;
|
|
1414
|
+
for (let i = 0; i < literals; i++)
|
|
1415
|
+
out[written++] = block[pos++];
|
|
1416
|
+
if (pos === end)
|
|
1417
|
+
break;
|
|
1418
|
+
if (pos + 2 > end)
|
|
1419
|
+
return void 0;
|
|
1420
|
+
const offset = block[pos] | block[pos + 1] << 8;
|
|
1421
|
+
pos += 2;
|
|
1422
|
+
if (offset === 0 || offset > written)
|
|
1423
|
+
return void 0;
|
|
1424
|
+
const match = extend2(token & 15);
|
|
1425
|
+
if (match === void 0)
|
|
1426
|
+
return void 0;
|
|
1427
|
+
const length = match + 4;
|
|
1428
|
+
if (written + length > size)
|
|
1429
|
+
return void 0;
|
|
1430
|
+
let from = written - offset;
|
|
1431
|
+
for (let i = 0; i < length; i++)
|
|
1432
|
+
out[written++] = out[from++];
|
|
1433
|
+
}
|
|
1434
|
+
return written === size ? out : void 0;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
// dist/transport/http/passport.js
|
|
1438
|
+
function loginCredentials(email, password, country) {
|
|
1439
|
+
const { clientPublicKeyHex, encryptedPassword } = encryptLoginPassword(password);
|
|
1440
|
+
return { email, password: encryptedPassword, ab: country, client_secret_info: { public_key: clientPublicKeyHex } };
|
|
1441
|
+
}
|
|
1442
|
+
function readLoginReply(data) {
|
|
1443
|
+
const userId = data.ap_cloud_user_id ?? data.user_id ?? data.userId;
|
|
1444
|
+
const authToken = data.auth_token ?? data.token;
|
|
1445
|
+
if (!userId || !authToken)
|
|
1446
|
+
return void 0;
|
|
1447
|
+
return {
|
|
1448
|
+
userId,
|
|
1449
|
+
accountUserId: data.user_id ?? data.userId,
|
|
1450
|
+
authToken,
|
|
1451
|
+
geoKey: data.geo_key,
|
|
1452
|
+
tokenExpiresAt: Number(data.token_expires_at ?? 0) || 0,
|
|
1453
|
+
twoFactorPending: !!(data.fa_info ?? {}).info
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
function signedHeaders(entry, encBody) {
|
|
1457
|
+
const ts = nowSec();
|
|
1458
|
+
const once = genId();
|
|
1459
|
+
return {
|
|
1460
|
+
"x-encryption-info": "algo_ecdh",
|
|
1461
|
+
"x-key-ident": entry.keyIdent,
|
|
1462
|
+
"x-request-ts": ts,
|
|
1463
|
+
"x-request-once": once,
|
|
1464
|
+
"x-signature": signRequest(entry.shareKey, ts, once, encBody)
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1073
1468
|
// dist/transport/http/mega-client.js
|
|
1074
1469
|
function parseMaybeJson(text2) {
|
|
1075
1470
|
if (text2.length === 0)
|
|
@@ -1437,17 +1832,11 @@ ${this.auth_?.authToken ?? ""}`;
|
|
|
1437
1832
|
const order = preferred === "text/plain" ? ["text/plain", "application/json"] : ["application/json", "text/plain"];
|
|
1438
1833
|
let last;
|
|
1439
1834
|
for (const contentType of order) {
|
|
1440
|
-
const ts = nowSec();
|
|
1441
|
-
const once = genId();
|
|
1442
1835
|
const headers = {
|
|
1443
1836
|
...this.baseHeaders(),
|
|
1444
1837
|
"content-type": contentType,
|
|
1445
|
-
|
|
1838
|
+
...signedHeaders(entry, encBody),
|
|
1446
1839
|
"x-replay-info": "replay",
|
|
1447
|
-
"x-key-ident": entry.keyIdent,
|
|
1448
|
-
"x-request-ts": ts,
|
|
1449
|
-
"x-request-once": once,
|
|
1450
|
-
"x-signature": signRequest(entry.shareKey, ts, once, encBody),
|
|
1451
1840
|
// Per-call header overrides (e.g. app-name=eufy_security to request a security-scoped
|
|
1452
1841
|
// MQTT cert on an existing eufy_mega session — see EufyMega.getUserMqttInfo).
|
|
1453
1842
|
...headerOverrides
|
|
@@ -1746,13 +2135,7 @@ ${this.auth_?.authToken ?? ""}`;
|
|
|
1746
2135
|
}
|
|
1747
2136
|
/** Build the /passport/login body (verify_code empty unless 2FA). */
|
|
1748
2137
|
loginBody(opts) {
|
|
1749
|
-
const
|
|
1750
|
-
const base = {
|
|
1751
|
-
email: this.cfg.email,
|
|
1752
|
-
password: encryptedPassword,
|
|
1753
|
-
ab: this.cfg.countryCode,
|
|
1754
|
-
client_secret_info: { public_key: clientPublicKeyHex }
|
|
1755
|
-
};
|
|
2138
|
+
const base = loginCredentials(this.cfg.email, this.cfg.password, this.cfg.countryCode);
|
|
1756
2139
|
if (opts.verifyCode)
|
|
1757
2140
|
return { ...base, verify_code: opts.verifyCode, login_id: "" };
|
|
1758
2141
|
if (opts.captchaId)
|
|
@@ -1990,15 +2373,12 @@ ${this.auth_?.authToken ?? ""}`;
|
|
|
1990
2373
|
if (cap.length)
|
|
1991
2374
|
this.logger.debug("[mega] captcha/fa:", JSON.stringify(Object.fromEntries(cap.map((k) => [k, res[k]]))));
|
|
1992
2375
|
}
|
|
1993
|
-
const
|
|
1994
|
-
|
|
1995
|
-
const authToken = res.auth_token ?? res.token;
|
|
1996
|
-
if (!userId || !authToken)
|
|
2376
|
+
const reply = readLoginReply(res);
|
|
2377
|
+
if (!reply)
|
|
1997
2378
|
throw new Error(`login returned no session: ${JSON.stringify(res).slice(0, 200)}`);
|
|
1998
|
-
const
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
this.auth_ = { userId, accountUserId, authToken, geoKey: res.geo_key };
|
|
2379
|
+
const { userId, accountUserId, authToken, geoKey } = reply;
|
|
2380
|
+
if (!isVerify && reply.twoFactorPending) {
|
|
2381
|
+
this.auth_ = { userId, accountUserId, authToken, geoKey };
|
|
2002
2382
|
this.pendingCaptchaId = void 0;
|
|
2003
2383
|
this.pending2fa = true;
|
|
2004
2384
|
await this.sendVerifyCode(messageType);
|
|
@@ -2006,8 +2386,8 @@ ${this.auth_?.authToken ?? ""}`;
|
|
|
2006
2386
|
}
|
|
2007
2387
|
this.pendingCaptchaId = void 0;
|
|
2008
2388
|
this.pending2fa = false;
|
|
2009
|
-
this.auth_ = { userId, accountUserId, authToken, geoKey
|
|
2010
|
-
this.tokenExpiresAt =
|
|
2389
|
+
this.auth_ = { userId, accountUserId, authToken, geoKey };
|
|
2390
|
+
this.tokenExpiresAt = reply.tokenExpiresAt;
|
|
2011
2391
|
this.sessionKey = void 0;
|
|
2012
2392
|
await this.ensureSessionKey();
|
|
2013
2393
|
this.persist();
|
|
@@ -2323,115 +2703,6 @@ function mqttUuidFrom(installId) {
|
|
|
2323
2703
|
return createHash4("sha256").update(installId).digest("hex").slice(0, 16);
|
|
2324
2704
|
}
|
|
2325
2705
|
|
|
2326
|
-
// dist/core/util.js
|
|
2327
|
-
var Timer = class {
|
|
2328
|
-
handle;
|
|
2329
|
-
/** (Re)arm to run `fn` after `ms`, cancelling any already-pending fire. */
|
|
2330
|
-
arm(ms, fn) {
|
|
2331
|
-
this.cancel();
|
|
2332
|
-
this.handle = setTimeout(() => {
|
|
2333
|
-
this.handle = void 0;
|
|
2334
|
-
fn();
|
|
2335
|
-
}, ms);
|
|
2336
|
-
this.handle.unref?.();
|
|
2337
|
-
}
|
|
2338
|
-
/** Cancel a pending fire. No-op if not armed. */
|
|
2339
|
-
cancel() {
|
|
2340
|
-
if (this.handle) {
|
|
2341
|
-
clearTimeout(this.handle);
|
|
2342
|
-
this.handle = void 0;
|
|
2343
|
-
}
|
|
2344
|
-
}
|
|
2345
|
-
/** Whether a fire is currently scheduled. */
|
|
2346
|
-
get pending() {
|
|
2347
|
-
return this.handle !== void 0;
|
|
2348
|
-
}
|
|
2349
|
-
};
|
|
2350
|
-
function assertNever(value) {
|
|
2351
|
-
throw new Error(`unhandled variant: ${JSON.stringify(value)}`);
|
|
2352
|
-
}
|
|
2353
|
-
function asBool(value) {
|
|
2354
|
-
if (typeof value === "string")
|
|
2355
|
-
return value === "1" || value.toLowerCase() === "true";
|
|
2356
|
-
return value === true || value === 1;
|
|
2357
|
-
}
|
|
2358
|
-
function clamp(value, min, max) {
|
|
2359
|
-
if (Number.isNaN(value))
|
|
2360
|
-
return min;
|
|
2361
|
-
return Math.max(min, Math.min(max, Math.round(value)));
|
|
2362
|
-
}
|
|
2363
|
-
function structuralEqual(a, b) {
|
|
2364
|
-
if (Object.is(a, b))
|
|
2365
|
-
return true;
|
|
2366
|
-
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null)
|
|
2367
|
-
return false;
|
|
2368
|
-
const aArr = Array.isArray(a);
|
|
2369
|
-
const bArr = Array.isArray(b);
|
|
2370
|
-
if (aArr !== bArr)
|
|
2371
|
-
return false;
|
|
2372
|
-
if (aArr && bArr) {
|
|
2373
|
-
if (a.length !== b.length)
|
|
2374
|
-
return false;
|
|
2375
|
-
for (let i = 0; i < a.length; i++)
|
|
2376
|
-
if (!structuralEqual(a[i], b[i]))
|
|
2377
|
-
return false;
|
|
2378
|
-
return true;
|
|
2379
|
-
}
|
|
2380
|
-
const aObj = a;
|
|
2381
|
-
const bObj = b;
|
|
2382
|
-
const aKeys = Object.keys(aObj);
|
|
2383
|
-
const bKeys = Object.keys(bObj);
|
|
2384
|
-
if (aKeys.length !== bKeys.length)
|
|
2385
|
-
return false;
|
|
2386
|
-
for (const k of aKeys) {
|
|
2387
|
-
if (!Object.prototype.hasOwnProperty.call(bObj, k))
|
|
2388
|
-
return false;
|
|
2389
|
-
if (!structuralEqual(aObj[k], bObj[k]))
|
|
2390
|
-
return false;
|
|
2391
|
-
}
|
|
2392
|
-
return true;
|
|
2393
|
-
}
|
|
2394
|
-
function coerceEnumValue(enumObj, value) {
|
|
2395
|
-
const n = Number(value);
|
|
2396
|
-
return Number.isInteger(n) && Object.values(enumObj).includes(n) ? n : void 0;
|
|
2397
|
-
}
|
|
2398
|
-
function enumValues(enumObj) {
|
|
2399
|
-
return Object.values(enumObj).join("/");
|
|
2400
|
-
}
|
|
2401
|
-
function enumLabels(enumObj) {
|
|
2402
|
-
return Object.fromEntries(Object.entries(enumObj).map(([name, value]) => [value, name]));
|
|
2403
|
-
}
|
|
2404
|
-
function jsonObject(text2) {
|
|
2405
|
-
if (typeof text2 !== "string")
|
|
2406
|
-
return void 0;
|
|
2407
|
-
try {
|
|
2408
|
-
const v = JSON.parse(text2);
|
|
2409
|
-
return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
2410
|
-
} catch {
|
|
2411
|
-
return void 0;
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
function u16le(n) {
|
|
2415
|
-
const b = Buffer.alloc(2);
|
|
2416
|
-
b.writeUInt16LE(n & 65535);
|
|
2417
|
-
return b;
|
|
2418
|
-
}
|
|
2419
|
-
function u16be(n) {
|
|
2420
|
-
const b = Buffer.alloc(2);
|
|
2421
|
-
b.writeUInt16BE(n & 65535);
|
|
2422
|
-
return b;
|
|
2423
|
-
}
|
|
2424
|
-
function u32le(n) {
|
|
2425
|
-
const b = Buffer.alloc(4);
|
|
2426
|
-
b.writeUInt32LE(n >>> 0);
|
|
2427
|
-
return b;
|
|
2428
|
-
}
|
|
2429
|
-
function u32be(n) {
|
|
2430
|
-
const b = Buffer.alloc(4);
|
|
2431
|
-
b.writeUInt32BE(n >>> 0);
|
|
2432
|
-
return b;
|
|
2433
|
-
}
|
|
2434
|
-
|
|
2435
2706
|
// dist/transport/mqtt/availability.js
|
|
2436
2707
|
function parseStateInfoSignal(topic, raw) {
|
|
2437
2708
|
const parsedTopic = parseSecureTopic(topic);
|
|
@@ -2556,13 +2827,6 @@ function parseAiotDpReport(raw) {
|
|
|
2556
2827
|
return Object.keys(out).length ? out : void 0;
|
|
2557
2828
|
}
|
|
2558
2829
|
|
|
2559
|
-
// dist/core/raw-dp-hex.js
|
|
2560
|
-
function hexToRawDp(hex) {
|
|
2561
|
-
if (hex.length === 0 || hex.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex))
|
|
2562
|
-
return void 0;
|
|
2563
|
-
return Buffer.from(hex, "hex").toString("base64");
|
|
2564
|
-
}
|
|
2565
|
-
|
|
2566
2830
|
// dist/transport/mqtt/biz-stream.js
|
|
2567
2831
|
var BIZ_PROTOCOL = {
|
|
2568
2832
|
/** Map-stream data: the frames this module parses. */
|
|
@@ -2735,28 +2999,16 @@ var DeviceType = {
|
|
|
2735
2999
|
LOCK_85D0: 202,
|
|
2736
3000
|
LOCK_85V0: 203,
|
|
2737
3001
|
LOCK_85P0: 209,
|
|
2738
|
-
NVR_S4_MAX: 300,
|
|
2739
|
-
CAMERA_POE_S4: 301,
|
|
2740
|
-
WALL_LIGHT_CAM_81A0: 10005,
|
|
2741
|
-
INDOOR_8W11: 10006,
|
|
2742
|
-
INDOOR_PT_CAMERA_C220: 10008,
|
|
2743
|
-
INDOOR_PT_CAMERA_C210: 10009,
|
|
2744
|
-
INDOOR_PT_CAMERA_C220_V2: 10010,
|
|
2745
|
-
INDOOR_PT_CAMERA_C220_V3: 10011,
|
|
2746
|
-
CAMERA_C35: 10035
|
|
2747
|
-
};
|
|
2748
|
-
|
|
2749
|
-
// dist/core/types.js
|
|
2750
|
-
var PRINTER_CATEGORY_RE = /ankermake|eufymake|fdm|3d_?print/i;
|
|
2751
|
-
function classifyDevice(raw) {
|
|
2752
|
-
const category = raw.category ?? "";
|
|
2753
|
-
const hasP2p = typeof raw.p2p_did === "string" && raw.p2p_did.length > 0;
|
|
2754
|
-
if (category === "eufy_security" || hasP2p)
|
|
2755
|
-
return { category, api: "mega", realtime: "p2p" };
|
|
2756
|
-
if (PRINTER_CATEGORY_RE.test(category))
|
|
2757
|
-
return { category, api: "ankermake", realtime: "ankermake-mqtt" };
|
|
2758
|
-
return { category, api: "mega", realtime: "smqtt" };
|
|
2759
|
-
}
|
|
3002
|
+
NVR_S4_MAX: 300,
|
|
3003
|
+
CAMERA_POE_S4: 301,
|
|
3004
|
+
WALL_LIGHT_CAM_81A0: 10005,
|
|
3005
|
+
INDOOR_8W11: 10006,
|
|
3006
|
+
INDOOR_PT_CAMERA_C220: 10008,
|
|
3007
|
+
INDOOR_PT_CAMERA_C210: 10009,
|
|
3008
|
+
INDOOR_PT_CAMERA_C220_V2: 10010,
|
|
3009
|
+
INDOOR_PT_CAMERA_C220_V3: 10011,
|
|
3010
|
+
CAMERA_C35: 10035
|
|
3011
|
+
};
|
|
2760
3012
|
|
|
2761
3013
|
// dist/model/classify.js
|
|
2762
3014
|
var STATION_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -2896,111 +3148,6 @@ function inferName(rec) {
|
|
|
2896
3148
|
return void 0;
|
|
2897
3149
|
}
|
|
2898
3150
|
|
|
2899
|
-
// dist/core/contracts.js
|
|
2900
|
-
var StoredSnapshotUnavailableError = class extends Error {
|
|
2901
|
-
reason;
|
|
2902
|
-
constructor(reason, message, options) {
|
|
2903
|
-
super(message, options);
|
|
2904
|
-
this.reason = reason;
|
|
2905
|
-
this.name = "StoredSnapshotUnavailableError";
|
|
2906
|
-
}
|
|
2907
|
-
};
|
|
2908
|
-
var RETRYABLE_LIVE_SNAPSHOT_REASONS = [
|
|
2909
|
-
"no-keyframe",
|
|
2910
|
-
"source-failed",
|
|
2911
|
-
"undecodable-burst"
|
|
2912
|
-
];
|
|
2913
|
-
var LiveSnapshotUnavailableError = class extends Error {
|
|
2914
|
-
reason;
|
|
2915
|
-
/** Whether another attempt could plausibly succeed without the host changing anything. */
|
|
2916
|
-
retryable;
|
|
2917
|
-
constructor(reason, message, options) {
|
|
2918
|
-
super(message, options);
|
|
2919
|
-
this.reason = reason;
|
|
2920
|
-
this.name = "LiveSnapshotUnavailableError";
|
|
2921
|
-
this.retryable = RETRYABLE_LIVE_SNAPSHOT_REASONS.includes(reason);
|
|
2922
|
-
}
|
|
2923
|
-
};
|
|
2924
|
-
var CameraDisabledError = class extends Error {
|
|
2925
|
-
camera;
|
|
2926
|
-
constructor(camera, options) {
|
|
2927
|
-
super(`camera${camera ? ` ${camera}` : ""} is disabled \u2014 no live stream possible`, options);
|
|
2928
|
-
this.camera = camera;
|
|
2929
|
-
this.name = "CameraDisabledError";
|
|
2930
|
-
}
|
|
2931
|
-
};
|
|
2932
|
-
var StationKeyUnavailableError = class extends Error {
|
|
2933
|
-
stationSn;
|
|
2934
|
-
/** Always true: the negotiation is per connection, so a later one may still produce a key. */
|
|
2935
|
-
retryable = true;
|
|
2936
|
-
constructor(stationSn, options) {
|
|
2937
|
-
super(`station ${stationSn} did not provide its session key, so nothing that requires one could be sent`, options);
|
|
2938
|
-
this.stationSn = stationSn;
|
|
2939
|
-
this.name = "StationKeyUnavailableError";
|
|
2940
|
-
}
|
|
2941
|
-
};
|
|
2942
|
-
var StationUnreachableError = class extends Error {
|
|
2943
|
-
stationSn;
|
|
2944
|
-
waitedMs;
|
|
2945
|
-
/** Always true: a station unreachable now may answer on a later attempt. */
|
|
2946
|
-
retryable = true;
|
|
2947
|
-
constructor(stationSn, waitedMs, options) {
|
|
2948
|
-
super(`station ${stationSn}'s P2P session did not connect within ${waitedMs}ms, so nothing could be sent to it`, options);
|
|
2949
|
-
this.stationSn = stationSn;
|
|
2950
|
-
this.waitedMs = waitedMs;
|
|
2951
|
-
this.name = "StationUnreachableError";
|
|
2952
|
-
}
|
|
2953
|
-
};
|
|
2954
|
-
var DeviceChannelUnresolvedError = class extends Error {
|
|
2955
|
-
sn;
|
|
2956
|
-
stationSn;
|
|
2957
|
-
constructor(sn, stationSn, options) {
|
|
2958
|
-
super(`${sn} has no usable channel on station ${stationSn}, so nothing was sent to it`, options);
|
|
2959
|
-
this.sn = sn;
|
|
2960
|
-
this.stationSn = stationSn;
|
|
2961
|
-
this.name = "DeviceChannelUnresolvedError";
|
|
2962
|
-
}
|
|
2963
|
-
};
|
|
2964
|
-
var LiveStreamStartError = class extends Error {
|
|
2965
|
-
reason;
|
|
2966
|
-
stage;
|
|
2967
|
-
timeoutMs;
|
|
2968
|
-
attempts;
|
|
2969
|
-
constructor(failure) {
|
|
2970
|
-
super(`live stream failed to start (${failure.reason} at ${failure.stage} after ${failure.attempts} attempts; ${failure.timeoutMs}ms deadline)`, failure.cause === void 0 ? void 0 : { cause: failure.cause });
|
|
2971
|
-
this.name = "LiveStreamStartError";
|
|
2972
|
-
this.reason = failure.reason;
|
|
2973
|
-
this.stage = failure.stage;
|
|
2974
|
-
this.timeoutMs = failure.timeoutMs;
|
|
2975
|
-
this.attempts = failure.attempts;
|
|
2976
|
-
}
|
|
2977
|
-
};
|
|
2978
|
-
var StateConvergenceError = class extends Error {
|
|
2979
|
-
sn;
|
|
2980
|
-
property;
|
|
2981
|
-
param;
|
|
2982
|
-
expected;
|
|
2983
|
-
observed;
|
|
2984
|
-
timeoutMs;
|
|
2985
|
-
constructor(failure) {
|
|
2986
|
-
super(`device ${failure.sn} did not report ${failure.property} as ${String(failure.expected)} within ${failure.timeoutMs}ms (param ${failure.param} read ${String(failure.observed)})`);
|
|
2987
|
-
this.name = "StateConvergenceError";
|
|
2988
|
-
this.sn = failure.sn;
|
|
2989
|
-
this.property = failure.property;
|
|
2990
|
-
this.param = failure.param;
|
|
2991
|
-
this.expected = failure.expected;
|
|
2992
|
-
this.observed = failure.observed;
|
|
2993
|
-
this.timeoutMs = failure.timeoutMs;
|
|
2994
|
-
}
|
|
2995
|
-
};
|
|
2996
|
-
var COMMAND_OBSERVATION = /* @__PURE__ */ Symbol("command-observation");
|
|
2997
|
-
function observeCommand(command, observation) {
|
|
2998
|
-
return Object.defineProperty(command, COMMAND_OBSERVATION, { configurable: true, value: observation });
|
|
2999
|
-
}
|
|
3000
|
-
function commandObservation(command) {
|
|
3001
|
-
return command[COMMAND_OBSERVATION];
|
|
3002
|
-
}
|
|
3003
|
-
|
|
3004
3151
|
// dist/model/capabilities/access.js
|
|
3005
3152
|
function setScalar(param, value, ctx, form = "auto") {
|
|
3006
3153
|
return { kind: "set-param", param, value, form, channel: ctx.channel };
|
|
@@ -7581,85 +7728,6 @@ var STORAGE = {
|
|
|
7581
7728
|
detection: { codecs: ["station"] }
|
|
7582
7729
|
};
|
|
7583
7730
|
|
|
7584
|
-
// dist/core/raw-dp-writer.js
|
|
7585
|
-
var WIRE = { VARINT: 0, LENGTH_DELIMITED: 2 };
|
|
7586
|
-
function encodeVarint(value) {
|
|
7587
|
-
if (!Number.isSafeInteger(value) || value < 0) {
|
|
7588
|
-
throw new Error(`varint: ${value} is not a non-negative safe integer`);
|
|
7589
|
-
}
|
|
7590
|
-
const out = [];
|
|
7591
|
-
let v = value;
|
|
7592
|
-
while (v > 127) {
|
|
7593
|
-
out.push(v % 128 + 128);
|
|
7594
|
-
v = Math.floor(v / 128);
|
|
7595
|
-
}
|
|
7596
|
-
out.push(v);
|
|
7597
|
-
return out;
|
|
7598
|
-
}
|
|
7599
|
-
function zigzag(value) {
|
|
7600
|
-
if (!Number.isSafeInteger(value))
|
|
7601
|
-
throw new Error(`zigzag: ${value} is not a safe integer`);
|
|
7602
|
-
return value < 0 ? -2 * value - 1 : 2 * value;
|
|
7603
|
-
}
|
|
7604
|
-
var RawDpWriter = class _RawDpWriter {
|
|
7605
|
-
body = [];
|
|
7606
|
-
/** A varint-valued field (`int32`, `uint32`, `bool`, an enum member). */
|
|
7607
|
-
int(field, value) {
|
|
7608
|
-
this.body.push(...encodeVarint(tag(field, WIRE.VARINT)), ...encodeVarint(value));
|
|
7609
|
-
return this;
|
|
7610
|
-
}
|
|
7611
|
-
/** A signed varint field (`sint32`, `sint64`), ZigZag-encoded — see {@link zigzag}. */
|
|
7612
|
-
sint(field, value) {
|
|
7613
|
-
return this.int(field, zigzag(value));
|
|
7614
|
-
}
|
|
7615
|
-
/** A boolean field, on protobuf's own terms: `1` or `0` in a varint. */
|
|
7616
|
-
bool(field, value) {
|
|
7617
|
-
return this.int(field, value ? 1 : 0);
|
|
7618
|
-
}
|
|
7619
|
-
/** A length-delimited field carrying raw bytes — a string, a blob, or a message built elsewhere. */
|
|
7620
|
-
bytes(field, value) {
|
|
7621
|
-
const bytes2 = value instanceof Uint8Array ? Array.from(value) : [...value];
|
|
7622
|
-
this.body.push(...encodeVarint(tag(field, WIRE.LENGTH_DELIMITED)), ...encodeVarint(bytes2.length), ...bytes2);
|
|
7623
|
-
return this;
|
|
7624
|
-
}
|
|
7625
|
-
/**
|
|
7626
|
-
* A nested sub-message, built by `build` into a writer of its own.
|
|
7627
|
-
*
|
|
7628
|
-
* The sub-message is emitted even when `build` writes nothing into it. That is not an oversight: an
|
|
7629
|
-
* EMPTY sub-message is how these protocols say "this subsystem exists and is in its zero state", as
|
|
7630
|
-
* opposed to saying nothing about it, and the readers on the other side of this file depend on the
|
|
7631
|
-
* distinction. Omitting the call is what says nothing about it.
|
|
7632
|
-
*/
|
|
7633
|
-
sub(field, build) {
|
|
7634
|
-
const inner = new _RawDpWriter();
|
|
7635
|
-
build(inner);
|
|
7636
|
-
return this.bytes(field, inner.toBytes());
|
|
7637
|
-
}
|
|
7638
|
-
/** The message body on its own, unframed — for nesting into another writer. */
|
|
7639
|
-
toBytes() {
|
|
7640
|
-
return [...this.body];
|
|
7641
|
-
}
|
|
7642
|
-
/**
|
|
7643
|
-
* The finished DP value: `varint(bodyLength) ++ body`, base64-encoded.
|
|
7644
|
-
*
|
|
7645
|
-
* This is the envelope `RawDpCodec.decode` unwraps, so a value produced here and read back through the
|
|
7646
|
-
* codec is a genuine round-trip rather than two implementations of the same guess.
|
|
7647
|
-
*/
|
|
7648
|
-
finish() {
|
|
7649
|
-
return Buffer.from([...encodeVarint(this.body.length), ...this.body]).toString("base64");
|
|
7650
|
-
}
|
|
7651
|
-
};
|
|
7652
|
-
function tag(field, wire) {
|
|
7653
|
-
if (!Number.isSafeInteger(field) || field < 1)
|
|
7654
|
-
throw new Error(`field number: ${field} is not a positive integer`);
|
|
7655
|
-
return field * 8 + wire;
|
|
7656
|
-
}
|
|
7657
|
-
function rawDp(build) {
|
|
7658
|
-
const w = new RawDpWriter();
|
|
7659
|
-
build(w);
|
|
7660
|
-
return w.finish();
|
|
7661
|
-
}
|
|
7662
|
-
|
|
7663
7731
|
// dist/model/capabilities/vacuum-dock.js
|
|
7664
7732
|
var VACUUM_DOCK_DP = 173;
|
|
7665
7733
|
var VACUUM_DOCK_INFO_DP = 169;
|
|
@@ -13364,58 +13432,6 @@ function parseCleanRecordDetail(blob, codec) {
|
|
|
13364
13432
|
};
|
|
13365
13433
|
}
|
|
13366
13434
|
|
|
13367
|
-
// dist/core/lz4-block.js
|
|
13368
|
-
var MAX_OUTPUT = 64 * 1024 * 1024;
|
|
13369
|
-
function lz4BlockDecompress(block, size) {
|
|
13370
|
-
if (!Number.isSafeInteger(size) || size < 0 || size > MAX_OUTPUT)
|
|
13371
|
-
return void 0;
|
|
13372
|
-
const out = Buffer.alloc(size);
|
|
13373
|
-
const end = block.length;
|
|
13374
|
-
let pos = 0;
|
|
13375
|
-
let written = 0;
|
|
13376
|
-
const extend2 = (base) => {
|
|
13377
|
-
let len = base;
|
|
13378
|
-
if (base !== 15)
|
|
13379
|
-
return len;
|
|
13380
|
-
for (; ; ) {
|
|
13381
|
-
if (pos >= end)
|
|
13382
|
-
return void 0;
|
|
13383
|
-
const extra = block[pos++];
|
|
13384
|
-
len += extra;
|
|
13385
|
-
if (extra !== 255)
|
|
13386
|
-
return len;
|
|
13387
|
-
}
|
|
13388
|
-
};
|
|
13389
|
-
while (pos < end) {
|
|
13390
|
-
const token = block[pos++];
|
|
13391
|
-
const literals = extend2(token >> 4);
|
|
13392
|
-
if (literals === void 0)
|
|
13393
|
-
return void 0;
|
|
13394
|
-
if (pos + literals > end || written + literals > size)
|
|
13395
|
-
return void 0;
|
|
13396
|
-
for (let i = 0; i < literals; i++)
|
|
13397
|
-
out[written++] = block[pos++];
|
|
13398
|
-
if (pos === end)
|
|
13399
|
-
break;
|
|
13400
|
-
if (pos + 2 > end)
|
|
13401
|
-
return void 0;
|
|
13402
|
-
const offset = block[pos] | block[pos + 1] << 8;
|
|
13403
|
-
pos += 2;
|
|
13404
|
-
if (offset === 0 || offset > written)
|
|
13405
|
-
return void 0;
|
|
13406
|
-
const match = extend2(token & 15);
|
|
13407
|
-
if (match === void 0)
|
|
13408
|
-
return void 0;
|
|
13409
|
-
const length = match + 4;
|
|
13410
|
-
if (written + length > size)
|
|
13411
|
-
return void 0;
|
|
13412
|
-
let from = written - offset;
|
|
13413
|
-
for (let i = 0; i < length; i++)
|
|
13414
|
-
out[written++] = out[from++];
|
|
13415
|
-
}
|
|
13416
|
-
return written === size ? out : void 0;
|
|
13417
|
-
}
|
|
13418
|
-
|
|
13419
13435
|
// dist/model/vacuum-map.js
|
|
13420
13436
|
var DOCK_KINDS = ["charger", "station"];
|
|
13421
13437
|
var MAP_QUALITIES = ["incomplete", "rough", "effective", "listFull"];
|
|
@@ -15214,6 +15230,7 @@ var CMD_DATABASE_IMAGE = 1308;
|
|
|
15214
15230
|
var CMD_DATABASE = 1306;
|
|
15215
15231
|
var DB_QUERY = { FULL_TABLE: 1e4, COMBINATION_WITH_AI: 10011 };
|
|
15216
15232
|
var GCM_AAD = Buffer.from("eufy security");
|
|
15233
|
+
var LEVEL2_SEQ_BASE = 16909056;
|
|
15217
15234
|
function paramReport(payload) {
|
|
15218
15235
|
const list = payload?.params;
|
|
15219
15236
|
if (!Array.isArray(list))
|
|
@@ -16318,11 +16335,6 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
16318
16335
|
this.seqNumber = this.seqNumber + 1 & 65535;
|
|
16319
16336
|
this.send(this.connectAddress, RequestMessageType.DATA, data);
|
|
16320
16337
|
}
|
|
16321
|
-
/**
|
|
16322
|
-
* Encrypt a level-2 command body (signCode 8): `tag(16) ‖ nonce(12) ‖ [seq,03,02,01](4) ‖
|
|
16323
|
-
* ciphertext`, AES-256-GCM under the negotiated session key, AAD "eufy security". Inverse of
|
|
16324
|
-
* `decryptLevel2`. The 4-byte sub-header is cleartext (skipped on decrypt); `seq` is a counter.
|
|
16325
|
-
*/
|
|
16326
16338
|
/**
|
|
16327
16339
|
* Decode a `CMD_VIDEO_FRAME` (1300) payload into clean Annex-B H.264 (the 22-byte frame header
|
|
16328
16340
|
* stripped). Reversed from the V6 app + live H.264 captures: the 22-byte header is
|
|
@@ -16389,6 +16401,11 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
16389
16401
|
}
|
|
16390
16402
|
return this.rsaModulusHex;
|
|
16391
16403
|
}
|
|
16404
|
+
/**
|
|
16405
|
+
* Encrypt a level-2 command body (signCode 8): `tag(16) ‖ nonce(12) ‖ seq(4) ‖ ciphertext`,
|
|
16406
|
+
* AES-256-GCM under the negotiated session key, AAD "eufy security". Inverse of `decryptLevel2`.
|
|
16407
|
+
* The 4-byte sub-header is cleartext (skipped on decrypt); `seq` counts up from {@link LEVEL2_SEQ_BASE}.
|
|
16408
|
+
*/
|
|
16392
16409
|
encryptLevel2(plaintext) {
|
|
16393
16410
|
if (!this.level2Key)
|
|
16394
16411
|
return void 0;
|
|
@@ -16396,8 +16413,8 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
16396
16413
|
const c = createCipheriv3("aes-256-gcm", this.level2Key, nonce);
|
|
16397
16414
|
c.setAAD(GCM_AAD);
|
|
16398
16415
|
const ct = Buffer.concat([c.update(plaintext), c.final()]);
|
|
16399
|
-
const sub2 = Buffer.
|
|
16400
|
-
|
|
16416
|
+
const sub2 = Buffer.alloc(4);
|
|
16417
|
+
sub2.writeUInt32LE(LEVEL2_SEQ_BASE + this.level2Seq++ >>> 0);
|
|
16401
16418
|
return Buffer.concat([c.getAuthTag(), nonce, sub2, ct]);
|
|
16402
16419
|
}
|
|
16403
16420
|
/** Send a no-arg command frame (e.g. CMD_GATEWAYINFO) on a channel (default: the station channel). */
|
|
@@ -27189,26 +27206,16 @@ var SolixClient = class _SolixClient {
|
|
|
27189
27206
|
}
|
|
27190
27207
|
/** Build the encrypted, signed `/passport/login` request body + headers for the negotiated key. */
|
|
27191
27208
|
async postLogin(kx, verifyCode, limitedToken) {
|
|
27192
|
-
const { clientPublicKeyHex, encryptedPassword } = encryptLoginPassword(this.password);
|
|
27193
27209
|
const bodyObj = {
|
|
27194
|
-
email
|
|
27195
|
-
password: encryptedPassword,
|
|
27196
|
-
ab: this.country,
|
|
27197
|
-
client_secret_info: { public_key: clientPublicKeyHex },
|
|
27210
|
+
...loginCredentials(this.email, this.password, this.country),
|
|
27198
27211
|
answer: "",
|
|
27199
27212
|
captcha_id: "",
|
|
27200
27213
|
verify_code: verifyCode ?? "",
|
|
27201
27214
|
login_id: ""
|
|
27202
27215
|
};
|
|
27203
27216
|
const encBody = encryptBody(JSON.stringify(bodyObj), kx.shareKey);
|
|
27204
|
-
const ts = nowSec();
|
|
27205
|
-
const once = genId();
|
|
27206
27217
|
return this.post(this.apiHost, SOLIX_ENDPOINTS.login, encBody, this.authHeaders({
|
|
27207
|
-
|
|
27208
|
-
"x-key-ident": kx.keyIdent,
|
|
27209
|
-
"x-request-ts": ts,
|
|
27210
|
-
"x-request-once": once,
|
|
27211
|
-
"x-signature": signRequest(kx.shareKey, ts, once, encBody),
|
|
27218
|
+
...signedHeaders(kx, encBody),
|
|
27212
27219
|
...limitedToken ? { "x-auth-token": limitedToken } : {}
|
|
27213
27220
|
}));
|
|
27214
27221
|
}
|
|
@@ -27223,13 +27230,12 @@ var SolixClient = class _SolixClient {
|
|
|
27223
27230
|
* observed refusing the header, which is consistent with the two ids agreeing on the accounts seen.
|
|
27224
27231
|
*/
|
|
27225
27232
|
classifyLogin(data, isVerify) {
|
|
27226
|
-
const
|
|
27227
|
-
|
|
27228
|
-
if (!userId || !authToken)
|
|
27233
|
+
const reply = readLoginReply(data);
|
|
27234
|
+
if (!reply)
|
|
27229
27235
|
throw new Error(`Solix login returned no session: ${JSON.stringify(data).slice(0, 160)}`);
|
|
27230
|
-
const
|
|
27231
|
-
if (!isVerify &&
|
|
27232
|
-
this.pending2fa = { limitedToken: authToken, userId, geoKey:
|
|
27236
|
+
const { userId, authToken } = reply;
|
|
27237
|
+
if (!isVerify && reply.twoFactorPending) {
|
|
27238
|
+
this.pending2fa = { limitedToken: authToken, userId, geoKey: reply.geoKey };
|
|
27233
27239
|
return { status: "2fa", method: "code sent by the passport" };
|
|
27234
27240
|
}
|
|
27235
27241
|
this.pending2fa = void 0;
|
|
@@ -27238,7 +27244,7 @@ var SolixClient = class _SolixClient {
|
|
|
27238
27244
|
userId,
|
|
27239
27245
|
gtoken: gtoken(userId),
|
|
27240
27246
|
apiHost: this.apiHost,
|
|
27241
|
-
tokenExpiresAt:
|
|
27247
|
+
tokenExpiresAt: reply.tokenExpiresAt
|
|
27242
27248
|
};
|
|
27243
27249
|
this.persist();
|
|
27244
27250
|
return { status: "ok", session: this.session_ };
|
|
@@ -27393,14 +27399,8 @@ var SolixClient = class _SolixClient {
|
|
|
27393
27399
|
throw new Error("not authenticated \u2014 call login() first");
|
|
27394
27400
|
const kx = await this.keyExchange();
|
|
27395
27401
|
const encBody = encryptBody(JSON.stringify(payload), kx.shareKey);
|
|
27396
|
-
const ts = nowSec();
|
|
27397
|
-
const once = genId();
|
|
27398
27402
|
const env = await this.post(this.apiHost, path, encBody, this.baseHeaders({
|
|
27399
|
-
|
|
27400
|
-
"x-key-ident": kx.keyIdent,
|
|
27401
|
-
"x-request-ts": ts,
|
|
27402
|
-
"x-request-once": once,
|
|
27403
|
-
"x-signature": signRequest(kx.shareKey, ts, once, encBody),
|
|
27403
|
+
...signedHeaders(kx, encBody),
|
|
27404
27404
|
"x-auth-token": this.session_.authToken,
|
|
27405
27405
|
gtoken: this.session_.gtoken
|
|
27406
27406
|
}));
|