@homebridge-eufy-security/eufy-security-client 3.7.2-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/.prettierignore/342/200/216 +8 -0
  2. package/.prettierrc +11 -0
  3. package/LICENSE +21 -0
  4. package/README.md +970 -0
  5. package/build/error.d.ts +138 -0
  6. package/build/error.js +190 -0
  7. package/build/error.js.map +1 -0
  8. package/build/eufysecurity.d.ts +180 -0
  9. package/build/eufysecurity.js +3148 -0
  10. package/build/eufysecurity.js.map +1 -0
  11. package/build/http/api.d.ts +119 -0
  12. package/build/http/api.js +1877 -0
  13. package/build/http/api.js.map +1 -0
  14. package/build/http/cache.d.ts +8 -0
  15. package/build/http/cache.js +34 -0
  16. package/build/http/cache.js.map +1 -0
  17. package/build/http/const.d.ts +8 -0
  18. package/build/http/const.js +3054 -0
  19. package/build/http/const.js.map +1 -0
  20. package/build/http/device.d.ts +490 -0
  21. package/build/http/device.js +5256 -0
  22. package/build/http/device.js.map +1 -0
  23. package/build/http/error.d.ts +73 -0
  24. package/build/http/error.js +101 -0
  25. package/build/http/error.js.map +1 -0
  26. package/build/http/index.d.ts +10 -0
  27. package/build/http/index.js +30 -0
  28. package/build/http/index.js.map +1 -0
  29. package/build/http/interfaces.d.ts +248 -0
  30. package/build/http/interfaces.js +3 -0
  31. package/build/http/interfaces.js.map +1 -0
  32. package/build/http/models.d.ts +608 -0
  33. package/build/http/models.js +3 -0
  34. package/build/http/models.js.map +1 -0
  35. package/build/http/parameter.d.ts +7 -0
  36. package/build/http/parameter.js +119 -0
  37. package/build/http/parameter.js.map +1 -0
  38. package/build/http/station.d.ts +382 -0
  39. package/build/http/station.js +15735 -0
  40. package/build/http/station.js.map +1 -0
  41. package/build/http/types.d.ts +1358 -0
  42. package/build/http/types.js +10333 -0
  43. package/build/http/types.js.map +1 -0
  44. package/build/http/utils.d.ts +89 -0
  45. package/build/http/utils.js +916 -0
  46. package/build/http/utils.js.map +1 -0
  47. package/build/index.d.ts +8 -0
  48. package/build/index.js +29 -0
  49. package/build/index.js.map +1 -0
  50. package/build/interfaces.d.ts +147 -0
  51. package/build/interfaces.js +7 -0
  52. package/build/interfaces.js.map +1 -0
  53. package/build/logging.d.ts +36 -0
  54. package/build/logging.js +119 -0
  55. package/build/logging.js.map +1 -0
  56. package/build/mqtt/interface.d.ts +6 -0
  57. package/build/mqtt/interface.js +3 -0
  58. package/build/mqtt/interface.js.map +1 -0
  59. package/build/mqtt/model.d.ts +24 -0
  60. package/build/mqtt/model.js +3 -0
  61. package/build/mqtt/model.js.map +1 -0
  62. package/build/mqtt/mqtt-eufy.crt +79 -0
  63. package/build/mqtt/proto/lock.proto +33 -0
  64. package/build/mqtt/service.d.ts +28 -0
  65. package/build/mqtt/service.js +196 -0
  66. package/build/mqtt/service.js.map +1 -0
  67. package/build/p2p/ble.d.ts +59 -0
  68. package/build/p2p/ble.js +281 -0
  69. package/build/p2p/ble.js.map +1 -0
  70. package/build/p2p/error.d.ts +49 -0
  71. package/build/p2p/error.js +69 -0
  72. package/build/p2p/error.js.map +1 -0
  73. package/build/p2p/index.d.ts +8 -0
  74. package/build/p2p/index.js +28 -0
  75. package/build/p2p/index.js.map +1 -0
  76. package/build/p2p/interfaces.d.ts +423 -0
  77. package/build/p2p/interfaces.js +3 -0
  78. package/build/p2p/interfaces.js.map +1 -0
  79. package/build/p2p/models.d.ts +295 -0
  80. package/build/p2p/models.js +3 -0
  81. package/build/p2p/models.js.map +1 -0
  82. package/build/p2p/session.d.ts +186 -0
  83. package/build/p2p/session.js +3737 -0
  84. package/build/p2p/session.js.map +1 -0
  85. package/build/p2p/talkback.d.ts +8 -0
  86. package/build/p2p/talkback.js +23 -0
  87. package/build/p2p/talkback.js.map +1 -0
  88. package/build/p2p/types.d.ts +1164 -0
  89. package/build/p2p/types.js +1219 -0
  90. package/build/p2p/types.js.map +1 -0
  91. package/build/p2p/utils.d.ts +72 -0
  92. package/build/p2p/utils.js +865 -0
  93. package/build/p2p/utils.js.map +1 -0
  94. package/build/push/client.d.ts +49 -0
  95. package/build/push/client.js +344 -0
  96. package/build/push/client.js.map +1 -0
  97. package/build/push/error.d.ts +73 -0
  98. package/build/push/error.js +101 -0
  99. package/build/push/error.js.map +1 -0
  100. package/build/push/index.d.ts +6 -0
  101. package/build/push/index.js +26 -0
  102. package/build/push/index.js.map +1 -0
  103. package/build/push/interfaces.d.ts +19 -0
  104. package/build/push/interfaces.js +3 -0
  105. package/build/push/interfaces.js.map +1 -0
  106. package/build/push/models.d.ts +328 -0
  107. package/build/push/models.js +38 -0
  108. package/build/push/models.js.map +1 -0
  109. package/build/push/parser.d.ts +25 -0
  110. package/build/push/parser.js +231 -0
  111. package/build/push/parser.js.map +1 -0
  112. package/build/push/proto/checkin.proto +266 -0
  113. package/build/push/proto/mcs.proto +328 -0
  114. package/build/push/service.d.ts +46 -0
  115. package/build/push/service.js +965 -0
  116. package/build/push/service.js.map +1 -0
  117. package/build/push/types.d.ts +220 -0
  118. package/build/push/types.js +244 -0
  119. package/build/push/types.js.map +1 -0
  120. package/build/push/utils.d.ts +7 -0
  121. package/build/push/utils.js +116 -0
  122. package/build/push/utils.js.map +1 -0
  123. package/build/utils.d.ts +115 -0
  124. package/build/utils.js +438 -0
  125. package/build/utils.js.map +1 -0
  126. package/eslint.config.mts +68 -0
  127. package/jest.config.js +14 -0
  128. package/package.json +85 -0
  129. package/scripts/cut_release.sh +31 -0
