Init
This commit is contained in:
59
build/p2p/ble.d.ts
vendored
Normal file
59
build/p2p/ble.d.ts
vendored
Normal 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
280
build/p2p/ble.js
Normal 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
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
49
build/p2p/error.d.ts
vendored
Normal 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
69
build/p2p/error.js
Normal 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
1
build/p2p/error.js.map
Normal 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
8
build/p2p/index.d.ts
vendored
Normal 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
28
build/p2p/index.js
Normal 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
1
build/p2p/index.js.map
Normal 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
388
build/p2p/interfaces.d.ts
vendored
Normal 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
3
build/p2p/interfaces.js
Normal file
@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=interfaces.js.map
|
||||
1
build/p2p/interfaces.js.map
Normal file
1
build/p2p/interfaces.js.map
Normal 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
284
build/p2p/models.d.ts
vendored
Normal 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
3
build/p2p/models.js
Normal 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
1
build/p2p/models.js.map
Normal 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
186
build/p2p/session.d.ts
vendored
Normal 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
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
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
8
build/p2p/talkback.d.ts
vendored
Normal 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
23
build/p2p/talkback.js
Normal 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
|
||||
1
build/p2p/talkback.js.map
Normal file
1
build/p2p/talkback.js.map
Normal 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
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
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
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
72
build/p2p/utils.d.ts
vendored
Normal 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
824
build/p2p/utils.js
Normal 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
1
build/p2p/utils.js.map
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user