iobroker.tapo 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/build/lib/utils/camera/tapoCamera.js +2 -1
- package/build/lib/utils/camera/tapoCamera.js.map +2 -2
- package/build/lib/utils/energyUsage.js.map +1 -1
- package/build/lib/utils/l510e.js +3 -3
- package/build/lib/utils/l510e.js.map +2 -2
- package/build/lib/utils/l520e.js +3 -5
- package/build/lib/utils/l520e.js.map +2 -2
- package/build/lib/utils/l530.js +64 -24
- package/build/lib/utils/l530.js.map +2 -2
- package/build/lib/utils/newTpLinkCipher.js +33 -12
- package/build/lib/utils/newTpLinkCipher.js.map +3 -3
- package/build/lib/utils/p100.js +98 -113
- package/build/lib/utils/p100.js.map +3 -3
- package/build/lib/utils/p110.js +31 -15
- package/build/lib/utils/p110.js.map +2 -2
- package/build/lib/utils/powerUsage.js.map +1 -1
- package/build/lib/utils/tpLinkCipher.js +10 -3
- package/build/lib/utils/tpLinkCipher.js.map +3 -3
- package/build/lib/utils/tplinkAccessory.js +17 -0
- package/build/lib/utils/tplinkAccessory.js.map +7 -0
- package/build/lib/utils/usage.js.map +1 -1
- package/build/main.js +3 -2
- package/build/main.js.map +3 -3
- package/io-package.json +27 -5
- package/package.json +25 -20
package/README.md
CHANGED
|
@@ -32,6 +32,15 @@ tapo.0.id.remote auf true/false setzen steuert den jeweiligen Befehl. Der Befehl
|
|
|
32
32
|
<https://forum.iobroker.net/topic/57336/test-adapter-tp-link-tapo/>
|
|
33
33
|
|
|
34
34
|
## Changelog
|
|
35
|
+
### 0.3.4 (2024-11-10)
|
|
36
|
+
|
|
37
|
+
- update Tapo local lib
|
|
38
|
+
|
|
39
|
+
### 0.3.3 (2024-06-17)
|
|
40
|
+
|
|
41
|
+
- ignore ssl legacy error
|
|
42
|
+
-
|
|
43
|
+
|
|
35
44
|
### 0.3.2 (2024-05-27)
|
|
36
45
|
|
|
37
46
|
update onvif lib to fix issues with newer cameras
|
|
@@ -45,7 +45,8 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
45
45
|
this.pendingAPIRequests = /* @__PURE__ */ new Map();
|
|
46
46
|
this.log.debug("Constructing Camera on host: " + config.ipAddress);
|
|
47
47
|
this.httpsAgent = new import_https.default.Agent({
|
|
48
|
-
rejectUnauthorized: false
|
|
48
|
+
rejectUnauthorized: false,
|
|
49
|
+
secureOptions: import_crypto.default.constants.SSL_OP_LEGACY_SERVER_CONNECT
|
|
49
50
|
});
|
|
50
51
|
this.cnonce = this.generateCnonce();
|
|
51
52
|
this.hashedMD5Password = import_crypto.default.createHash("md5").update(config.password).digest("hex").toUpperCase();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/utils/camera/tapoCamera.ts"],
|
|
4
|
-
"sourcesContent": ["import fetch, { RequestInit } from \"node-fetch\";\nimport https, { Agent } from \"https\";\nimport crypto from \"crypto\";\nimport { OnvifCamera } from \"./onvifCamera\";\nimport type {\n TAPOCameraEncryptedRequest,\n TAPOCameraEncryptedResponse,\n TAPOCameraRequest,\n TAPOCameraResponse,\n TAPOCameraResponseDeviceInfo,\n TAPOCameraResponseGetAlert,\n TAPOCameraResponseGetLensMask,\n} from \"./types/tapo\";\n\nconst MAX_LOGIN_RETRIES = 3;\nconst AES_BLOCK_SIZE = 16;\n\ntype CameraConfig = {\n name: string;\n ipAddress: string;\n username: string;\n password: string;\n streamUser: string;\n streamPassword: string;\n\n pullInterval?: number;\n disableStreaming?: boolean;\n disablePrivacyAccessory?: boolean;\n disableAlarmAccessory?: boolean;\n disableMotionAccessory?: boolean;\n lowQuality?: boolean;\n\n videoConfig?: VideoConfig;\n\n privacyAccessoryName?: string;\n alarmAccessoryName?: string;\n};\nexport class TAPOCamera extends OnvifCamera {\n private readonly kStreamPort = 554;\n private readonly httpsAgent: Agent;\n\n private readonly hashedMD5Password: string;\n private readonly hashedSha256Password: string;\n private passwordEncryptionMethod: \"md5\" | \"sha256\" | null = \"md5\";\n\n private isSecureConnectionValue: boolean | null = null;\n\n private stokPromise: (() => Promise<string>) | undefined;\n\n private readonly cnonce: string;\n private lsk: Buffer | undefined;\n private ivb: Buffer | undefined;\n private seq: number | undefined;\n private stok: string | undefined;\n\n private loginRetryCount = 0;\n\n constructor(\n protected readonly log: any,\n protected readonly config: CameraConfig,\n ) {\n super(log, config);\n this.log.debug(\"Constructing Camera on host: \" + config.ipAddress);\n\n this.httpsAgent = new https.Agent({\n rejectUnauthorized: false,\n });\n\n this.cnonce = this.generateCnonce();\n\n this.hashedMD5Password = crypto.createHash(\"md5\").update(config.password).digest(\"hex\").toUpperCase();\n this.hashedSha256Password = crypto.createHash(\"sha256\").update(config.password).digest(\"hex\").toUpperCase();\n }\n\n private getUsername() {\n return this.config.username || \"admin\";\n }\n\n private getHeaders() {\n const headers: Record<string, string> = {\n Host: `https://${this.config.ipAddress}`,\n Referer: `https://${this.config.ipAddress}`,\n Accept: \"application/json\",\n \"Accept-Encoding\": \"gzip, deflate\",\n \"User-Agent\": \"Tapo CameraClient Android\",\n Connection: \"close\",\n requestByApp: \"true\",\n \"Content-Type\": \"application/json; charset=UTF-8\",\n };\n return headers;\n }\n\n private getHashedPassword() {\n if (this.passwordEncryptionMethod === \"md5\") {\n return this.hashedMD5Password;\n } else if (this.passwordEncryptionMethod === \"sha256\") {\n return this.hashedSha256Password;\n } else {\n throw new Error(\"Unknown password encryption method \" + this.passwordEncryptionMethod + \"!\");\n }\n }\n\n private fetch(url: string, data: RequestInit) {\n return fetch(url, {\n agent: this.httpsAgent,\n headers: this.getHeaders(),\n ...data,\n });\n }\n\n private generateEncryptionToken(tokenType: string, nonce: string): Buffer {\n const hashedKey = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.getHashedPassword() + nonce)\n .digest(\"hex\")\n .toUpperCase();\n return crypto\n .createHash(\"sha256\")\n .update(tokenType + this.cnonce + nonce + hashedKey)\n .digest()\n .slice(0, 16);\n }\n\n getAuthenticatedStreamUrl(lowQuality = false) {\n const prefix = `rtsp://${this.config.streamUser}:${this.config.streamPassword}@${this.config.ipAddress}:${this.kStreamPort}`;\n return lowQuality ? `${prefix}/stream2` : `${prefix}/stream1`;\n }\n\n private generateCnonce() {\n return crypto.randomBytes(8).toString(\"hex\").toUpperCase();\n }\n\n private validateDeviceConfirm(nonce: string, deviceConfirm: string) {\n const hashedNoncesWithSHA256 = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.hashedSha256Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n const hashedNoncesWithMD5 = crypto\n .createHash(\"md5\")\n .update(this.cnonce + this.hashedMD5Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n\n if (deviceConfirm === hashedNoncesWithSHA256 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"sha256\";\n return true;\n }\n\n if (deviceConfirm === hashedNoncesWithMD5 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"md5\";\n return true;\n }\n\n return false;\n }\n\n async refreshStok(loginRetryCount = 0): Promise<string> {\n const isSecureConnection = await this.isSecureConnection();\n\n let response = null;\n let responseData = null;\n\n let fetchParams = {};\n if (isSecureConnection) {\n this.log.debug(\"StokRefresh: Using secure connection\");\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n cnonce: this.cnonce,\n encrypt_type: \"3\",\n username: this.getUsername(),\n },\n }),\n };\n } else {\n this.log.debug(\"StokRefresh: Using unsecure connection\");\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n username: this.getUsername(),\n password: this.getHashedPassword(),\n hashed: true,\n },\n }),\n };\n }\n\n response = await this.fetch(`https://${this.config.ipAddress}`, fetchParams);\n responseData = await response.json();\n\n this.log.debug(\"StokRefresh: Login response :>> \" + response.status + JSON.stringify(responseData));\n\n if (response.status === 401) {\n if (responseData?.result?.data?.code === 40411) {\n throw new Error(\"Invalid credentials\");\n }\n }\n const nonce = responseData?.result?.data?.nonce;\n const deviceConfirm = responseData?.result?.data?.device_confirm;\n\n if (isSecureConnection && nonce && deviceConfirm) {\n if (!this.validateDeviceConfirm(nonce, deviceConfirm)) {\n throw new Error(\"Invalid device confirm\");\n }\n\n const digestPasswd = crypto\n .createHash(\"sha256\")\n .update(this.getHashedPassword() + this.cnonce + nonce)\n .digest(\"hex\")\n .toUpperCase();\n\n const digestPasswdFull = Buffer.concat([\n Buffer.from(digestPasswd, \"utf8\"),\n Buffer.from(this.cnonce!, \"utf8\"),\n Buffer.from(nonce, \"utf8\"),\n ]).toString(\"utf8\");\n\n response = await this.fetch(`https://${this.config.ipAddress}`, {\n method: \"POST\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n cnonce: this.cnonce,\n encrypt_type: \"3\",\n digest_passwd: digestPasswdFull,\n username: this.getUsername(),\n },\n }),\n });\n\n responseData = await response.json();\n\n this.log.debug(\"StokRefresh: Start_seq response :>>\", response.status, JSON.stringify(responseData));\n\n if (responseData?.result?.start_seq) {\n if (responseData?.result?.user_group !== \"root\") {\n // # encrypted control via 3rd party account does not seem to be supported\n // # see https://github.com/JurajNyiri/HomeAssistant-Tapo-Control/issues/456\n throw new Error(\"Incorrect user_group detected\");\n }\n\n this.lsk = this.generateEncryptionToken(\"lsk\", nonce);\n this.ivb = this.generateEncryptionToken(\"ivb\", nonce);\n this.seq = responseData.result.start_seq;\n }\n }\n\n if (responseData?.result?.data?.sec_left > 0) {\n throw new Error(`StokRefresh: Temporary Suspension: Try again in ${responseData.result.data.sec_left} seconds`);\n }\n\n if (responseData?.data?.code == -40404 && responseData?.data?.sec_left > 0) {\n throw new Error(`StokRefresh: Temporary Suspension: Try again in ${responseData.data.sec_left} seconds`);\n }\n\n if (responseData?.result?.stok) {\n this.stok = responseData.result.stok;\n this.log.debug(\"StokRefresh: Success :>>\" + this.stok);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return this.stok!;\n }\n\n if (responseData?.error_code === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {\n this.log.debug(\n `Unexpected response, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.` + response.status + JSON.stringify(responseData),\n );\n return this.refreshStok(loginRetryCount + 1);\n }\n\n throw new Error(\"Invalid authentication data\");\n }\n\n async isSecureConnection() {\n if (this.isSecureConnectionValue === null) {\n const response = await this.fetch(`https://${this.config.ipAddress}`, {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n encrypt_type: \"3\",\n username: this.getUsername(),\n },\n }),\n });\n this.log.debug(JSON.stringify(response));\n const json = await response.json();\n\n this.log.debug(\"isSecureConnection response :>> \" + response.status + json);\n\n this.isSecureConnectionValue = json.error_code == -40413 && json?.result?.data?.encrypt_type?.includes(\"3\");\n }\n\n return this.isSecureConnectionValue;\n }\n\n getStok(loginRetryCount = 0): Promise<string> {\n if (this.stok) {\n return new Promise((resolve) => resolve(this.stok!));\n }\n\n if (!this.stokPromise) {\n this.stokPromise = () => this.refreshStok(loginRetryCount);\n }\n\n return this.stokPromise()\n .then(() => {\n return this.stok!;\n })\n .finally(() => {\n this.stokPromise = undefined;\n });\n }\n\n private async getAuthenticatedAPIURL(loginRetryCount = 0) {\n const token = await this.getStok(loginRetryCount);\n return `https://${this.config.ipAddress}/stok=${token}/ds`;\n }\n\n encryptRequest(request: string) {\n const cipher = crypto.createCipheriv(\"aes-128-cbc\", this.lsk!, this.ivb!);\n let ct_bytes = cipher.update(this.encryptPad(request, AES_BLOCK_SIZE), \"utf-8\", \"hex\");\n ct_bytes += cipher.final(\"hex\");\n return Buffer.from(ct_bytes, \"hex\");\n }\n\n private encryptPad(text: string, blocksize: number) {\n const padSize = blocksize - (text.length % blocksize);\n const padding = String.fromCharCode(padSize).repeat(padSize);\n return text + padding;\n }\n\n private decryptResponse(response: string): string {\n const decipher = crypto.createDecipheriv(\"aes-128-cbc\", this.lsk!, this.ivb!);\n let decrypted = decipher.update(response, \"base64\", \"utf-8\");\n decrypted += decipher.final(\"utf-8\");\n return this.encryptUnpad(decrypted, AES_BLOCK_SIZE);\n }\n\n private encryptUnpad(text: string, blockSize: number): string {\n const paddingLength = Number(text[text.length - 1]) || 0;\n if (paddingLength > blockSize || paddingLength > text.length) {\n throw new Error(\"Invalid padding\");\n }\n for (let i = text.length - paddingLength; i < text.length; i++) {\n if (text.charCodeAt(i) !== paddingLength) {\n throw new Error(\"Invalid padding\");\n }\n }\n return text.slice(0, text.length - paddingLength).toString();\n }\n\n private getTapoTag(request: TAPOCameraEncryptedRequest) {\n const tag = crypto\n .createHash(\"sha256\")\n .update(this.getHashedPassword() + this.cnonce)\n .digest(\"hex\")\n .toUpperCase();\n return crypto\n .createHash(\"sha256\")\n .update(tag + JSON.stringify(request) + this.seq!.toString())\n .digest(\"hex\")\n .toUpperCase();\n }\n\n private pendingAPIRequests: Map<string, Promise<TAPOCameraResponse>> = new Map();\n\n private async apiRequest(req: TAPOCameraRequest, loginRetryCount = 0): Promise<TAPOCameraResponse> {\n const reqJson = JSON.stringify(req);\n\n if (this.pendingAPIRequests.has(reqJson)) {\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n this.log.debug(\"API new request: \" + reqJson);\n\n this.pendingAPIRequests.set(\n reqJson,\n (async () => {\n try {\n const isSecureConnection = await this.isSecureConnection();\n const url = await this.getAuthenticatedAPIURL(loginRetryCount);\n\n const fetchParams: RequestInit = {\n method: \"post\",\n };\n\n if (this.seq && isSecureConnection) {\n const encryptedRequest: TAPOCameraEncryptedRequest = {\n method: \"securePassthrough\",\n params: {\n request: Buffer.from(this.encryptRequest(JSON.stringify(req))).toString(\"base64\"),\n },\n };\n fetchParams.headers = {\n ...this.getHeaders(),\n Tapo_tag: this.getTapoTag(encryptedRequest),\n Seq: this.seq.toString(),\n };\n fetchParams.body = JSON.stringify(encryptedRequest);\n this.seq += 1;\n } else {\n fetchParams.body = JSON.stringify(req);\n }\n\n const response = await this.fetch(url, fetchParams);\n let json = await response.json();\n\n if (isSecureConnection) {\n const encryptedResponse = json as TAPOCameraEncryptedResponse;\n if (encryptedResponse.result.response) {\n const decryptedResponse = this.decryptResponse(encryptedResponse.result.response);\n json = JSON.parse(decryptedResponse) as TAPOCameraResponse;\n }\n } else {\n json = json as TAPOCameraResponse;\n }\n\n this.log.debug(`API response: ` + response.status, JSON.stringify(json));\n\n // Apparently the Tapo C200 returns 500 on successful requests,\n // but it's indicating an expiring token, therefore refresh the token next time\n if (isSecureConnection && response.status === 500) {\n this.stok = undefined;\n }\n\n // Check if we have to refresh the token\n if (json.error_code === -40401 || json.error_code === -1) {\n this.log.debug(\"API request failed, reauthenticating\");\n this.stok = undefined;\n return this.apiRequest(req, loginRetryCount + 1);\n }\n\n return json as TAPOCameraResponse;\n } finally {\n this.pendingAPIRequests.delete(reqJson);\n }\n })(),\n );\n\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n async setLensMaskConfig(value: boolean) {\n this.log.debug(\"Processing setLensMaskConfig\" + value);\n\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setLensMaskConfig\",\n params: {\n lens_mask: {\n lens_mask_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n if (json.error_code !== 0) {\n throw new Error(\"Failed to perform action\");\n }\n }\n\n async setAlertConfig(value: boolean) {\n this.log.debug(\"Processing setAlertConfig\" + value);\n\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setAlertConfig\",\n params: {\n msg_alarm: {\n chn1_msg_alarm_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n return json.error_code !== 0;\n }\n async setForceWhitelampState(value: boolean) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setForceWhitelampState\",\n params: {\n image: {\n switch: {\n force_wtl_state: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n return json.error_code !== 0;\n }\n async moveMotorStep(angle: string) {\n angle = angle.toString();\n const json = await this.apiRequest({ method: \"do\", motor: { movestep: { direction: angle } } });\n\n return json.error_code !== 0;\n }\n\n async moveMotor(x: number, y: number) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [{ method: \"do\", motor: { move: { x_coord: x, y_coord: y } } }],\n },\n });\n\n return json.error_code !== 0;\n }\n\n async getBasicInfo() {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"getDeviceInfo\",\n params: {\n device_info: {\n name: [\"basic_info\"],\n },\n },\n },\n ],\n },\n });\n\n const info = json.result.responses[0] as TAPOCameraResponseDeviceInfo;\n return info.result.device_info.basic_info;\n }\n\n async getStatus(): Promise<{ lensMask: boolean; alert: boolean }> {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"getAlertConfig\",\n params: {\n msg_alarm: {\n name: \"chn1_msg_alarm_info\",\n },\n },\n },\n {\n method: \"getLensMaskConfig\",\n params: {\n lens_mask: {\n name: \"lens_mask_info\",\n },\n },\n },\n {\n method: \"getForceWhitelampState\",\n params: {\n image: {\n name: \"switch\",\n },\n },\n },\n ],\n },\n });\n this.log.debug(`getStatus json: ${JSON.stringify(json)}`);\n if (json.error_code !== 0) {\n throw new Error(\"Camera replied with error\");\n }\n if (!json.result.responses) {\n throw new Error(\"Camera replied with invalid response\");\n }\n const alertConfig = json.result.responses.find((r) => r.method === \"getAlertConfig\") as TAPOCameraResponseGetAlert;\n\n const forceWhitelampState = json.result.responses.find((r) => r.method === \"getForceWhitelampState\") as TAPOCameraResponseGetForce;\n const lensMaskConfig = json.result.responses.find((r) => r.method === \"getLensMaskConfig\") as TAPOCameraResponseGetLensMask;\n\n return {\n alert: alertConfig.result.msg_alarm.chn1_msg_alarm_info.enabled === \"on\",\n lensMask: lensMaskConfig.result.lens_mask.lens_mask_info.enabled === \"on\",\n forceWhiteLamp: forceWhitelampState.result.image ? forceWhitelampState.result.image.switch.force_wtl_state === \"on\" : false,\n };\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import fetch, { RequestInit } from \"node-fetch\";\nimport https, { Agent } from \"https\";\nimport crypto from \"crypto\";\nimport { OnvifCamera } from \"./onvifCamera\";\nimport type {\n TAPOCameraEncryptedRequest,\n TAPOCameraEncryptedResponse,\n TAPOCameraRequest,\n TAPOCameraResponse,\n TAPOCameraResponseDeviceInfo,\n TAPOCameraResponseGetAlert,\n TAPOCameraResponseGetLensMask,\n} from \"./types/tapo\";\n\nconst MAX_LOGIN_RETRIES = 3;\nconst AES_BLOCK_SIZE = 16;\n\ntype CameraConfig = {\n name: string;\n ipAddress: string;\n username: string;\n password: string;\n streamUser: string;\n streamPassword: string;\n\n pullInterval?: number;\n disableStreaming?: boolean;\n disablePrivacyAccessory?: boolean;\n disableAlarmAccessory?: boolean;\n disableMotionAccessory?: boolean;\n lowQuality?: boolean;\n\n videoConfig?: VideoConfig;\n\n privacyAccessoryName?: string;\n alarmAccessoryName?: string;\n};\nexport class TAPOCamera extends OnvifCamera {\n private readonly kStreamPort = 554;\n private readonly httpsAgent: Agent;\n\n private readonly hashedMD5Password: string;\n private readonly hashedSha256Password: string;\n private passwordEncryptionMethod: \"md5\" | \"sha256\" | null = \"md5\";\n\n private isSecureConnectionValue: boolean | null = null;\n\n private stokPromise: (() => Promise<string>) | undefined;\n\n private readonly cnonce: string;\n private lsk: Buffer | undefined;\n private ivb: Buffer | undefined;\n private seq: number | undefined;\n private stok: string | undefined;\n\n private loginRetryCount = 0;\n\n constructor(\n protected readonly log: any,\n protected readonly config: CameraConfig,\n ) {\n super(log, config);\n this.log.debug(\"Constructing Camera on host: \" + config.ipAddress);\n\n this.httpsAgent = new https.Agent({\n rejectUnauthorized: false,\n secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,\n });\n\n this.cnonce = this.generateCnonce();\n\n this.hashedMD5Password = crypto.createHash(\"md5\").update(config.password).digest(\"hex\").toUpperCase();\n this.hashedSha256Password = crypto.createHash(\"sha256\").update(config.password).digest(\"hex\").toUpperCase();\n }\n\n private getUsername() {\n return this.config.username || \"admin\";\n }\n\n private getHeaders() {\n const headers: Record<string, string> = {\n Host: `https://${this.config.ipAddress}`,\n Referer: `https://${this.config.ipAddress}`,\n Accept: \"application/json\",\n \"Accept-Encoding\": \"gzip, deflate\",\n \"User-Agent\": \"Tapo CameraClient Android\",\n Connection: \"close\",\n requestByApp: \"true\",\n \"Content-Type\": \"application/json; charset=UTF-8\",\n };\n return headers;\n }\n\n private getHashedPassword() {\n if (this.passwordEncryptionMethod === \"md5\") {\n return this.hashedMD5Password;\n } else if (this.passwordEncryptionMethod === \"sha256\") {\n return this.hashedSha256Password;\n } else {\n throw new Error(\"Unknown password encryption method \" + this.passwordEncryptionMethod + \"!\");\n }\n }\n\n private fetch(url: string, data: RequestInit) {\n return fetch(url, {\n agent: this.httpsAgent,\n headers: this.getHeaders(),\n ...data,\n });\n }\n\n private generateEncryptionToken(tokenType: string, nonce: string): Buffer {\n const hashedKey = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.getHashedPassword() + nonce)\n .digest(\"hex\")\n .toUpperCase();\n return crypto\n .createHash(\"sha256\")\n .update(tokenType + this.cnonce + nonce + hashedKey)\n .digest()\n .slice(0, 16);\n }\n\n getAuthenticatedStreamUrl(lowQuality = false) {\n const prefix = `rtsp://${this.config.streamUser}:${this.config.streamPassword}@${this.config.ipAddress}:${this.kStreamPort}`;\n return lowQuality ? `${prefix}/stream2` : `${prefix}/stream1`;\n }\n\n private generateCnonce() {\n return crypto.randomBytes(8).toString(\"hex\").toUpperCase();\n }\n\n private validateDeviceConfirm(nonce: string, deviceConfirm: string) {\n const hashedNoncesWithSHA256 = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.hashedSha256Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n const hashedNoncesWithMD5 = crypto\n .createHash(\"md5\")\n .update(this.cnonce + this.hashedMD5Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n\n if (deviceConfirm === hashedNoncesWithSHA256 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"sha256\";\n return true;\n }\n\n if (deviceConfirm === hashedNoncesWithMD5 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"md5\";\n return true;\n }\n\n return false;\n }\n\n async refreshStok(loginRetryCount = 0): Promise<string> {\n const isSecureConnection = await this.isSecureConnection();\n\n let response = null;\n let responseData = null;\n\n let fetchParams = {};\n if (isSecureConnection) {\n this.log.debug(\"StokRefresh: Using secure connection\");\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n cnonce: this.cnonce,\n encrypt_type: \"3\",\n username: this.getUsername(),\n },\n }),\n };\n } else {\n this.log.debug(\"StokRefresh: Using unsecure connection\");\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n username: this.getUsername(),\n password: this.getHashedPassword(),\n hashed: true,\n },\n }),\n };\n }\n\n response = await this.fetch(`https://${this.config.ipAddress}`, fetchParams);\n responseData = await response.json();\n\n this.log.debug(\"StokRefresh: Login response :>> \" + response.status + JSON.stringify(responseData));\n\n if (response.status === 401) {\n if (responseData?.result?.data?.code === 40411) {\n throw new Error(\"Invalid credentials\");\n }\n }\n const nonce = responseData?.result?.data?.nonce;\n const deviceConfirm = responseData?.result?.data?.device_confirm;\n\n if (isSecureConnection && nonce && deviceConfirm) {\n if (!this.validateDeviceConfirm(nonce, deviceConfirm)) {\n throw new Error(\"Invalid device confirm\");\n }\n\n const digestPasswd = crypto\n .createHash(\"sha256\")\n .update(this.getHashedPassword() + this.cnonce + nonce)\n .digest(\"hex\")\n .toUpperCase();\n\n const digestPasswdFull = Buffer.concat([\n Buffer.from(digestPasswd, \"utf8\"),\n Buffer.from(this.cnonce!, \"utf8\"),\n Buffer.from(nonce, \"utf8\"),\n ]).toString(\"utf8\");\n\n response = await this.fetch(`https://${this.config.ipAddress}`, {\n method: \"POST\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n cnonce: this.cnonce,\n encrypt_type: \"3\",\n digest_passwd: digestPasswdFull,\n username: this.getUsername(),\n },\n }),\n });\n\n responseData = await response.json();\n\n this.log.debug(\"StokRefresh: Start_seq response :>>\", response.status, JSON.stringify(responseData));\n\n if (responseData?.result?.start_seq) {\n if (responseData?.result?.user_group !== \"root\") {\n // # encrypted control via 3rd party account does not seem to be supported\n // # see https://github.com/JurajNyiri/HomeAssistant-Tapo-Control/issues/456\n throw new Error(\"Incorrect user_group detected\");\n }\n\n this.lsk = this.generateEncryptionToken(\"lsk\", nonce);\n this.ivb = this.generateEncryptionToken(\"ivb\", nonce);\n this.seq = responseData.result.start_seq;\n }\n }\n\n if (responseData?.result?.data?.sec_left > 0) {\n throw new Error(`StokRefresh: Temporary Suspension: Try again in ${responseData.result.data.sec_left} seconds`);\n }\n\n if (responseData?.data?.code == -40404 && responseData?.data?.sec_left > 0) {\n throw new Error(`StokRefresh: Temporary Suspension: Try again in ${responseData.data.sec_left} seconds`);\n }\n\n if (responseData?.result?.stok) {\n this.stok = responseData.result.stok;\n this.log.debug(\"StokRefresh: Success :>>\" + this.stok);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return this.stok!;\n }\n\n if (responseData?.error_code === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {\n this.log.debug(\n `Unexpected response, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.` + response.status + JSON.stringify(responseData),\n );\n return this.refreshStok(loginRetryCount + 1);\n }\n\n throw new Error(\"Invalid authentication data\");\n }\n\n async isSecureConnection() {\n if (this.isSecureConnectionValue === null) {\n const response = await this.fetch(`https://${this.config.ipAddress}`, {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n encrypt_type: \"3\",\n username: this.getUsername(),\n },\n }),\n });\n this.log.debug(JSON.stringify(response));\n const json = await response.json();\n\n this.log.debug(\"isSecureConnection response :>> \" + response.status + json);\n\n this.isSecureConnectionValue = json.error_code == -40413 && json?.result?.data?.encrypt_type?.includes(\"3\");\n }\n\n return this.isSecureConnectionValue;\n }\n\n getStok(loginRetryCount = 0): Promise<string> {\n if (this.stok) {\n return new Promise((resolve) => resolve(this.stok!));\n }\n\n if (!this.stokPromise) {\n this.stokPromise = () => this.refreshStok(loginRetryCount);\n }\n\n return this.stokPromise()\n .then(() => {\n return this.stok!;\n })\n .finally(() => {\n this.stokPromise = undefined;\n });\n }\n\n private async getAuthenticatedAPIURL(loginRetryCount = 0) {\n const token = await this.getStok(loginRetryCount);\n return `https://${this.config.ipAddress}/stok=${token}/ds`;\n }\n\n encryptRequest(request: string) {\n const cipher = crypto.createCipheriv(\"aes-128-cbc\", this.lsk!, this.ivb!);\n let ct_bytes = cipher.update(this.encryptPad(request, AES_BLOCK_SIZE), \"utf-8\", \"hex\");\n ct_bytes += cipher.final(\"hex\");\n return Buffer.from(ct_bytes, \"hex\");\n }\n\n private encryptPad(text: string, blocksize: number) {\n const padSize = blocksize - (text.length % blocksize);\n const padding = String.fromCharCode(padSize).repeat(padSize);\n return text + padding;\n }\n\n private decryptResponse(response: string): string {\n const decipher = crypto.createDecipheriv(\"aes-128-cbc\", this.lsk!, this.ivb!);\n let decrypted = decipher.update(response, \"base64\", \"utf-8\");\n decrypted += decipher.final(\"utf-8\");\n return this.encryptUnpad(decrypted, AES_BLOCK_SIZE);\n }\n\n private encryptUnpad(text: string, blockSize: number): string {\n const paddingLength = Number(text[text.length - 1]) || 0;\n if (paddingLength > blockSize || paddingLength > text.length) {\n throw new Error(\"Invalid padding\");\n }\n for (let i = text.length - paddingLength; i < text.length; i++) {\n if (text.charCodeAt(i) !== paddingLength) {\n throw new Error(\"Invalid padding\");\n }\n }\n return text.slice(0, text.length - paddingLength).toString();\n }\n\n private getTapoTag(request: TAPOCameraEncryptedRequest) {\n const tag = crypto\n .createHash(\"sha256\")\n .update(this.getHashedPassword() + this.cnonce)\n .digest(\"hex\")\n .toUpperCase();\n return crypto\n .createHash(\"sha256\")\n .update(tag + JSON.stringify(request) + this.seq!.toString())\n .digest(\"hex\")\n .toUpperCase();\n }\n\n private pendingAPIRequests: Map<string, Promise<TAPOCameraResponse>> = new Map();\n\n private async apiRequest(req: TAPOCameraRequest, loginRetryCount = 0): Promise<TAPOCameraResponse> {\n const reqJson = JSON.stringify(req);\n\n if (this.pendingAPIRequests.has(reqJson)) {\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n this.log.debug(\"API new request: \" + reqJson);\n\n this.pendingAPIRequests.set(\n reqJson,\n (async () => {\n try {\n const isSecureConnection = await this.isSecureConnection();\n const url = await this.getAuthenticatedAPIURL(loginRetryCount);\n\n const fetchParams: RequestInit = {\n method: \"post\",\n };\n\n if (this.seq && isSecureConnection) {\n const encryptedRequest: TAPOCameraEncryptedRequest = {\n method: \"securePassthrough\",\n params: {\n request: Buffer.from(this.encryptRequest(JSON.stringify(req))).toString(\"base64\"),\n },\n };\n fetchParams.headers = {\n ...this.getHeaders(),\n Tapo_tag: this.getTapoTag(encryptedRequest),\n Seq: this.seq.toString(),\n };\n fetchParams.body = JSON.stringify(encryptedRequest);\n this.seq += 1;\n } else {\n fetchParams.body = JSON.stringify(req);\n }\n\n const response = await this.fetch(url, fetchParams);\n let json = await response.json();\n\n if (isSecureConnection) {\n const encryptedResponse = json as TAPOCameraEncryptedResponse;\n if (encryptedResponse.result.response) {\n const decryptedResponse = this.decryptResponse(encryptedResponse.result.response);\n json = JSON.parse(decryptedResponse) as TAPOCameraResponse;\n }\n } else {\n json = json as TAPOCameraResponse;\n }\n\n this.log.debug(`API response: ` + response.status, JSON.stringify(json));\n\n // Apparently the Tapo C200 returns 500 on successful requests,\n // but it's indicating an expiring token, therefore refresh the token next time\n if (isSecureConnection && response.status === 500) {\n this.stok = undefined;\n }\n\n // Check if we have to refresh the token\n if (json.error_code === -40401 || json.error_code === -1) {\n this.log.debug(\"API request failed, reauthenticating\");\n this.stok = undefined;\n return this.apiRequest(req, loginRetryCount + 1);\n }\n\n return json as TAPOCameraResponse;\n } finally {\n this.pendingAPIRequests.delete(reqJson);\n }\n })(),\n );\n\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n async setLensMaskConfig(value: boolean) {\n this.log.debug(\"Processing setLensMaskConfig\" + value);\n\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setLensMaskConfig\",\n params: {\n lens_mask: {\n lens_mask_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n if (json.error_code !== 0) {\n throw new Error(\"Failed to perform action\");\n }\n }\n\n async setAlertConfig(value: boolean) {\n this.log.debug(\"Processing setAlertConfig\" + value);\n\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setAlertConfig\",\n params: {\n msg_alarm: {\n chn1_msg_alarm_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n return json.error_code !== 0;\n }\n async setForceWhitelampState(value: boolean) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setForceWhitelampState\",\n params: {\n image: {\n switch: {\n force_wtl_state: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n return json.error_code !== 0;\n }\n async moveMotorStep(angle: string) {\n angle = angle.toString();\n const json = await this.apiRequest({ method: \"do\", motor: { movestep: { direction: angle } } });\n\n return json.error_code !== 0;\n }\n\n async moveMotor(x: number, y: number) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [{ method: \"do\", motor: { move: { x_coord: x, y_coord: y } } }],\n },\n });\n\n return json.error_code !== 0;\n }\n\n async getBasicInfo() {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"getDeviceInfo\",\n params: {\n device_info: {\n name: [\"basic_info\"],\n },\n },\n },\n ],\n },\n });\n\n const info = json.result.responses[0] as TAPOCameraResponseDeviceInfo;\n return info.result.device_info.basic_info;\n }\n\n async getStatus(): Promise<{ lensMask: boolean; alert: boolean }> {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"getAlertConfig\",\n params: {\n msg_alarm: {\n name: \"chn1_msg_alarm_info\",\n },\n },\n },\n {\n method: \"getLensMaskConfig\",\n params: {\n lens_mask: {\n name: \"lens_mask_info\",\n },\n },\n },\n {\n method: \"getForceWhitelampState\",\n params: {\n image: {\n name: \"switch\",\n },\n },\n },\n ],\n },\n });\n this.log.debug(`getStatus json: ${JSON.stringify(json)}`);\n if (json.error_code !== 0) {\n throw new Error(\"Camera replied with error\");\n }\n if (!json.result.responses) {\n throw new Error(\"Camera replied with invalid response\");\n }\n const alertConfig = json.result.responses.find((r) => r.method === \"getAlertConfig\") as TAPOCameraResponseGetAlert;\n\n const forceWhitelampState = json.result.responses.find((r) => r.method === \"getForceWhitelampState\") as TAPOCameraResponseGetForce;\n const lensMaskConfig = json.result.responses.find((r) => r.method === \"getLensMaskConfig\") as TAPOCameraResponseGetLensMask;\n\n return {\n alert: alertConfig.result.msg_alarm.chn1_msg_alarm_info.enabled === \"on\",\n lensMask: lensMaskConfig.result.lens_mask.lens_mask_info.enabled === \"on\",\n forceWhiteLamp: forceWhitelampState.result.image ? forceWhitelampState.result.image.switch.force_wtl_state === \"on\" : false,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["https", "crypto", "fetch"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/energyUsage.ts"],
|
|
4
|
-
"sourcesContent": ["export class EnergyUsage{\n
|
|
4
|
+
"sourcesContent": ["export class EnergyUsage{\n current_power!: number;\n}"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,YAAW;AAExB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/lib/utils/l510e.js
CHANGED
|
@@ -27,7 +27,7 @@ __export(l510e_exports, {
|
|
|
27
27
|
default: () => L510E
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(l510e_exports);
|
|
30
|
-
var import_p100 = __toESM(require("./p100"));
|
|
30
|
+
var import_p100 = __toESM(require("./p100.js"));
|
|
31
31
|
class L510E extends import_p100.default {
|
|
32
32
|
constructor(log, ipAddress, email, password, timeout) {
|
|
33
33
|
super(log, ipAddress, email, password, timeout);
|
|
@@ -38,8 +38,8 @@ class L510E extends import_p100.default {
|
|
|
38
38
|
this.timeout = timeout;
|
|
39
39
|
this.log.debug("Constructing L510E on host: " + ipAddress);
|
|
40
40
|
}
|
|
41
|
-
async getDeviceInfo() {
|
|
42
|
-
return super.getDeviceInfo().then(() => {
|
|
41
|
+
async getDeviceInfo(force) {
|
|
42
|
+
return super.getDeviceInfo(force).then(() => {
|
|
43
43
|
return this.getSysInfo();
|
|
44
44
|
});
|
|
45
45
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/l510e.ts"],
|
|
4
|
-
"sourcesContent": ["import
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import { LightSysinfo } from \"./types.js\";\nimport P100 from \"./p100.js\";\n\nexport default class L510E extends P100 {\n private _lightSysInfo!: LightSysinfo;\n\n constructor(\n public readonly log: any,\n public readonly ipAddress: string,\n public readonly email: string,\n public readonly password: string,\n public readonly timeout: number,\n ) {\n super(log, ipAddress, email, password, timeout);\n this.log.debug(\"Constructing L510E on host: \" + ipAddress);\n }\n\n async getDeviceInfo(force?: boolean): Promise<LightSysinfo> {\n return super.getDeviceInfo(force).then(() => {\n return this.getSysInfo();\n });\n }\n\n async setBrightness(brightness: number): Promise<boolean> {\n const payload =\n \"{\" +\n '\"method\": \"set_device_info\",' +\n '\"params\": {' +\n '\"brightness\": ' +\n brightness +\n \"},\" +\n '\"requestTimeMils\": ' +\n Math.round(Date.now() * 1000) +\n \"\" +\n \"};\";\n\n return this.sendRequest(payload);\n }\n\n protected setSysInfo(sysInfo: LightSysinfo) {\n this._lightSysInfo = sysInfo;\n this._lightSysInfo.last_update = Date.now();\n }\n\n public getSysInfo(): LightSysinfo {\n return this._lightSysInfo;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kBAAiB;AAEjB,MAAO,cAA4B,YAAAA,QAAK;AAAA,EAGtC,YACkB,KACA,WACA,OACA,UACA,SAChB;AACA,UAAM,KAAK,WAAW,OAAO,UAAU,OAAO;AAN9B;AACA;AACA;AACA;AACA;AAGhB,SAAK,IAAI,MAAM,iCAAiC,SAAS;AAAA,EAC3D;AAAA,EAEA,MAAM,cAAc,OAAwC;AAC1D,WAAO,MAAM,cAAc,KAAK,EAAE,KAAK,MAAM;AAC3C,aAAO,KAAK,WAAW;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,YAAsC;AACxD,UAAM,UACJ,2DAIA,aACA,0BAEA,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,IAE5B;AAEF,WAAO,KAAK,YAAY,OAAO;AAAA,EACjC;AAAA,EAEU,WAAW,SAAuB;AAC1C,SAAK,gBAAgB;AACrB,SAAK,cAAc,cAAc,KAAK,IAAI;AAAA,EAC5C;AAAA,EAEO,aAA2B;AAChC,WAAO,KAAK;AAAA,EACd;AACF;",
|
|
6
6
|
"names": ["P100"]
|
|
7
7
|
}
|
package/build/lib/utils/l520e.js
CHANGED
|
@@ -38,8 +38,8 @@ class L520E extends import_l510e.default {
|
|
|
38
38
|
this.timeout = timeout;
|
|
39
39
|
this.log.debug("Constructing L510E on host: " + ipAddress);
|
|
40
40
|
}
|
|
41
|
-
async getDeviceInfo() {
|
|
42
|
-
return super.getDeviceInfo().then(() => {
|
|
41
|
+
async getDeviceInfo(force) {
|
|
42
|
+
return super.getDeviceInfo(force).then(() => {
|
|
43
43
|
return this.getSysInfo();
|
|
44
44
|
});
|
|
45
45
|
}
|
|
@@ -48,9 +48,7 @@ class L520E extends import_l510e.default {
|
|
|
48
48
|
this.log.debug("Color Temp Tapo :" + transformedColorTemp);
|
|
49
49
|
const roundedValue = transformedColorTemp > 6500 ? 6500 : transformedColorTemp < 2500 ? 2500 : transformedColorTemp;
|
|
50
50
|
const payload = '{"method": "set_device_info","params": {"hue": 0,"saturation": 0,"color_temp": ' + roundedValue + '},"requestTimeMils": ' + Math.round(Date.now() * 1e3) + "};";
|
|
51
|
-
return this.
|
|
52
|
-
return true;
|
|
53
|
-
});
|
|
51
|
+
return this.sendRequest(payload);
|
|
54
52
|
}
|
|
55
53
|
transformColorTemp(value) {
|
|
56
54
|
return Math.floor(1e6 / value);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/l520e.ts"],
|
|
4
|
-
"sourcesContent": ["import L510E from \"./l510e\";\nimport { ColorTempLightSysinfo } from \"./types\";\n\nexport default class L520E extends L510E {\n private _colorTempSysInfo!:
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAGlB,MAAO,cAA4B,aAAAA,QAAM;AAAA,
|
|
4
|
+
"sourcesContent": ["import L510E from \"./l510e\";\nimport { ColorTempLightSysinfo } from \"./types\";\n\nexport default class L520E extends L510E {\n\n private _colorTempSysInfo!:ColorTempLightSysinfo;\n\n constructor(\n public readonly log: any,\n public readonly ipAddress: string,\n public readonly email: string,\n public readonly password: string,\n public readonly timeout: number,\n ) {\n super(log, ipAddress, email, password, timeout);\n this.log.debug('Constructing L510E on host: ' + ipAddress);\n }\n\n async getDeviceInfo(force?:boolean): Promise<ColorTempLightSysinfo>{\n return super.getDeviceInfo(force).then(() => {\n return this.getSysInfo();\n });\n }\n\n async setColorTemp(color_temp:number):Promise<boolean>{\n const transformedColorTemp = this.transformColorTemp(color_temp);\n this.log.debug('Color Temp Tapo :' + transformedColorTemp);\n\n const roundedValue = transformedColorTemp > 6500 ? 6500 : transformedColorTemp < 2500 ? \n 2500 : transformedColorTemp;\n\n const payload = '{'+\n '\"method\": \"set_device_info\",'+\n '\"params\": {'+\n '\"hue\": 0,' +\n '\"saturation\": 0,' +\n '\"color_temp\": ' + roundedValue +\n '},'+\n '\"requestTimeMils\": ' + Math.round(Date.now() * 1000) + ''+\n '};';\n\n return this.sendRequest(payload);\n }\n\n private transformColorTemp(value: number):number{\n return Math.floor(1000000 / value);\n }\n\n async getColorTemp(): Promise<number>{\n return super.getDeviceInfo().then(() => {\n return this.calculateColorTemp(this.getSysInfo().color_temp);\n });\n }\n\n calculateColorTemp(tapo_color_temp:number):number{\n const newValue = this.transformColorTemp(tapo_color_temp);\n return newValue > 400 ? 400 : (newValue < 154 ? 154 : newValue);\n }\n\n protected setSysInfo(sysInfo:ColorTempLightSysinfo){\n this._colorTempSysInfo = sysInfo;\n this._colorTempSysInfo.last_update = Date.now();\n }\n\n public getSysInfo():ColorTempLightSysinfo{\n return this._colorTempSysInfo;\n }\n}"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAGlB,MAAO,cAA4B,aAAAA,QAAM;AAAA,EAIvC,YACkB,KACA,WACA,OACA,UACA,SAChB;AACA,UAAM,KAAK,WAAW,OAAO,UAAU,OAAO;AAN9B;AACA;AACA;AACA;AACA;AAGhB,SAAK,IAAI,MAAM,iCAAiC,SAAS;AAAA,EAC3D;AAAA,EAEA,MAAM,cAAc,OAA+C;AACjE,WAAO,MAAM,cAAc,KAAK,EAAE,KAAK,MAAM;AAC3C,aAAO,KAAK,WAAW;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAAa,YAAmC;AACpD,UAAM,uBAAuB,KAAK,mBAAmB,UAAU;AAC/D,SAAK,IAAI,MAAM,sBAAsB,oBAAoB;AAEzD,UAAM,eAAe,uBAAuB,OAAO,OAAO,uBAAuB,OAC/E,OAAO;AAET,UAAM,UAAU,oFAKiB,eACnB,0BACwB,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,IACpD;AAEd,WAAO,KAAK,YAAY,OAAO;AAAA,EACjC;AAAA,EAEQ,mBAAmB,OAAqB;AAC9C,WAAO,KAAK,MAAM,MAAU,KAAK;AAAA,EACnC;AAAA,EAEA,MAAM,eAA+B;AACnC,WAAO,MAAM,cAAc,EAAE,KAAK,MAAM;AACtC,aAAO,KAAK,mBAAmB,KAAK,WAAW,EAAE,UAAU;AAAA,IAC7D,CAAC;AAAA,EACH;AAAA,EAEA,mBAAmB,iBAA8B;AAC/C,UAAM,WAAW,KAAK,mBAAmB,eAAe;AACxD,WAAO,WAAW,MAAM,MAAO,WAAW,MAAM,MAAM;AAAA,EACxD;AAAA,EAEU,WAAW,SAA8B;AACjD,SAAK,oBAAoB;AACzB,SAAK,kBAAkB,cAAc,KAAK,IAAI;AAAA,EAChD;AAAA,EAEO,aAAkC;AACvC,WAAO,KAAK;AAAA,EACd;AACF;",
|
|
6
6
|
"names": ["L510E"]
|
|
7
7
|
}
|
package/build/lib/utils/l530.js
CHANGED
|
@@ -42,8 +42,8 @@ class L530 extends import_l520e.default {
|
|
|
42
42
|
current: 0
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
-
async getDeviceInfo() {
|
|
46
|
-
return super.getDeviceInfo().then(() => {
|
|
45
|
+
async getDeviceInfo(force) {
|
|
46
|
+
return super.getDeviceInfo(force).then(() => {
|
|
47
47
|
return this.getSysInfo();
|
|
48
48
|
});
|
|
49
49
|
}
|
|
@@ -54,6 +54,7 @@ class L530 extends import_l520e.default {
|
|
|
54
54
|
if (!saturation) {
|
|
55
55
|
saturation = 0;
|
|
56
56
|
}
|
|
57
|
+
this.log.debug("Setting color: " + hue + ", " + saturation);
|
|
57
58
|
const payload = '{"method": "set_device_info","params": {"hue": ' + Math.round(hue) + ',"color_temp": 0,"saturation": ' + Math.round(saturation) + '},"requestTimeMils": ' + Math.round(Date.now() * 1e3) + "};";
|
|
58
59
|
return this.sendRequest(payload);
|
|
59
60
|
}
|
|
@@ -66,33 +67,72 @@ class L530 extends import_l520e.default {
|
|
|
66
67
|
}
|
|
67
68
|
async getEnergyUsage() {
|
|
68
69
|
const payload = '{"method": "get_device_usage","requestTimeMils": ' + Math.round(Date.now() * 1e3) + "};";
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
70
|
+
this.log.debug("getEnergyUsage called");
|
|
71
|
+
if (this.is_klap) {
|
|
72
|
+
this.log.debug("getEnergyUsage is klap");
|
|
73
|
+
return this.handleKlapRequest(payload).then((response) => {
|
|
74
|
+
this.log.debug("Consumption: " + JSON.stringify(response));
|
|
75
|
+
if (response && response.result) {
|
|
76
|
+
this._consumption = {
|
|
77
|
+
total: response.result.power_usage.today / 1e3,
|
|
78
|
+
current: this._consumption ? response.result.power_usage.today / this.toHours(response.result.time_usage.today) : 0
|
|
79
|
+
};
|
|
80
|
+
} else {
|
|
81
|
+
this._consumption = {
|
|
82
|
+
total: 0,
|
|
83
|
+
current: 0
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return response.result;
|
|
87
|
+
}).catch((error) => {
|
|
88
|
+
if (error.message && error.message.indexOf("9999") > 0) {
|
|
89
|
+
return this.reconnect().then(() => {
|
|
90
|
+
return this.handleKlapRequest(payload).then(() => {
|
|
91
|
+
return true;
|
|
92
|
+
});
|
|
87
93
|
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
return this.handleRequest(payload).then((response) => {
|
|
99
|
+
this.log.debug("Consumption: " + response);
|
|
100
|
+
if (response && response.result) {
|
|
101
|
+
this._consumption = {
|
|
102
|
+
total: response.result.power_usage.today / 1e3,
|
|
103
|
+
current: this._consumption ? response.result.power_usage.today / this.toHours(response.result.time_usage.today) : 0
|
|
104
|
+
};
|
|
105
|
+
} else {
|
|
106
|
+
this._consumption = {
|
|
107
|
+
total: 0,
|
|
108
|
+
current: 0
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return response.result;
|
|
112
|
+
}).catch((error) => {
|
|
113
|
+
if (error.message && error.message.indexOf("9999") > 0) {
|
|
114
|
+
return this.reconnect().then(() => {
|
|
115
|
+
return this.handleRequest(payload).then(() => {
|
|
116
|
+
return true;
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
92
123
|
}
|
|
93
124
|
getPowerConsumption() {
|
|
125
|
+
if (!this.getSysInfo().device_on) {
|
|
126
|
+
return {
|
|
127
|
+
total: this._consumption.total,
|
|
128
|
+
current: 0
|
|
129
|
+
};
|
|
130
|
+
}
|
|
94
131
|
return this._consumption;
|
|
95
132
|
}
|
|
133
|
+
toHours(minutes) {
|
|
134
|
+
return minutes / 60;
|
|
135
|
+
}
|
|
96
136
|
}
|
|
97
137
|
// Annotate the CommonJS export names for ESM import in node:
|
|
98
138
|
0 && (module.exports = {});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/l530.ts"],
|
|
4
|
-
"sourcesContent": ["import L520E from \"./l520e\";\nimport { PowerUsage } from \"./powerUsage\";\nimport { ColorLightSysinfo, ConsumptionInfo } from \"./types\";\n\nexport default class L530 extends L520E {\n private _colorLightSysInfo!:
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAIlB,MAAO,aAA2B,aAAAA,QAAM;AAAA,
|
|
4
|
+
"sourcesContent": ["import L520E from \"./l520e\";\nimport { PowerUsage } from \"./powerUsage\";\nimport { ColorLightSysinfo, ConsumptionInfo } from \"./types\";\n\nexport default class L530 extends L520E {\n\n private _colorLightSysInfo!:ColorLightSysinfo;\n private _consumption!:ConsumptionInfo;\n\n constructor(\n public readonly log: any,\n public readonly ipAddress: string,\n public readonly email: string,\n public readonly password: string,\n public readonly timeout: number,\n ) {\n super(log, ipAddress, email, password, timeout);\n this.log.debug('Constructing L530 on host: ' + ipAddress);\n this._consumption = {\n total: 0,\n current: 0,\n };\n }\n\n async getDeviceInfo(force?:boolean): Promise<ColorLightSysinfo>{\n return super.getDeviceInfo(force).then(() => {\n return this.getSysInfo();\n });\n }\n\n async setColor(hue:number, saturation:number):Promise<boolean>{\n if(!hue){\n hue = 0;\n }\n if(!saturation){\n saturation = 0;\n }\n this.log.debug('Setting color: ' + hue + ', ' + saturation);\n const payload = '{'+\n '\"method\": \"set_device_info\",'+\n '\"params\": {'+\n '\"hue\": ' + Math.round(hue) + ','+\n '\"color_temp\": 0,' +\n '\"saturation\": ' + Math.round(saturation) +\n '},'+\n '\"requestTimeMils\": ' + Math.round(Date.now() * 1000) + ''+\n '};';\n\n return this.sendRequest(payload);\n }\n\n protected setSysInfo(sysInfo:ColorLightSysinfo){\n this._colorLightSysInfo = sysInfo;\n this._colorLightSysInfo.last_update = Date.now();\n }\n\n public getSysInfo():ColorLightSysinfo{\n return this._colorLightSysInfo;\n }\n\n async getEnergyUsage():Promise<PowerUsage>{ \n const payload = '{'+\n '\"method\": \"get_device_usage\",'+\n '\"requestTimeMils\": ' + Math.round(Date.now() * 1000) + ''+\n '};';\n this.log.debug('getEnergyUsage called');\n\n if(this.is_klap){\n this.log.debug('getEnergyUsage is klap');\n\n return this.handleKlapRequest(payload).then((response)=>{\n this.log.debug('Consumption: ' + JSON.stringify(response));\n if(response && response.result){\n this._consumption = {\n total: response.result.power_usage.today / 1000,\n current: this._consumption ? response.result.power_usage.today / this.toHours(response.result.time_usage.today) : 0,\n };\n } else{\n this._consumption = {\n total: 0,\n current: 0,\n };\n }\n \n return response.result;\n }).catch((error)=>{\n if(error.message && error.message.indexOf('9999') > 0){\n return this.reconnect().then(()=>{\n return this.handleKlapRequest(payload).then(()=>{\n return true;\n });\n });\n }\n return false;\n });\n }else{\n return this.handleRequest(payload).then((response)=>{\n this.log.debug('Consumption: ' + response);\n if(response && response.result){\n this._consumption = {\n total: response.result.power_usage.today / 1000,\n current: this._consumption ? response.result.power_usage.today / this.toHours(response.result.time_usage.today) : 0,\n };\n } else{\n this._consumption = {\n total: 0,\n current: 0,\n };\n }\n \n return response.result;\n }).catch((error)=>{\n if(error.message && error.message.indexOf('9999') > 0){\n return this.reconnect().then(()=>{\n return this.handleRequest(payload).then(()=>{\n return true;\n });\n });\n }\n return false;\n });\n }\n \n }\n\n public getPowerConsumption():ConsumptionInfo{\n if(!this.getSysInfo().device_on){\n return {\n total: this._consumption.total,\n current: 0,\n };\n }\n return this._consumption;\n }\n\n private toHours(minutes: number):number{\n return minutes/60;\n }\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["L520E"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,29 +17,37 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
18
24
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
25
|
var newTpLinkCipher_exports = {};
|
|
20
26
|
__export(newTpLinkCipher_exports, {
|
|
21
27
|
default: () => NewTpLinkCipher
|
|
22
28
|
});
|
|
23
29
|
module.exports = __toCommonJS(newTpLinkCipher_exports);
|
|
30
|
+
var import_crypto = __toESM(require("crypto"));
|
|
24
31
|
class NewTpLinkCipher {
|
|
25
|
-
constructor(localSeed, remoteSeed, authHash) {
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
constructor(localSeed, remoteSeed, authHash, log) {
|
|
33
|
+
this.log = log;
|
|
34
|
+
this._crypto = import_crypto.default;
|
|
35
|
+
if (authHash) {
|
|
36
|
+
this.calculateKey(localSeed, remoteSeed, authHash);
|
|
37
|
+
this.calculateIvSeq(localSeed, remoteSeed, authHash);
|
|
38
|
+
this.calculateSig(localSeed, remoteSeed, authHash);
|
|
39
|
+
}
|
|
30
40
|
}
|
|
31
41
|
encrypt(data) {
|
|
32
42
|
this.seq += 1;
|
|
33
43
|
if (typeof data === "string") {
|
|
34
44
|
data = Buffer.from(data, "utf8");
|
|
35
45
|
}
|
|
36
|
-
const cipher = this.
|
|
46
|
+
const cipher = this._crypto.createCipheriv("aes-128-cbc", this.key, this.ivSeqPair());
|
|
37
47
|
const cipherText = Buffer.concat([cipher.update(data), cipher.final()]);
|
|
38
48
|
const seqBuffer = Buffer.alloc(4);
|
|
39
49
|
seqBuffer.writeInt32BE(this.seq, 0);
|
|
40
|
-
const hash = this.
|
|
50
|
+
const hash = this._crypto.createHash("sha256");
|
|
41
51
|
hash.update(Buffer.concat([this.sig, seqBuffer, cipherText]));
|
|
42
52
|
const signature = hash.digest();
|
|
43
53
|
return {
|
|
@@ -46,24 +56,35 @@ class NewTpLinkCipher {
|
|
|
46
56
|
};
|
|
47
57
|
}
|
|
48
58
|
decrypt(data) {
|
|
49
|
-
const decipher = this.
|
|
59
|
+
const decipher = this._crypto.createDecipheriv("aes-128-cbc", this.key, this.ivSeqPair());
|
|
50
60
|
const decrypted = Buffer.concat([decipher.update(data.subarray(32)), decipher.final()]);
|
|
51
|
-
|
|
61
|
+
const dec = decrypted.toString("utf8");
|
|
62
|
+
this.log.debug("decrypted: " + dec);
|
|
63
|
+
let dec_fixed = "";
|
|
64
|
+
if (dec.match(/{"error_code":([-0-9]+)[^,}]$/)) {
|
|
65
|
+
dec_fixed = dec.replace(/{"error_code":([-0-9]+)[^,}]/gm, '{"error_code":"$1"}');
|
|
66
|
+
} else if (dec.match(/{"error_code":([-0-9]+)}$/)) {
|
|
67
|
+
dec_fixed = dec.replace(/{"error_code":([-0-9]+)}$/gm, '{"error_code":"$1"}');
|
|
68
|
+
} else {
|
|
69
|
+
dec_fixed = dec.replace(/{"error_code":([-0-9]+)[^,}](.*)/gm, '{"error_code":"$1",$2');
|
|
70
|
+
}
|
|
71
|
+
this.log.debug("decrypted fixed: " + dec_fixed);
|
|
72
|
+
return dec_fixed;
|
|
52
73
|
}
|
|
53
74
|
calculateKey(local_seed, remote_seed, auth_hash) {
|
|
54
75
|
const buf = Buffer.concat([Buffer.from("lsk"), local_seed, remote_seed, auth_hash]);
|
|
55
|
-
const hash = this.
|
|
76
|
+
const hash = this._crypto.createHash("sha256").update(buf).digest();
|
|
56
77
|
this.key = hash.subarray(0, 16);
|
|
57
78
|
}
|
|
58
79
|
calculateIvSeq(local_seed, remote_seed, auth_hash) {
|
|
59
80
|
const buf = Buffer.concat([Buffer.from("iv"), local_seed, remote_seed, auth_hash]);
|
|
60
|
-
const ivBuf = this.
|
|
81
|
+
const ivBuf = this._crypto.createHash("sha256").update(buf).digest();
|
|
61
82
|
this.seq = ivBuf.subarray(-4).readInt32BE(0);
|
|
62
83
|
this.iv = ivBuf.subarray(0, 12);
|
|
63
84
|
}
|
|
64
85
|
calculateSig(local_seed, remote_seed, auth_hash) {
|
|
65
86
|
const payload = Buffer.concat([Buffer.from("ldk"), local_seed, remote_seed, auth_hash]);
|
|
66
|
-
this.sig = this.
|
|
87
|
+
this.sig = this._crypto.createHash("sha256").update(payload).digest().subarray(0, 28);
|
|
67
88
|
}
|
|
68
89
|
ivSeqPair() {
|
|
69
90
|
const seq = Buffer.alloc(4);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/newTpLinkCipher.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import crypto from \"crypto\";\n\nexport default class NewTpLinkCipher {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public iv: any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public key: any;\n private _crypto = crypto;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public sig: any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public seq: any;\n\n constructor(\n localSeed: Buffer,\n remoteSeed: Buffer,\n authHash: Buffer | undefined,\n public readonly log: any,\n ) {\n if (authHash) {\n this.calculateKey(localSeed, remoteSeed, authHash);\n this.calculateIvSeq(localSeed, remoteSeed, authHash);\n this.calculateSig(localSeed, remoteSeed, authHash);\n }\n }\n\n public encrypt(data: Buffer | string) {\n this.seq += 1;\n\n if (typeof data === \"string\") {\n data = Buffer.from(data, \"utf8\");\n }\n\n const cipher = this._crypto.createCipheriv(\"aes-128-cbc\", this.key, this.ivSeqPair());\n const cipherText = Buffer.concat([cipher.update(data), cipher.final()]);\n\n const seqBuffer = Buffer.alloc(4);\n seqBuffer.writeInt32BE(this.seq, 0);\n\n const hash = this._crypto.createHash(\"sha256\");\n hash.update(Buffer.concat([this.sig, seqBuffer, cipherText]));\n\n const signature = hash.digest();\n\n return {\n encryptedPayload: Buffer.concat([signature, cipherText]),\n seq: this.seq,\n };\n }\n\n public decrypt(data: Buffer) {\n const decipher = this._crypto.createDecipheriv(\"aes-128-cbc\", this.key, this.ivSeqPair());\n const decrypted = Buffer.concat([decipher.update(data.subarray(32)), decipher.final()]);\n\n const dec = decrypted.toString(\"utf8\");\n this.log.debug(\"decrypted: \" + dec);\n\n //Some times the json returned is malformed, or the number returned in error_code\n //is not valid e.g. -0301, so we need to use regex to replace the malformed/invalid json parts\n let dec_fixed = \"\";\n if (dec.match(/{\"error_code\":([-0-9]+)[^,}]$/)) {\n dec_fixed = dec.replace(/{\"error_code\":([-0-9]+)[^,}]/gm, '{\"error_code\":\"$1\"}');\n } else if (dec.match(/{\"error_code\":([-0-9]+)}$/)) {\n dec_fixed = dec.replace(/{\"error_code\":([-0-9]+)}$/gm, '{\"error_code\":\"$1\"}');\n } else {\n dec_fixed = dec.replace(/{\"error_code\":([-0-9]+)[^,}](.*)/gm, '{\"error_code\":\"$1\",$2');\n }\n\n this.log.debug(\"decrypted fixed: \" + dec_fixed);\n\n return dec_fixed;\n }\n\n private calculateKey(local_seed: Buffer, remote_seed: Buffer, auth_hash: Buffer) {\n const buf = Buffer.concat([Buffer.from(\"lsk\"), local_seed, remote_seed, auth_hash]);\n const hash = this._crypto.createHash(\"sha256\").update(buf).digest();\n this.key = hash.subarray(0, 16);\n }\n\n private calculateIvSeq(local_seed: Buffer, remote_seed: Buffer, auth_hash: Buffer) {\n const buf = Buffer.concat([Buffer.from(\"iv\"), local_seed, remote_seed, auth_hash]);\n const ivBuf = this._crypto.createHash(\"sha256\").update(buf).digest();\n this.seq = ivBuf.subarray(-4).readInt32BE(0);\n this.iv = ivBuf.subarray(0, 12);\n }\n\n private calculateSig(local_seed: Buffer, remote_seed: Buffer, auth_hash: Buffer) {\n const payload = Buffer.concat([Buffer.from(\"ldk\"), local_seed, remote_seed, auth_hash]);\n this.sig = this._crypto.createHash(\"sha256\").update(payload).digest().subarray(0, 28);\n }\n\n private ivSeqPair() {\n const seq = Buffer.alloc(4);\n seq.writeInt32BE(this.seq, 0);\n return Buffer.concat([this.iv, seq]);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["crypto"]
|
|
7
7
|
}
|