This commit is contained in:
2025-11-11 00:04:55 -06:00
parent a76ad41fde
commit 40538eddfd
6405 changed files with 1289756 additions and 0 deletions

59
build/p2p/ble.d.ts vendored Normal file
View File

@ -0,0 +1,59 @@
export declare enum BleParameterIndex {
ZERO = -96,
ONE = -95,
TWO = -94,
THREE = -93,
FOUR = -92,
FIVE = -91,
SIX = -90,
SEVEN = -89,
EIGHT = -88,
NINE = -87,
TEN = -86,
ELEVEN = -85,
TWELVE = -84,
THIRTEEN = -83
}
export declare class BleCommandFactory {
private static readonly HEADER;
private data?;
private commandCode?;
private versionCode?;
private dataType?;
private packageFlag?;
private unknown?;
private additionalDataSeparatorByte?;
private additionalData?;
private responseCode?;
private encrypted?;
private partial?;
static parseLockV12(data: string | Buffer): BleCommandFactory;
static parseSmartSafe(data: string | Buffer): BleCommandFactory;
static parseSmartLock(data: string | Buffer): BleCommandFactory;
toString: () => string;
private setResponseCode;
getResponseCode(): number | undefined;
setVersionCode(version: number): BleCommandFactory;
getVersionCode(): number | undefined;
setCommandCode(command: number): BleCommandFactory;
getCommandCode(): number | undefined;
setDataType(type: number): BleCommandFactory;
getDataType(): number | undefined;
setPackageFlag(flag: number): BleCommandFactory;
getPackageFlag(): number | undefined;
setAdditionalDataSeparator(separator: number): BleCommandFactory;
getAdditionalDataSeparator(): Buffer | undefined;
setAdditionalData(data: Buffer): BleCommandFactory;
getAdditionalData(): Buffer | undefined;
setData(data: Buffer): BleCommandFactory;
getData(): Buffer | undefined;
setUnknown(data: Buffer): BleCommandFactory;
static generateHash(data: Buffer): number;
isEncrypted(): boolean | undefined;
setEncrypted(encrypted: boolean): BleCommandFactory;
isPartial(): boolean | undefined;
setPartial(partial: boolean): BleCommandFactory;
getLockV12Command(): Buffer;
getSmartSafeCommand(): Buffer;
getSmartLockCommand(): Buffer;
}

280
build/p2p/ble.js Normal file
View File

@ -0,0 +1,280 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BleCommandFactory = exports.BleParameterIndex = void 0;
const error_1 = require("./error");
var BleParameterIndex;
(function (BleParameterIndex) {
BleParameterIndex[BleParameterIndex["ZERO"] = -96] = "ZERO";
BleParameterIndex[BleParameterIndex["ONE"] = -95] = "ONE";
BleParameterIndex[BleParameterIndex["TWO"] = -94] = "TWO";
BleParameterIndex[BleParameterIndex["THREE"] = -93] = "THREE";
BleParameterIndex[BleParameterIndex["FOUR"] = -92] = "FOUR";
BleParameterIndex[BleParameterIndex["FIVE"] = -91] = "FIVE";
BleParameterIndex[BleParameterIndex["SIX"] = -90] = "SIX";
BleParameterIndex[BleParameterIndex["SEVEN"] = -89] = "SEVEN";
BleParameterIndex[BleParameterIndex["EIGHT"] = -88] = "EIGHT";
BleParameterIndex[BleParameterIndex["NINE"] = -87] = "NINE";
BleParameterIndex[BleParameterIndex["TEN"] = -86] = "TEN";
BleParameterIndex[BleParameterIndex["ELEVEN"] = -85] = "ELEVEN";
BleParameterIndex[BleParameterIndex["TWELVE"] = -84] = "TWELVE";
BleParameterIndex[BleParameterIndex["THIRTEEN"] = -83] = "THIRTEEN";
})(BleParameterIndex || (exports.BleParameterIndex = BleParameterIndex = {}));
class BleCommandFactory {
static HEADER = Buffer.from([-1, 9]);
data;
commandCode;
versionCode;
dataType;
packageFlag;
unknown;
additionalDataSeparatorByte;
additionalData;
responseCode;
encrypted;
partial;
static parseLockV12(data) {
if (typeof data === "string") {
data = Buffer.from(data, "hex");
}
if (data.readInt8(0) !== BleCommandFactory.HEADER[0] && data.readInt8(1) !== BleCommandFactory.HEADER[1]) {
throw new error_1.BleInvalidDataHeaderError("Invalid BLE data header");
}
const fac = new BleCommandFactory();
fac.setVersionCode(data.readUint8(4));
fac.setCommandCode(data.readUint8(6));
fac.setDataType(data.readUint8());
fac.setPackageFlag(data.readInt8(7));
fac.setResponseCode(fac.getPackageFlag() === -64 ? data.readUint8(8) : data.readUint8(12));
fac.setData(data.subarray(fac.getPackageFlag() === -64 ? 8 : 12, data.length - 1)); //TODO: Verify if position 8 is correct for data (i think it should be 9 or 13)...
if (BleCommandFactory.generateHash(data.subarray(0, data.length - 1)) !== data.readUint8(data.length - 1)) {
throw new error_1.BleInvalidChecksumError("Invalid BLE data, checksum mismatch");
}
return fac;
}
static parseSmartSafe(data) {
return BleCommandFactory.parseLockV12(data);
}
static parseSmartLock(data) {
if (typeof data === "string") {
data = Buffer.from(data, "hex");
}
if (data.length < 9 || (data.readInt8(0) !== BleCommandFactory.HEADER[0] && data.readInt8(1) !== BleCommandFactory.HEADER[1])) {
throw new error_1.BleInvalidDataHeaderError("Invalid BLE data header");
}
if (BleCommandFactory.generateHash(data.subarray(0, data.length - 1)) !== data.readUint8(data.length - 1)) {
throw new error_1.BleInvalidChecksumError("Invalid BLE data, checksum mismatch");
}
const fac = new BleCommandFactory();
const flags = data.readUint16BE(7);
fac.setVersionCode(data.readUint8(4));
fac.setDataType(data.readUint8(6));
fac.setPartial((flags >> 15) === 1);
fac.setEncrypted(((flags << 1) >> 15) === 1);
fac.setCommandCode(((flags << 4) & 32767) >> 4);
fac.setData(data.subarray(9, data.length - 1));
return fac;
}
toString = () => {
return `BleCommandFactory (versionCode: ${this.versionCode} commandCode: ${this.commandCode} dataType: ${this.dataType} partial: ${this.partial} encrypted: ${this.encrypted} data: ${this.data?.toString("hex")} packageFlag: ${this.packageFlag} responseCode: ${this.responseCode})`;
};
setResponseCode(code) {
this.responseCode = code;
}
getResponseCode() {
return this.responseCode;
}
setVersionCode(version) {
this.versionCode = version;
return this;
}
getVersionCode() {
return this.versionCode;
}
setCommandCode(command) {
this.commandCode = command;
return this;
}
getCommandCode() {
return this.commandCode;
}
setDataType(type) {
this.dataType = type;
return this;
}
getDataType() {
return this.dataType;
}
setPackageFlag(flag) {
this.packageFlag = flag;
return this;
}
getPackageFlag() {
return this.packageFlag;
}
setAdditionalDataSeparator(separator) {
this.additionalDataSeparatorByte = Buffer.from([separator]);
return this;
}
getAdditionalDataSeparator() {
return this.additionalDataSeparatorByte;
}
setAdditionalData(data) {
this.additionalData = data;
return this;
}
getAdditionalData() {
return this.additionalData;
}
setData(data) {
this.data = data;
return this;
}
getData() {
return this.data;
}
setUnknown(data) {
this.unknown = data;
return this;
}
static generateHash(data) {
let result = 0;
for (const value of data) {
result = result ^ value;
}
return result;
}
isEncrypted() {
return this.encrypted;
}
setEncrypted(encrypted) {
this.encrypted = encrypted;
return this;
}
isPartial() {
return this.partial;
}
setPartial(partial) {
this.partial = partial;
return this;
}
getLockV12Command() {
if (this.versionCode === undefined)
throw new error_1.BleVersionCodeError("BleCommandFactory version code value missing");
if (this.dataType === undefined)
throw new error_1.BleDataTypeError("BleCommandFactory data type value missing");
if (this.commandCode === undefined)
throw new error_1.BleCommandCodeError("BleCommandFactory command code value missing");
if (this.data === undefined)
throw new error_1.BleDataError("BleCommandFactory data value missing");
if (this.additionalData === undefined)
throw new error_1.BleAdditionalDataError("BleCommandFactory additional data value missing");
this.setAdditionalDataSeparator(BleParameterIndex.ZERO);
const bVersionCode = Buffer.from([this.versionCode]);
const bDataType = Buffer.from([this.dataType]);
const bCommandCode = Buffer.from([this.commandCode]);
const bPackageFlag = this.packageFlag === undefined ? Buffer.from([-64]) : Buffer.from([this.packageFlag]);
const bAdditionalDataLength = Buffer.from([this.additionalData.length]);
const size = Buffer.allocUnsafe(2);
size.writeInt16LE(BleCommandFactory.HEADER.length +
size.length +
bVersionCode.length +
bDataType.length +
bCommandCode.length +
bPackageFlag.length +
this.additionalDataSeparatorByte.length +
bAdditionalDataLength.length +
this.additionalData.length +
this.data.length +
1 // Hash
);
const data = Buffer.concat([
BleCommandFactory.HEADER,
size,
bVersionCode,
bDataType,
bCommandCode,
bPackageFlag,
this.additionalDataSeparatorByte,
bAdditionalDataLength,
this.additionalData,
this.data
]);
const hash = BleCommandFactory.generateHash(data);
return Buffer.concat([data, Buffer.from([hash])]);
}
getSmartSafeCommand() {
if (this.versionCode === undefined)
throw new error_1.BleVersionCodeError("BleCommandFactory version code value missing");
if (this.dataType === undefined)
throw new error_1.BleDataTypeError("BleCommandFactory data type value missing");
if (this.commandCode === undefined)
throw new error_1.BleCommandCodeError("BleCommandFactory command code value missing");
if (this.data === undefined)
throw new error_1.BleDataError("BleCommandFactory data value missing");
const bVersionCode = Buffer.from([this.versionCode]);
const bDataType = Buffer.from([this.dataType]);
const bCommandCode = Buffer.from([this.commandCode]);
const bPackageFlag = this.packageFlag === undefined ? Buffer.from([-64]) : Buffer.from([this.packageFlag]);
const size = Buffer.allocUnsafe(2);
size.writeInt16LE(BleCommandFactory.HEADER.length +
size.length +
bVersionCode.length +
bDataType.length +
bCommandCode.length +
bPackageFlag.length +
this.data.length +
1 // Hash
);
const data = Buffer.concat([
BleCommandFactory.HEADER,
size,
bVersionCode,
bDataType,
bCommandCode,
bPackageFlag,
this.data
]);
const hash = BleCommandFactory.generateHash(data);
return Buffer.concat([data, Buffer.from([hash])]);
}
getSmartLockCommand() {
if (this.versionCode === undefined)
throw new error_1.BleVersionCodeError("BleCommandFactory version code value missing");
if (this.dataType === undefined)
throw new error_1.BleDataTypeError("BleCommandFactory data type value missing");
if (this.commandCode === undefined)
throw new error_1.BleCommandCodeError("BleCommandFactory command code value missing");
if (this.data === undefined)
throw new error_1.BleDataError("BleCommandFactory data value missing");
const bVersionCode = Buffer.from([this.versionCode]);
const bDataType = Buffer.from([this.dataType]);
const unknown = Buffer.alloc(1);
const partial = false;
const encrypted = true;
const commandCodeEncoded = Buffer.allocUnsafe(2);
commandCodeEncoded.writeInt16BE(((partial ? 1 : 0) << 15) + ((encrypted ? 1 : 0) << 14) + this.commandCode);
const size = Buffer.allocUnsafe(2);
size.writeInt16LE(BleCommandFactory.HEADER.length +
size.length +
bVersionCode.length +
unknown.length +
bDataType.length +
commandCodeEncoded.length +
this.data.length +
1 // Hash
);
const data = Buffer.concat([
BleCommandFactory.HEADER,
size,
bVersionCode,
unknown,
bDataType,
commandCodeEncoded,
this.data
]);
const hash = BleCommandFactory.generateHash(data);
return Buffer.concat([data, Buffer.from([hash])]);
}
}
exports.BleCommandFactory = BleCommandFactory;
//# sourceMappingURL=ble.js.map

