'use strict'; angular.module('copayApp.services') .factory('ledger', function(bwcService) { var root = {}; var LEDGER_CHROME_ID = "kkdpmhnladdopljabkgpacgpliggeeaf"; root.callbacks = {}; root.hasSession = function() { root._message({ command:"has_session" }); } root.getXPubKey = function(index, callback) { root.callbacks["get_xpubkey"] = callback; root._messageAfterSession({ command:"get_xpubkey", path:root._getPath(index) }) }; root.signTx = function(txp, index, callback) { root.callbacks["sign_p2sh"] = callback; var redeemScripts = []; var paths = []; var tx = bwcService.getUtils().buildTx(txp); for (var i=0; i=0; i--) { res += Convert.toHexByte(x.byteAt(i)); } return new ByteString(res, GP.HEX); } return root; }); var Convert = {}; /** * Convert a binary string to his hexadecimal representation * @param {String} src binary string * @static * @returns {String} hexadecimal representation */ Convert.stringToHex = function(src) { var r = ""; var hexes = new Array ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"); for (var i=0; i> 4] + hexes [src.charCodeAt(i) & 0xf];} return r; } /** * Convert an hexadecimal string to its binary representation * @param {String} src hexadecimal string * @static * @return {Array} byte array * @throws {InvalidString} if the string isn't properly formatted */ Convert.hexToBin = function(src) { var result = ""; var digits = "0123456789ABCDEF"; if ((src.length % 2) != 0) { throw "Invalid string"; } src = src.toUpperCase(); for (var i=0; i> 4) + digits.charAt(number & 0x0F); } /** * Convert a number to a two digits hexadecimal string (similar to toHexDigit) * @static * @param {Number} number number to convert * @returns {String} converted number */ Convert.toHexByte = function(number) { return Convert.toHexDigit(number); } /** * Convert a BCD number to a two digits hexadecimal string * @static * @param {Number} number number to convert * @returns {String} converted number */ Convert.toHexByteBCD = function(numberBCD) { var number = ((numberBCD / 10) * 16) + (numberBCD % 10); return Convert.toHexDigit(number); } /** * Convert a number to an hexadecimal short number * @static * @param {Number} number number to convert * @returns {String} converted number */ Convert.toHexShort = function(number) { return Convert.toHexDigit((number >> 8) & 0xff) + Convert.toHexDigit(number & 0xff); } /** * Convert a number to an hexadecimal int number * @static * @param {Number} number number to convert * @returns {String} converted number */ Convert.toHexInt = function(number) { return Convert.toHexDigit((number >> 24) & 0xff) + Convert.toHexDigit((number >> 16) & 0xff) + Convert.toHexDigit((number >> 8) & 0xff) + Convert.toHexDigit(number & 0xff); } var GP = {}; GP.ASCII = 1; GP.HEX = 5; /** * @class GPScript ByteString implementation * @param {String} value initial value * @param {HEX|ASCII} encoding encoding to use * @property {Number} length length of the ByteString * @constructs */ var ByteString = function(value, encoding) { this.encoding = encoding; this.hasBuffer = (typeof Buffer != 'undefined'); if (this.hasBuffer && (value instanceof Buffer)) { this.value = value; this.encoding = GP.HEX; } else { switch(encoding) { case GP.HEX: if (!this.hasBuffer) { this.value = Convert.hexToBin(value); } else { this.value = new Buffer(value, 'hex'); } break; case GP.ASCII: if (!this.hasBuffer) { this.value = value; } else { this.value = new Buffer(value, 'ascii'); } break; default: throw "Invalid arguments"; } } this.length = this.value.length; } /** * Retrieve the byte value at the given index * @param {Number} index index * @returns {Number} byte value */ ByteString.prototype.byteAt = function(index) { if (arguments.length < 1) { throw "Argument missing"; } if (typeof index != "number") { throw "Invalid index"; } if ((index < 0) || (index >= this.value.length)) { throw "Invalid index offset"; } if (!this.hasBuffer) { return Convert.readHexDigit(Convert.stringToHex(this.value.substring(index, index + 1))); } else { return this.value[index]; } } /** * Retrieve a subset of the ByteString * @param {Number} offset offset to start at * @param {Number} [count] size of the target ByteString (default : use the remaining length) * @returns {ByteString} subset of the original ByteString */ ByteString.prototype.bytes = function(offset, count) { var result; if (arguments.length < 1) { throw "Argument missing"; } if (typeof offset != "number") { throw "Invalid offset"; } //if ((offset < 0) || (offset >= this.value.length)) { if (offset < 0) { throw "Invalid offset"; } if (typeof count == "number") { if (count < 0) { throw "Invalid count"; } if (!this.hasBuffer) { result = new ByteString(this.value.substring(offset, offset + count), GP.ASCII); } else { result = new Buffer(count); this.value.copy(result, 0, offset, offset + count); } } else if (typeof count == "undefined") { if (!this.hasBuffer) { result = new ByteString(this.value.substring(offset), GP.ASCII); } else { result = new Buffer(this.value.length - offset); this.value.copy(result, 0, offset, this.value.length); } } else { throw "Invalid count"; } if (!this.hasBuffer) { result.encoding = this.encoding; return result; } else { return new ByteString(result, GP.HEX); } } /** * Appends two ByteString * @param {ByteString} target ByteString to append * @returns {ByteString} result of the concatenation */ ByteString.prototype.concat = function(target) { if (arguments.length < 1) { throw "Not enough arguments"; } if (!(target instanceof ByteString)) { throw "Invalid argument"; } if (!this.hasBuffer) { var result = this.value + target.value; var x = new ByteString(result, GP.ASCII); x.encoding = this.encoding; return x; } else { var result = Buffer.concat([this.value, target.value]); return new ByteString(result, GP.HEX); } } /** * Check if two ByteString are equal * @param {ByteString} target ByteString to check against * @returns {Boolean} true if the two ByteString are equal */ ByteString.prototype.equals = function(target) { if (arguments.length < 1) { throw "Not enough arguments"; } if (!(target instanceof ByteString)) { throw "Invalid argument"; } if (!this.hasBuffer) { return (this.value == target.value); } else { return Buffer.equals(this.value, target.value); } } /** * Convert the ByteString to a String using the given encoding * @param {HEX|ASCII|UTF8|BASE64|CN} encoding encoding to use * @return {String} converted content */ ByteString.prototype.toString = function(encoding) { var targetEncoding = this.encoding; if (arguments.length >= 1) { if (typeof encoding != "number") { throw "Invalid encoding"; } switch(encoding) { case GP.HEX: case GP.ASCII: targetEncoding = encoding; break; default: throw "Unsupported arguments"; } targetEncoding = encoding; } switch(targetEncoding) { case GP.HEX: if (!this.hasBuffer) { return Convert.stringToHex(this.value); } else { return this.value.toString('hex'); } case GP.ASCII: if (!this.hasBuffer) { return this.value; } else { return this.value.toString(); } default: throw "Unsupported"; } } ByteString.prototype.toStringIE = function(encoding) { return this.toString(encoding); } ByteString.prototype.toBuffer = function() { return this.value; }