UNPKG

node-red-contrib-tplink-tapo-connect-api

Version:

This unofficial node-RED node allows connection to TP-Link Tapo devices. This project has been enhanced with AI support to enable new features. Starting with v0.50, we have added support for the KLAP protocol. To prioritize the operation of this node, we

139 lines 5.95 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TapoCrypto = void 0; const crypto = __importStar(require("crypto")); const crypto_js_1 = __importDefault(require("crypto-js")); class TapoCrypto { static generateKeyPair() { const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 1024, publicKeyEncoding: { type: 'pkcs1', format: 'pem' }, privateKeyEncoding: { type: 'pkcs1', format: 'pem' } }); return { publicKey, privateKey }; } static encryptWithPublicKey(data, publicKey) { const buffer = Buffer.from(data, 'utf8'); // Try OAEP first (modern), then fallback to PKCS#1 v1.5 (legacy) try { console.log('[CRYPTO-DEBUG] Attempting RSA encryption with OAEP padding'); const encrypted = crypto.publicEncrypt({ key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha1' // KLAP uses SHA1 for OAEP }, buffer); console.log('[CRYPTO-DEBUG] OAEP encryption successful'); return encrypted.toString('base64'); } catch (oaepError) { console.log('[CRYPTO-DEBUG] OAEP encryption failed, using PKCS#1 v1.5:', oaepError); const encrypted = crypto.publicEncrypt({ key: publicKey, padding: crypto.constants.RSA_PKCS1_PADDING }, buffer); console.log('[CRYPTO-DEBUG] PKCS#1 v1.5 encryption successful (legacy mode)'); return encrypted.toString('base64'); } } static decryptWithPrivateKey(encryptedData, privateKey) { const buffer = Buffer.from(encryptedData, 'base64'); // Try OAEP first (modern, more secure), then fallback to PKCS#1 v1.5 (legacy compatibility) try { console.log('[CRYPTO-DEBUG] Attempting RSA decryption with OAEP padding'); const decrypted = crypto.privateDecrypt({ key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha1' // KLAP uses SHA1 for OAEP }, buffer); console.log('[CRYPTO-DEBUG] OAEP decryption successful'); return decrypted.toString('utf8'); } catch (oaepError) { console.log('[CRYPTO-DEBUG] OAEP decryption failed, trying PKCS#1 v1.5:', oaepError); try { const decrypted = crypto.privateDecrypt({ key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING }, buffer); console.log('[CRYPTO-DEBUG] PKCS#1 v1.5 decryption successful (legacy mode)'); return decrypted.toString('utf8'); } catch (pkcsError) { console.error('[CRYPTO-DEBUG] Both OAEP and PKCS#1 v1.5 decryption failed'); throw new Error(`RSA decryption failed with both padding methods. OAEP: ${oaepError}; PKCS#1: ${pkcsError}`); } } } static aesEncrypt(data, key, iv) { const encrypted = crypto_js_1.default.AES.encrypt(data, crypto_js_1.default.enc.Utf8.parse(key), { iv: crypto_js_1.default.enc.Utf8.parse(iv), mode: crypto_js_1.default.mode.CBC, padding: crypto_js_1.default.pad.Pkcs7 }); return encrypted.toString(); } static aesDecrypt(encryptedData, key, iv) { const decrypted = crypto_js_1.default.AES.decrypt(encryptedData, crypto_js_1.default.enc.Utf8.parse(key), { iv: crypto_js_1.default.enc.Utf8.parse(iv), mode: crypto_js_1.default.mode.CBC, padding: crypto_js_1.default.pad.Pkcs7 }); return decrypted.toString(crypto_js_1.default.enc.Utf8); } static generateRandomString(length) { return crypto.randomBytes(length).toString('hex').slice(0, length); } static sha256(data) { return crypto.createHash('sha256').update(data).digest('hex'); } static base64Encode(data) { return Buffer.from(data, 'utf8').toString('base64'); } static base64Decode(data) { return Buffer.from(data, 'base64').toString('utf8'); } } exports.TapoCrypto = TapoCrypto; //# sourceMappingURL=crypto.js.map