1
build/p2p/ble.js.map Normal file

File diff suppressed because one or more lines are too long

49
build/p2p/error.d.ts vendored Normal file
View File

@ -0,0 +1,49 @@
import { BaseError, Jsonable } from "../error";
export declare class BleVersionCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleCommandCodeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleDataTypeError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleDataError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleAdditionalDataError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleAdditionalDataSeparatorError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleInvalidDataHeaderError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}
export declare class BleInvalidChecksumError extends BaseError {
constructor(message: string, options?: {
cause?: Error;
context?: Jsonable;
});
}

69
build/p2p/error.js Normal file
View File

@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BleInvalidChecksumError = exports.BleInvalidDataHeaderError = exports.BleAdditionalDataSeparatorError = exports.BleAdditionalDataError = exports.BleDataError = exports.BleDataTypeError = exports.BleCommandCodeError = exports.BleVersionCodeError = void 0;
const error_1 = require("../error");
class BleVersionCodeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleVersionCodeError.name;
}
}
exports.BleVersionCodeError = BleVersionCodeError;
class BleCommandCodeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleCommandCodeError.name;
}
}
exports.BleCommandCodeError = BleCommandCodeError;
class BleDataTypeError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleDataTypeError.name;
}
}
exports.BleDataTypeError = BleDataTypeError;
class BleDataError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleDataError.name;
}
}
exports.BleDataError = BleDataError;
class BleAdditionalDataError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleAdditionalDataError.name;
}
}
exports.BleAdditionalDataError = BleAdditionalDataError;
class BleAdditionalDataSeparatorError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleAdditionalDataSeparatorError.name;
}
}
exports.BleAdditionalDataSeparatorError = BleAdditionalDataSeparatorError;
class BleInvalidDataHeaderError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleInvalidDataHeaderError.name;
}
}
exports.BleInvalidDataHeaderError = BleInvalidDataHeaderError;
class BleInvalidChecksumError extends error_1.BaseError {
constructor(message, options = {}) {
super(message, options);
Object.setPrototypeOf(this, new.target.prototype);
this.name = BleInvalidChecksumError.name;
}
}
exports.BleInvalidChecksumError = BleInvalidChecksumError;
//# sourceMappingURL=error.js.map

1
build/p2p/error.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/p2p/error.ts"],"names":[],"mappings":";;;AAAA,oCAA+C;AAC/C,MAAa,mBAAoB,SAAQ,iBAAS;IAC9C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC;IACzC,CAAC;CACJ;AAND,kDAMC;AAED,MAAa,mBAAoB,SAAQ,iBAAS;IAC9C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC;IACzC,CAAC;CACJ;AAND,kDAMC;AAED,MAAa,gBAAiB,SAAQ,iBAAS;IAC3C,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC;IACtC,CAAC;CACJ;AAND,4CAMC;AAED,MAAa,YAAa,SAAQ,iBAAS;IACvC,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;IAClC,CAAC;CACJ;AAND,oCAMC;AAED,MAAa,sBAAuB,SAAQ,iBAAS;IACjD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC;IAC5C,CAAC;CACJ;AAND,wDAMC;AAED,MAAa,+BAAgC,SAAQ,iBAAS;IAC1D,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC,IAAI,CAAC;IACrD,CAAC;CACJ;AAND,0EAMC;AAED,MAAa,yBAA0B,SAAQ,iBAAS;IACpD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC,IAAI,CAAC;IAC/C,CAAC;CACJ;AAND,8DAMC;AAED,MAAa,uBAAwB,SAAQ,iBAAS;IAClD,YAAY,OAAe,EAAE,UAAiD,EAAE;QAC5E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC,IAAI,CAAC;IAC7C,CAAC;CACJ;AAND,0DAMC"}

8
build/p2p/index.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
export * from "./interfaces";
export * from "./models";
export * from "./session";
export * from "./types";
export * from "./talkback";
export * from "./ble";
export * from "./error";
export { isPrivateIp, getLocalIpAddress } from "./utils";

28
build/p2p/index.js Normal file
View File

@ -0,0 +1,28 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLocalIpAddress = exports.isPrivateIp = void 0;
__exportStar(require("./interfaces"), exports);
__exportStar(require("./models"), exports);
__exportStar(require("./session"), exports);
__exportStar(require("./types"), exports);
__exportStar(require("./talkback"), exports);
__exportStar(require("./ble"), exports);
__exportStar(require("./error"), exports);
var utils_1 = require("./utils");
Object.defineProperty(exports, "isPrivateIp", { enumerable: true, get: function () { return utils_1.isPrivateIp; } });
Object.defineProperty(exports, "getLocalIpAddress", { enumerable: true, get: function () { return utils_1.getLocalIpAddress; } });
//# sourceMappingURL=index.js.map

1
build/p2p/index.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/p2p/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,2CAAyB;AACzB,4CAA0B;AAC1B,0CAAwB;AACxB,6CAA2B;AAC3B,wCAAsB;AACtB,0CAAwB;AACxB,iCAAyD;AAAhD,oGAAA,WAAW,OAAA;AAAE,0GAAA,iBAAiB,OAAA"}

388
build/p2p/interfaces.d.ts vendored Normal file
View File