@@ -0,0 +1,865 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ 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;
40
+ 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;
41
+ exports.isP2PQueueMessage = isP2PQueueMessage;
42
+ const node_rsa_1 = __importDefault(require("node-rsa"));
43
+ const CryptoJS = __importStar(require("crypto-js"));
44
+ const crypto_1 = require("crypto");
45
+ const os = __importStar(require("os"));
46
+ const types_1 = require("./types");
47
+ const device_1 = require("../http/device");
48
+ const ble_1 = require("./ble");
49
+ const logging_1 = require("../logging");
50
+ exports.MAGIC_WORD = "XZYH";
51
+ const isPrivateIp = (ip) => /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
52
+ /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
53
+ /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
54
+ /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
55
+ /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
56
+ /^f[cd][0-9a-f]{2}:/i.test(ip) ||
57
+ /^fe80:/i.test(ip) ||
58
+ /^::1$/.test(ip) ||
59
+ /^::$/.test(ip);
60
+ exports.isPrivateIp = isPrivateIp;
61
+ const stringWithLength = (input, chunkLength = 128) => {
62
+ const stringAsBuffer = Buffer.from(input);
63
+ const bufferSize = stringAsBuffer.byteLength < chunkLength
64
+ ? chunkLength
65
+ : Math.ceil(stringAsBuffer.byteLength / chunkLength) * chunkLength;
66
+ const result = Buffer.alloc(bufferSize);
67
+ stringAsBuffer.copy(result);
68
+ return result;
69
+ };
70
+ const getLocalIpAddress = (init = "") => {
71
+ const ifaces = os.networkInterfaces();
72
+ let localAddress = init;
73
+ for (const name in ifaces) {
74
+ const iface = ifaces[name].filter(function (details) {
75
+ return details.family === "IPv4" && details.internal === false;
76
+ });
77
+ if (iface.length > 0) {
78
+ localAddress = iface[0].address;
79
+ break;
80
+ }
81
+ }
82
+ return localAddress;
83
+ };
84
+ exports.getLocalIpAddress = getLocalIpAddress;
85
+ const p2pDidToBuffer = (p2pDid) => {
86
+ const p2pArray = p2pDid.split("-");
87
+ const buf1 = stringWithLength(p2pArray[0], 8);
88
+ const buf2 = Buffer.allocUnsafe(4);
89
+ buf2.writeUInt32BE(Number.parseInt(p2pArray[1]), 0);
90
+ const buf3 = stringWithLength(p2pArray[2], 8);
91
+ return Buffer.concat([buf1, buf2, buf3], 20);
92
+ };
93
+ const isP2PCommandEncrypted = function (cmd) {
94
+ return [
95
+ 1001, 1002, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1015, 1017, 1019, 1035, 1045, 1056, 1145, 1146, 1152,
96
+ 1200, 1207, 1210, 1213, 1214, 1226, 1227, 1229, 1230, 1233, 1236, 1240, 1241, 1243, 1246, 1272, 1273, 1275, 1400,
97
+ 1401, 1402, 1403, 1408, 1409, 1410, 1412, 1413, 1506, 1507, 1607, 1609, 1610, 1611, 1702, 1703, 1704, 1705, 1706,
98
+ 1707, 1708, 1709, 1013, 1202, 1205, 1206, 1024, 1025, 1132, 1215, 1216, 1217, 1414, 1026, 1164, 1201, 1027, 1047,
99
+ 1048, 1029, 1034, 1036, 1043, 1057, 1203, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1232, 1234, 1235, 1237, 1238,
100
+ 1248, 1253, 1257, 1269, 1800, 1037, 1040, 1038, 1049, 1050, 1051, 1054, 1060, 1204, 1254, 1255, 1256, 1258, 1259,
101
+ 1260, 1261, 1262, 1264, 1271, 1350, 1404, 1101, 1106, 1108, 1110, 1111, 1112, 1113, 1114, 1116, 1117, 1118, 1119,
102
+ 1121, 1103, 1129, 1211, 1228, 1231, 1242, 1249, 1250, 1251, 1252, 1405, 1406, 1407, 1700,
103
+ ].includes(cmd);
104
+ };
105
+ exports.isP2PCommandEncrypted = isP2PCommandEncrypted;
106
+ const getP2PCommandEncryptionKey = function (serialNumber, p2pDid) {
107
+ return `${serialNumber.slice(-7)}${p2pDid.substring(p2pDid.indexOf("-"), p2pDid.indexOf("-") + 9)}`;
108
+ };
109
+ exports.getP2PCommandEncryptionKey = getP2PCommandEncryptionKey;
110
+ const encryptP2PData = (data, key) => {
111
+ const cipher = (0, crypto_1.createCipheriv)("aes-128-ecb", key, null);
112
+ cipher.setAutoPadding(false);
113
+ return Buffer.concat([cipher.update(data), cipher.final()]);
114
+ };
115
+ exports.encryptP2PData = encryptP2PData;
116
+ const decryptP2PData = (data, key) => {
117
+ const decipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", key, null);
118
+ decipher.setAutoPadding(false);
119
+ return Buffer.concat([decipher.update(data), decipher.final()]);
120
+ };
121
+ exports.decryptP2PData = decryptP2PData;
122
+ const paddingP2PData = (data, blocksize = 16) => {
123
+ const bufferSize = data.byteLength < blocksize ? blocksize : Math.ceil(data.byteLength / blocksize) * blocksize;
124
+ const result = Buffer.alloc(bufferSize);
125
+ data.copy(result);
126
+ return result;
127
+ };
128
+ exports.paddingP2PData = paddingP2PData;
129
+ const buildLookupWithKeyPayload = (socket, p2pDid, dskKey) => {
130
+ const p2pDidBuffer = p2pDidToBuffer(p2pDid);
131
+ const addressInfo = socket.address();
132
+ const port = addressInfo.port;
133
+ const portAsBuffer = Buffer.allocUnsafe(2);
134
+ portAsBuffer.writeUInt16LE(port, 0);
135
+ //const ip = socket.address().address;
136
+ const ip = (0, exports.getLocalIpAddress)(addressInfo.address);
137
+ const temp_buff = [];
138
+ ip.split(".")
139
+ .reverse()
140
+ .forEach((element) => {
141
+ temp_buff.push(Number.parseInt(element));
142
+ });
143
+ const ipAsBuffer = Buffer.from(temp_buff);
144
+ const splitter = Buffer.from([0x00, 0x02]);
145
+ const magic = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00]);
146
+ const dskKeyAsBuffer = Buffer.from(dskKey);
147
+ const fourEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00]);
148
+ return Buffer.concat([p2pDidBuffer, splitter, portAsBuffer, ipAsBuffer, magic, dskKeyAsBuffer, fourEmpty]);
149
+ };
150
+ exports.buildLookupWithKeyPayload = buildLookupWithKeyPayload;
151
+ const buildLookupWithKeyPayload2 = (p2pDid, dskKey) => {
152
+ const p2pDidBuffer = p2pDidToBuffer(p2pDid);
153
+ const dskKeyAsBuffer = Buffer.from(dskKey);
154
+ const fourEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00]);
155
+ return Buffer.concat([p2pDidBuffer, dskKeyAsBuffer, fourEmpty]);
156
+ };
157
+ exports.buildLookupWithKeyPayload2 = buildLookupWithKeyPayload2;
158
+ const buildLookupWithKeyPayload3 = (p2pDid, address, data) => {
159
+ const p2pDidBuffer = p2pDidToBuffer(p2pDid);
160
+ const portAsBuffer = Buffer.allocUnsafe(2);
161
+ portAsBuffer.writeUInt16LE(address.port, 0);
162
+ const temp_buff = [];
163
+ address.host
164
+ .split(".")
165
+ .reverse()
166
+ .forEach((element) => {
167
+ temp_buff.push(Number.parseInt(element));
168
+ });
169
+ const ipAsBuffer = Buffer.from(temp_buff);
170
+ const splitter = Buffer.from([0x00, 0x02]);
171
+ const eightEmpty = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
172
+ return Buffer.concat([p2pDidBuffer, splitter, portAsBuffer, ipAsBuffer, eightEmpty, data]);
173
+ };
174
+ exports.buildLookupWithKeyPayload3 = buildLookupWithKeyPayload3;
175
+ const buildCheckCamPayload = (p2pDid) => {
176
+ const p2pDidBuffer = p2pDidToBuffer(p2pDid);
177
+ const magic = Buffer.from([0x00, 0x00, 0x00]);
178
+ return Buffer.concat([p2pDidBuffer, magic]);
179
+ };
180
+ exports.buildCheckCamPayload = buildCheckCamPayload;
181
+ const buildCheckCamPayload2 = (p2pDid, data) => {
182
+ const p2pDidBuffer = p2pDidToBuffer(p2pDid);
183
+ const magic = Buffer.from([0x00, 0x00, 0x00, 0x00]);
184
+ return Buffer.concat([data, p2pDidBuffer, magic]);
185
+ };
186
+ exports.buildCheckCamPayload2 = buildCheckCamPayload2;
187
+ const buildIntCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, strValue = "", channel = 255) => {
188
+ const emptyBuffer = Buffer.from([0x00, 0x00]);
189
+ const magicBuffer = Buffer.from([0x01, 0x00]);
190
+ const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
191
+ const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
192
+ const valueBuffer = Buffer.allocUnsafe(4);
193
+ valueBuffer.writeUInt32LE(value, 0);
194
+ const headerBuffer = Buffer.allocUnsafe(2);
195
+ const strValueBuffer = strValue.length === 0 ? Buffer.from([]) : stringWithLength(strValue);
196
+ const tmpDataBuffer = Buffer.concat([valueBuffer, strValueBuffer]);
197
+ const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
198
+ headerBuffer.writeUInt16LE(dataBuffer.length, 0);
199
+ return Buffer.concat([
200
+ headerBuffer,
201
+ emptyBuffer,
202
+ magicBuffer,
203
+ channelBuffer,
204
+ emptyBuffer,
205
+ encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer,
206
+ ]);
207
+ };
208
+ exports.buildIntCommandPayload = buildIntCommandPayload;
209
+ const buildStringTypeCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, strValue, strValueSub, channel = 255) => {
210
+ const emptyBuffer = Buffer.from([0x00, 0x00]);
211
+ const magicBuffer = Buffer.from([0x01, 0x00]);
212
+ const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
213
+ const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
214
+ const someBuffer = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00]);
215
+ const strValueBuffer = stringWithLength(strValue);
216
+ const strValueSubBuffer = stringWithLength(strValueSub);
217
+ const headerBuffer = Buffer.allocUnsafe(2);
218
+ const tmpDataBuffer = Buffer.concat([someBuffer, strValueBuffer, strValueSubBuffer]);
219
+ const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
220
+ headerBuffer.writeUInt16LE(dataBuffer.length, 0);
221
+ return Buffer.concat([
222
+ headerBuffer,
223
+ emptyBuffer,
224
+ magicBuffer,
225
+ channelBuffer,
226
+ emptyBuffer,
227
+ encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer,
228
+ ]);
229
+ };
230
+ exports.buildStringTypeCommandPayload = buildStringTypeCommandPayload;
231
+ const buildIntStringCommandPayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, valueSub = 0, strValue = "", strValueSub = "", channel = 0) => {
232
+ const emptyBuffer = Buffer.from([0x00, 0x00]);
233
+ const magicBuffer = Buffer.from([0x01, 0x00]);
234
+ const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
235
+ const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
236
+ const someintBuffer = Buffer.allocUnsafe(4);
237
+ someintBuffer.writeUInt32LE(valueSub, 0);
238
+ const valueBuffer = Buffer.allocUnsafe(4);
239
+ valueBuffer.writeUInt32LE(value, 0);
240
+ const strValueBuffer = strValue.length === 0 ? Buffer.from([]) : stringWithLength(strValue);
241
+ const strValueSubBuffer = strValueSub.length === 0 ? Buffer.from([]) : stringWithLength(strValueSub);
242
+ const headerBuffer = Buffer.allocUnsafe(2);
243
+ const tmpDataBuffer = Buffer.concat([someintBuffer, valueBuffer, strValueBuffer, strValueSubBuffer]);
244
+ const dataBuffer = encrypted ? (0, exports.paddingP2PData)(tmpDataBuffer) : tmpDataBuffer;
245
+ headerBuffer.writeUInt16LE(dataBuffer.length, 0);
246
+ return Buffer.concat([
247
+ headerBuffer,
248
+ emptyBuffer,
249
+ magicBuffer,
250
+ channelBuffer,
251
+ emptyBuffer,
252
+ encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer,
253
+ ]);
254
+ };
255
+ exports.buildIntStringCommandPayload = buildIntStringCommandPayload;
256
+ const sendMessage = async (socket, address, msgID, payload) => {
257
+ if (!payload)
258
+ payload = Buffer.from([]);
259
+ const payloadLen = Buffer.allocUnsafe(2);
260
+ payloadLen.writeUInt16BE(payload.length, 0);
261
+ const message = Buffer.concat([msgID, payloadLen, payload], 4 + payload.length);
262
+ return new Promise((resolve, reject) => {
263
+ socket.send(message, address.port, address.host, (err, bytes) => {
264
+ return err ? reject(err) : resolve(bytes);
265
+ });
266
+ });
267
+ };
268
+ exports.sendMessage = sendMessage;
269
+ const hasHeader = (msg, searchedType) => {
270
+ const header = Buffer.allocUnsafe(2);
271
+ msg.copy(header, 0, 0, 2);
272
+ return Buffer.compare(header, searchedType) === 0;
273
+ };
274
+ exports.hasHeader = hasHeader;
275
+ const buildCommandHeader = (seqNumber, commandType, p2pDataTypeHeader = null) => {
276
+ let dataTypeBuffer = types_1.P2PDataTypeHeader.DATA;
277
+ if (p2pDataTypeHeader !== null &&
278
+ (Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.DATA) === 0 ||
279
+ Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.BINARY) === 0 ||
280
+ Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.CONTROL) === 0 ||
281
+ Buffer.compare(p2pDataTypeHeader, types_1.P2PDataTypeHeader.VIDEO) === 0)) {
282
+ dataTypeBuffer = p2pDataTypeHeader;
283
+ }
284
+ const seqAsBuffer = Buffer.allocUnsafe(2);
285
+ seqAsBuffer.writeUInt16BE(seqNumber, 0);
286
+ const magicString = Buffer.from(exports.MAGIC_WORD);
287
+ const commandTypeBuffer = Buffer.allocUnsafe(2);
288
+ commandTypeBuffer.writeUInt16LE(commandType, 0);
289
+ return Buffer.concat([dataTypeBuffer, seqAsBuffer, magicString, commandTypeBuffer]);
290
+ };
291
+ exports.buildCommandHeader = buildCommandHeader;
292
+ const buildCommandWithStringTypePayload = (encryptionType, encryptionKey, serialNumber, p2pDid, commandType, value, channel = 0) => {
293
+ const headerBuffer = Buffer.allocUnsafe(2);
294
+ const emptyBuffer = Buffer.from([0x00, 0x00]);
295
+ const magicBuffer = Buffer.from([0x01, 0x00]);
296
+ const encrypted = (0, exports.isP2PCommandEncrypted)(commandType) && encryptionType !== types_1.EncryptionType.NONE && encryptionKey?.length === 16;
297
+ const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]);
298
+ const dataBuffer = encrypted ? (0, exports.paddingP2PData)(Buffer.from(value)) : Buffer.from(value);
299
+ headerBuffer.writeUInt16LE(dataBuffer.length, 0);
300
+ return Buffer.concat([
301
+ headerBuffer,
302
+ emptyBuffer,
303
+ magicBuffer,
304
+ channelBuffer,
305
+ emptyBuffer,
306
+ encrypted ? (0, exports.encryptP2PData)(dataBuffer, encryptionKey) : dataBuffer,
307
+ ]);
308
+ };
309
+ exports.buildCommandWithStringTypePayload = buildCommandWithStringTypePayload;
310
+ const sortP2PMessageParts = (messages) => {
311
+ let completeMessage = Buffer.from([]);
312
+ Object.keys(messages)
313
+ .map(Number)
314
+ .sort((a, b) => {
315
+ if (Math.abs(a - b) > 65000) {
316
+ if (a < b) {
317
+ return 1;
318
+ }
319
+ else if (b < a) {
320
+ return -1;
321
+ }
322
+ }
323
+ return a - b;
324
+ }) // assure the seqNumbers are in correct order
325
+ .forEach((key) => {
326
+ completeMessage = Buffer.concat([completeMessage, messages[key]]);
327
+ });
328
+ return completeMessage;
329
+ };
330
+ exports.sortP2PMessageParts = sortP2PMessageParts;
331
+ const getRSAPrivateKey = (pem, enableEmbeddedPKCS1Support = false) => {
332
+ const key = new node_rsa_1.default();
333
+ if (pem.indexOf("\n") !== -1) {
334
+ pem = pem.replaceAll("\n", "");
335
+ }
336
+ if (pem.startsWith("-----BEGIN RSA PRIVATE KEY-----")) {
337
+ pem = pem.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "");
338
+ }
339
+ key.importKey(pem, "pkcs8");
340
+ const options = {
341
+ encryptionScheme: "pkcs1",
342
+ };
343
+ if (enableEmbeddedPKCS1Support) {
344
+ options.environment = "browser";
345
+ }
346
+ key.setOptions(options);
347
+ return key;
348
+ };
349
+ exports.getRSAPrivateKey = getRSAPrivateKey;
350
+ const getNewRSAPrivateKey = (enableEmbeddedPKCS1Support = false) => {
351
+ const key = new node_rsa_1.default({ b: 1024 });
352
+ const options = {
353
+ encryptionScheme: "pkcs1",
354
+ };
355
+ if (enableEmbeddedPKCS1Support) {
356
+ options.environment = "browser";
357
+ }
358
+ key.setOptions(options);
359
+ return key;
360
+ };
361
+ exports.getNewRSAPrivateKey = getNewRSAPrivateKey;
362
+ const decryptAESData = (hexkey, data) => {
363
+ const key = CryptoJS.enc.Hex.parse(hexkey);
364
+ const cipherParams = CryptoJS.lib.CipherParams.create({
365
+ ciphertext: CryptoJS.enc.Hex.parse(data.toString("hex")),
366
+ });
367
+ const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
368
+ mode: CryptoJS.mode.ECB,
369
+ padding: CryptoJS.pad.NoPadding,
370
+ });
371
+ return Buffer.from(CryptoJS.enc.Hex.stringify(decrypted), "hex");
372
+ };
373
+ exports.decryptAESData = decryptAESData;
374
+ const findStartCode = (data) => {
375
+ if (data !== undefined && data.length > 0) {
376
+ if (data.length >= 4) {
377
+ const startcode = [...data.subarray(0, 4)];
378
+ if ((startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 1) ||
379
+ (startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 0 && startcode[3] === 1))
380
+ return true;
381
+ }
382
+ else if (data.length === 3) {
383
+ const startcode = [...data.subarray(0, 3)];
384
+ if (startcode[0] === 0 && startcode[1] === 0 && startcode[2] === 1)
385
+ return true;
386
+ }
387
+ }
388
+ return false;
389
+ };
390
+ exports.findStartCode = findStartCode;
391
+ const isIFrame = (data) => {
392
+ const validValues = [64, 66, 68, 78, 101, 103];
393
+ if (data !== undefined && data.length > 0) {
394
+ if (data.length >= 5) {
395
+ const startcode = [...data.subarray(0, 5)];
396
+ if (validValues.includes(startcode[3]) || validValues.includes(startcode[4]))
397
+ return true;
398
+ }
399
+ }
400
+ return false;
401
+ };
402
+ exports.isIFrame = isIFrame;
403
+ const decryptLockAESData = (key, iv, data) => {
404
+ const ekey = CryptoJS.enc.Hex.parse(key);
405
+ const eiv = CryptoJS.enc.Hex.parse(iv);
406
+ const cipherParams = CryptoJS.lib.CipherParams.create({
407
+ ciphertext: CryptoJS.enc.Hex.parse(data.toString("hex")),
408
+ });
409
+ const decrypted = CryptoJS.AES.decrypt(cipherParams, ekey, {
410
+ iv: eiv,
411
+ mode: CryptoJS.mode.CBC,
412
+ padding: CryptoJS.pad.Pkcs7,
413
+ });
414
+ return Buffer.from(CryptoJS.enc.Hex.stringify(decrypted), "hex");
415
+ };
416
+ exports.decryptLockAESData = decryptLockAESData;
417
+ const encryptLockAESData = (key, iv, data) => {
418
+ const ekey = CryptoJS.enc.Hex.parse(key);
419
+ const eiv = CryptoJS.enc.Hex.parse(iv);
420
+ const encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Hex.parse(data.toString("hex")), ekey, {
421
+ iv: eiv,
422
+ mode: CryptoJS.mode.CBC,
423
+ padding: CryptoJS.pad.Pkcs7,
424
+ });
425
+ return Buffer.from(CryptoJS.enc.Hex.stringify(encrypted.ciphertext), "hex");
426
+ };
427
+ exports.encryptLockAESData = encryptLockAESData;
428
+ const generateBasicLockAESKey = (adminID, stationSN) => {
429
+ const encoder = new TextEncoder();
430
+ const encOwnerID = encoder.encode(adminID);
431
+ const encStationSerial = encoder.encode(stationSN);
432
+ const array = [104, -83, -72, 38, -107, 99, -110, 17, -95, -121, 54, 57, -46, -98, -111, 89];
433
+ for (let i = 0; i < 16; i++) {
434
+ array[i] =
435
+ array[i] + encStationSerial[(encStationSerial[i] * 3 + 5) % 16] + encOwnerID[(encOwnerID[i] * 3 + 5) % 40];
436
+ }
437
+ return Buffer.from(array).toString("hex");
438
+ };
439
+ exports.generateBasicLockAESKey = generateBasicLockAESKey;
440
+ const getCurrentTimeInSeconds = function () {
441
+ return Math.trunc(new Date().getTime() / 1000);
442
+ };
443
+ exports.getCurrentTimeInSeconds = getCurrentTimeInSeconds;
444
+ const generateLockSequence = (deviceType, serialnumber) => {
445
+ if (deviceType !== undefined && serialnumber !== undefined)
446
+ if (device_1.Device.isLockWifi(deviceType, serialnumber) || device_1.Device.isLockWifiNoFinger(deviceType))
447
+ return Math.trunc(Math.random() * 1000);
448
+ return (0, exports.getCurrentTimeInSeconds)();
449
+ };
450
+ exports.generateLockSequence = generateLockSequence;
451
+ const encodeLockPayload = (data) => {
452
+ const encoder = new TextEncoder();
453
+ const encData = encoder.encode(data);
454
+ const length = encData.length;
455
+ const old_buffer = Buffer.from(encData);
456
+ if (length % 16 == 0) {
457
+ return old_buffer;
458
+ }
459
+ const new_length = (Math.trunc(length / 16) + 1) * 16;
460
+ const new_buffer = Buffer.alloc(new_length);
461
+ old_buffer.copy(new_buffer, 0);
462
+ return new_buffer;
463
+ };
464
+ exports.encodeLockPayload = encodeLockPayload;
465
+ const getLockVectorBytes = (data) => {
466
+ const encoder = new TextEncoder();
467
+ const encData = encoder.encode(data);
468
+ const old_buffer = Buffer.from(encData);
469
+ if (encData.length >= 16)
470
+ return old_buffer.toString("hex");
471
+ const new_buffer = Buffer.alloc(16);
472
+ old_buffer.copy(new_buffer, 0);
473
+ return new_buffer.toString("hex");
474
+ };
475
+ exports.getLockVectorBytes = getLockVectorBytes;
476
+ const decodeLockPayload = (data) => {
477
+ const decoder = new TextDecoder();
478
+ return decoder.decode(data);
479
+ };
480
+ exports.decodeLockPayload = decodeLockPayload;
481
+ const decodeBase64 = (data) => {
482
+ const base64RegExp = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/;
483
+ if (base64RegExp.test(data))
484
+ return Buffer.from(data, "base64");
485
+ return Buffer.from(data);
486
+ };
487
+ exports.decodeBase64 = decodeBase64;
488
+ const eslTimestamp = function (timestamp_in_sec = new Date().getTime() / 1000) {
489
+ const array = [];
490
+ for (let pos = 0; pos < 4; pos++) {
491
+ array[pos] = (timestamp_in_sec >> (pos * 8)) & 255;
492
+ }
493
+ return array;
494
+ };
495
+ exports.eslTimestamp = eslTimestamp;
496
+ const generateAdvancedLockAESKey = () => {
497
+ const randomBytesArray = [...(0, crypto_1.randomBytes)(16)];
498
+ let result = "";
499
+ for (let pos = 0; pos < randomBytesArray.length; pos++) {
500
+ result += "0123456789ABCDEF".charAt((randomBytesArray[pos] >> 4) & 15);
501
+ result += "0123456789ABCDEF".charAt(randomBytesArray[pos] & 15);
502
+ }
503
+ return result;
504
+ };
505
+ exports.generateAdvancedLockAESKey = generateAdvancedLockAESKey;
506
+ const getVideoCodec = (data) => {
507
+ if (data !== undefined && data.length > 0) {
508
+ if (data.length >= 5) {
509
+ const h265Values = [38, 64, 66, 68, 78];
510
+ const startcode = [...data.subarray(0, 5)];
511
+ if (h265Values.includes(startcode[3]) || h265Values.includes(startcode[4])) {
512
+ return types_1.VideoCodec.H265;
513
+ }
514
+ else if (startcode[3] === 103 || startcode[4] === 103) {
515
+ return types_1.VideoCodec.H264;
516
+ }
517
+ }
518
+ return types_1.VideoCodec.H264;
519
+ }
520
+ return types_1.VideoCodec.UNKNOWN; // Maybe return h264 as Eufy does?
521
+ };
522
+ exports.getVideoCodec = getVideoCodec;
523
+ const checkT8420 = (serialNumber) => {
524
+ if (!(serialNumber !== undefined &&
525
+ serialNumber !== null &&
526
+ serialNumber.length > 0 &&
527
+ serialNumber.startsWith("T8420")) ||
528
+ serialNumber.length <= 7 ||
529
+ serialNumber[6] != "6") {
530
+ return false;
531
+ }
532
+ return true;
533
+ };
534
+ exports.checkT8420 = checkT8420;
535
+ const buildVoidCommandPayload = (channel = 255) => {
536
+ const headerBuffer = Buffer.from([0x00, 0x00]);
537
+ const emptyBuffer = Buffer.from([0x00, 0x00]);
538
+ const magicBuffer = Buffer.from([0x01, 0x00]);
539
+ const channelBuffer = Buffer.from([channel, 0x00]);
540
+ return Buffer.concat([headerBuffer, emptyBuffer, magicBuffer, channelBuffer, emptyBuffer]);
541
+ };
542
+ exports.buildVoidCommandPayload = buildVoidCommandPayload;
543
+ function isP2PQueueMessage(type) {
544
+ return type.p2pCommand !== undefined;
545
+ }
546
+ const encryptPayloadData = (data, key, iv) => {
547
+ const cipher = (0, crypto_1.createCipheriv)("aes-128-cbc", key, iv);
548
+ return Buffer.concat([cipher.update(data), cipher.final()]);
549
+ };
550
+ exports.encryptPayloadData = encryptPayloadData;
551
+ const decryptPayloadData = (data, key, iv) => {
552
+ const cipher = (0, crypto_1.createDecipheriv)("aes-128-cbc", key, iv);
553
+ return Buffer.concat([cipher.update(data), cipher.final()]);
554
+ };
555
+ exports.decryptPayloadData = decryptPayloadData;
556
+ const eufyKDF = (key) => {
557
+ const hash_length = 32;
558
+ const digest_length = 48;
559
+ const staticBuffer = Buffer.from("ECIES");
560
+ const steps = Math.ceil(digest_length / hash_length);
561
+ const buffer = Buffer.alloc(hash_length * steps);
562
+ let tmpBuffer = staticBuffer;
563
+ for (let step = 0; step < steps; ++step) {
564
+ tmpBuffer = (0, crypto_1.createHmac)("sha256", key).update(tmpBuffer).digest();
565
+ const digest = (0, crypto_1.createHmac)("sha256", key)
566
+ .update(Buffer.concat([tmpBuffer, staticBuffer]))
567
+ .digest();
568
+ digest.copy(buffer, hash_length * step);
569
+ }
570
+ return buffer.subarray(0, digest_length);
571
+ };
572
+ exports.eufyKDF = eufyKDF;
573
+ const getAdvancedLockKey = (key, publicKey) => {
574
+ const ecdh = (0, crypto_1.createECDH)("prime256v1");
575
+ ecdh.generateKeys();
576
+ const secret = ecdh.computeSecret(Buffer.concat([Buffer.from("04", "hex"), Buffer.from(publicKey, "hex")]));
577
+ const randomValue = (0, crypto_1.randomBytes)(16);
578
+ const derivedKey = (0, exports.eufyKDF)(secret);
579
+ const encryptedData = (0, exports.encryptPayloadData)(key, derivedKey.subarray(0, 16), randomValue);
580
+ const hmac = (0, crypto_1.createHmac)("sha256", derivedKey.subarray(16));
581
+ hmac.update(randomValue);
582
+ hmac.update(encryptedData);
583
+ const hmacDigest = hmac.digest();
584
+ return Buffer.concat([
585
+ Buffer.from(ecdh.getPublicKey("hex", "compressed"), "hex"),
586
+ randomValue,
587
+ encryptedData,
588
+ hmacDigest,
589
+ ]).toString("hex");
590
+ };
591
+ exports.getAdvancedLockKey = getAdvancedLockKey;
592
+ const getLockV12Key = (key, publicKey) => {
593
+ const ecdh = (0, crypto_1.createECDH)("prime256v1");
594
+ ecdh.generateKeys();
595
+ const secret = ecdh.computeSecret(Buffer.concat([Buffer.from("04", "hex"), Buffer.from(publicKey, "hex")]));
596
+ const randomValue = (0, crypto_1.randomBytes)(16);
597
+ const derivedKey = (0, exports.eufyKDF)(secret);
598
+ const encryptedData = (0, exports.encryptPayloadData)(Buffer.from(key, "hex"), derivedKey.subarray(0, 16), randomValue);
599
+ const hmac = (0, crypto_1.createHmac)("sha256", derivedKey.subarray(16));
600
+ hmac.update(randomValue);
601
+ hmac.update(encryptedData);
602
+ const hmacDigest = hmac.digest();
603
+ return Buffer.concat([
604
+ Buffer.from(ecdh.getPublicKey("hex", "compressed"), "hex"),
605
+ randomValue,
606
+ encryptedData,
607
+ hmacDigest,
608
+ ]).toString("hex");
609
+ };
610
+ exports.getLockV12Key = getLockV12Key;
611
+ const buildTalkbackAudioFrameHeader = (audioData, channel = 0) => {
612
+ const audioDataLength = Buffer.allocUnsafe(4);
613
+ audioDataLength.writeUInt32LE(audioData.length);
614
+ const unknown1 = Buffer.alloc(1);
615
+ const audioType = Buffer.alloc(1);
616
+ const audioSeq = Buffer.alloc(2);
617
+ const audioTimestamp = Buffer.alloc(8);
618
+ const audioDataHeader = Buffer.concat([audioDataLength, unknown1, audioType, audioSeq, audioTimestamp]);
619
+ const bytesToRead = Buffer.allocUnsafe(4);
620
+ bytesToRead.writeUInt32LE(audioData.length + audioDataHeader.length);
621
+ const magicBuffer = Buffer.from([0x01, 0x00]);
622
+ const channelBuffer = Buffer.from([channel, 0x00]);
623
+ const emptyBuffer = Buffer.from([0x00, 0x00]);
624
+ return Buffer.concat([bytesToRead, magicBuffer, channelBuffer, emptyBuffer, audioDataHeader]);
625
+ };
626
+ exports.buildTalkbackAudioFrameHeader = buildTalkbackAudioFrameHeader;
627
+ const decodeP2PCloudIPs = (data) => {
628
+ const lookupTable = Buffer.from("4959433db5bf6da347534f6165e371e9677f02030badb3892b2f35c16b8b959711e5a70deff1050783fb9d3bc5c713171d1f2529d3df", "hex");
629
+ const [encoded, name = "name not included"] = data.split(":");
630
+ const output = Buffer.alloc(encoded.length / 2);
631
+ for (let i = 0; i <= data.length / 2; i++) {
632
+ let z = 0x39; // 57 // '9'
633
+ for (let j = 0; j < i; j++) {
634
+ z = z ^ output[j];
635
+ }
636
+ const x = data.charCodeAt(i * 2 + 1) - "A".charCodeAt(0);
637
+ const y = (data.charCodeAt(i * 2) - "A".charCodeAt(0)) * 0x10;
638
+ output[i] = z ^ lookupTable[i % lookupTable.length] ^ (x + y);
639
+ }
640
+ const result = [];
641
+ output
642
+ .toString("utf8")
643
+ .split(",")
644
+ .forEach((ip) => {
645
+ if (ip !== "") {
646
+ result.push({ host: ip, port: 32100 });
647
+ }
648
+ });
649
+ return result;
650
+ };
651
+ exports.decodeP2PCloudIPs = decodeP2PCloudIPs;
652
+ const decodeSmartSafeData = function (deviceSN, data) {
653
+ const response = ble_1.BleCommandFactory.parseSmartSafe(data);
654
+ return {
655
+ versionCode: response.getVersionCode(),
656
+ dataType: response.getDataType(),
657
+ commandCode: response.getCommandCode(),
658
+ packageFlag: response.getPackageFlag(),
659
+ responseCode: response.getResponseCode(),
660
+ data: (0, exports.decryptPayloadData)(response.getData(), Buffer.from(deviceSN), Buffer.from(device_1.SmartSafe.IV, "hex")),
661
+ };
662
+ };
663
+ exports.decodeSmartSafeData = decodeSmartSafeData;
664
+ const getSmartSafeP2PCommand = function (deviceSN, user_id, command, intCommand, channel, sequence, data) {
665
+ const encPayload = (0, exports.encryptPayloadData)(data, Buffer.from(deviceSN), Buffer.from(device_1.SmartSafe.IV, "hex"));
666
+ const bleCommand = new ble_1.BleCommandFactory()
667
+ .setVersionCode(device_1.SmartSafe.VERSION_CODE)
668
+ .setCommandCode(intCommand)
669
+ .setDataType(-1)
670
+ .setData(encPayload)
671
+ .getSmartSafeCommand();
672
+ logging_1.rootP2PLogger.debug(`Generate smart safe command`, {
673
+ deviceSN: deviceSN,
674
+ userId: user_id,
675
+ command: command,
676
+ intCommand: intCommand,
677
+ channel: channel,
678
+ sequence: sequence,
679
+ data: data.toString("hex"),
680
+ });
681
+ return {
682
+ commandType: types_1.CommandType.CMD_SET_PAYLOAD,
683
+ value: JSON.stringify({
684
+ account_id: user_id,
685
+ cmd: command,
686
+ mChannel: channel,
687
+ mValue3: 0,
688
+ payload: {
689
+ data: bleCommand.toString("hex"),
690
+ prj_id: command,
691
+ seq_num: sequence,
692
+ },
693
+ }),
694
+ channel: channel,
695
+ };
696
+ };
697
+ exports.getSmartSafeP2PCommand = getSmartSafeP2PCommand;
698
+ const getLockP2PCommand = function (deviceSN, user_id, command, channel, lockPublicKey, payload) {
699
+ const key = (0, exports.generateAdvancedLockAESKey)();
700
+ const ecdhKey = (0, exports.getAdvancedLockKey)(key, lockPublicKey);
701
+ const iv = (0, exports.getLockVectorBytes)(deviceSN);
702
+ const encPayload = (0, exports.encryptLockAESData)(key, iv, Buffer.from(JSON.stringify(payload)));
703
+ logging_1.rootP2PLogger.debug(`Generate lock command`, {
704
+ deviceSN: deviceSN,
705
+ userId: user_id,
706
+ command: command,
707
+ channel: channel,
708
+ data: JSON.stringify(payload),
709
+ });
710
+ return {
711
+ commandType: types_1.CommandType.CMD_SET_PAYLOAD,
712
+ value: JSON.stringify({
713
+ key: ecdhKey,
714
+ account_id: user_id,
715
+ cmd: command,
716
+ mChannel: channel,
717
+ mValue3: 0,
718
+ payload: encPayload.toString("base64"),
719
+ }).replace(/=/g, "\\u003d"),
720
+ channel: channel,
721
+ aesKey: key,
722
+ };
723
+ };
724
+ exports.getLockP2PCommand = getLockP2PCommand;
725
+ const getLockV12P2PCommand = function (deviceSN, user_id, command, channel, lockPublicKey, sequence, data) {
726
+ const key = (0, exports.generateAdvancedLockAESKey)();
727
+ const encryptedAesKey = (0, exports.getLockV12Key)(key, lockPublicKey);
728
+ const iv = (0, exports.getLockVectorBytes)(deviceSN);
729
+ const encPayload = (0, exports.encryptPayloadData)(data, Buffer.from(key, "hex"), Buffer.from(iv, "hex"));
730
+ logging_1.rootP2PLogger.debug(`Generate smart lock v12 command`, {
731
+ deviceSN: deviceSN,
732
+ userId: user_id,
733
+ command: command,
734
+ channel: channel,
735
+ sequence: sequence,
736
+ data: data.toString("hex"),
737
+ });
738
+ const bleCommand = new ble_1.BleCommandFactory()
739
+ .setVersionCode(device_1.Lock.VERSION_CODE_LOCKV12)
740
+ .setCommandCode(Number.parseInt(types_1.ESLBleCommand[types_1.ESLCommand[command]])) //TODO: Change internal command identification?
741
+ .setDataType(-1)
742
+ .setData(encPayload)
743
+ .setAdditionalData(Buffer.from(encryptedAesKey, "hex"));
744
+ return {
745
+ aesKey: key,
746
+ bleCommand: bleCommand.getCommandCode(),
747
+ payload: {
748
+ commandType: types_1.CommandType.CMD_SET_PAYLOAD,
749
+ value: JSON.stringify({
750
+ account_id: user_id,
751
+ cmd: types_1.CommandType.CMD_SET_PAYLOAD_LOCKV12,
752
+ mChannel: channel,
753
+ mValue3: 0,
754
+ payload: {
755
+ apiCommand: command,
756
+ lock_payload: bleCommand.getLockV12Command().toString("hex"),
757
+ seq_num: sequence,
758
+ },
759
+ }),
760
+ },
761
+ };
762
+ };
763
+ exports.getLockV12P2PCommand = getLockV12P2PCommand;
764
+ const DecimalToRGBColor = function (color) {
765
+ return {
766
+ red: (color >> 16) & 0xff,
767
+ green: (color >> 8) & 0xff,
768
+ blue: color & 0xff,
769
+ };
770
+ };
771
+ exports.DecimalToRGBColor = DecimalToRGBColor;
772
+ const RGBColorToDecimal = function (color) {
773
+ return (color.red << 16) + (color.green << 8) + color.blue;
774
+ };
775
+ exports.RGBColorToDecimal = RGBColorToDecimal;
776
+ const getNullTerminatedString = function (data, encoding) {
777
+ const index = data.indexOf(0);
778
+ return data.toString(encoding, 0, index === -1 ? data.length : index);
779
+ };
780
+ exports.getNullTerminatedString = getNullTerminatedString;
781
+ const isUsbCharging = function (value) {
782
+ return (value & 1) == 1;
783
+ };
784
+ exports.isUsbCharging = isUsbCharging;
785
+ const isSolarCharging = function (value) {
786
+ return ((value >> 2) & 1) == 1;
787
+ };
788
+ exports.isSolarCharging = isSolarCharging;
789
+ const isPlugSolarCharging = function (value) {
790
+ return ((value >> 3) & 1) == 1;
791
+ };
792
+ exports.isPlugSolarCharging = isPlugSolarCharging;
793
+ const isCharging = function (value) {
794
+ return (0, exports.isUsbCharging)(value) || (0, exports.isSolarCharging)(value) || (0, exports.isPlugSolarCharging)(value);
795
+ };
796
+ exports.isCharging = isCharging;
797
+ const getSmartLockCurrentTimeInSeconds = function () {
798
+ return Math.trunc(new Date().getTime() / 1000) | Math.trunc(Math.random() * 100);
799
+ };
800
+ exports.getSmartLockCurrentTimeInSeconds = getSmartLockCurrentTimeInSeconds;
801
+ const generateSmartLockAESKey = (adminUserId, time) => {
802
+ const buffer = Buffer.allocUnsafe(4);
803
+ buffer.writeUint32BE(time);
804
+ return Buffer.concat([Buffer.from(adminUserId.substring(adminUserId.length - 12)), buffer]);
805
+ };
806
+ exports.generateSmartLockAESKey = generateSmartLockAESKey;
807
+ const getSmartLockP2PCommand = function (deviceSN, user_id, command, channel, sequence, data, functionType = types_1.SmartLockFunctionType.TYPE_2) {
808
+ const time = (0, exports.getSmartLockCurrentTimeInSeconds)();
809
+ const key = (0, exports.generateSmartLockAESKey)(user_id, time);
810
+ const iv = (0, exports.getLockVectorBytes)(deviceSN);
811
+ const encPayload = (0, exports.encryptPayloadData)(data, key, Buffer.from(iv, "hex"));
812
+ logging_1.rootP2PLogger.debug(`Generate smart lock command`, {
813
+ deviceSN: deviceSN,
814
+ userId: user_id,
815
+ command: command,
816
+ channel: channel,
817
+ sequence: sequence,
818
+ data: data.toString("hex"),
819
+ functionType: functionType,
820
+ });
821
+ let commandCode = 0;
822
+ if (functionType === types_1.SmartLockFunctionType.TYPE_1) {
823
+ commandCode = Number.parseInt(types_1.SmartLockBleCommandFunctionType1[types_1.SmartLockCommand[command]]);
824
+ }
825
+ else if (functionType === types_1.SmartLockFunctionType.TYPE_2) {
826
+ commandCode = Number.parseInt(types_1.SmartLockBleCommandFunctionType2[types_1.SmartLockCommand[command]]);
827
+ }
828
+ const bleCommand = new ble_1.BleCommandFactory()
829
+ .setVersionCode(device_1.Lock.VERSION_CODE_SMART_LOCK)
830
+ .setCommandCode(commandCode)
831
+ .setDataType(functionType)
832
+ .setData(encPayload);
833
+ return {
834
+ bleCommand: bleCommand.getCommandCode(),
835
+ payload: {
836
+ commandType: types_1.CommandType.CMD_SET_PAYLOAD,
837
+ value: JSON.stringify({
838
+ account_id: user_id,
839
+ cmd: types_1.CommandType.CMD_TRANSFER_PAYLOAD,
840
+ mChannel: channel,
841
+ mValue3: 0,
842
+ payload: {
843
+ apiCommand: command,
844
+ lock_payload: bleCommand.getSmartLockCommand().toString("hex"),
845
+ seq_num: sequence,
846
+ time: time,
847
+ },
848
+ }),
849
+ },
850
+ };
851
+ };
852
+ exports.getSmartLockP2PCommand = getSmartLockP2PCommand;
853
+ const readNullTerminatedBuffer = (input) => {
854
+ const index = input.indexOf(new Uint8Array([0]));
855
+ if (index === -1) {
856
+ const result = Buffer.alloc(input.length);
857
+ input.copy(result);
858
+ return result;
859
+ }
860
+ const result = Buffer.alloc(input.subarray(0, index).length);
861
+ input.subarray(0, index).copy(result);
862
+ return result;
863
+ };
864
+ exports.readNullTerminatedBuffer = readNullTerminatedBuffer;
865
+ //# sourceMappingURL=utils.js.map