UNPKG

@octalmage/node-appletv

Version:

A Node.js library for communicating with an Apple TV

111 lines (89 loc) 3.25 kB
/** * Type Length Value encoding/decoding, used by HAP as a wire format. * https://en.wikipedia.org/wiki/Type-length-value * * Originally based on code from github:KhaosT/HAP-NodeJS@0c8fd88 used * used per the terms of the Apache Software License v2. * * Original code copyright Khaos Tian <khaos.tian@gmail.com> * * Modifications copyright Zach Bean <zb@forty2.com> * * Reformatted for ES6-style module * * Rewrote encode() to be non-recursive; also simplified the logic * * Rewrote decode() */ const Tag = { PairingMethod: 0x00, Username: 0x01, Salt: 0x02, // salt is 16 bytes long // could be either the SRP client public key (384 bytes) or the ED25519 public key (32 bytes), depending on context PublicKey: 0x03, Proof: 0x04, // 64 bytes EncryptedData: 0x05, Sequence: 0x06, ErrorCode: 0x07, BackOff: 0x08, Signature: 0x0A, // 64 bytes MFiCertificate: 0x09, MFiSignature: 0x0A }; function encode(type, data, ...args: any[]): Buffer { var encodedTLVBuffer = Buffer.alloc(0); // coerce data to Buffer if needed if (typeof data === 'number') data = Buffer.from([data]); else if (typeof data === 'string') data = Buffer.from(data); if (data.length <= 255) { encodedTLVBuffer = Buffer.concat([Buffer.from([type,data.length]),data]); } else { var leftLength = data.length; var tempBuffer = Buffer.alloc(0); var currentStart = 0; for (; leftLength > 0;) { if (leftLength >= 255) { tempBuffer = Buffer.concat([tempBuffer,Buffer.from([type,0xFF]),data.slice(currentStart, currentStart + 255)]); leftLength -= 255; currentStart = currentStart + 255; } else { tempBuffer = Buffer.concat([tempBuffer,Buffer.from([type,leftLength]),data.slice(currentStart, currentStart + leftLength)]); leftLength -= leftLength; } } encodedTLVBuffer = tempBuffer; } // do we have more to encode? if (arguments.length > 2) { // chop off the first two arguments which we already processed, and process the rest recursively var remainingArguments = Array.prototype.slice.call(arguments, 2); var remainingTLVBuffer = encode.apply(this, remainingArguments); // append the remaining encoded arguments directly to the buffer encodedTLVBuffer = Buffer.concat([encodedTLVBuffer, remainingTLVBuffer]); } return encodedTLVBuffer; } function decode(data): {} { var objects = {}; var leftLength = data.length; var currentIndex = 0; for (; leftLength > 0;) { var type = data[currentIndex]; var length = data[currentIndex+1]; currentIndex += 2; leftLength -= 2; var newData = data.slice(currentIndex, currentIndex+length); if (objects[type]) { objects[type] = Buffer.concat([objects[type],newData]); } else { objects[type] = newData; } currentIndex += length; leftLength -= length; } return objects; } export default { Tag, encode, decode }