@ -0,0 +1,388 @@
import * as NodeRSA from "node-rsa";
import { Readable } from "stream";
import { SortedMap } from "sweet-collections";
import { AlarmMode, DeviceType, MicStatus, ParamType, TriggerType, VideoType } from "../http/types";
import { Address, CmdCameraInfoResponse, CommandResult, CustomData, StorageInfoBodyHB3 } from "./models";
import { TalkbackStream } from "./talkback";
import { AlarmEvent, AudioCodec, CommandType, DatabaseReturnCode, IndoorSoloSmartdropCommandType, P2PDataType, SmartSafeAlarm911Event, SmartSafeShakeAlarmEvent, P2PStorageType, TFCardStatus, VideoCodec, InternalP2PCommandType } from "./types";
export interface P2PClientProtocolEvents {
"alarm mode": (mode: AlarmMode) => void;
"camera info": (cameraInfo: CmdCameraInfoResponse) => void;
"connect": (address: Address) => void;
"close": () => void;
"command": (result: CommandResult) => void;
"download started": (channel: number, metadata: StreamMetadata, videoStream: Readable, audioStream: Readable) => void;
"download finished": (channel: number) => void;
"livestream started": (channel: number, metadata: StreamMetadata, videoStream: Readable, audioStream: Readable) => void;
"livestream stopped": (channel: number) => void;
"livestream error": (channel: number, error: Error) => void;
"wifi rssi": (channel: number, rssi: number) => void;
"rtsp url": (channel: number, rtspUrl: string) => void;
"parameter": (channel: number, param: number, value: string) => void;
"timeout": () => void;
"runtime state": (channel: number, batteryLevel: number, temperature: number) => void;
"charging state": (channel: number, chargeType: number, batteryLevel: number) => void;
"rtsp livestream started": (channel: number) => void;
"rtsp livestream stopped": (channel: number) => void;
"floodlight manual switch": (channel: number, enabled: boolean) => void;
"alarm delay": (alarmDelayEvent: AlarmEvent, alarmDelay: number) => void;
"alarm armed": () => void;
"alarm event": (alarmEvent: AlarmEvent) => void;
"talkback started": (channel: number, talkbackStream: TalkbackStream) => void;
"talkback stopped": (channel: number) => void;
"talkback error": (channel: number, error: Error) => void;
"secondary command": (result: CommandResult) => void;
"jammed": (channel: number) => void;
"low battery": (channel: number) => void;
"shake alarm": (channel: number, detail: SmartSafeShakeAlarmEvent) => void;
"911 alarm": (channel: number, detail: SmartSafeAlarm911Event) => void;
"wrong try-protect alarm": (channel: number) => void;
"sd info ex": (sdStatus: TFCardStatus, sdCapacity: number, sdCapacityAvailable: number) => void;
"image download": (file: string, image: Buffer) => void;
"tfcard status": (channel: number, status: TFCardStatus) => void;
"database query latest": (returnCode: DatabaseReturnCode, data: Array<DatabaseQueryLatestInfo>) => void;
"database query local": (returnCode: DatabaseReturnCode, data: Array<DatabaseQueryLocal>) => void;
"database count by date": (returnCode: DatabaseReturnCode, data: Array<DatabaseCountByDate>) => void;
"database delete": (returnCode: DatabaseReturnCode, failedIds: Array<unknown>) => void;
"sensor status": (channel: number, status: number) => void;
"garage door status": (channel: number, doorId: number, status: number) => void;
"storage info hb3": (channel: number, storageInfo: StorageInfoBodyHB3) => void;
"sequence error": (channel: number, command: number, sequence: number, serialnumber: string) => void;
}
export interface P2PQueueMessage {
p2pCommandType: InternalP2PCommandType;
p2pCommand: P2PCommand;
nestedCommandType?: CommandType;
nestedCommandType2?: number;
timestamp: number;
customData?: CustomData;
}
export interface P2PMessageState {
sequence: number;
commandType: CommandType;
nestedCommandType?: CommandType | IndoorSoloSmartdropCommandType | ParamType;
nestedCommandType2?: number;
channel: number;
data: Buffer;
retries: number;
acknowledged: boolean;
returnCode?: number;
retryTimeout?: NodeJS.Timeout;
timeout?: NodeJS.Timeout;
customData?: CustomData;
}
export interface P2PMessageParts {
[index: number]: Buffer;
}
export interface P2PMessage {
bytesToRead: number;
type: P2PDataType;
seqNo: number;
data: Buffer;
}
export interface P2PDataHeader {
commandId: number;
bytesToRead: number;
channel: number;
signCode: number;
type: number;
}
export interface P2PDataMessage extends P2PDataHeader {
seqNo: number;
dataType: P2PDataType;
data: Buffer;
}
export interface P2PDataMessageBuilder {
header: P2PDataHeader;
bytesRead: number;
messages: P2PMessageParts;
}
export interface P2PDataMessageState {
leftoverData: Buffer;
queuedData: SortedMap<number, P2PMessage>;
rsaKey: NodeRSA | null;
videoStream: Readable | null;
audioStream: Readable | null;
invalidStream: boolean;
p2pStreaming: boolean;
p2pStreamNotStarted: boolean;
p2pStreamChannel: number;
p2pStreamFirstAudioDataReceived: boolean;
p2pStreamFirstVideoDataReceived: boolean;
p2pStreamMetadata: StreamMetadata;
p2pStreamingTimeout?: NodeJS.Timeout;
rtspStream: {
[index: number]: boolean;
};
rtspStreaming: {
[index: number]: boolean;
};
waitForSeqNoTimeout?: NodeJS.Timeout;
waitForAudioData?: NodeJS.Timeout;
receivedFirstIFrame: boolean;
preFrameVideoData: Buffer;
p2pTalkback: boolean;
p2pTalkbackChannel: number;
}
export interface P2PDataMessageVideo {
streamType: number;
videoSeqNo: number;
videoFPS: number;
videoWidth: number;
videoHeight: number;
videoTimestamp: number;
videoDataLength: number;
aesKey: string;
}
export interface P2PDataMessageAudio {
audioType: number;
audioSeqNo: number;
audioTimestamp: number;
audioDataLength: number;
}
export interface StreamMetadata {
videoCodec: VideoCodec;
videoFPS: number;
videoWidth: number;
videoHeight: number;
audioCodec: AudioCodec;
}
export interface DeviceSerial {
[index: number]: {
sn: string;
adminUserId: string;
};
}
export interface P2PCommand {
commandType: CommandType;
value?: number | string;
valueSub?: number;
strValue?: string;
strValueSub?: string;
channel?: number;
}
export interface P2PVideoMessageState {
sequence: number;
channel: number;
data: Buffer;
retries: number;
timeout?: NodeJS.Timeout;
}
export interface P2PDatabaseQueryLatestInfoResponse {
device_sn: string;
payload: {
event_count: number;
crop_hb3_path: string;
crop_cloud_path: string;
};
}
export interface P2PDatabaseCountByDateResponse {
days: string;
count: number;
}
export interface P2PDatabaseQueryLocalHistoryRecordInfo {
record_id: number;
account: string;
station_sn: string;
device_sn: string;
device_type: DeviceType;
start_time: string;
end_time: string;
frame_num: number;
storage_type: P2PStorageType;
storage_cloud: boolean;
cipher_id: number;
vision: number;
video_type: VideoType;
has_lock: boolean;
automation_id: number;
trigger_type: TriggerType;
push_mode: number;
mic_status: MicStatus;
res_change: number;
res_best_width: number;
res_best_height: number;
self_learning: number;
int_reserve: number;
int_extra: number;
storage_path: string;
thumb_path: string;
write_status: number;
str_extra: string;
cloud_path: string;
folder_size: number;
storage_status: number;
storage_label: string;
time_zone: string;
mp4_cloud: string;
snapshot_cloud: string;
table_version: string;
update_time: string;
}
export interface P2PDatabaseQueryLocalRecordCropPictureInfo {
picture_id: number;
record_id: number;
station_sn: string;
device_sn: string;
detection_type: number;
person_id: number;
crop_path: string;
event_time: string;
str_reserve: string;
person_recog_flag: boolean;
crop_pic_quality: number;
pic_marking_flag: boolean;
group_id: number;
int_reserve: number;
crop_id: number;
start_time: string;
reserve2_int: number;
reserve2_date: string;
reserve2_string: string;
storage_type: P2PStorageType;
storage_status: number;
storage_label: string;
table_version: string;
update_time: string;
}
export interface P2PDatabaseQueryLocalResponse {
payload: Array<P2PDatabaseQueryLocalHistoryRecordInfo> | Array<P2PDatabaseQueryLocalRecordCropPictureInfo>;
table_name: string;
}
export interface P2PDatabaseDeleteResponse {
failed_delete: Array<unknown>;
}
export interface P2PDatabaseResponse {
data: Array<P2PDatabaseQueryLatestInfoResponse> | Array<P2PDatabaseCountByDateResponse> | Array<P2PDatabaseQueryLocalResponse> | P2PDatabaseDeleteResponse;
start_id?: number;
end_id?: number;
count?: number;
transaction: string;
table: string;
cmd: number;
mIntRet: DatabaseReturnCode;
version: string;
msg: string;
}
export interface DatabaseQueryLatestInfoBase {
device_sn: string;
event_count: number;
}
export interface DatabaseQueryLatestInfoCloud extends DatabaseQueryLatestInfoBase {
crop_cloud_path: string;
}
export interface DatabaseQueryLatestInfoLocal extends DatabaseQueryLatestInfoBase {
crop_local_path: string;
}
export type DatabaseQueryLatestInfo = DatabaseQueryLatestInfoCloud | DatabaseQueryLatestInfoLocal;
export interface DatabaseCountByDate {
day: Date;
count: number;
}
export interface HistoryRecordInfo {
device_type: DeviceType;
account: string;
start_time: Date;
end_time: Date;
frame_num: number;
storage_type: P2PStorageType;
storage_cloud: boolean;
cipher_id: number;
vision: number;
video_type: VideoType;
has_lock: boolean;
automation_id: number;
trigger_type: TriggerType;
push_mode: number;
mic_status: MicStatus;
res_change: number;
res_best_width: number;
res_best_height: number;
self_learning: number;
storage_path: string;
thumb_path: string;
write_status: number;
cloud_path: string;
folder_size: number;
storage_status: number;
storage_label: string;
time_zone: string;
mp4_cloud: string;
snapshot_cloud: string;
table_version: string;
}
export interface CropPictureInfo {
picture_id: number;
detection_type: number;
person_id: number;
crop_path: string;
event_time: Date | null;
person_recog_flag: boolean;
crop_pic_quality: number;
pic_marking_flag: boolean;
group_id: number;
crop_id: number;
start_time: Date;
storage_type: P2PStorageType;
storage_status: number;
storage_label: string;
table_version: string;
update_time: string;
}
export interface DatabaseQueryLocal {
record_id: number;
station_sn: string;
device_sn?: string;
history: HistoryRecordInfo;
picture: Array<CropPictureInfo>;
}
export interface RGBColor {
red: number;
green: number;
blue: number;
}
export interface InternalColoredLighting {
color: number;
}
export interface DynamicLighting {
name: string;
mode: number;
speed: number;
colors: Array<RGBColor>;
}
export interface InternalDynamicLighting {
name: string;
mode: number;
id: number;
speed: number;
colors: Array<number>;
}
export interface MotionZonePoint {
x: number;
y: number;
}
export interface MotionZonePoints {
points: Array<MotionZonePoint>;
}
export interface MotionZone {
polygens: Array<MotionZonePoints>;
}
export interface VideoStreamingRecordingQuality {
mode_0: {
quality: number;
};
mode_1: {
quality: number;
};
cur_mode: number;
}
export interface CrossTrackingGroupEntry {
value: Array<string>;
}
export interface CustomDataType {
[index: number]: {
channel: number;
customData: CustomData;
timestamp: number;
};
}

3
build/p2p/interfaces.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=interfaces.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../src/p2p/interfaces.ts"],"names":[],"mappings":""}

284
build/p2p/models.d.ts vendored Normal file
View File

@ -0,0 +1,284 @@
import { PropertyValue } from "../http";
import { CommandName, PropertyName } from "../http/types";
import { SmartSafeEventValueDetail } from "../push/models";
import { CommandType } from "./types";
export interface Address {
host: string;
port: number;
}
export interface CmdCameraInfoResponse {
params: Array<{
dev_type: number;
param_type: number;
param_value: string;
}>;
main_sw_version: string;
sec_sw_version: string;
db_bypass_str?: Array<{
channel: number;
param_type: number;
param_value: string;
}>;
}
export interface PropertyData {
name: PropertyName;
value: PropertyValue;
}
export interface CommandData {
name: CommandName;
value?: any;
}
export interface CustomData {
property?: PropertyData;
command?: CommandData;
onSuccess?: () => void;
onFailure?: () => void;
}
export interface CommandResult {
customData?: CustomData;
command_type: CommandType;
channel: number;
return_code: number;
}
export interface CmdNotifyPayload {
cmd: number;
payload: ESLStationP2PThroughData | ESLAdvancedLockStatusNotification | SmartSafeSettingsNotification | SmartSafeStatusNotification | ESLBleV12P2PThroughData | EntrySensorStatus | GarageDoorStatus | StorageInfoHB3 | SmartLockP2PSequenceData | string;
payloadLen?: number;
}
export interface ESLStationP2PThroughData {
channel?: number;
lock_cmd: number;
lock_payload: string;
seq_num?: number;
stationSn?: string;
}
export interface ESLAdvancedLockStatusNotification {
code: number;
slBattery: string;
slState: string;
trigger: number;
}
export interface ESLAdvancedLockStatusNotificationT8530 extends ESLAdvancedLockStatusNotification {
slOpenDirection: string;
}
export interface SmartSafeSettingsNotification {
data: string;
prj_id: number;
}
export interface SmartSafeStatusNotification {
event_type: number;
event_time: number;
event_value: number | SmartSafeEventValueDetail;
}
export interface SmartSafeNotificationResponse {
versionCode: number;
commandCode: number;
packageFlag: number;
dataType: number;
responseCode: number;
data: Buffer;
}
export interface LockAdvancedOnOffRequestBasePayload {
shortUserId: string;
slOperation: number;
userId: string;
userName: string;
}
export interface LockAdvancedOnOffRequestPayload extends LockAdvancedOnOffRequestBasePayload {
seq_num: number;
}
export interface AdvancedLockSetParamsType {
[index: string]: unknown;
autoLockTime: number;
isAutoLock: number;
isLockNotification: number;
isNotification: number;
isOneTouchLock: number;
isSchedule: number;
isScramblePasscode: number;
isUnLockNotification: number;
isWrongTryProtect: number;
lockDownTime: number;
lockSound: number;
paramType: number;
scheduleEnd: string;
scheduleStart: string;
wrongTryTime: number;
seq_num: number;
}
export interface AdvancedLockSetParamsTypeT8520 {
[index: string]: unknown;
autoLockTime: number;
isAutoLock: number;
isLockNotification: number;
isNotification: number;
isOneTouchLock: number;
isSchedule: number;
isScramblePasscode: number;
isUnLockNotification: number;
isWrongTryProtect: number;
lockDownTime: number;
lockOpenDirection: number;
lockVolume: number;
nightVisionEnhance: number;
openLeftAlarmEnable: number;
openLeftAlarmScheduleEnd: string;
openLeftAlarmScheduleStart: string;
openLeftAlarmScheduled: number;
openLeftAlarmTimer: number;
openLeftAlarmWays: number;
paramType: number;
scheduleEnd: string;
scheduleStart: string;
tamperAlarmEnable: number;
tamperAlarmScheduleEnd: string;
tamperAlarmScheduleStart: string;
tamperAlarmScheduled: number;
tamperAlarmWays: number;
wrongTryTime: number;
}
export interface LockP2PCommandType {
commandType: CommandType;
value: string;
channel: number;
aesKey: string;
}
export interface LockP2PCommandPayloadType {
key: string;
account_id: string;
cmd: CommandType;
mChannel: number;
mValue3: number;
payload: string;
}
export interface ESLBleV12P2PThroughData {
dev_sn: string;
lock_payload: string;
}
export interface LockV12P2PCommandPayloadType {
account_id: string;
cmd: CommandType;
mChannel: number;
mValue3: number;
payload: {
apiCommand: number;
lock_payload: string;
seq_num: number;
};
}
export interface LockV12P2PCommandType {
commandType: CommandType;
value: string;
}
export interface SmartSafeP2PCommandPayloadType {
account_id: string;
cmd: CommandType;
mChannel: number;
mValue3: number;
payload: {
data: string;
prj_id: CommandType;
seq_num: number;
};
}
export interface SmartSafeP2PCommandType {
commandType: CommandType;
value: string;
channel: number;
}
export interface CmdDatabaseImageResponse {
file: string;
content: string;
}
export interface EntrySensorStatus {
status: number;
}
export interface GarageDoorStatus {
type: number;
notify_tag: string;
door_id: number;
}
export interface StorageInfoHB3 {
cmd: number;
version: number;
mIntRet: number;
msg: string;
old_storage_label: string;
cur_storage_label: string;
body: StorageInfoBodyHB3;
}
export interface StorageInfoBodyHB3 {
body_version: number;
storage_days: number;
storage_events: number;
con_video_hours: number;
format_transaction: string;
format_errcode: number;
hdd_info: StorageInfoHddHB3;
move_disk_info: StorageInfoMoveDiskInfoHB3;
emmc_info: StorageInfoEmmcHB3;
}
export interface StorageInfoHddHB3 {
serial_number: string;
disk_path: string;
disk_size: number;
system_size: number;
disk_used: number;
video_used: number;
video_size: number;
cur_temperate: number;
parted_status: number;
work_status: number;
hdd_label: string;
health: number;
device_module: string;
hdd_type: number;
}
export interface StorageInfoMoveDiskInfoHB3 {
disk_path: string;
disk_size: number;
disk_used: number;
part_layout_arr: string[];
data: string[];
}
export interface StorageInfoEmmcHB3 {
disk_nominal: number;
disk_size: number;
system_size: number;
disk_used: number;
data_used_percent: number;
swap_size: number;
video_size: number;
video_used: number;
data_partition_size: number;
eol_percent: number;
work_status: number;
health: number;
}
export interface SmartLockP2PCommandPayloadType {
account_id: string;
cmd: CommandType;
mChannel: number;
mValue3: number;
payload: {
apiCommand: number;
lock_payload: string;
seq_num: number;
time: number;
};
}
export interface SmartLockP2PCommandType {
commandType: CommandType;
value: string;
}
export interface SmartLockP2PThroughData {
dev_sn: string;
lock_payload: string;
time: string;
}
export interface SmartLockP2PSequenceData {
lock_cmd: number;
seq_num: number;
dev_sn: string;
bus_type?: number;
}

3
build/p2p/models.js Normal file
View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=models.js.map

1
build/p2p/models.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/p2p/models.ts"],"names":[],"mappings":""}

186
build/p2p/session.d.ts vendored Normal file
View File

@ -0,0 +1,186 @@
import { TypedEmitter } from "tiny-typed-emitter";
import * as NodeRSA from "node-rsa";
import { Address, CustomData } from "./models";
import { CommandType, P2PDataType, P2PConnectionType } from "./types";
import { P2PClientProtocolEvents, P2PCommand } from "./interfaces";
import { StationListResponse } from "../http/models";
import { HTTPApi } from "../http/api";
export declare class P2PClientProtocol extends TypedEmitter<P2PClientProtocolEvents> {
private readonly MAX_RETRIES;
private readonly MAX_COMMAND_RESULT_WAIT;
private readonly MAX_GATEWAY_COMMAND_RESULT_WAIT;
private readonly MAX_CONNECTION_TIMEOUT;
private readonly MAX_AKNOWLEDGE_TIMEOUT;
private readonly MAX_LOOKUP_TIMEOUT;
private readonly LOCAL_LOOKUP_RETRY_TIMEOUT;
private readonly LOOKUP_RETRY_TIMEOUT;
private readonly LOOKUP2_TIMEOUT;
private readonly LOOKUP2_RETRY_TIMEOUT;
private readonly MAX_EXPECTED_SEQNO_WAIT;
private readonly HEARTBEAT_INTERVAL;
private readonly MAX_COMMAND_QUEUE_TIMEOUT;
private readonly AUDIO_CODEC_ANALYZE_TIMEOUT;
private readonly KEEPALIVE_INTERVAL;
private readonly ESD_DISCONNECT_TIMEOUT;
private readonly MAX_STREAM_DATA_WAIT;
private readonly RESEND_NOT_ACKNOWLEDGED_COMMAND;
private readonly UDP_RECVBUFFERSIZE_BYTES;
private readonly MAX_PAYLOAD_BYTES;
private readonly MAX_PACKET_BYTES;
private readonly MAX_VIDEO_PACKET_BYTES;
private readonly P2P_DATA_HEADER_BYTES;
private readonly MAX_SEQUENCE_NUMBER;
private readonly LOOP_RUNAWAY_LIMIT;
private readonly SEQUENCE_PROCESSING_BOUNDARY;
private socket;
private binded;
private connected;
private connecting;
private terminating;
private p2pTurnHandshaking;
private p2pTurnConfirmed;
private seqNumber;
private offsetDataSeqNumber;
private videoSeqNumber;
private lockSeqNumber;
private expectedSeqNo;
private currentMessageBuilder;
private currentMessageState;
private talkbackStream?;
private downloadTotalBytes;
private downloadReceivedBytes;
private cloudAddresses;
private messageStates;
private messageVideoStates;
private sendQueue;
private connectTimeout?;
private lookupTimeout?;
private localLookupRetryTimeout?;
private lookupRetryTimeout?;
private lookup2Timeout?;
private lookup2RetryTimeout?;
private heartbeatTimeout?;
private keepaliveTimeout?;
private esdDisconnectTimeout?;
private secondaryCommandTimeout?;
private connectTime;
private lastPong;
private lastPongData;
private connectionType;
private energySavingDevice;
private p2pSeqMapping;
private p2pDataSeqNumber;
private connectAddress;
private localIPAddress;
private preferredIPAddress;
private listeningPort;
private dskKey;
private dskExpiration;
private deviceSNs;
private api;
private rawStation;
private customDataStaging;
private lockPublicKey;
private lockAESKeys;
private channel;
private encryption;
private p2pKey?;
private enableEmbeddedPKCS1Support;
constructor(rawStation: StationListResponse, api: HTTPApi, ipAddress?: string, listeningPort?: number, publicKey?: string, enableEmbeddedPKCS1Support?: boolean);
private _incrementSequence;
private _isBetween;
private _wasSequenceNumberAlreadyProcessed;
private _initialize;
private initializeMessageBuilder;
private initializeMessageState;
private _clearTimeout;
private _clearMessageStateTimeouts;
private _clearMessageVideoStateTimeouts;
private _clearHeartbeatTimeout;
private _clearKeepaliveTimeout;
private _clearConnectTimeout;
private _clearLookupTimeout;
private _clearLocalLookupRetryTimeout;
private _clearLookupRetryTimeout;
private _clearLookup2RetryTimeout;
private _clearLookup2Timeout;
private _clearESDDisconnectTimeout;
private _clearSecondaryCommandTimeout;
private sendMessage;
private _disconnected;
private closeEnergySavingDevice;
private renewDSKKey;
private localLookup;
private cloudLookup;
private cloudLookup2;
private cloudLookupWithTurnServer;
private localLookupByAddress;
private cloudLookupByAddress;
private cloudLookupByAddress2;
private cloudLookupByAddressWithTurnServer;
isConnected(): boolean;
private _startConnectTimeout;
private _connect;
private lookup;
connect(host?: string): Promise<void>;
private sendCamCheck;
private sendCamCheck2;
sendPing(address: Address): Promise<void>;
sendCommandWithIntString(p2pcommand: P2PCommand, customData?: CustomData): void;
sendCommandWithInt(p2pcommand: P2PCommand, customData?: CustomData): void;
sendCommandWithStringPayload(p2pcommand: P2PCommand, customData?: CustomData): void;
sendCommandWithString(p2pcommand: P2PCommand, customData?: CustomData): void;
sendCommandPing(channel?: number): void;
sendCommandDevicePing(channel?: number): void;
sendCommandWithoutData(commandType: CommandType, channel?: number): void;
private sendQueuedMessage;
private sendCommand;
private resendNotAcknowledgedCommand;
private _sendCommand;
private handleMsg;
private parseDataMessage;
private handleData;
private isIFrame;
private waitForStreamData;
private handleDataBinaryAndVideo;
private handleDataControl;
private sendAck;
private getDataType;
close(): Promise<void>;
private getHeartbeatInterval;
private onClose;
private onError;
private scheduleHeartbeat;
private scheduleP2PKeepalive;
getDownloadRSAPrivateKey(): NodeRSA;
setDownloadRSAPrivateKeyPem(pem: string): void;
getRSAPrivateKey(): NodeRSA | null;
private initializeStream;
private endStream;
private endRTSPStream;
private emitStreamStartEvent;
private emitStreamStopEvent;
isStreaming(channel: number, datatype: P2PDataType): boolean;
isLiveStreaming(channel: number): boolean;
private isCurrentlyStreaming;
isRTSPLiveStreaming(channel: number): boolean;
isDownloading(channel: number): boolean;
getLockSequenceNumber(): number;
incLockSequenceNumber(): number;
setConnectionType(type: P2PConnectionType): void;
getConnectionType(): P2PConnectionType;
isEnergySavingDevice(): boolean;
private getDSKKeys;
updateRawStation(value: StationListResponse): void;
private initializeTalkbackStream;
private sendTalkbackAudioFrame;
private onTalkbackStreamClose;
private onTalkbackStreamError;
private _sendVideoData;
isTalkbackOngoing(channel: number): boolean;
startTalkback(channel?: number): void;
stopTalkback(channel?: number): void;
setLockAESKey(commandCode: number, aesKey: string): void;
getLockAESKey(commandCode: number): string | undefined;
isConnecting(): boolean;
}

2678
build/p2p/session.js Normal file

File diff suppressed because it is too large Load Diff

1
build/p2p/session.js.map Normal file

File diff suppressed because one or more lines are too long

8
build/p2p/talkback.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
import { Transform } from "stream";
export declare class TalkbackStream extends Transform {
private isStreaming;
constructor();
_transform(data: Buffer, _encoding: string, callback: (err?: Error | null) => void): void;
startTalkback(): void;
stopTalkback(): void;
}

23
build/p2p/talkback.js Normal file
View File

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TalkbackStream = void 0;
const stream_1 = require("stream");
class TalkbackStream extends stream_1.Transform {
isStreaming = false;
constructor() {
super();
}
_transform(data, _encoding, callback) {
if (this.isStreaming)
this.push(data);
callback();
}
startTalkback() {
this.isStreaming = true;
}
stopTalkback() {
this.isStreaming = false;
}
}
exports.TalkbackStream = TalkbackStream;
//# sourceMappingURL=talkback.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"talkback.js","sourceRoot":"","sources":["../../src/p2p/talkback.ts"],"names":[],"mappings":";;;AAAA,mCAAmC;AAEnC,MAAa,cAAe,SAAQ,kBAAS;IAEjC,WAAW,GAAG,KAAK,CAAC;IAE5B;QACI,KAAK,EAAE,CAAC;IACZ,CAAC;IAED,UAAU,CAAC,IAAY,EAAE,SAAiB,EAAE,QAAsC;QAC9E,IAAG,IAAI,CAAC,WAAW;YACf,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,QAAQ,EAAE,CAAC;IACf,CAAC;IAEM,aAAa;QAChB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC5B,CAAC;IAEM,YAAY;QACf,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC7B,CAAC;CACJ;AArBD,wCAqBC"}

1164
build/p2p/types.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

1219
build/p2p/types.js Normal file

File diff suppressed because it is too large Load Diff

1
build/p2p/types.js.map Normal file

File diff suppressed because one or more lines are too long

72
build/p2p/utils.d.ts vendored Normal file
View File

@ -0,0 +1,72 @@
import { Socket } from "dgram";
import NodeRSA from "node-rsa";
import { P2PMessageParts, P2PMessageState, P2PQueueMessage, RGBColor } from "./interfaces";
import { CommandType, ESLCommand, LockV12P2PCommand, SmartSafeCommandCode, VideoCodec, EncryptionType, SmartLockP2PCommand, SmartLockFunctionType, SmartLockCommand } from "./types";
import { Address, LockP2PCommandType, SmartSafeNotificationResponse, SmartSafeP2PCommandType } from "./models";
import { DeviceType } from "../http/types";
export declare const MAGIC_WORD = "XZYH";
export declare const isPrivateIp: (ip: string) => boolean;
export declare const getLocalIpAddress: (init?: string) => string;
export declare const isP2PCommandEncrypted: (cmd: CommandType) => boolean;
export declare const getP2PCommandEncryptionKey: (serialNumber: string, p2pDid: string) => string;
export declare const encryptP2PData: (data: Buffer, key: Buffer) => Buffer;
export declare const decryptP2PData: (data: Buffer, key: Buffer) => Buffer;
export declare const paddingP2PData: (data: Buffer, blocksize?: number) => Buffer;
export declare const buildLookupWithKeyPayload: (socket: Socket, p2pDid: string, dskKey: string) => Buffer;
export declare const buildLookupWithKeyPayload2: (p2pDid: string, dskKey: string) => Buffer;
export declare const buildLookupWithKeyPayload3: (p2pDid: string, address: Address, data: Buffer) => Buffer;
export declare const buildCheckCamPayload: (p2pDid: string) => Buffer;
export declare const buildCheckCamPayload2: (p2pDid: string, data: Buffer) => Buffer;
export declare const buildIntCommandPayload: (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: number, strValue?: string, channel?: number) => Buffer;
export declare const buildStringTypeCommandPayload: (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, strValue: string, strValueSub: string, channel?: number) => Buffer;
export declare const buildIntStringCommandPayload: (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: number, valueSub?: number, strValue?: string, strValueSub?: string, channel?: number) => Buffer;
export declare const sendMessage: (socket: Socket, address: {
host: string;
port: number;
}, msgID: Buffer, payload?: Buffer) => Promise<number>;
export declare const hasHeader: (msg: Buffer, searchedType: Buffer) => boolean;
export declare const buildCommandHeader: (seqNumber: number, commandType: CommandType, p2pDataTypeHeader?: Buffer | null) => Buffer;
export declare const buildCommandWithStringTypePayload: (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: string, channel?: number) => Buffer;
export declare const sortP2PMessageParts: (messages: P2PMessageParts) => Buffer;
export declare const getRSAPrivateKey: (pem: string, enableEmbeddedPKCS1Support?: boolean) => NodeRSA;
export declare const getNewRSAPrivateKey: (enableEmbeddedPKCS1Support?: boolean) => NodeRSA;
export declare const decryptAESData: (hexkey: string, data: Buffer) => Buffer;
export declare const findStartCode: (data: Buffer) => boolean;
export declare const isIFrame: (data: Buffer) => boolean;
export declare const decryptLockAESData: (key: string, iv: string, data: Buffer) => Buffer;
export declare const encryptLockAESData: (key: string, iv: string, data: Buffer) => Buffer;
export declare const generateBasicLockAESKey: (adminID: string, stationSN: string) => string;
export declare const getCurrentTimeInSeconds: () => number;
export declare const generateLockSequence: (deviceType?: DeviceType, serialnumber?: string) => number;
export declare const encodeLockPayload: (data: string) => Buffer;
export declare const getLockVectorBytes: (data: string) => string;
export declare const decodeLockPayload: (data: Buffer) => string;
export declare const decodeBase64: (data: string) => Buffer;
export declare const eslTimestamp: (timestamp_in_sec?: number) => number[];
export declare const generateAdvancedLockAESKey: () => string;
export declare const getVideoCodec: (data: Buffer) => VideoCodec;
export declare const checkT8420: (serialNumber: string) => boolean;
export declare const buildVoidCommandPayload: (channel?: number) => Buffer;
export declare function isP2PQueueMessage(type: P2PQueueMessage | P2PMessageState): type is P2PQueueMessage;
export declare const encryptPayloadData: (data: string | Buffer, key: Buffer, iv: Buffer) => Buffer;
export declare const decryptPayloadData: (data: Buffer, key: Buffer, iv: Buffer) => Buffer;
export declare const eufyKDF: (key: Buffer) => Buffer;
export declare const getAdvancedLockKey: (key: string, publicKey: string) => string;
export declare const getLockV12Key: (key: string, publicKey: string) => string;
export declare const buildTalkbackAudioFrameHeader: (audioData: Buffer, channel?: number) => Buffer;
export declare const decodeP2PCloudIPs: (data: string) => Array<Address>;
export declare const decodeSmartSafeData: (deviceSN: string, data: Buffer) => SmartSafeNotificationResponse;
export declare const getSmartSafeP2PCommand: (deviceSN: string, user_id: string, command: CommandType, intCommand: SmartSafeCommandCode, channel: number, sequence: number, data: Buffer) => SmartSafeP2PCommandType;
export declare const getLockP2PCommand: (deviceSN: string, user_id: string, command: CommandType, channel: number, lockPublicKey: string, payload: any) => LockP2PCommandType;
export declare const getLockV12P2PCommand: (deviceSN: string, user_id: string, command: CommandType | ESLCommand, channel: number, lockPublicKey: string, sequence: number, data: Buffer) => LockV12P2PCommand;
export declare const DecimalToRGBColor: (color: number) => RGBColor;
export declare const RGBColorToDecimal: (color: RGBColor) => number;
export declare const getNullTerminatedString: (data: Buffer, encoding?: BufferEncoding) => string;
export declare const isUsbCharging: (value: number) => boolean;
export declare const isSolarCharging: (value: number) => boolean;
export declare const isPlugSolarCharging: (value: number) => boolean;
export declare const isCharging: (value: number) => boolean;
export declare const getSmartLockCurrentTimeInSeconds: () => number;
export declare const generateSmartLockAESKey: (adminUserId: string, time: number) => Buffer;
export declare const getSmartLockP2PCommand: (deviceSN: string, user_id: string, command: CommandType | SmartLockCommand, channel: number, sequence: number, data: Buffer, functionType?: SmartLockFunctionType) => SmartLockP2PCommand;
export declare const readNullTerminatedBuffer: (input: Buffer) => Buffer;

824
build/p2p/utils.js Normal file
View File

@ -0,0 +1,824 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLockP2PCommand = exports.getSmartSafeP2PCommand = exports.decodeSmartSafeData = exports.decodeP2PCloudIPs = exports.buildTalkbackAudioFrameHeader = exports.getLockV12Key = exports.getAdvancedLockKey = exports.eufyKDF = exports.decryptPayloadData = exports.encryptPayloadData = exports.buildVoidCommandPayload = exports.checkT8420 = exports.getVideoCodec = exports.generateAdvancedLockAESKey = exports.eslTimestamp = exports.decodeBase64 = exports.decodeLockPayload = exports.getLockVectorBytes = exports.encodeLockPayload = exports.generateLockSequence = exports.getCurrentTimeInSeconds = exports.generateBasicLockAESKey = exports.encryptLockAESData = exports.decryptLockAESData = exports.isIFrame = exports.findStartCode = exports.decryptAESData = exports.getNewRSAPrivateKey = exports.getRSAPrivateKey = exports.sortP2PMessageParts = exports.buildCommandWithStringTypePayload = exports.buildCommandHeader = exports.hasHeader = exports.sendMessage = exports.buildIntStringCommandPayload = exports.buildStringTypeCommandPayload = exports.buildIntCommandPayload = exports.buildCheckCamPayload2 = exports.buildCheckCamPayload = exports.buildLookupWithKeyPayload3 = exports.buildLookupWithKeyPayload2 = exports.buildLookupWithKeyPayload = exports.paddingP2PData = exports.decryptP2PData = exports.encryptP2PData = exports.getP2PCommandEncryptionKey = exports.isP2PCommandEncrypted = exports.getLocalIpAddress = exports.isPrivateIp = exports.MAGIC_WORD = void 0;
exports.readNullTerminatedBuffer = exports.getSmartLockP2PCommand = exports.generateSmartLockAESKey = exports.getSmartLockCurrentTimeInSeconds = exports.isCharging = exports.isPlugSolarCharging = exports.isSolarCharging = exports.isUsbCharging = exports.getNullTerminatedString = exports.RGBColorToDecimal = exports.DecimalToRGBColor = exports.getLockV12P2PCommand = void 0;
exports.isP2PQueueMessage = isP2PQueueMessage;
const node_rsa_1 = __importDefault(require("node-rsa"));
const CryptoJS = __importStar(require("crypto-js"));
const crypto_1 = require("crypto");
const os = __importStar(require("os"));
const types_1 = require("./types");
const device_1 = require("../http/device");
const ble_1 = require("./ble");
const logging_1 = require("../logging");
exports.MAGIC_WORD = "XZYH";
const isPrivateIp = (ip) => /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^f[cd][0-9a-f]{2}:/i.test(ip) ||
/^fe80:/i.test(ip) ||
/^::1$/.test(ip) ||
/^::$/.test(ip);
exports.isPrivateIp = isPrivateIp;
const stringWithLength = (input, chunkLength = 128) => {
const stringAsBuffer = Buffer.from(input);
const bufferSize = stringAsBuffer.byteLength < chunkLength ? chunkLength : Math.ceil(stringAsBuffer.byteLength / chunkLength) * chunkLength;
const result = Buffer.alloc(bufferSize);
stringAsBuffer.copy(result);
return result;
};
const getLocalIpAddress = (init = "") => {
const ifaces = os.networkInterfaces();
let localAddress = init;
for (const name in ifaces) {
const iface = ifaces[name].filter(function (details) {
return details.family === "IPv4" && details.internal === false;
});
if (iface.length > 0) {
localAddress = iface[0].address;
break;
}
}
return localAddress;
};
exports.getLocalIpAddress = getLocalIpAddress;
const p2pDidToBuffer = (p2pDid) => {
const p2pArray = p2pDid.split("-");
const buf1 = stringWithLength(p2pArray[0], 8);
const buf2 = Buffer.allocUnsafe(4);
buf2.writeUInt32BE(Number.parseInt(p2pArray[1]), 0);
const buf3 = stringWithLength(p2pArray[2], 8);
return Buffer.concat([buf1, buf2, buf3], 20);
};
const isP2PCommandEncrypted = function (cmd) {
return [1001, 1002, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1015, 1017, 1019, 1035, 1045, 1056, 1145, 1146, 1152, 1200, 1207, 1210, 1213, 1214, 1226, 1227, 1229, 1230, 1233, 1236, 1240, 1241, 1243, 1246, 1272, 1273, 1275, 1400, 1401, 1402, 1403, 1408, 1409, 1410, 1412, 1413, 1506, 1507, 1607, 1609, 1610, 1611, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1013, 1202, 1205, 1206, 1024, 1025, 1132, 1215, 1216, 1217, 1414, 1026, 1164, 1201, 1027, 1047, 1048, 1029, 1034, 1036, 1043, 1057, 1203, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1232, 1234, 1235, 1237, 1238, 1248, 1253, 1257, 1269, 1800, 1037, 1040, 1038, 1049, 1050, 1051, 1054, 1060, 1204, 1254, 1255, 1256, 1258, 1259, 1260, 1261, 1262, 1264, 1271, 1350, 1404, 1101, 1106, 1108, 1110, 1111, 1112, 1113, 1114, 1116, 1117, 1118, 1119, 1121, 1103, 1129, 1211, 1228, 1231, 1242, 1249, 1250, 1251, 1252, 1405, 1406, 1407, 1700].includes(cmd);
};
exports.isP2PCommandEncrypted = isP2PCommandEncrypted;
const getP2PCommandEncryptionKey = function (serialNumber, p2pDid) {
return `${serialNumber.slice(-7)}${p2pDid.substring(p2pDid.indexOf("-"), p2pDid.indexOf("-") + 9)}`;
};
exports.getP2PCommandEncryptionKey = getP2PCommandEncryptionKey;
const encryptP2PData = (data, key) => {
const cipher = (0, crypto_1.createCipheriv)("aes-128-ecb", key, null);
cipher.setAutoPadding(false);
return Buffer.concat([
cipher.update(data),
cipher.final()
]);
};
exports.encryptP2PData = encryptP2PData;
const decryptP2PData = (data, key) => {
const decipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", key, null);
decipher.setAutoPadding(false);
return Buffer.concat([
decipher.update(data),
decipher.final()
]);
};
exports.decryptP2PData = decryptP2PData;
const paddingP2PData = (data, blocksize = 16) => {
const bufferSize = data.byteLength < blocksize ? blocksize : Math.ceil(data.byteLength / blocksize) * blocksize;
const result = Buffer.alloc(bufferSize);
data.copy(result);
return result;
};
exports.paddingP2PData = paddingP2PData;
const buildLookupWithKeyPayload = (socket, p2pDid, dskKey) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const addressInfo = socket.address();
const port = addressInfo.port;
const portAsBuffer = Buffer.allocUnsafe(2);
portAsBuffer.writeUInt16LE(port, 0);
//const ip = socket.address().address;
const ip = (0, exports.getLocalIpAddress)(addressInfo.address);
const temp_buff = [];
ip.split(".").reverse().forEach(element => {
temp_buff.push(Number.parseInt(element));
});
const ipAsBuffer = Buffer.from(temp_buff);
const splitter = Buffer.from([0x00, 0x02]);
const magic = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00]);
const dskKeyAsBuffer = Buffer.from(dskKey);
const fourEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00]);
return Buffer.concat([p2pDidBuffer, splitter, portAsBuffer, ipAsBuffer, magic, dskKeyAsBuffer, fourEmpty]);
};
exports.buildLookupWithKeyPayload = buildLookupWithKeyPayload;
const buildLookupWithKeyPayload2 = (p2pDid, dskKey) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const dskKeyAsBuffer = Buffer.from(dskKey);
const fourEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00]);
return Buffer.concat([p2pDidBuffer, dskKeyAsBuffer, fourEmpty]);
};
exports.buildLookupWithKeyPayload2 = buildLookupWithKeyPayload2;
const buildLookupWithKeyPayload3 = (p2pDid, address, data) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const portAsBuffer = Buffer.allocUnsafe(2);
portAsBuffer.writeUInt16LE(address.port, 0);
const temp_buff = [];
address.host.split(".").reverse().forEach(element => {
temp_buff.push(Number.parseInt(element));
});
const ipAsBuffer = Buffer.from(temp_buff);
const splitter = Buffer.from([0x00, 0x02]);
const eightEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
return Buffer.concat([p2pDidBuffer, splitter, portAsBuffer, ipAsBuffer, eightEmpty, data]);
};
exports.buildLookupWithKeyPayload3 = buildLookupWithKeyPayload3;
const buildCheckCamPayload = (p2pDid) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const magic = Buffer.from([0x00, 0x00, 0x00]);
return Buffer.concat([p2pDidBuffer, magic]);
};
exports.buildCheckCamPayload = buildCheckCamPayload;
const buildCheckCamPayload2 = (p2pDid, data) => {
const p2pDidBuffer = p2pDidToBuffer(p2pDid);
const magic = Buffer.from([0x00, 0x00, 0x00, 0x00]);
return Buffer.concat([data, p2pDidBuffer, magic]);
};
exports.buildCheckCamPayload2 = buildCheckCamPayload2;
const buildIntCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, strValue = "", channel = 255) => {
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
const valueBuffer = Buffer.allocUnsafe(4);
valueBuffer.writeUInt32LE(value, 0);
const headerBuffer = Buffer.allocUnsafe(2);
const strValueBuffer = strValue.length === 0 ? Buffer.from([]) : stringWithLength(strValue);
const tmpDataBuffer = Buffer.concat([
valueBuffer,
strValueBuffer
]);
const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
headerBuffer.writeUInt16LE(dataBuffer.length, 0);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer,
encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer
]);
};
exports.buildIntCommandPayload = buildIntCommandPayload;
const buildStringTypeCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, strValue, strValueSub, channel = 255) => {
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
const someBuffer = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00]);
const strValueBuffer = stringWithLength(strValue);
const strValueSubBuffer = stringWithLength(strValueSub);
const headerBuffer = Buffer.allocUnsafe(2);
const tmpDataBuffer = Buffer.concat([
someBuffer,
strValueBuffer,
strValueSubBuffer
]);
const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
headerBuffer.writeUInt16LE(dataBuffer.length, 0);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer,
encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer
]);
};
exports.buildStringTypeCommandPayload = buildStringTypeCommandPayload;
const buildIntStringCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, valueSub = 0, strValue = "", strValueSub = "", channel = 0) => {
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
const someintBuffer = Buffer.allocUnsafe(4);
someintBuffer.writeUInt32LE(valueSub, 0);
const valueBuffer = Buffer.allocUnsafe(4);
valueBuffer.writeUInt32LE(value, 0);
const strValueBuffer = strValue.length === 0 ? Buffer.from([]) : stringWithLength(strValue);
const strValueSubBuffer = strValueSub.length === 0 ? Buffer.from([]) : stringWithLength(strValueSub);
const headerBuffer = Buffer.allocUnsafe(2);
const tmpDataBuffer = Buffer.concat([
someintBuffer,
valueBuffer,
strValueBuffer,
strValueSubBuffer
]);
const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
headerBuffer.writeUInt16LE(dataBuffer.length, 0);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer,
encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer
]);
};
exports.buildIntStringCommandPayload = buildIntStringCommandPayload;
const sendMessage = async (socket, address, msgID, payload) => {
if (!payload)
payload = Buffer.from([]);
const payloadLen = Buffer.allocUnsafe(2);
payloadLen.writeUInt16BE(payload.length, 0);
const message = Buffer.concat([msgID, payloadLen, payload], 4 + payload.length);
return new Promise((resolve, reject) => {
socket.send(message, address.port, address.host, (err, bytes) => {
return err ? reject(err) : resolve(bytes);
});
});
};
exports.sendMessage = sendMessage;
const hasHeader = (msg, searchedType) => {
const header = Buffer.allocUnsafe(2);
msg.copy(header, 0, 0, 2);
return Buffer.compare(header, searchedType) === 0;
};
exports.hasHeader = hasHeader;
const buildCommandHeader = (seqNumber, commandType, p2pDataTypeHeader = null) => {
let dataTypeBuffer = types_1.P2PDataTypeHeader.DATA;
if (p2pDataTypeHeader !== null &&
(Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.DATA) === 0 ||
Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.BINARY) === 0 ||
Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.CONTROL) === 0 ||
Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.VIDEO) === 0)) {
dataTypeBuffer = p2pDataTypeHeader;
}
const seqAsBuffer = Buffer.allocUnsafe(2);
seqAsBuffer.writeUInt16BE(seqNumber, 0);
const magicString = Buffer.from(exports.MAGIC_WORD);
const commandTypeBuffer = Buffer.allocUnsafe(2);
commandTypeBuffer.writeUInt16LE(commandType, 0);
return Buffer.concat([dataTypeBuffer, seqAsBuffer, magicString, commandTypeBuffer]);
};
exports.buildCommandHeader = buildCommandHeader;
const buildCommandWithStringTypePayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, channel = 0) => {
const headerBuffer = Buffer.allocUnsafe(2);
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
const dataBuffer = encrypted ? (0, exports.paddingP2PData)(Buffer.from(value)) : Buffer.from(value);
headerBuffer.writeUInt16LE(dataBuffer.length, 0);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer,
encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer
]);
};
exports.buildCommandWithStringTypePayload = buildCommandWithStringTypePayload;
const sortP2PMessageParts = (messages) => {
let completeMessage = Buffer.from([]);
Object.keys(messages).map(Number)
.sort((a, b) => {
if (Math.abs(a - b) > 65000) {
if (a < b) {
return 1;
}
else if (b < a) {
return -1;
}
}
return a - b;
}) // assure the seqNumbers are in correct order
.forEach((key) => {
completeMessage = Buffer.concat([completeMessage, messages[key]]);
});
return completeMessage;
};
exports.sortP2PMessageParts = sortP2PMessageParts;
const getRSAPrivateKey = (pem, enableEmbeddedPKCS1Support = false) => {
const key = new node_rsa_1.default();
if (pem.indexOf("\n") !== -1) {
pem = pem.replaceAll("\n", "");
}
if (pem.startsWith("-----BEGIN RSA PRIVATE KEY-----")) {
pem = pem.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "");
}
key.importKey(pem, "pkcs8");
const options = {
encryptionScheme: "pkcs1"
};
if (enableEmbeddedPKCS1Support) {
options.environment = "browser";
}
key.setOptions(options);
return key;
};
exports.getRSAPrivateKey = getRSAPrivateKey;
const getNewRSAPrivateKey = (enableEmbeddedPKCS1Support = false) => {
const key = new node_rsa_1.default({ b: 1024 });
const options = {
encryptionScheme: "pkcs1"
};
if (enableEmbeddedPKCS1Support) {
options.environment = "browser";
}
key.setOptions(options);
return key;
};
exports.getNewRSAPrivateKey = getNewRSAPrivateKey;
const decryptAESData = (hexkey, data) => {
const key = CryptoJS.enc.Hex.parse(hexkey);
const cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext: CryptoJS.enc.Hex.parse(data.toString("hex"))
});
const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.NoPadding
});
return Buffer.from(CryptoJS.enc.Hex.stringify(decrypted), "hex");
};
exports.decryptAESData = decryptAESData;
const findStartCode = (data) => {
if (data !== undefined && data.length > 0) {
if (data.length >= 4) {
const startcode = [...data.subarray(0, 4)];
if ((startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 1) || (startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 0 && startcode[3] === 1))
return true;
}
else if (data.length === 3) {
const startcode = [...data.subarray(0, 3)];
if ((startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 1))
return true;
}
}
return false;
};
exports.findStartCode = findStartCode;
const isIFrame = (data) => {
const validValues = [64, 66, 68, 78, 101, 103];
if (data !== undefined && data.length > 0) {
if (data.length >= 5) {
const startcode = [...data.subarray(0, 5)];
if (validValues.includes(startcode[3]) || validValues.includes(startcode[4]))
return true;
}
}
return false;
};
exports.isIFrame = isIFrame;
const decryptLockAESData = (key, iv, data) => {
const ekey = CryptoJS.enc.Hex.parse(key);
const eiv = CryptoJS.enc.Hex.parse(iv);
const cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext: CryptoJS.enc.Hex.parse(data.toString("hex"))
});
const decrypted = CryptoJS.AES.decrypt(cipherParams, ekey, {
iv: eiv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return Buffer.from(CryptoJS.enc.Hex.stringify(decrypted), "hex");
};
exports.decryptLockAESData = decryptLockAESData;
const encryptLockAESData = (key, iv, data) => {
const ekey = CryptoJS.enc.Hex.parse(key);
const eiv = CryptoJS.enc.Hex.parse(iv);
const encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(data.toString("hex")), ekey, {
iv: eiv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return Buffer.from(CryptoJS.enc.Hex.stringify(encrypted.ciphertext), "hex");
};
exports.encryptLockAESData = encryptLockAESData;
const generateBasicLockAESKey = (adminID, stationSN) => {
const encoder = new TextEncoder();
const encOwnerID = encoder.encode(adminID);
const encStationSerial = encoder.encode(stationSN);
const array = [104, -83, -72, 38, -107, 99, -110, 17, -95, -121, 54, 57, -46, -98, -111, 89];
for (let i = 0; i < 16; i++) {
array[i] = (array[i] + encStationSerial[((encStationSerial[i] * 3) + 5) % 16] + encOwnerID[((encOwnerID[i] * 3) + 5) % 40]);
}
return Buffer.from(array).toString("hex");
};
exports.generateBasicLockAESKey = generateBasicLockAESKey;
const getCurrentTimeInSeconds = function () {
return Math.trunc(new Date().getTime() / 1000);
};
exports.getCurrentTimeInSeconds = getCurrentTimeInSeconds;
const generateLockSequence = (deviceType, serialnumber) => {
if (deviceType !== undefined && serialnumber !== undefined)
if (device_1.Device.isLockWifi(deviceType, serialnumber) || device_1.Device.isLockWifiNoFinger(deviceType))
return Math.trunc(Math.random() * 1000);
return (0, exports.getCurrentTimeInSeconds)();
};
exports.generateLockSequence = generateLockSequence;
const encodeLockPayload = (data) => {
const encoder = new TextEncoder();
const encData = encoder.encode(data);
const length = encData.length;
const old_buffer = Buffer.from(encData);
if (length % 16 == 0) {
return old_buffer;
}
const new_length = (Math.trunc(length / 16) + 1) * 16;
const new_buffer = Buffer.alloc(new_length);
old_buffer.copy(new_buffer, 0);
return new_buffer;
};
exports.encodeLockPayload = encodeLockPayload;
const getLockVectorBytes = (data) => {
const encoder = new TextEncoder();
const encData = encoder.encode(data);
const old_buffer = Buffer.from(encData);
if (encData.length >= 16)
return old_buffer.toString("hex");
const new_buffer = Buffer.alloc(16);
old_buffer.copy(new_buffer, 0);
return new_buffer.toString("hex");
};
exports.getLockVectorBytes = getLockVectorBytes;
const decodeLockPayload = (data) => {
const decoder = new TextDecoder();
return decoder.decode(data);
};
exports.decodeLockPayload = decodeLockPayload;
const decodeBase64 = (data) => {
const base64RegExp = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/;
if (base64RegExp.test(data))
return Buffer.from(data, "base64");
return Buffer.from(data);
};
exports.decodeBase64 = decodeBase64;
const eslTimestamp = function (timestamp_in_sec = new Date().getTime() / 1000) {
const array = [];
for (let pos = 0; pos < 4; pos++) {
array[pos] = ((timestamp_in_sec >> (pos * 8)) & 255);
}
return array;
};
exports.eslTimestamp = eslTimestamp;
const generateAdvancedLockAESKey = () => {
const randomBytesArray = [...(0, crypto_1.randomBytes)(16)];
let result = "";
for (let pos = 0; pos < randomBytesArray.length; pos++) {
result += "0123456789ABCDEF".charAt((randomBytesArray[pos] >> 4) & 15);
result += "0123456789ABCDEF".charAt(randomBytesArray[pos] & 15);
}
return result;
};
exports.generateAdvancedLockAESKey = generateAdvancedLockAESKey;
const getVideoCodec = (data) => {
if (data !== undefined && data.length > 0) {
if (data.length >= 5) {
const h265Values = [38, 64, 66, 68, 78];
const startcode = [...data.subarray(0, 5)];
if (h265Values.includes(startcode[3]) || h265Values.includes(startcode[4])) {
return types_1.VideoCodec.H265;
}
else if (startcode[3] === 103 || startcode[4] === 103) {
return types_1.VideoCodec.H264;
}
}
return types_1.VideoCodec.H264;
}
return types_1.VideoCodec.UNKNOWN; // Maybe return h264 as Eufy does?
};
exports.getVideoCodec = getVideoCodec;
const checkT8420 = (serialNumber) => {
if (!(serialNumber !== undefined && serialNumber !== null && serialNumber.length > 0 && serialNumber.startsWith("T8420")) || serialNumber.length <= 7 || serialNumber[6] != "6") {
return false;
}
return true;
};
exports.checkT8420 = checkT8420;
const buildVoidCommandPayload = (channel = 255) => {
const headerBuffer = Buffer.from([0x00, 0x00]);
const emptyBuffer = Buffer.from([0x00, 0x00]);
const magicBuffer = Buffer.from([0x01, 0x00]);
const channelBuffer = Buffer.from([channel, 0x00]);
return Buffer.concat([
headerBuffer,
emptyBuffer,
magicBuffer,
channelBuffer,
emptyBuffer
]);
};
exports.buildVoidCommandPayload = buildVoidCommandPayload;
function isP2PQueueMessage(type) {
return type.p2pCommand !== undefined;
}
const encryptPayloadData = (data, key, iv) => {
const cipher = (0, crypto_1.createCipheriv)("aes-128-cbc", key, iv);
return Buffer.concat([
cipher.update(data),
cipher.final()
]);
};
exports.encryptPayloadData = encryptPayloadData;
const decryptPayloadData = (data, key, iv) => {
const cipher = (0, crypto_1.createDecipheriv)("aes-128-cbc", key, iv);
return Buffer.concat([
cipher.update(data),
cipher.final()
]);
};
exports.decryptPayloadData = decryptPayloadData;
const eufyKDF = (key) => {
const hash_length = 32;
const digest_length = 48;
const staticBuffer = Buffer.from("ECIES");
const steps = Math.ceil(digest_length / hash_length);
const buffer = Buffer.alloc(hash_length * steps);
let tmpBuffer = staticBuffer;
for (let step = 0; step < steps; ++step) {
tmpBuffer = (0, crypto_1.createHmac)("sha256", key).update(tmpBuffer).digest();
const digest = (0, crypto_1.createHmac)("sha256", key).update(Buffer.concat([tmpBuffer, staticBuffer])).digest();
digest.copy(buffer, hash_length * step);
}
return buffer.subarray(0, digest_length);
};
exports.eufyKDF = eufyKDF;
const getAdvancedLockKey = (key, publicKey) => {
const ecdh = (0, crypto_1.createECDH)("prime256v1");
ecdh.generateKeys();
const secret = ecdh.computeSecret(Buffer.concat([Buffer.from("04", "hex"), Buffer.from(publicKey, "hex")]));
const randomValue = (0, crypto_1.randomBytes)(16);
const derivedKey = (0, exports.eufyKDF)(secret);
const encryptedData = (0, exports.encryptPayloadData)(key, derivedKey.subarray(0, 16), randomValue);
const hmac = (0, crypto_1.createHmac)("sha256", derivedKey.subarray(16));
hmac.update(randomValue);
hmac.update(encryptedData);
const hmacDigest = hmac.digest();
return Buffer.concat([Buffer.from(ecdh.getPublicKey("hex", "compressed"), "hex"), randomValue, encryptedData, hmacDigest]).toString("hex");
};
exports.getAdvancedLockKey = getAdvancedLockKey;
const getLockV12Key = (key, publicKey) => {
const ecdh = (0, crypto_1.createECDH)("prime256v1");
ecdh.generateKeys();
const secret = ecdh.computeSecret(Buffer.concat([Buffer.from("04", "hex"), Buffer.from(publicKey, "hex")]));
const randomValue = (0, crypto_1.randomBytes)(16);
const derivedKey = (0, exports.eufyKDF)(secret);
const encryptedData = (0, exports.encryptPayloadData)(Buffer.from(key, "hex"), derivedKey.subarray(0, 16), randomValue);
const hmac = (0, crypto_1.createHmac)("sha256", derivedKey.subarray(16));
hmac.update(randomValue);
hmac.update(encryptedData);
const hmacDigest = hmac.digest();
return Buffer.concat([Buffer.from(ecdh.getPublicKey("hex", "compressed"), "hex"), randomValue, encryptedData, hmacDigest]).toString("hex");
};
exports.getLockV12Key = getLockV12Key;
const buildTalkbackAudioFrameHeader = (audioData, channel = 0) => {
const audioDataLength = Buffer.allocUnsafe(4);
audioDataLength.writeUInt32LE(audioData.length);
const unknown1 = Buffer.alloc(1);
const audioType = Buffer.alloc(1);
const audioSeq = Buffer.alloc(2);
const audioTimestamp = Buffer.alloc(8);
const audioDataHeader = Buffer.concat([audioDataLength, unknown1, audioType, audioSeq, audioTimestamp]);
const bytesToRead = Buffer.allocUnsafe(4);
bytesToRead.writeUInt32LE(audioData.length + audioDataHeader.length);
const magicBuffer = Buffer.from([0x01, 0x00]);
const channelBuffer = Buffer.from([channel, 0x00]);
const emptyBuffer = Buffer.from([0x00, 0x00]);
return Buffer.concat([
bytesToRead,
magicBuffer,
channelBuffer,
emptyBuffer,
audioDataHeader
]);
};
exports.buildTalkbackAudioFrameHeader = buildTalkbackAudioFrameHeader;
const decodeP2PCloudIPs = (data) => {
const lookupTable = Buffer.from("4959433db5bf6da347534f6165e371e9677f02030badb3892b2f35c16b8b959711e5a70deff1050783fb9d3bc5c713171d1f2529d3df", "hex");
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [encoded, name = "name not included"] = data.split(":");
const output = Buffer.alloc(encoded.length / 2);
for (let i = 0; i <= data.length / 2; i++) {
let z = 0x39; // 57 // '9'
for (let j = 0; j < i; j++) {
z = z ^ output[j];
}
const x = (data.charCodeAt(i * 2 + 1) - "A".charCodeAt(0));
const y = (data.charCodeAt(i * 2) - "A".charCodeAt(0)) * 0x10;
output[i] = z ^ lookupTable[i % lookupTable.length] ^ x + y;
}
const result = [];
output.toString("utf8").split(",").forEach((ip) => {
if (ip !== "") {
result.push({ host: ip, port: 32100 });
}
});
return result;
};
exports.decodeP2PCloudIPs = decodeP2PCloudIPs;
const decodeSmartSafeData = function (deviceSN, data) {
const response = ble_1.BleCommandFactory.parseSmartSafe(data);
return {
versionCode: response.getVersionCode(),
dataType: response.getDataType(),
commandCode: response.getCommandCode(),
packageFlag: response.getPackageFlag(),
responseCode: response.getResponseCode(),
data: (0, exports.decryptPayloadData)(response.getData(), Buffer.from(deviceSN), Buffer.from(device_1.SmartSafe.IV, "hex"))
};
};
exports.decodeSmartSafeData = decodeSmartSafeData;
const getSmartSafeP2PCommand = function (deviceSN, user_id, command, intCommand, channel, sequence, data) {
const encPayload = (0, exports.encryptPayloadData)(data, Buffer.from(deviceSN), Buffer.from(device_1.SmartSafe.IV, "hex"));
const bleCommand = new ble_1.BleCommandFactory()
.setVersionCode(device_1.SmartSafe.VERSION_CODE)
.setCommandCode(intCommand)
.setDataType(-1)
.setData(encPayload)
.getSmartSafeCommand();
logging_1.rootP2PLogger.debug(`Generate smart safe command`, { deviceSN: deviceSN, userId: user_id, command: command, intCommand: intCommand, channel: channel, sequence: sequence, data: data.toString("hex") });
return {
commandType: types_1.CommandType.CMD_SET_PAYLOAD,
value: JSON.stringify({
account_id: user_id,
cmd: command,
mChannel: channel,
mValue3: 0,
payload: {
data: bleCommand.toString("hex"),
prj_id: command,
seq_num: sequence,
}
}),
channel: channel
};
};
exports.getSmartSafeP2PCommand = getSmartSafeP2PCommand;
const getLockP2PCommand = function (deviceSN, user_id, command, channel, lockPublicKey, payload) {
const key = (0, exports.generateAdvancedLockAESKey)();
const ecdhKey = (0, exports.getAdvancedLockKey)(key, lockPublicKey);
const iv = (0, exports.getLockVectorBytes)(deviceSN);
const encPayload = (0, exports.encryptLockAESData)(key, iv, Buffer.from(JSON.stringify(payload)));
logging_1.rootP2PLogger.debug(`Generate lock command`, { deviceSN: deviceSN, userId: user_id, command: command, channel: channel, data: JSON.stringify(payload) });
return {
commandType: types_1.CommandType.CMD_SET_PAYLOAD,
value: JSON.stringify({
key: ecdhKey,
account_id: user_id,
cmd: command,
mChannel: channel,
mValue3: 0,
payload: encPayload.toString("base64")
}).replace(/=/g, "\\u003d"),
channel: channel,
aesKey: key
};
};
exports.getLockP2PCommand = getLockP2PCommand;
const getLockV12P2PCommand = function (deviceSN, user_id, command, channel, lockPublicKey, sequence, data) {
const key = (0, exports.generateAdvancedLockAESKey)();
const encryptedAesKey = (0, exports.getLockV12Key)(key, lockPublicKey);
const iv = (0, exports.getLockVectorBytes)(deviceSN);
const encPayload = (0, exports.encryptPayloadData)(data, Buffer.from(key, "hex"), Buffer.from(iv, "hex"));
logging_1.rootP2PLogger.debug(`Generate smart lock v12 command`, { deviceSN: deviceSN, userId: user_id, command: command, channel: channel, sequence: sequence, data: data.toString("hex") });
const bleCommand = new ble_1.BleCommandFactory()
.setVersionCode(device_1.Lock.VERSION_CODE_LOCKV12)
.setCommandCode(Number.parseInt(types_1.ESLBleCommand[types_1.ESLCommand[command]])) //TODO: Change internal command identification?
.setDataType(-1)
.setData(encPayload)
.setAdditionalData(Buffer.from(encryptedAesKey, "hex"));
return {
aesKey: key,
bleCommand: bleCommand.getCommandCode(),
payload: {
commandType: types_1.CommandType.CMD_SET_PAYLOAD,
value: JSON.stringify({
account_id: user_id,
cmd: types_1.CommandType.CMD_SET_PAYLOAD_LOCKV12,
mChannel: channel,
mValue3: 0,
payload: {
apiCommand: command,
lock_payload: bleCommand.getLockV12Command().toString("hex"),
seq_num: sequence,
}
})
}
};
};
exports.getLockV12P2PCommand = getLockV12P2PCommand;
const DecimalToRGBColor = function (color) {
return {
red: (color >> 16) & 0xff,
green: (color >> 8) & 0xff,
blue: color & 0xff,
};
};
exports.DecimalToRGBColor = DecimalToRGBColor;
const RGBColorToDecimal = function (color) {
return (color.red << 16) + (color.green << 8) + (color.blue);
};
exports.RGBColorToDecimal = RGBColorToDecimal;
const getNullTerminatedString = function (data, encoding) {
const index = data.indexOf(0);
return data.toString(encoding, 0, index === -1 ? data.length : index);
};
exports.getNullTerminatedString = getNullTerminatedString;
const isUsbCharging = function (value) {
return (value & 1) == 1;
};
exports.isUsbCharging = isUsbCharging;
const isSolarCharging = function (value) {
return ((value >> 2) & 1) == 1;
};
exports.isSolarCharging = isSolarCharging;
const isPlugSolarCharging = function (value) {
return ((value >> 3) & 1) == 1;
};
exports.isPlugSolarCharging = isPlugSolarCharging;
const isCharging = function (value) {
return (0, exports.isUsbCharging)(value) || (0, exports.isSolarCharging)(value) || (0, exports.isPlugSolarCharging)(value);
};
exports.isCharging = isCharging;
const getSmartLockCurrentTimeInSeconds = function () {
return Math.trunc(new Date().getTime() / 1000) | Math.trunc(Math.random() * 100);
};
exports.getSmartLockCurrentTimeInSeconds = getSmartLockCurrentTimeInSeconds;
const generateSmartLockAESKey = (adminUserId, time) => {
const buffer = Buffer.allocUnsafe(4);
buffer.writeUint32BE(time);
return Buffer.concat([Buffer.from(adminUserId.substring(adminUserId.length - 12)), buffer]);
};
exports.generateSmartLockAESKey = generateSmartLockAESKey;
const getSmartLockP2PCommand = function (deviceSN, user_id, command, channel, sequence, data, functionType = types_1.SmartLockFunctionType.TYPE_2) {
const time = (0, exports.getSmartLockCurrentTimeInSeconds)();
const key = (0, exports.generateSmartLockAESKey)(user_id, time);
const iv = (0, exports.getLockVectorBytes)(deviceSN);
const encPayload = (0, exports.encryptPayloadData)(data, key, Buffer.from(iv, "hex"));
logging_1.rootP2PLogger.debug(`Generate smart lock command`, { deviceSN: deviceSN, userId: user_id, command: command, channel: channel, sequence: sequence, data: data.toString("hex"), functionType: functionType });
let commandCode = 0;
if (functionType === types_1.SmartLockFunctionType.TYPE_1) {
commandCode = Number.parseInt(types_1.SmartLockBleCommandFunctionType1[types_1.SmartLockCommand[command]]);
}
else if (functionType === types_1.SmartLockFunctionType.TYPE_2) {
commandCode = Number.parseInt(types_1.SmartLockBleCommandFunctionType2[types_1.SmartLockCommand[command]]);
}
const bleCommand = new ble_1.BleCommandFactory()
.setVersionCode(device_1.Lock.VERSION_CODE_SMART_LOCK)
.setCommandCode(commandCode)
.setDataType(functionType)
.setData(encPayload);
return {
bleCommand: bleCommand.getCommandCode(),
payload: {
commandType: types_1.CommandType.CMD_SET_PAYLOAD,
value: JSON.stringify({
account_id: user_id,
cmd: types_1.CommandType.CMD_TRANSFER_PAYLOAD,
mChannel: channel,
mValue3: 0,
payload: {
apiCommand: command,
lock_payload: bleCommand.getSmartLockCommand().toString("hex"),
seq_num: sequence,
time: time,
}
})
}
};
};
exports.getSmartLockP2PCommand = getSmartLockP2PCommand;
const readNullTerminatedBuffer = (input) => {
const index = input.indexOf(new Uint8Array([0]));
if (index === -1) {
const result = Buffer.alloc(input.length);
input.copy(result);
return result;
}
const result = Buffer.alloc(input.subarray(0, index).length);
input.subarray(0, index).copy(result);
return result;
};
exports.readNullTerminatedBuffer = readNullTerminatedBuffer;
//# sourceMappingURL=utils.js.map

1
build/p2p/utils.js.map Normal file

File diff suppressed because one or more lines are too long