"use strict"; let ethers = {}; const w = window; if (w._ethers == null) { console.log("WARNING: @ethersproject/hardware-wallet requires ethers loaded first"); } else { ethers = w._ethers; } const version = "hardware-wallets/5.0.2"; var global$1 = (typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}); var lookup = []; var revLookup = []; var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array; var inited = false; function init () { inited = true; var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; for (var i = 0, len = code.length; i < len; ++i) { lookup[i] = code[i]; revLookup[code.charCodeAt(i)] = i; } revLookup['-'.charCodeAt(0)] = 62; revLookup['_'.charCodeAt(0)] = 63; } function toByteArray (b64) { if (!inited) { init(); } var i, j, l, tmp, placeHolders, arr; var len = b64.length; if (len % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') } // the number of equal signs (place holders) // if there are two placeholders, than the two characters before it // represent one byte // if there is only one, then the three characters before it represent 2 bytes // this is just a cheap hack to not do indexOf twice placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0; // base64 is 4/3 + up to two characters of the original data arr = new Arr(len * 3 / 4 - placeHolders); // if there are placeholders, only get up to the last complete 4 chars l = placeHolders > 0 ? len - 4 : len; var L = 0; for (i = 0, j = 0; i < l; i += 4, j += 3) { tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]; arr[L++] = (tmp >> 16) & 0xFF; arr[L++] = (tmp >> 8) & 0xFF; arr[L++] = tmp & 0xFF; } if (placeHolders === 2) { tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4); arr[L++] = tmp & 0xFF; } else if (placeHolders === 1) { tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2); arr[L++] = (tmp >> 8) & 0xFF; arr[L++] = tmp & 0xFF; } return arr } function tripletToBase64 (num) { return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] } function encodeChunk (uint8, start, end) { var tmp; var output = []; for (var i = start; i < end; i += 3) { tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]); output.push(tripletToBase64(tmp)); } return output.join('') } function fromByteArray (uint8) { if (!inited) { init(); } var tmp; var len = uint8.length; var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes var output = ''; var parts = []; var maxChunkLength = 16383; // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))); } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { tmp = uint8[len - 1]; output += lookup[tmp >> 2]; output += lookup[(tmp << 4) & 0x3F]; output += '=='; } else if (extraBytes === 2) { tmp = (uint8[len - 2] << 8) + (uint8[len - 1]); output += lookup[tmp >> 10]; output += lookup[(tmp >> 4) & 0x3F]; output += lookup[(tmp << 2) & 0x3F]; output += '='; } parts.push(output); return parts.join('') } function read (buffer, offset, isLE, mLen, nBytes) { var e, m; var eLen = nBytes * 8 - mLen - 1; var eMax = (1 << eLen) - 1; var eBias = eMax >> 1; var nBits = -7; var i = isLE ? (nBytes - 1) : 0; var d = isLE ? -1 : 1; var s = buffer[offset + i]; i += d; e = s & ((1 << (-nBits)) - 1); s >>= (-nBits); nBits += eLen; for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} m = e & ((1 << (-nBits)) - 1); e >>= (-nBits); nBits += mLen; for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} if (e === 0) { e = 1 - eBias; } else if (e === eMax) { return m ? NaN : ((s ? -1 : 1) * Infinity) } else { m = m + Math.pow(2, mLen); e = e - eBias; } return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } function write (buffer, value, offset, isLE, mLen, nBytes) { var e, m, c; var eLen = nBytes * 8 - mLen - 1; var eMax = (1 << eLen) - 1; var eBias = eMax >> 1; var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0); var i = isLE ? 0 : (nBytes - 1); var d = isLE ? 1 : -1; var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; value = Math.abs(value); if (isNaN(value) || value === Infinity) { m = isNaN(value) ? 1 : 0; e = eMax; } else { e = Math.floor(Math.log(value) / Math.LN2); if (value * (c = Math.pow(2, -e)) < 1) { e--; c *= 2; } if (e + eBias >= 1) { value += rt / c; } else { value += rt * Math.pow(2, 1 - eBias); } if (value * c >= 2) { e++; c /= 2; } if (e + eBias >= eMax) { m = 0; e = eMax; } else if (e + eBias >= 1) { m = (value * c - 1) * Math.pow(2, mLen); e = e + eBias; } else { m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); e = 0; } } for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} e = (e << mLen) | m; eLen += mLen; for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} buffer[offset + i - d] |= s * 128; } var toString = {}.toString; var isArray = Array.isArray || function (arr) { return toString.call(arr) == '[object Array]'; }; var INSPECT_MAX_BYTES = 50; /** * If `Buffer.TYPED_ARRAY_SUPPORT`: * === true Use Uint8Array implementation (fastest) * === false Use Object implementation (most compatible, even IE6) * * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, * Opera 11.6+, iOS 4.2+. * * Due to various browser bugs, sometimes the Object implementation will be used even * when the browser supports typed arrays. * * Note: * * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. * * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. * * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of * incorrect length in some situations. * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they * get the Object implementation, which is slower but behaves correctly. */ Buffer.TYPED_ARRAY_SUPPORT = global$1.TYPED_ARRAY_SUPPORT !== undefined ? global$1.TYPED_ARRAY_SUPPORT : true; /* * Export kMaxLength after typed array support is determined. */ var _kMaxLength = kMaxLength(); function typedArraySupport () { return true; // rollup issues // try { // var arr = new Uint8Array(1) // arr.__proto__ = { // __proto__: Uint8Array.prototype, // foo: function () { return 42 } // } // return arr.foo() === 42 && // typed array instances can be augmented // typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` // arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` // } catch (e) { // return false // } } function kMaxLength () { return Buffer.TYPED_ARRAY_SUPPORT ? 0x7fffffff : 0x3fffffff } function createBuffer (that, length) { if (kMaxLength() < length) { throw new RangeError('Invalid typed array length') } if (Buffer.TYPED_ARRAY_SUPPORT) { // Return an augmented `Uint8Array` instance, for best performance that = new Uint8Array(length); that.__proto__ = Buffer.prototype; } else { // Fallback: Return an object instance of the Buffer class if (that === null) { that = new Buffer(length); } that.length = length; } return that } /** * The Buffer constructor returns instances of `Uint8Array` that have their * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of * `Uint8Array`, so the returned instances will have all the node `Buffer` methods * and the `Uint8Array` methods. Square bracket notation works as expected -- it * returns a single octet. * * The `Uint8Array` prototype remains unmodified. */ function Buffer (arg, encodingOrOffset, length) { if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { return new Buffer(arg, encodingOrOffset, length) } // Common case. if (typeof arg === 'number') { if (typeof encodingOrOffset === 'string') { throw new Error( 'If encoding is specified then the first argument must be a string' ) } return allocUnsafe(this, arg) } return from(this, arg, encodingOrOffset, length) } Buffer.poolSize = 8192; // not used by this implementation // TODO: Legacy, not needed anymore. Remove in next major version. Buffer._augment = function (arr) { arr.__proto__ = Buffer.prototype; return arr }; function from (that, value, encodingOrOffset, length) { if (typeof value === 'number') { throw new TypeError('"value" argument must not be a number') } if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { return fromArrayBuffer(that, value, encodingOrOffset, length) } if (typeof value === 'string') { return fromString(that, value, encodingOrOffset) } return fromObject(that, value) } /** * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError * if value is a number. * Buffer.from(str[, encoding]) * Buffer.from(array) * Buffer.from(buffer) * Buffer.from(arrayBuffer[, byteOffset[, length]]) **/ Buffer.from = function (value, encodingOrOffset, length) { return from(null, value, encodingOrOffset, length) }; if (Buffer.TYPED_ARRAY_SUPPORT) { Buffer.prototype.__proto__ = Uint8Array.prototype; Buffer.__proto__ = Uint8Array; if (typeof Symbol !== 'undefined' && Symbol.species && Buffer[Symbol.species] === Buffer) { // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 // Object.defineProperty(Buffer, Symbol.species, { // value: null, // configurable: true // }) } } function assertSize (size) { if (typeof size !== 'number') { throw new TypeError('"size" argument must be a number') } else if (size < 0) { throw new RangeError('"size" argument must not be negative') } } function alloc (that, size, fill, encoding) { assertSize(size); if (size <= 0) { return createBuffer(that, size) } if (fill !== undefined) { // Only pay attention to encoding if it's a string. This // prevents accidentally sending in a number that would // be interpretted as a start offset. return typeof encoding === 'string' ? createBuffer(that, size).fill(fill, encoding) : createBuffer(that, size).fill(fill) } return createBuffer(that, size) } /** * Creates a new filled Buffer instance. * alloc(size[, fill[, encoding]]) **/ Buffer.alloc = function (size, fill, encoding) { return alloc(null, size, fill, encoding) }; function allocUnsafe (that, size) { assertSize(size); that = createBuffer(that, size < 0 ? 0 : checked(size) | 0); if (!Buffer.TYPED_ARRAY_SUPPORT) { for (var i = 0; i < size; ++i) { that[i] = 0; } } return that } /** * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. * */ Buffer.allocUnsafe = function (size) { return allocUnsafe(null, size) }; /** * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. */ Buffer.allocUnsafeSlow = function (size) { return allocUnsafe(null, size) }; function fromString (that, string, encoding) { if (typeof encoding !== 'string' || encoding === '') { encoding = 'utf8'; } if (!Buffer.isEncoding(encoding)) { throw new TypeError('"encoding" must be a valid string encoding') } var length = byteLength(string, encoding) | 0; that = createBuffer(that, length); var actual = that.write(string, encoding); if (actual !== length) { // Writing a hex string, for example, that contains invalid characters will // cause everything after the first invalid character to be ignored. (e.g. // 'abxxcd' will be treated as 'ab') that = that.slice(0, actual); } return that } function fromArrayLike (that, array) { var length = array.length < 0 ? 0 : checked(array.length) | 0; that = createBuffer(that, length); for (var i = 0; i < length; i += 1) { that[i] = array[i] & 255; } return that } function fromArrayBuffer (that, array, byteOffset, length) { array.byteLength; // this throws if `array` is not a valid ArrayBuffer if (byteOffset < 0 || array.byteLength < byteOffset) { throw new RangeError('\'offset\' is out of bounds') } if (array.byteLength < byteOffset + (length || 0)) { throw new RangeError('\'length\' is out of bounds') } if (byteOffset === undefined && length === undefined) { array = new Uint8Array(array); } else if (length === undefined) { array = new Uint8Array(array, byteOffset); } else { array = new Uint8Array(array, byteOffset, length); } if (Buffer.TYPED_ARRAY_SUPPORT) { // Return an augmented `Uint8Array` instance, for best performance that = array; that.__proto__ = Buffer.prototype; } else { // Fallback: Return an object instance of the Buffer class that = fromArrayLike(that, array); } return that } function fromObject (that, obj) { if (internalIsBuffer(obj)) { var len = checked(obj.length) | 0; that = createBuffer(that, len); if (that.length === 0) { return that } obj.copy(that, 0, 0, len); return that } if (obj) { if ((typeof ArrayBuffer !== 'undefined' && obj.buffer instanceof ArrayBuffer) || 'length' in obj) { if (typeof obj.length !== 'number' || isnan(obj.length)) { return createBuffer(that, 0) } return fromArrayLike(that, obj) } if (obj.type === 'Buffer' && isArray(obj.data)) { return fromArrayLike(that, obj.data) } } throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') } function checked (length) { // Note: cannot use `length < kMaxLength()` here because that fails when // length is NaN (which is otherwise coerced to zero.) if (length >= kMaxLength()) { throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + kMaxLength().toString(16) + ' bytes') } return length | 0 } function SlowBuffer (length) { if (+length != length) { // eslint-disable-line eqeqeq length = 0; } return Buffer.alloc(+length) } Buffer.isBuffer = isBuffer; function internalIsBuffer (b) { return !!(b != null && b._isBuffer) } Buffer.compare = function compare (a, b) { if (!internalIsBuffer(a) || !internalIsBuffer(b)) { throw new TypeError('Arguments must be Buffers') } if (a === b) return 0 var x = a.length; var y = b.length; for (var i = 0, len = Math.min(x, y); i < len; ++i) { if (a[i] !== b[i]) { x = a[i]; y = b[i]; break } } if (x < y) return -1 if (y < x) return 1 return 0 }; Buffer.isEncoding = function isEncoding (encoding) { switch (String(encoding).toLowerCase()) { case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'latin1': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return true default: return false } }; Buffer.concat = function concat (list, length) { if (!isArray(list)) { throw new TypeError('"list" argument must be an Array of Buffers') } if (list.length === 0) { return Buffer.alloc(0) } var i; if (length === undefined) { length = 0; for (i = 0; i < list.length; ++i) { length += list[i].length; } } var buffer = Buffer.allocUnsafe(length); var pos = 0; for (i = 0; i < list.length; ++i) { var buf = list[i]; if (!internalIsBuffer(buf)) { throw new TypeError('"list" argument must be an Array of Buffers') } buf.copy(buffer, pos); pos += buf.length; } return buffer }; function byteLength (string, encoding) { if (internalIsBuffer(string)) { return string.length } if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { return string.byteLength } if (typeof string !== 'string') { string = '' + string; } var len = string.length; if (len === 0) return 0 // Use a for loop to avoid recursion var loweredCase = false; for (;;) { switch (encoding) { case 'ascii': case 'latin1': case 'binary': return len case 'utf8': case 'utf-8': case undefined: return utf8ToBytes(string).length case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return len * 2 case 'hex': return len >>> 1 case 'base64': return base64ToBytes(string).length default: if (loweredCase) return utf8ToBytes(string).length // assume utf8 encoding = ('' + encoding).toLowerCase(); loweredCase = true; } } } Buffer.byteLength = byteLength; function slowToString (encoding, start, end) { var loweredCase = false; // No need to verify that "this.length <= MAX_UINT32" since it's a read-only // property of a typed array. // This behaves neither like String nor Uint8Array in that we set start/end // to their upper/lower bounds if the value passed is out of range. // undefined is handled specially as per ECMA-262 6th Edition, // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. if (start === undefined || start < 0) { start = 0; } // Return early if start > this.length. Done here to prevent potential uint32 // coercion fail below. if (start > this.length) { return '' } if (end === undefined || end > this.length) { end = this.length; } if (end <= 0) { return '' } // Force coersion to uint32. This will also coerce falsey/NaN values to 0. end >>>= 0; start >>>= 0; if (end <= start) { return '' } if (!encoding) encoding = 'utf8'; while (true) { switch (encoding) { case 'hex': return hexSlice(this, start, end) case 'utf8': case 'utf-8': return utf8Slice(this, start, end) case 'ascii': return asciiSlice(this, start, end) case 'latin1': case 'binary': return latin1Slice(this, start, end) case 'base64': return base64Slice(this, start, end) case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return utf16leSlice(this, start, end) default: if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) encoding = (encoding + '').toLowerCase(); loweredCase = true; } } } // The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect // Buffer instances. Buffer.prototype._isBuffer = true; function swap (b, n, m) { var i = b[n]; b[n] = b[m]; b[m] = i; } Buffer.prototype.swap16 = function swap16 () { var len = this.length; if (len % 2 !== 0) { throw new RangeError('Buffer size must be a multiple of 16-bits') } for (var i = 0; i < len; i += 2) { swap(this, i, i + 1); } return this }; Buffer.prototype.swap32 = function swap32 () { var len = this.length; if (len % 4 !== 0) { throw new RangeError('Buffer size must be a multiple of 32-bits') } for (var i = 0; i < len; i += 4) { swap(this, i, i + 3); swap(this, i + 1, i + 2); } return this }; Buffer.prototype.swap64 = function swap64 () { var len = this.length; if (len % 8 !== 0) { throw new RangeError('Buffer size must be a multiple of 64-bits') } for (var i = 0; i < len; i += 8) { swap(this, i, i + 7); swap(this, i + 1, i + 6); swap(this, i + 2, i + 5); swap(this, i + 3, i + 4); } return this }; Buffer.prototype.toString = function toString () { var length = this.length | 0; if (length === 0) return '' if (arguments.length === 0) return utf8Slice(this, 0, length) return slowToString.apply(this, arguments) }; Buffer.prototype.equals = function equals (b) { if (!internalIsBuffer(b)) throw new TypeError('Argument must be a Buffer') if (this === b) return true return Buffer.compare(this, b) === 0 }; Buffer.prototype.inspect = function inspect () { var str = ''; var max = INSPECT_MAX_BYTES; if (this.length > 0) { str = this.toString('hex', 0, max).match(/.{2}/g).join(' '); if (this.length > max) str += ' ... '; } return '' }; Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { if (!internalIsBuffer(target)) { throw new TypeError('Argument must be a Buffer') } if (start === undefined) { start = 0; } if (end === undefined) { end = target ? target.length : 0; } if (thisStart === undefined) { thisStart = 0; } if (thisEnd === undefined) { thisEnd = this.length; } if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { throw new RangeError('out of range index') } if (thisStart >= thisEnd && start >= end) { return 0 } if (thisStart >= thisEnd) { return -1 } if (start >= end) { return 1 } start >>>= 0; end >>>= 0; thisStart >>>= 0; thisEnd >>>= 0; if (this === target) return 0 var x = thisEnd - thisStart; var y = end - start; var len = Math.min(x, y); var thisCopy = this.slice(thisStart, thisEnd); var targetCopy = target.slice(start, end); for (var i = 0; i < len; ++i) { if (thisCopy[i] !== targetCopy[i]) { x = thisCopy[i]; y = targetCopy[i]; break } } if (x < y) return -1 if (y < x) return 1 return 0 }; // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, // OR the last index of `val` in `buffer` at offset <= `byteOffset`. // // Arguments: // - buffer - a Buffer to search // - val - a string, Buffer, or number // - byteOffset - an index into `buffer`; will be clamped to an int32 // - encoding - an optional encoding, relevant is val is a string // - dir - true for indexOf, false for lastIndexOf function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { // Empty buffer means no match if (buffer.length === 0) return -1 // Normalize byteOffset if (typeof byteOffset === 'string') { encoding = byteOffset; byteOffset = 0; } else if (byteOffset > 0x7fffffff) { byteOffset = 0x7fffffff; } else if (byteOffset < -0x80000000) { byteOffset = -0x80000000; } byteOffset = +byteOffset; // Coerce to Number. if (isNaN(byteOffset)) { // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer byteOffset = dir ? 0 : (buffer.length - 1); } // Normalize byteOffset: negative offsets start from the end of the buffer if (byteOffset < 0) byteOffset = buffer.length + byteOffset; if (byteOffset >= buffer.length) { if (dir) return -1 else byteOffset = buffer.length - 1; } else if (byteOffset < 0) { if (dir) byteOffset = 0; else return -1 } // Normalize val if (typeof val === 'string') { val = Buffer.from(val, encoding); } // Finally, search either indexOf (if dir is true) or lastIndexOf if (internalIsBuffer(val)) { // Special case: looking for empty string/buffer always fails if (val.length === 0) { return -1 } return arrayIndexOf(buffer, val, byteOffset, encoding, dir) } else if (typeof val === 'number') { val = val & 0xFF; // Search for a byte value [0-255] if (Buffer.TYPED_ARRAY_SUPPORT && typeof Uint8Array.prototype.indexOf === 'function') { if (dir) { return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) } else { return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) } } return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) } throw new TypeError('val must be string, number or Buffer') } function arrayIndexOf (arr, val, byteOffset, encoding, dir) { var indexSize = 1; var arrLength = arr.length; var valLength = val.length; if (encoding !== undefined) { encoding = String(encoding).toLowerCase(); if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') { if (arr.length < 2 || val.length < 2) { return -1 } indexSize = 2; arrLength /= 2; valLength /= 2; byteOffset /= 2; } } function read (buf, i) { if (indexSize === 1) { return buf[i] } else { return buf.readUInt16BE(i * indexSize) } } var i; if (dir) { var foundIndex = -1; for (i = byteOffset; i < arrLength; i++) { if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { if (foundIndex === -1) foundIndex = i; if (i - foundIndex + 1 === valLength) return foundIndex * indexSize } else { if (foundIndex !== -1) i -= i - foundIndex; foundIndex = -1; } } } else { if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength; for (i = byteOffset; i >= 0; i--) { var found = true; for (var j = 0; j < valLength; j++) { if (read(arr, i + j) !== read(val, j)) { found = false; break } } if (found) return i } } return -1 } Buffer.prototype.includes = function includes (val, byteOffset, encoding) { return this.indexOf(val, byteOffset, encoding) !== -1 }; Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { return bidirectionalIndexOf(this, val, byteOffset, encoding, true) }; Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { return bidirectionalIndexOf(this, val, byteOffset, encoding, false) }; function hexWrite (buf, string, offset, length) { offset = Number(offset) || 0; var remaining = buf.length - offset; if (!length) { length = remaining; } else { length = Number(length); if (length > remaining) { length = remaining; } } // must be an even number of digits var strLen = string.length; if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') if (length > strLen / 2) { length = strLen / 2; } for (var i = 0; i < length; ++i) { var parsed = parseInt(string.substr(i * 2, 2), 16); if (isNaN(parsed)) return i buf[offset + i] = parsed; } return i } function utf8Write (buf, string, offset, length) { return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) } function asciiWrite (buf, string, offset, length) { return blitBuffer(asciiToBytes(string), buf, offset, length) } function latin1Write (buf, string, offset, length) { return asciiWrite(buf, string, offset, length) } function base64Write (buf, string, offset, length) { return blitBuffer(base64ToBytes(string), buf, offset, length) } function ucs2Write (buf, string, offset, length) { return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) } Buffer.prototype.write = function write (string, offset, length, encoding) { // Buffer#write(string) if (offset === undefined) { encoding = 'utf8'; length = this.length; offset = 0; // Buffer#write(string, encoding) } else if (length === undefined && typeof offset === 'string') { encoding = offset; length = this.length; offset = 0; // Buffer#write(string, offset[, length][, encoding]) } else if (isFinite(offset)) { offset = offset | 0; if (isFinite(length)) { length = length | 0; if (encoding === undefined) encoding = 'utf8'; } else { encoding = length; length = undefined; } // legacy write(string, encoding, offset, length) - remove in v0.13 } else { throw new Error( 'Buffer.write(string, encoding, offset[, length]) is no longer supported' ) } var remaining = this.length - offset; if (length === undefined || length > remaining) length = remaining; if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { throw new RangeError('Attempt to write outside buffer bounds') } if (!encoding) encoding = 'utf8'; var loweredCase = false; for (;;) { switch (encoding) { case 'hex': return hexWrite(this, string, offset, length) case 'utf8': case 'utf-8': return utf8Write(this, string, offset, length) case 'ascii': return asciiWrite(this, string, offset, length) case 'latin1': case 'binary': return latin1Write(this, string, offset, length) case 'base64': // Warning: maxLength not taken into account in base64Write return base64Write(this, string, offset, length) case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return ucs2Write(this, string, offset, length) default: if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) encoding = ('' + encoding).toLowerCase(); loweredCase = true; } } }; Buffer.prototype.toJSON = function toJSON () { return { type: 'Buffer', data: Array.prototype.slice.call(this._arr || this, 0) } }; function base64Slice (buf, start, end) { if (start === 0 && end === buf.length) { return fromByteArray(buf) } else { return fromByteArray(buf.slice(start, end)) } } function utf8Slice (buf, start, end) { end = Math.min(buf.length, end); var res = []; var i = start; while (i < end) { var firstByte = buf[i]; var codePoint = null; var bytesPerSequence = (firstByte > 0xEF) ? 4 : (firstByte > 0xDF) ? 3 : (firstByte > 0xBF) ? 2 : 1; if (i + bytesPerSequence <= end) { var secondByte, thirdByte, fourthByte, tempCodePoint; switch (bytesPerSequence) { case 1: if (firstByte < 0x80) { codePoint = firstByte; } break case 2: secondByte = buf[i + 1]; if ((secondByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F); if (tempCodePoint > 0x7F) { codePoint = tempCodePoint; } } break case 3: secondByte = buf[i + 1]; thirdByte = buf[i + 2]; if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F); if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { codePoint = tempCodePoint; } } break case 4: secondByte = buf[i + 1]; thirdByte = buf[i + 2]; fourthByte = buf[i + 3]; if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F); if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { codePoint = tempCodePoint; } } } } if (codePoint === null) { // we did not generate a valid codePoint so insert a // replacement char (U+FFFD) and advance only 1 byte codePoint = 0xFFFD; bytesPerSequence = 1; } else if (codePoint > 0xFFFF) { // encode to utf16 (surrogate pair dance) codePoint -= 0x10000; res.push(codePoint >>> 10 & 0x3FF | 0xD800); codePoint = 0xDC00 | codePoint & 0x3FF; } res.push(codePoint); i += bytesPerSequence; } return decodeCodePointsArray(res) } // Based on http://stackoverflow.com/a/22747272/680742, the browser with // the lowest limit is Chrome, with 0x10000 args. // We go 1 magnitude less, for safety var MAX_ARGUMENTS_LENGTH = 0x1000; function decodeCodePointsArray (codePoints) { var len = codePoints.length; if (len <= MAX_ARGUMENTS_LENGTH) { return String.fromCharCode.apply(String, codePoints) // avoid extra slice() } // Decode in chunks to avoid "call stack size exceeded". var res = ''; var i = 0; while (i < len) { res += String.fromCharCode.apply( String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) ); } return res } function asciiSlice (buf, start, end) { var ret = ''; end = Math.min(buf.length, end); for (var i = start; i < end; ++i) { ret += String.fromCharCode(buf[i] & 0x7F); } return ret } function latin1Slice (buf, start, end) { var ret = ''; end = Math.min(buf.length, end); for (var i = start; i < end; ++i) { ret += String.fromCharCode(buf[i]); } return ret } function hexSlice (buf, start, end) { var len = buf.length; if (!start || start < 0) start = 0; if (!end || end < 0 || end > len) end = len; var out = ''; for (var i = start; i < end; ++i) { out += toHex(buf[i]); } return out } function utf16leSlice (buf, start, end) { var bytes = buf.slice(start, end); var res = ''; for (var i = 0; i < bytes.length; i += 2) { res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256); } return res } Buffer.prototype.slice = function slice (start, end) { var len = this.length; start = ~~start; end = end === undefined ? len : ~~end; if (start < 0) { start += len; if (start < 0) start = 0; } else if (start > len) { start = len; } if (end < 0) { end += len; if (end < 0) end = 0; } else if (end > len) { end = len; } if (end < start) end = start; var newBuf; if (Buffer.TYPED_ARRAY_SUPPORT) { newBuf = this.subarray(start, end); newBuf.__proto__ = Buffer.prototype; } else { var sliceLen = end - start; newBuf = new Buffer(sliceLen, undefined); for (var i = 0; i < sliceLen; ++i) { newBuf[i] = this[i + start]; } } return newBuf }; /* * Need to make sure that buffer isn't trying to write out of bounds. */ function checkOffset (offset, ext, length) { if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') } Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { offset = offset | 0; byteLength = byteLength | 0; if (!noAssert) checkOffset(offset, byteLength, this.length); var val = this[offset]; var mul = 1; var i = 0; while (++i < byteLength && (mul *= 0x100)) { val += this[offset + i] * mul; } return val }; Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { offset = offset | 0; byteLength = byteLength | 0; if (!noAssert) { checkOffset(offset, byteLength, this.length); } var val = this[offset + --byteLength]; var mul = 1; while (byteLength > 0 && (mul *= 0x100)) { val += this[offset + --byteLength] * mul; } return val }; Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { if (!noAssert) checkOffset(offset, 1, this.length); return this[offset] }; Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { if (!noAssert) checkOffset(offset, 2, this.length); return this[offset] | (this[offset + 1] << 8) }; Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { if (!noAssert) checkOffset(offset, 2, this.length); return (this[offset] << 8) | this[offset + 1] }; Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length); return ((this[offset]) | (this[offset + 1] << 8) | (this[offset + 2] << 16)) + (this[offset + 3] * 0x1000000) }; Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length); return (this[offset] * 0x1000000) + ((this[offset + 1] << 16) | (this[offset + 2] << 8) | this[offset + 3]) }; Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { offset = offset | 0; byteLength = byteLength | 0; if (!noAssert) checkOffset(offset, byteLength, this.length); var val = this[offset]; var mul = 1; var i = 0; while (++i < byteLength && (mul *= 0x100)) { val += this[offset + i] * mul; } mul *= 0x80; if (val >= mul) val -= Math.pow(2, 8 * byteLength); return val }; Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { offset = offset | 0; byteLength = byteLength | 0; if (!noAssert) checkOffset(offset, byteLength, this.length); var i = byteLength; var mul = 1; var val = this[offset + --i]; while (i > 0 && (mul *= 0x100)) { val += this[offset + --i] * mul; } mul *= 0x80; if (val >= mul) val -= Math.pow(2, 8 * byteLength); return val }; Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { if (!noAssert) checkOffset(offset, 1, this.length); if (!(this[offset] & 0x80)) return (this[offset]) return ((0xff - this[offset] + 1) * -1) }; Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { if (!noAssert) checkOffset(offset, 2, this.length); var val = this[offset] | (this[offset + 1] << 8); return (val & 0x8000) ? val | 0xFFFF0000 : val }; Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { if (!noAssert) checkOffset(offset, 2, this.length); var val = this[offset + 1] | (this[offset] << 8); return (val & 0x8000) ? val | 0xFFFF0000 : val }; Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length); return (this[offset]) | (this[offset + 1] << 8) | (this[offset + 2] << 16) | (this[offset + 3] << 24) }; Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length); return (this[offset] << 24) | (this[offset + 1] << 16) | (this[offset + 2] << 8) | (this[offset + 3]) }; Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length); return read(this, offset, true, 23, 4) }; Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { if (!noAssert) checkOffset(offset, 4, this.length); return read(this, offset, false, 23, 4) }; Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { if (!noAssert) checkOffset(offset, 8, this.length); return read(this, offset, true, 52, 8) }; Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { if (!noAssert) checkOffset(offset, 8, this.length); return read(this, offset, false, 52, 8) }; function checkInt (buf, value, offset, ext, max, min) { if (!internalIsBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') if (offset + ext > buf.length) throw new RangeError('Index out of range') } Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { value = +value; offset = offset | 0; byteLength = byteLength | 0; if (!noAssert) { var maxBytes = Math.pow(2, 8 * byteLength) - 1; checkInt(this, value, offset, byteLength, maxBytes, 0); } var mul = 1; var i = 0; this[offset] = value & 0xFF; while (++i < byteLength && (mul *= 0x100)) { this[offset + i] = (value / mul) & 0xFF; } return offset + byteLength }; Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { value = +value; offset = offset | 0; byteLength = byteLength | 0; if (!noAssert) { var maxBytes = Math.pow(2, 8 * byteLength) - 1; checkInt(this, value, offset, byteLength, maxBytes, 0); } var i = byteLength - 1; var mul = 1; this[offset + i] = value & 0xFF; while (--i >= 0 && (mul *= 0x100)) { this[offset + i] = (value / mul) & 0xFF; } return offset + byteLength }; Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0); if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value); this[offset] = (value & 0xff); return offset + 1 }; function objectWriteUInt16 (buf, value, offset, littleEndian) { if (value < 0) value = 0xffff + value + 1; for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> (littleEndian ? i : 1 - i) * 8; } } Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value & 0xff); this[offset + 1] = (value >>> 8); } else { objectWriteUInt16(this, value, offset, true); } return offset + 2 }; Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value >>> 8); this[offset + 1] = (value & 0xff); } else { objectWriteUInt16(this, value, offset, false); } return offset + 2 }; function objectWriteUInt32 (buf, value, offset, littleEndian) { if (value < 0) value = 0xffffffff + value + 1; for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff; } } Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset + 3] = (value >>> 24); this[offset + 2] = (value >>> 16); this[offset + 1] = (value >>> 8); this[offset] = (value & 0xff); } else { objectWriteUInt32(this, value, offset, true); } return offset + 4 }; Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value >>> 24); this[offset + 1] = (value >>> 16); this[offset + 2] = (value >>> 8); this[offset + 3] = (value & 0xff); } else { objectWriteUInt32(this, value, offset, false); } return offset + 4 }; Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { value = +value; offset = offset | 0; if (!noAssert) { var limit = Math.pow(2, 8 * byteLength - 1); checkInt(this, value, offset, byteLength, limit - 1, -limit); } var i = 0; var mul = 1; var sub = 0; this[offset] = value & 0xFF; while (++i < byteLength && (mul *= 0x100)) { if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { sub = 1; } this[offset + i] = ((value / mul) >> 0) - sub & 0xFF; } return offset + byteLength }; Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { value = +value; offset = offset | 0; if (!noAssert) { var limit = Math.pow(2, 8 * byteLength - 1); checkInt(this, value, offset, byteLength, limit - 1, -limit); } var i = byteLength - 1; var mul = 1; var sub = 0; this[offset + i] = value & 0xFF; while (--i >= 0 && (mul *= 0x100)) { if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { sub = 1; } this[offset + i] = ((value / mul) >> 0) - sub & 0xFF; } return offset + byteLength }; Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80); if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value); if (value < 0) value = 0xff + value + 1; this[offset] = (value & 0xff); return offset + 1 }; Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value & 0xff); this[offset + 1] = (value >>> 8); } else { objectWriteUInt16(this, value, offset, true); } return offset + 2 }; Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value >>> 8); this[offset + 1] = (value & 0xff); } else { objectWriteUInt16(this, value, offset, false); } return offset + 2 }; Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value & 0xff); this[offset + 1] = (value >>> 8); this[offset + 2] = (value >>> 16); this[offset + 3] = (value >>> 24); } else { objectWriteUInt32(this, value, offset, true); } return offset + 4 }; Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { value = +value; offset = offset | 0; if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); if (value < 0) value = 0xffffffff + value + 1; if (Buffer.TYPED_ARRAY_SUPPORT) { this[offset] = (value >>> 24); this[offset + 1] = (value >>> 16); this[offset + 2] = (value >>> 8); this[offset + 3] = (value & 0xff); } else { objectWriteUInt32(this, value, offset, false); } return offset + 4 }; function checkIEEE754 (buf, value, offset, ext, max, min) { if (offset + ext > buf.length) throw new RangeError('Index out of range') if (offset < 0) throw new RangeError('Index out of range') } function writeFloat (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38); } write(buf, value, offset, littleEndian, 23, 4); return offset + 4 } Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { return writeFloat(this, value, offset, true, noAssert) }; Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { return writeFloat(this, value, offset, false, noAssert) }; function writeDouble (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308); } write(buf, value, offset, littleEndian, 52, 8); return offset + 8 } Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { return writeDouble(this, value, offset, true, noAssert) }; Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { return writeDouble(this, value, offset, false, noAssert) }; // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) Buffer.prototype.copy = function copy (target, targetStart, start, end) { if (!start) start = 0; if (!end && end !== 0) end = this.length; if (targetStart >= target.length) targetStart = target.length; if (!targetStart) targetStart = 0; if (end > 0 && end < start) end = start; // Copy 0 bytes; we're done if (end === start) return 0 if (target.length === 0 || this.length === 0) return 0 // Fatal error conditions if (targetStart < 0) { throw new RangeError('targetStart out of bounds') } if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') if (end < 0) throw new RangeError('sourceEnd out of bounds') // Are we oob? if (end > this.length) end = this.length; if (target.length - targetStart < end - start) { end = target.length - targetStart + start; } var len = end - start; var i; if (this === target && start < targetStart && targetStart < end) { // descending copy from end for (i = len - 1; i >= 0; --i) { target[i + targetStart] = this[i + start]; } } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { // ascending copy from start for (i = 0; i < len; ++i) { target[i + targetStart] = this[i + start]; } } else { Uint8Array.prototype.set.call( target, this.subarray(start, start + len), targetStart ); } return len }; // Usage: // buffer.fill(number[, offset[, end]]) // buffer.fill(buffer[, offset[, end]]) // buffer.fill(string[, offset[, end]][, encoding]) Buffer.prototype.fill = function fill (val, start, end, encoding) { // Handle string cases: if (typeof val === 'string') { if (typeof start === 'string') { encoding = start; start = 0; end = this.length; } else if (typeof end === 'string') { encoding = end; end = this.length; } if (val.length === 1) { var code = val.charCodeAt(0); if (code < 256) { val = code; } } if (encoding !== undefined && typeof encoding !== 'string') { throw new TypeError('encoding must be a string') } if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { throw new TypeError('Unknown encoding: ' + encoding) } } else if (typeof val === 'number') { val = val & 255; } // Invalid ranges are not set to a default, so can range check early. if (start < 0 || this.length < start || this.length < end) { throw new RangeError('Out of range index') } if (end <= start) { return this } start = start >>> 0; end = end === undefined ? this.length : end >>> 0; if (!val) val = 0; var i; if (typeof val === 'number') { for (i = start; i < end; ++i) { this[i] = val; } } else { var bytes = internalIsBuffer(val) ? val : utf8ToBytes(new Buffer(val, encoding).toString()); var len = bytes.length; for (i = 0; i < end - start; ++i) { this[i + start] = bytes[i % len]; } } return this }; // HELPER FUNCTIONS // ================ var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g; function base64clean (str) { // Node strips out invalid characters like \n and \t from the string, base64-js does not str = stringtrim(str).replace(INVALID_BASE64_RE, ''); // Node converts strings with length < 2 to '' if (str.length < 2) return '' // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not while (str.length % 4 !== 0) { str = str + '='; } return str } function stringtrim (str) { if (str.trim) return str.trim() return str.replace(/^\s+|\s+$/g, '') } function toHex (n) { if (n < 16) return '0' + n.toString(16) return n.toString(16) } function utf8ToBytes (string, units) { units = units || Infinity; var codePoint; var length = string.length; var leadSurrogate = null; var bytes = []; for (var i = 0; i < length; ++i) { codePoint = string.charCodeAt(i); // is surrogate component if (codePoint > 0xD7FF && codePoint < 0xE000) { // last char was a lead if (!leadSurrogate) { // no lead yet if (codePoint > 0xDBFF) { // unexpected trail if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); continue } else if (i + 1 === length) { // unpaired lead if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); continue } // valid lead leadSurrogate = codePoint; continue } // 2 leads in a row if (codePoint < 0xDC00) { if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); leadSurrogate = codePoint; continue } // valid surrogate pair codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000; } else if (leadSurrogate) { // valid bmp char, but last char was a lead if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); } leadSurrogate = null; // encode utf8 if (codePoint < 0x80) { if ((units -= 1) < 0) break bytes.push(codePoint); } else if (codePoint < 0x800) { if ((units -= 2) < 0) break bytes.push( codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80 ); } else if (codePoint < 0x10000) { if ((units -= 3) < 0) break bytes.push( codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80 ); } else if (codePoint < 0x110000) { if ((units -= 4) < 0) break bytes.push( codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80 ); } else { throw new Error('Invalid code point') } } return bytes } function asciiToBytes (str) { var byteArray = []; for (var i = 0; i < str.length; ++i) { // Node's code seems to be doing this and not & 0x7F.. byteArray.push(str.charCodeAt(i) & 0xFF); } return byteArray } function utf16leToBytes (str, units) { var c, hi, lo; var byteArray = []; for (var i = 0; i < str.length; ++i) { if ((units -= 2) < 0) break c = str.charCodeAt(i); hi = c >> 8; lo = c % 256; byteArray.push(lo); byteArray.push(hi); } return byteArray } function base64ToBytes (str) { return toByteArray(base64clean(str)) } function blitBuffer (src, dst, offset, length) { for (var i = 0; i < length; ++i) { if ((i + offset >= dst.length) || (i >= src.length)) break dst[i + offset] = src[i]; } return i } function isnan (val) { return val !== val // eslint-disable-line no-self-compare } // the following is from is-buffer, also by Feross Aboukhadijeh and with same lisence // The _isBuffer check is for Safari 5-7 support, because it's missing // Object.prototype.constructor. Remove this eventually function isBuffer(obj) { return obj != null && (!!obj._isBuffer || isFastBuffer(obj) || isSlowBuffer(obj)) } function isFastBuffer (obj) { return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) } // For Node v0.10 support. Remove this eventually. function isSlowBuffer (obj) { return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isFastBuffer(obj.slice(0, 0)) } /******************************************************************************** * Ledger Node JS API * (c) 2016-2017 Ledger * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ function defer() { let resolve, reject; let promise = new Promise(function (success, failure) { resolve = success; reject = failure; }); if (!resolve || !reject) throw "defer() error"; // this never happens and is just to make flow happy return { promise, resolve, reject }; } // TODO use bip32-path library function splitPath(path) { let result = []; let components = path.split("/"); components.forEach(element => { let number = parseInt(element, 10); if (isNaN(number)) { return; // FIXME shouldn't it throws instead? } if (element.length > 1 && element[element.length - 1] === "'") { number += 0x80000000; } result.push(number); }); return result; } // TODO use async await function eachSeries(arr, fun) { return arr.reduce((p, e) => p.then(() => fun(e)), Promise.resolve()); } function foreach(arr, callback) { function iterate(index, array, result) { if (index >= array.length) { return result; } else return callback(array[index], index).then(function (res) { result.push(res); return iterate(index + 1, array, result); }); } return Promise.resolve().then(() => iterate(0, arr, [])); } function doIf(condition, callback) { return Promise.resolve().then(() => { if (condition) { return callback(); } }); } function asyncWhile(predicate, callback) { function iterate(result) { if (!predicate()) { return result; } else { return callback().then(res => { result.push(res); return iterate(result); }); } } return Promise.resolve([]).then(iterate); } /* eslint-disable no-continue */ /* eslint-disable no-param-reassign */ /* eslint-disable no-prototype-builtins */ var errorClasses = {}; var deserializers = {}; var addCustomErrorDeserializer = function (name, deserializer) { deserializers[name] = deserializer; }; var createCustomErrorClass = function (name) { var C = function CustomError(message, fields) { Object.assign(this, fields); this.name = name; this.message = message || name; this.stack = new Error().stack; }; C.prototype = new Error(); errorClasses[name] = C; return C; }; // inspired from https://github.com/programble/errio/blob/master/index.js var deserializeError = function (object) { if (typeof object === "object" && object) { try { // $FlowFixMe FIXME HACK var msg = JSON.parse(object.message); if (msg.message && msg.name) { object = msg; } } catch (e) { // nothing } var error = void 0; if (typeof object.name === "string") { var name_1 = object.name; var des = deserializers[name_1]; if (des) { error = des(object); } else { var constructor = name_1 === "Error" ? Error : errorClasses[name_1]; if (!constructor) { console.warn("deserializing an unknown class '" + name_1 + "'"); constructor = createCustomErrorClass(name_1); } error = Object.create(constructor.prototype); try { for (var prop in object) { if (object.hasOwnProperty(prop)) { error[prop] = object[prop]; } } } catch (e) { // sometimes setting a property can fail (e.g. .name) } } } else { error = new Error(object.message); } if (!error.stack && Error.captureStackTrace) { Error.captureStackTrace(error, deserializeError); } return error; } return new Error(String(object)); }; // inspired from https://github.com/sindresorhus/serialize-error/blob/master/index.js var serializeError = function (value) { if (!value) return value; if (typeof value === "object") { return destroyCircular(value, []); } if (typeof value === "function") { return "[Function: " + (value.name || "anonymous") + "]"; } return value; }; // https://www.npmjs.com/package/destroy-circular function destroyCircular(from, seen) { var to = {}; seen.push(from); for (var _i = 0, _a = Object.keys(from); _i < _a.length; _i++) { var key = _a[_i]; var value = from[key]; if (typeof value === "function") { continue; } if (!value || typeof value !== "object") { to[key] = value; continue; } if (seen.indexOf(from[key]) === -1) { to[key] = destroyCircular(from[key], seen.slice(0)); continue; } to[key] = "[Circular]"; } if (typeof from.name === "string") { to.name = from.name; } if (typeof from.message === "string") { to.message = from.message; } if (typeof from.stack === "string") { to.stack = from.stack; } return to; } var AccountNameRequiredError = createCustomErrorClass("AccountNameRequired"); var AccountNotSupported = createCustomErrorClass("AccountNotSupported"); var AmountRequired = createCustomErrorClass("AmountRequired"); var BluetoothRequired = createCustomErrorClass("BluetoothRequired"); var BtcUnmatchedApp = createCustomErrorClass("BtcUnmatchedApp"); var CantOpenDevice = createCustomErrorClass("CantOpenDevice"); var CashAddrNotSupported = createCustomErrorClass("CashAddrNotSupported"); var CurrencyNotSupported = createCustomErrorClass("CurrencyNotSupported"); var DeviceAppVerifyNotSupported = createCustomErrorClass("DeviceAppVerifyNotSupported"); var DeviceGenuineSocketEarlyClose = createCustomErrorClass("DeviceGenuineSocketEarlyClose"); var DeviceNotGenuineError = createCustomErrorClass("DeviceNotGenuine"); var DeviceOnDashboardExpected = createCustomErrorClass("DeviceOnDashboardExpected"); var DeviceOnDashboardUnexpected = createCustomErrorClass("DeviceOnDashboardUnexpected"); var DeviceInOSUExpected = createCustomErrorClass("DeviceInOSUExpected"); var DeviceHalted = createCustomErrorClass("DeviceHalted"); var DeviceNameInvalid = createCustomErrorClass("DeviceNameInvalid"); var DeviceSocketFail = createCustomErrorClass("DeviceSocketFail"); var DeviceSocketNoBulkStatus = createCustomErrorClass("DeviceSocketNoBulkStatus"); var DisconnectedDevice = createCustomErrorClass("DisconnectedDevice"); var DisconnectedDeviceDuringOperation = createCustomErrorClass("DisconnectedDeviceDuringOperation"); var EnpointConfigError = createCustomErrorClass("EnpointConfig"); var EthAppPleaseEnableContractData = createCustomErrorClass("EthAppPleaseEnableContractData"); var FeeEstimationFailed = createCustomErrorClass("FeeEstimationFailed"); var FirmwareNotRecognized = createCustomErrorClass("FirmwareNotRecognized"); var HardResetFail = createCustomErrorClass("HardResetFail"); var InvalidXRPTag = createCustomErrorClass("InvalidXRPTag"); var InvalidAddress = createCustomErrorClass("InvalidAddress"); var InvalidAddressBecauseDestinationIsAlsoSource = createCustomErrorClass("InvalidAddressBecauseDestinationIsAlsoSource"); var LatestMCUInstalledError = createCustomErrorClass("LatestMCUInstalledError"); var UnknownMCU = createCustomErrorClass("UnknownMCU"); var LedgerAPIError = createCustomErrorClass("LedgerAPIError"); var LedgerAPIErrorWithMessage = createCustomErrorClass("LedgerAPIErrorWithMessage"); var LedgerAPINotAvailable = createCustomErrorClass("LedgerAPINotAvailable"); var ManagerAppAlreadyInstalledError = createCustomErrorClass("ManagerAppAlreadyInstalled"); var ManagerAppRelyOnBTCError = createCustomErrorClass("ManagerAppRelyOnBTC"); var ManagerAppDepInstallRequired = createCustomErrorClass("ManagerAppDepInstallRequired"); var ManagerAppDepUninstallRequired = createCustomErrorClass("ManagerAppDepUninstallRequired"); var ManagerDeviceLockedError = createCustomErrorClass("ManagerDeviceLocked"); var ManagerFirmwareNotEnoughSpaceError = createCustomErrorClass("ManagerFirmwareNotEnoughSpace"); var ManagerNotEnoughSpaceError = createCustomErrorClass("ManagerNotEnoughSpace"); var ManagerUninstallBTCDep = createCustomErrorClass("ManagerUninstallBTCDep"); var NetworkDown = createCustomErrorClass("NetworkDown"); var NoAddressesFound = createCustomErrorClass("NoAddressesFound"); var NotEnoughBalance = createCustomErrorClass("NotEnoughBalance"); var NotEnoughBalanceToDelegate = createCustomErrorClass("NotEnoughBalanceToDelegate"); var NotEnoughBalanceInParentAccount = createCustomErrorClass("NotEnoughBalanceInParentAccount"); var NotEnoughSpendableBalance = createCustomErrorClass("NotEnoughSpendableBalance"); var NotEnoughBalanceBecauseDestinationNotCreated = createCustomErrorClass("NotEnoughBalanceBecauseDestinationNotCreated"); var NoAccessToCamera = createCustomErrorClass("NoAccessToCamera"); var NotEnoughGas = createCustomErrorClass("NotEnoughGas"); var NotSupportedLegacyAddress = createCustomErrorClass("NotSupportedLegacyAddress"); var GasLessThanEstimate = createCustomErrorClass("GasLessThanEstimate"); var PasswordsDontMatchError = createCustomErrorClass("PasswordsDontMatch"); var PasswordIncorrectError = createCustomErrorClass("PasswordIncorrect"); var RecommendSubAccountsToEmpty = createCustomErrorClass("RecommendSubAccountsToEmpty"); var RecommendUndelegation = createCustomErrorClass("RecommendUndelegation"); var TimeoutTagged = createCustomErrorClass("TimeoutTagged"); var UnexpectedBootloader = createCustomErrorClass("UnexpectedBootloader"); var MCUNotGenuineToDashboard = createCustomErrorClass("MCUNotGenuineToDashboard"); var RecipientRequired = createCustomErrorClass("RecipientRequired"); var UnavailableTezosOriginatedAccountReceive = createCustomErrorClass("UnavailableTezosOriginatedAccountReceive"); var UnavailableTezosOriginatedAccountSend = createCustomErrorClass("UnavailableTezosOriginatedAccountSend"); var UpdateFetchFileFail = createCustomErrorClass("UpdateFetchFileFail"); var UpdateIncorrectHash = createCustomErrorClass("UpdateIncorrectHash"); var UpdateIncorrectSig = createCustomErrorClass("UpdateIncorrectSig"); var UpdateYourApp = createCustomErrorClass("UpdateYourApp"); var UserRefusedDeviceNameChange = createCustomErrorClass("UserRefusedDeviceNameChange"); var UserRefusedAddress = createCustomErrorClass("UserRefusedAddress"); var UserRefusedFirmwareUpdate = createCustomErrorClass("UserRefusedFirmwareUpdate"); var UserRefusedAllowManager = createCustomErrorClass("UserRefusedAllowManager"); var UserRefusedOnDevice = createCustomErrorClass("UserRefusedOnDevice"); // TODO rename because it's just for transaction refusal var TransportOpenUserCancelled = createCustomErrorClass("TransportOpenUserCancelled"); var TransportInterfaceNotAvailable = createCustomErrorClass("TransportInterfaceNotAvailable"); var TransportRaceCondition = createCustomErrorClass("TransportRaceCondition"); var TransportWebUSBGestureRequired = createCustomErrorClass("TransportWebUSBGestureRequired"); var DeviceShouldStayInApp = createCustomErrorClass("DeviceShouldStayInApp"); var WebsocketConnectionError = createCustomErrorClass("WebsocketConnectionError"); var WebsocketConnectionFailed = createCustomErrorClass("WebsocketConnectionFailed"); var WrongDeviceForAccount = createCustomErrorClass("WrongDeviceForAccount"); var WrongAppForCurrency = createCustomErrorClass("WrongAppForCurrency"); var ETHAddressNonEIP = createCustomErrorClass("ETHAddressNonEIP"); var CantScanQRCode = createCustomErrorClass("CantScanQRCode"); var FeeNotLoaded = createCustomErrorClass("FeeNotLoaded"); var FeeRequired = createCustomErrorClass("FeeRequired"); var FeeTooHigh = createCustomErrorClass("FeeTooHigh"); var SyncError = createCustomErrorClass("SyncError"); var PairingFailed = createCustomErrorClass("PairingFailed"); var GenuineCheckFailed = createCustomErrorClass("GenuineCheckFailed"); var LedgerAPI4xx = createCustomErrorClass("LedgerAPI4xx"); var LedgerAPI5xx = createCustomErrorClass("LedgerAPI5xx"); var FirmwareOrAppUpdateRequired = createCustomErrorClass("FirmwareOrAppUpdateRequired"); // db stuff, no need to translate var NoDBPathGiven = createCustomErrorClass("NoDBPathGiven"); var DBWrongPassword = createCustomErrorClass("DBWrongPassword"); var DBNotReset = createCustomErrorClass("DBNotReset"); /** * TransportError is used for any generic transport errors. * e.g. Error thrown when data received by exchanges are incorrect or if exchanged failed to communicate with the device for various reason. */ function TransportError(message, id) { this.name = "TransportError"; this.message = message; this.stack = new Error().stack; this.id = id; } TransportError.prototype = new Error(); addCustomErrorDeserializer("TransportError", function (e) { return new TransportError(e.message, e.id); }); var StatusCodes = { PIN_REMAINING_ATTEMPTS: 0x63c0, INCORRECT_LENGTH: 0x6700, MISSING_CRITICAL_PARAMETER: 0x6800, COMMAND_INCOMPATIBLE_FILE_STRUCTURE: 0x6981, SECURITY_STATUS_NOT_SATISFIED: 0x6982, CONDITIONS_OF_USE_NOT_SATISFIED: 0x6985, INCORRECT_DATA: 0x6a80, NOT_ENOUGH_MEMORY_SPACE: 0x6a84, REFERENCED_DATA_NOT_FOUND: 0x6a88, FILE_ALREADY_EXISTS: 0x6a89, INCORRECT_P1_P2: 0x6b00, INS_NOT_SUPPORTED: 0x6d00, CLA_NOT_SUPPORTED: 0x6e00, TECHNICAL_PROBLEM: 0x6f00, OK: 0x9000, MEMORY_PROBLEM: 0x9240, NO_EF_SELECTED: 0x9400, INVALID_OFFSET: 0x9402, FILE_NOT_FOUND: 0x9404, INCONSISTENT_FILE: 0x9408, ALGORITHM_NOT_SUPPORTED: 0x9484, INVALID_KCV: 0x9485, CODE_NOT_INITIALIZED: 0x9802, ACCESS_CONDITION_NOT_FULFILLED: 0x9804, CONTRADICTION_SECRET_CODE_STATUS: 0x9808, CONTRADICTION_INVALIDATION: 0x9810, CODE_BLOCKED: 0x9840, MAX_VALUE_REACHED: 0x9850, GP_AUTH_FAILED: 0x6300, LICENSING: 0x6f42, HALTED: 0x6faa, }; function getAltStatusMessage(code) { switch (code) { // improve text of most common errors case 0x6700: return "Incorrect length"; case 0x6800: return "Missing critical parameter"; case 0x6982: return "Security not satisfied (dongle locked or have invalid access rights)"; case 0x6985: return "Condition of use not satisfied (denied by the user?)"; case 0x6a80: return "Invalid data received"; case 0x6b00: return "Invalid parameter received"; } if (0x6f00 <= code && code <= 0x6fff) { return "Internal error, please report"; } } /** * Error thrown when a device returned a non success status. * the error.statusCode is one of the `StatusCodes` exported by this library. */ function TransportStatusError(statusCode) { this.name = "TransportStatusError"; var statusText = Object.keys(StatusCodes).find(function (k) { return StatusCodes[k] === statusCode; }) || "UNKNOWN_ERROR"; var smsg = getAltStatusMessage(statusCode) || statusText; var statusCodeStr = statusCode.toString(16); this.message = "Ledger device: " + smsg + " (0x" + statusCodeStr + ")"; this.stack = new Error().stack; this.statusCode = statusCode; this.statusText = statusText; } TransportStatusError.prototype = new Error(); addCustomErrorDeserializer("TransportStatusError", function (e) { return new TransportStatusError(e.statusCode); }); const remapTransactionRelatedErrors = e => { if (e && e.statusCode === 0x6a80) { return new EthAppPleaseEnableContractData("Please enable Contract data on the Ethereum app Settings"); } return e; }; /** * Ethereum API * * @example * import Eth from "@ledgerhq/hw-app-eth"; * const eth = new Eth(transport) */ class Eth { constructor(transport, scrambleKey = "w0w") { this.transport = void 0; this.transport = transport; transport.decorateAppAPIMethods(this, ["getAddress", "provideERC20TokenInformation", "signTransaction", "signPersonalMessage", "getAppConfiguration"], scrambleKey); } /** * get Ethereum address for a given BIP 32 path. * @param path a path in BIP 32 format * @option boolDisplay optionally enable or not the display * @option boolChaincode optionally enable or not the chaincode request * @return an object with a publicKey, address and (optionally) chainCode * @example * eth.getAddress("44'/60'/0'/0/0").then(o => o.address) */ getAddress(path, boolDisplay, boolChaincode) { let paths = splitPath(path); let buffer = Buffer.alloc(1 + paths.length * 4); buffer[0] = paths.length; paths.forEach((element, index) => { buffer.writeUInt32BE(element, 1 + 4 * index); }); return this.transport.send(0xe0, 0x02, boolDisplay ? 0x01 : 0x00, boolChaincode ? 0x01 : 0x00, buffer).then(response => { let result = {}; let publicKeyLength = response[0]; let addressLength = response[1 + publicKeyLength]; result.publicKey = response.slice(1, 1 + publicKeyLength).toString("hex"); result.address = "0x" + response.slice(1 + publicKeyLength + 1, 1 + publicKeyLength + 1 + addressLength).toString("ascii"); if (boolChaincode) { result.chainCode = response.slice(1 + publicKeyLength + 1 + addressLength, 1 + publicKeyLength + 1 + addressLength + 32).toString("hex"); } return result; }); } /** * This commands provides a trusted description of an ERC 20 token * to associate a contract address with a ticker and number of decimals. * * It shall be run immediately before performing a transaction involving a contract * calling this contract address to display the proper token information to the user if necessary. * * @param {*} info: a blob from "erc20.js" utilities that contains all token information. * * @example * import { byContractAddress } from "@ledgerhq/hw-app-eth/erc20" * const zrxInfo = byContractAddress("0xe41d2489571d322189246dafa5ebde1f4699f498") * if (zrxInfo) await appEth.provideERC20TokenInformation(zrxInfo) * const signed = await appEth.signTransaction(path, rawTxHex) */ provideERC20TokenInformation({ data }) { return this.transport.send(0xe0, 0x0a, 0x00, 0x00, data).then(() => true, e => { if (e && e.statusCode === 0x6d00) { // this case happen for older version of ETH app, since older app version had the ERC20 data hardcoded, it's fine to assume it worked. // we return a flag to know if the call was effective or not return false; } throw e; }); } /** * You can sign a transaction and retrieve v, r, s given the raw transaction and the BIP 32 path of the account to sign * @example eth.signTransaction("44'/60'/0'/0/0", "e8018504e3b292008252089428ee52a8f3d6e5d15f8b131996950d7f296c7952872bd72a2487400080").then(result => ...) */ signTransaction(path, rawTxHex) { let paths = splitPath(path); let offset = 0; let rawTx = Buffer.from(rawTxHex, "hex"); let toSend = []; let response; while (offset !== rawTx.length) { let maxChunkSize = offset === 0 ? 150 - 1 - paths.length * 4 : 150; let chunkSize = offset + maxChunkSize > rawTx.length ? rawTx.length - offset : maxChunkSize; let buffer = Buffer.alloc(offset === 0 ? 1 + paths.length * 4 + chunkSize : chunkSize); if (offset === 0) { buffer[0] = paths.length; paths.forEach((element, index) => { buffer.writeUInt32BE(element, 1 + 4 * index); }); rawTx.copy(buffer, 1 + 4 * paths.length, offset, offset + chunkSize); } else { rawTx.copy(buffer, 0, offset, offset + chunkSize); } toSend.push(buffer); offset += chunkSize; } return foreach(toSend, (data, i) => this.transport.send(0xe0, 0x04, i === 0 ? 0x00 : 0x80, 0x00, data).then(apduResponse => { response = apduResponse; })).then(() => { const v = response.slice(0, 1).toString("hex"); const r = response.slice(1, 1 + 32).toString("hex"); const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex"); return { v, r, s }; }, e => { throw remapTransactionRelatedErrors(e); }); } /** */ getAppConfiguration() { return this.transport.send(0xe0, 0x06, 0x00, 0x00).then(response => { let result = {}; result.arbitraryDataEnabled = response[0] & 0x01; result.version = "" + response[1] + "." + response[2] + "." + response[3]; return result; }); } /** * You can sign a message according to eth_sign RPC call and retrieve v, r, s given the message and the BIP 32 path of the account to sign. * @example eth.signPersonalMessage("44'/60'/0'/0/0", Buffer.from("test").toString("hex")).then(result => { var v = result['v'] - 27; v = v.toString(16); if (v.length < 2) { v = "0" + v; } console.log("Signature 0x" + result['r'] + result['s'] + v); }) */ signPersonalMessage(path, messageHex) { let paths = splitPath(path); let offset = 0; let message = Buffer.from(messageHex, "hex"); let toSend = []; let response; while (offset !== message.length) { let maxChunkSize = offset === 0 ? 150 - 1 - paths.length * 4 - 4 : 150; let chunkSize = offset + maxChunkSize > message.length ? message.length - offset : maxChunkSize; let buffer = Buffer.alloc(offset === 0 ? 1 + paths.length * 4 + 4 + chunkSize : chunkSize); if (offset === 0) { buffer[0] = paths.length; paths.forEach((element, index) => { buffer.writeUInt32BE(element, 1 + 4 * index); }); buffer.writeUInt32BE(message.length, 1 + 4 * paths.length); message.copy(buffer, 1 + 4 * paths.length + 4, offset, offset + chunkSize); } else { message.copy(buffer, 0, offset, offset + chunkSize); } toSend.push(buffer); offset += chunkSize; } return foreach(toSend, (data, i) => this.transport.send(0xe0, 0x08, i === 0 ? 0x00 : 0x80, 0x00, data).then(apduResponse => { response = apduResponse; })).then(() => { const v = response[0]; const r = response.slice(1, 1 + 32).toString("hex"); const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex"); return { v, r, s }; }); } } var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function commonjsRequire () { throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs'); } function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } function getCjsExportFromNamespace (n) { return n && n['default'] || n; } // Copyright 2014 Google Inc. All rights reserved // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd /** * @fileoverview The U2F api. */ 'use strict'; /** Namespace for the U2F api. * @type {Object} */ var u2f = u2f || {}; var googleU2fApi = u2f; // Adaptation for u2f-api package /** * The U2F extension id * @type {string} * @const */ u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd'; /** * Message types for messsages to/from the extension * @const * @enum {string} */ u2f.MessageTypes = { 'U2F_REGISTER_REQUEST': 'u2f_register_request', 'U2F_SIGN_REQUEST': 'u2f_sign_request', 'U2F_REGISTER_RESPONSE': 'u2f_register_response', 'U2F_SIGN_RESPONSE': 'u2f_sign_response' }; /** * Response status codes * @const * @enum {number} */ u2f.ErrorCodes = { 'OK': 0, 'OTHER_ERROR': 1, 'BAD_REQUEST': 2, 'CONFIGURATION_UNSUPPORTED': 3, 'DEVICE_INELIGIBLE': 4, 'TIMEOUT': 5 }; /** * A message type for registration requests * @typedef {{ * type: u2f.MessageTypes, * signRequests: Array., * registerRequests: ?Array., * timeoutSeconds: ?number, * requestId: ?number * }} */ u2f.Request; /** * A message for registration responses * @typedef {{ * type: u2f.MessageTypes, * responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse), * requestId: ?number * }} */ u2f.Response; /** * An error object for responses * @typedef {{ * errorCode: u2f.ErrorCodes, * errorMessage: ?string * }} */ u2f.Error; /** * Data object for a single sign request. * @typedef {{ * version: string, * challenge: string, * keyHandle: string, * appId: string * }} */ u2f.SignRequest; /** * Data object for a sign response. * @typedef {{ * keyHandle: string, * signatureData: string, * clientData: string * }} */ u2f.SignResponse; /** * Data object for a registration request. * @typedef {{ * version: string, * challenge: string, * appId: string * }} */ u2f.RegisterRequest; /** * Data object for a registration response. * @typedef {{ * registrationData: string, * clientData: string * }} */ u2f.RegisterResponse; // Low level MessagePort API support /** * Call MessagePort disconnect */ u2f.disconnect = function() { if (u2f.port_ && u2f.port_.port_) { u2f.port_.port_.disconnect(); u2f.port_ = null; } }; /** * Sets up a MessagePort to the U2F extension using the * available mechanisms. * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback */ u2f.getMessagePort = function(callback) { if (typeof chrome != 'undefined' && chrome.runtime) { // The actual message here does not matter, but we need to get a reply // for the callback to run. Thus, send an empty signature request // in order to get a failure response. var msg = { type: u2f.MessageTypes.U2F_SIGN_REQUEST, signRequests: [] }; chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function() { if (!chrome.runtime.lastError) { // We are on a whitelisted origin and can talk directly // with the extension. u2f.getChromeRuntimePort_(callback); } else { // chrome.runtime was available, but we couldn't message // the extension directly, use iframe u2f.getIframePort_(callback); } }); } else { // chrome.runtime was not available at all, which is normal // when this origin doesn't have access to any extensions. u2f.getIframePort_(callback); } }; /** * Connects directly to the extension via chrome.runtime.connect * @param {function(u2f.WrappedChromeRuntimePort_)} callback * @private */ u2f.getChromeRuntimePort_ = function(callback) { var port = chrome.runtime.connect(u2f.EXTENSION_ID, {'includeTlsChannelId': true}); setTimeout(function() { callback(null, new u2f.WrappedChromeRuntimePort_(port)); }, 0); }; /** * A wrapper for chrome.runtime.Port that is compatible with MessagePort. * @param {Port} port * @constructor * @private */ u2f.WrappedChromeRuntimePort_ = function(port) { this.port_ = port; }; /** * Posts a message on the underlying channel. * @param {Object} message */ u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) { this.port_.postMessage(message); }; /** * Emulates the HTML 5 addEventListener interface. Works only for the * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage. * @param {string} eventName * @param {function({data: Object})} handler */ u2f.WrappedChromeRuntimePort_.prototype.addEventListener = function(eventName, handler) { var name = eventName.toLowerCase(); if (name == 'message' || name == 'onmessage') { this.port_.onMessage.addListener(function(message) { // Emulate a minimal MessageEvent object handler({'data': message}); }); } else { console.error('WrappedChromeRuntimePort only supports onMessage'); } }; /** * Sets up an embedded trampoline iframe, sourced from the extension. * @param {function(MessagePort)} callback * @private */ u2f.getIframePort_ = function(callback) { // Create the iframe var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID; var iframe = document.createElement('iframe'); iframe.src = iframeOrigin + '/u2f-comms.html'; iframe.setAttribute('style', 'display:none'); document.body.appendChild(iframe); var hasCalledBack = false; var channel = new MessageChannel(); var ready = function(message) { if (message.data == 'ready') { channel.port1.removeEventListener('message', ready); if (!hasCalledBack) { hasCalledBack = true; callback(null, channel.port1); } } else { console.error('First event on iframe port was not "ready"'); } }; channel.port1.addEventListener('message', ready); channel.port1.start(); iframe.addEventListener('load', function() { // Deliver the port to the iframe and initialize iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]); }); // Give this 200ms to initialize, after that, we treat this method as failed setTimeout(function() { if (!hasCalledBack) { hasCalledBack = true; callback(new Error("IFrame extension not supported")); } }, 200); }; // High-level JS API /** * Default extension response timeout in seconds. * @const */ u2f.EXTENSION_TIMEOUT_SEC = 30; /** * A singleton instance for a MessagePort to the extension. * @type {MessagePort|u2f.WrappedChromeRuntimePort_} * @private */ u2f.port_ = null; /** * Callbacks waiting for a port * @type {Array.} * @private */ u2f.waitingForPort_ = []; /** * A counter for requestIds. * @type {number} * @private */ u2f.reqCounter_ = 0; /** * A map from requestIds to client callbacks * @type {Object.} * @private */ u2f.callbackMap_ = {}; /** * Creates or retrieves the MessagePort singleton to use. * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback * @private */ u2f.getPortSingleton_ = function(callback) { if (u2f.port_) { callback(null, u2f.port_); } else { if (u2f.waitingForPort_.length == 0) { u2f.getMessagePort(function(err, port) { if (!err) { u2f.port_ = port; u2f.port_.addEventListener('message', /** @type {function(Event)} */ (u2f.responseHandler_)); } // Careful, here be async callbacks. Maybe. while (u2f.waitingForPort_.length) u2f.waitingForPort_.shift()(err, port); }); } u2f.waitingForPort_.push(callback); } }; /** * Handles response messages from the extension. * @param {MessageEvent.} message * @private */ u2f.responseHandler_ = function(message) { var response = message.data; var reqId = response['requestId']; if (!reqId || !u2f.callbackMap_[reqId]) { console.error('Unknown or missing requestId in response.'); return; } var cb = u2f.callbackMap_[reqId]; delete u2f.callbackMap_[reqId]; cb(null, response['responseData']); }; /** * Calls the callback with true or false as first and only argument * @param {Function} callback */ u2f.isSupported = function(callback) { u2f.getPortSingleton_(function(err, port) { callback(!err); }); }; /** * Dispatches an array of sign requests to available U2F tokens. * @param {Array.} signRequests * @param {function((u2f.Error|u2f.SignResponse))} callback * @param {number=} opt_timeoutSeconds */ u2f.sign = function(signRequests, callback, opt_timeoutSeconds) { u2f.getPortSingleton_(function(err, port) { if (err) return callback(err); var reqId = ++u2f.reqCounter_; u2f.callbackMap_[reqId] = callback; var req = { type: u2f.MessageTypes.U2F_SIGN_REQUEST, signRequests: signRequests, timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ? opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC), requestId: reqId }; port.postMessage(req); }); }; /** * Dispatches register requests to available U2F tokens. An array of sign * requests identifies already registered tokens. * @param {Array.} registerRequests * @param {Array.} signRequests * @param {function((u2f.Error|u2f.RegisterResponse))} callback * @param {number=} opt_timeoutSeconds */ u2f.register = function(registerRequests, signRequests, callback, opt_timeoutSeconds) { u2f.getPortSingleton_(function(err, port) { if (err) return callback(err); var reqId = ++u2f.reqCounter_; u2f.callbackMap_[reqId] = callback; var req = { type: u2f.MessageTypes.U2F_REGISTER_REQUEST, signRequests: signRequests, registerRequests: registerRequests, timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ? opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC), requestId: reqId }; port.postMessage(req); }); }; 'use strict'; var u2fApi = API; // Feature detection (yes really) var isBrowser = ( typeof navigator !== 'undefined' ) && !!navigator.userAgent; var isSafari = isBrowser && navigator.userAgent.match( /Safari\// ) && !navigator.userAgent.match( /Chrome\// ); var isEDGE = isBrowser && navigator.userAgent.match( /Edge\/1[2345]/ ); var _backend = null; function getBackend( Promise ) { if ( !_backend ) _backend = new Promise( function( resolve, reject ) { function notSupported( ) { // Note; {native: true} means *not* using Google's hack resolve( { u2f: null, native: true } ); } if ( !isBrowser ) return notSupported( ); if ( isSafari ) // Safari doesn't support U2F, and the Safari-FIDO-U2F // extension lacks full support (Multi-facet apps), so we // block it until proper support. return notSupported( ); var hasNativeSupport = ( typeof window.u2f !== 'undefined' ) && ( typeof window.u2f.sign === 'function' ); if ( hasNativeSupport ) resolve( { u2f: window.u2f, native: true } ); if ( isEDGE ) // We don't want to check for Google's extension hack on EDGE // as it'll cause trouble (popups, etc) return notSupported( ); if ( location.protocol === 'http:' ) // U2F isn't supported over http, only https return notSupported( ); if ( typeof MessageChannel === 'undefined' ) // Unsupported browser, the chrome hack would throw return notSupported( ); // Test for google extension support googleU2fApi.isSupported( function( ok ) { if ( ok ) resolve( { u2f: googleU2fApi, native: false } ); else notSupported( ); } ); } ); return _backend; } function API( Promise ) { return { isSupported : isSupported.bind( Promise ), ensureSupport : ensureSupport.bind( Promise ), register : register.bind( Promise ), sign : sign.bind( Promise ), ErrorCodes : API.ErrorCodes, ErrorNames : API.ErrorNames }; } API.ErrorCodes = { CANCELLED: -1, OK: 0, OTHER_ERROR: 1, BAD_REQUEST: 2, CONFIGURATION_UNSUPPORTED: 3, DEVICE_INELIGIBLE: 4, TIMEOUT: 5 }; API.ErrorNames = { "-1": "CANCELLED", "0": "OK", "1": "OTHER_ERROR", "2": "BAD_REQUEST", "3": "CONFIGURATION_UNSUPPORTED", "4": "DEVICE_INELIGIBLE", "5": "TIMEOUT" }; function makeError( msg, err ) { var code = err != null ? err.errorCode : 1; // Default to OTHER_ERROR var type = API.ErrorNames[ '' + code ]; var error = new Error( msg ); error.metaData = { type: type, code: code }; return error; } function deferPromise( Promise, promise ) { var ret = { }; ret.promise = new Promise( function( resolve, reject ) { ret.resolve = resolve; ret.reject = reject; promise.then( resolve, reject ); } ); /** * Reject request promise and disconnect port if 'disconnect' flag is true * @param {string} msg * @param {boolean} disconnect */ ret.promise.cancel = function( msg, disconnect ) { getBackend( Promise ) .then( function( backend ) { if ( disconnect && !backend.native ) backend.u2f.disconnect( ); ret.reject( makeError( msg, { errorCode: -1 } ) ); } ); }; return ret; } function defer$1( Promise, fun ) { return deferPromise( Promise, new Promise( function( resolve, reject ) { try { fun && fun( resolve, reject ); } catch ( err ) { reject( err ); } } ) ); } function isSupported( ) { var Promise = this; return getBackend( Promise ) .then( function( backend ) { return !!backend.u2f; } ); } function _ensureSupport( backend ) { if ( !backend.u2f ) { if ( location.protocol === 'http:' ) throw new Error( "U2F isn't supported over http, only https" ); throw new Error( "U2F not supported" ); } } function ensureSupport( ) { var Promise = this; return getBackend( Promise ) .then( _ensureSupport ); } function register( registerRequests, signRequests /* = null */, timeout ) { var Promise = this; if ( !Array.isArray( registerRequests ) ) registerRequests = [ registerRequests ]; if ( typeof signRequests === 'number' && typeof timeout === 'undefined' ) { timeout = signRequests; signRequests = null; } if ( !signRequests ) signRequests = [ ]; return deferPromise( Promise, getBackend( Promise ) .then( function( backend ) { _ensureSupport( backend ); var native = backend.native; var u2f = backend.u2f; return new Promise( function( resolve, reject ) { function cbNative( response ) { if ( response.errorCode ) reject( makeError( "Registration failed", response ) ); else { delete response.errorCode; resolve( response ); } } function cbChrome( err, response ) { if ( err ) reject( err ); else if ( response.errorCode ) reject( makeError( "Registration failed", response ) ); else resolve( response ); } if ( native ) { var appId = registerRequests[ 0 ].appId; u2f.register( appId, registerRequests, signRequests, cbNative, timeout ); } else { u2f.register( registerRequests, signRequests, cbChrome, timeout ); } } ); } ) ).promise; } function sign( signRequests, timeout ) { var Promise = this; if ( !Array.isArray( signRequests ) ) signRequests = [ signRequests ]; return deferPromise( Promise, getBackend( Promise ) .then( function( backend ) { _ensureSupport( backend ); var native = backend.native; var u2f = backend.u2f; return new Promise( function( resolve, reject ) { function cbNative( response ) { if ( response.errorCode ) reject( makeError( "Sign failed", response ) ); else { delete response.errorCode; resolve( response ); } } function cbChrome( err, response ) { if ( err ) reject( err ); else if ( response.errorCode ) reject( makeError( "Sign failed", response ) ); else resolve( response ); } if ( native ) { var appId = signRequests[ 0 ].appId; var challenge = signRequests[ 0 ].challenge; u2f.sign( appId, challenge, signRequests, cbNative, timeout ); } else { u2f.sign( signRequests, cbChrome, timeout ); } } ); } ) ).promise; } function makeDefault( func ) { API[ func ] = function( ) { if ( !commonjsGlobal.Promise ) // This is very unlikely to ever happen, since browsers // supporting U2F will most likely support Promises. throw new Error( "The platform doesn't natively support promises" ); var args = [ ].slice.call( arguments ); return API( commonjsGlobal.Promise )[ func ].apply( null, args ); }; } // Provide default functions using the built-in Promise if available. makeDefault( 'isSupported' ); makeDefault( 'ensureSupport' ); makeDefault( 'register' ); makeDefault( 'sign' ); 'use strict'; var u2fApi$1 = u2fApi; var u2fApi_1 = u2fApi$1.isSupported; var u2fApi_2 = u2fApi$1.sign; // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; var R = typeof Reflect === 'object' ? Reflect : null; var ReflectApply = R && typeof R.apply === 'function' ? R.apply : function ReflectApply(target, receiver, args) { return Function.prototype.apply.call(target, receiver, args); }; var ReflectOwnKeys; if (R && typeof R.ownKeys === 'function') { ReflectOwnKeys = R.ownKeys; } else if (Object.getOwnPropertySymbols) { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target) .concat(Object.getOwnPropertySymbols(target)); }; } else { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target); }; } function ProcessEmitWarning(warning) { if (console && console.warn) console.warn(warning); } var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { return value !== value; }; function EventEmitter() { EventEmitter.init.call(this); } var events = EventEmitter; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._eventsCount = 0; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. var defaultMaxListeners = 10; function checkListener(listener) { if (typeof listener !== 'function') { throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); } } Object.defineProperty(EventEmitter, 'defaultMaxListeners', { enumerable: true, get: function() { return defaultMaxListeners; }, set: function(arg) { if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); } defaultMaxListeners = arg; } }); EventEmitter.init = function() { if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) { this._events = Object.create(null); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); } this._maxListeners = n; return this; }; function _getMaxListeners(that) { if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners; return that._maxListeners; } EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; EventEmitter.prototype.emit = function emit(type) { var args = []; for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); var doError = (type === 'error'); var events = this._events; if (events !== undefined) doError = (doError && events.error === undefined); else if (!doError) return false; // If there is no 'error' event listener then throw. if (doError) { var er; if (args.length > 0) er = args[0]; if (er instanceof Error) { // Note: The comments on the `throw` lines are intentional, they show // up in Node's output if this results in an unhandled exception. throw er; // Unhandled 'error' event } // At least give some kind of context to the user var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); err.context = er; throw err; // Unhandled 'error' event } var handler = events[type]; if (handler === undefined) return false; if (typeof handler === 'function') { ReflectApply(handler, this, args); } else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args); } return true; }; function _addListener(target, type, listener, prepend) { var m; var events; var existing; checkListener(listener); events = target._events; if (events === undefined) { events = target._events = Object.create(null); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener !== undefined) { target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; } if (existing === undefined) { // Optimize the case of one listener. Don't need the extra array object. existing = events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; // If we've already got an array, just append. } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); } // Check for listener leak m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + String(type) + ' listeners ' + 'added. Use emitter.setMaxListeners() to ' + 'increase limit'); w.name = 'MaxListenersExceededWarning'; w.emitter = target; w.type = type; w.count = existing.length; ProcessEmitWarning(w); } } return target; } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) return this.listener.call(this.target); return this.listener.apply(this.target, arguments); } } function _onceWrap(target, type, listener) { var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; var wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped; } EventEmitter.prototype.once = function once(type, listener) { checkListener(listener); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { checkListener(listener); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; // Emits a 'removeListener' event if and only if the listener was removed. EventEmitter.prototype.removeListener = function removeListener(type, listener) { var list, events, position, i, originalListener; checkListener(listener); events = this._events; if (events === undefined) return this; list = events[type]; if (list === undefined) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = Object.create(null); else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { position = -1; for (i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (position === 0) list.shift(); else { spliceOne(list, position); } if (list.length === 1) events[type] = list[0]; if (events.removeListener !== undefined) this.emit('removeListener', type, originalListener || listener); } return this; }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events, i; events = this._events; if (events === undefined) return this; // not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { this._events = Object.create(null); this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) this._events = Object.create(null); else delete events[type]; } return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); var key; for (i = 0; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = Object.create(null); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners !== undefined) { // LIFO order for (i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } } return this; }; function _listeners(target, type, unwrap) { var events = target._events; if (events === undefined) return []; var evlistener = events[type]; if (evlistener === undefined) return []; if (typeof evlistener === 'function') return unwrap ? [evlistener.listener || evlistener] : [evlistener]; return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); } EventEmitter.prototype.listeners = function listeners(type) { return _listeners(this, type, true); }; EventEmitter.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false); }; EventEmitter.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }; EventEmitter.prototype.listenerCount = listenerCount; function listenerCount(type) { var events = this._events; if (events !== undefined) { var evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener !== undefined) { return evlistener.length; } } return 0; } EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; }; function arrayClone(arr, n) { var copy = new Array(n); for (var i = 0; i < n; ++i) copy[i] = arr[i]; return copy; } function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } /** */ /** * Transport defines the generic interface to share between node/u2f impl * A **Descriptor** is a parametric type that is up to be determined for the implementation. * it can be for instance an ID, an file path, a URL,... */ class Transport { constructor() { this.exchangeTimeout = 30000; this._events = new events(); this.send = async (cla, ins, p1, p2, data = Buffer.alloc(0), statusList = [StatusCodes.OK]) => { if (data.length >= 256) { throw new TransportError("data.length exceed 256 bytes limit. Got: " + data.length, "DataLengthTooBig"); } const response = await this.exchange(Buffer.concat([Buffer.from([cla, ins, p1, p2]), Buffer.from([data.length]), data])); const sw = response.readUInt16BE(response.length - 2); if (!statusList.some(s => s === sw)) { throw new TransportStatusError(sw); } return response; }; this.exchangeBusyPromise = void 0; this.exchangeAtomicImpl = async f => { if (this.exchangeBusyPromise) { throw new TransportError("Transport race condition", "RaceCondition"); } let resolveBusy; const busyPromise = new Promise(r => { resolveBusy = r; }); this.exchangeBusyPromise = busyPromise; try { const res = await f(); return res; } finally { if (resolveBusy) resolveBusy(); this.exchangeBusyPromise = null; } }; this._appAPIlock = null; } /** * low level api to communicate with the device * This method is for implementations to implement but should not be directly called. * Instead, the recommanded way is to use send() method * @param apdu the data to send * @return a Promise of response data */ exchange(_apdu) { throw new Error("exchange not implemented"); } /** * set the "scramble key" for the next exchanges with the device. * Each App can have a different scramble key and they internally will set it at instanciation. * @param key the scramble key */ setScrambleKey(_key) {} /** * close the exchange with the device. * @return a Promise that ends when the transport is closed. */ close() { return Promise.resolve(); } /** * Listen to an event on an instance of transport. * Transport implementation can have specific events. Here is the common events: * * `"disconnect"` : triggered if Transport is disconnected */ on(eventName, cb) { this._events.on(eventName, cb); } /** * Stop listening to an event on an instance of transport. */ off(eventName, cb) { this._events.removeListener(eventName, cb); } emit(event, ...args) { this._events.emit(event, ...args); } /** * Enable or not logs of the binary exchange */ setDebugMode() { console.warn("setDebugMode is deprecated. use @ledgerhq/logs instead. No logs are emitted in this anymore."); } /** * Set a timeout (in milliseconds) for the exchange call. Only some transport might implement it. (e.g. U2F) */ setExchangeTimeout(exchangeTimeout) { this.exchangeTimeout = exchangeTimeout; } /** * wrapper on top of exchange to simplify work of the implementation. * @param cla * @param ins * @param p1 * @param p2 * @param data * @param statusList is a list of accepted status code (shorts). [0x9000] by default * @return a Promise of response buffer */ /** * create() allows to open the first descriptor available or * throw if there is none or if timeout is reached. * This is a light helper, alternative to using listen() and open() (that you may need for any more advanced usecase) * @example TransportFoo.create().then(transport => ...) */ static create(openTimeout = 3000, listenTimeout) { return new Promise((resolve, reject) => { let found = false; const sub = this.listen({ next: e => { found = true; if (sub) sub.unsubscribe(); if (listenTimeoutId) clearTimeout(listenTimeoutId); this.open(e.descriptor, openTimeout).then(resolve, reject); }, error: e => { if (listenTimeoutId) clearTimeout(listenTimeoutId); reject(e); }, complete: () => { if (listenTimeoutId) clearTimeout(listenTimeoutId); if (!found) { reject(new TransportError(this.ErrorMessage_NoDeviceFound, "NoDeviceFound")); } } }); const listenTimeoutId = listenTimeout ? setTimeout(() => { sub.unsubscribe(); reject(new TransportError(this.ErrorMessage_ListenTimeout, "ListenTimeout")); }, listenTimeout) : null; }); } decorateAppAPIMethods(self, methods, scrambleKey) { for (let methodName of methods) { self[methodName] = this.decorateAppAPIMethod(methodName, self[methodName], self, scrambleKey); } } decorateAppAPIMethod(methodName, f, ctx, scrambleKey) { return async (...args) => { const { _appAPIlock } = this; if (_appAPIlock) { return Promise.reject(new TransportError("Ledger Device is busy (lock " + _appAPIlock + ")", "TransportLocked")); } try { this._appAPIlock = methodName; this.setScrambleKey(scrambleKey); return await f.apply(ctx, args); } finally { this._appAPIlock = null; } }; } } Transport.isSupported = void 0; Transport.list = void 0; Transport.listen = void 0; Transport.open = void 0; Transport.ErrorMessage_ListenTimeout = "No Ledger device found (timeout)"; Transport.ErrorMessage_NoDeviceFound = "No Ledger device found"; /** * A Log object */ let id = 0; const subscribers = []; /** * log something * @param type a namespaced identifier of the log (it is not a level like "debug", "error" but more like "apdu-in", "apdu-out", etc...) * @param message a clear message of the log associated to the type */ const log = (type, message, data) => { const obj = { type, id: String(++id), date: new Date() }; if (message) obj.message = message; if (data) obj.data = data; dispatch(obj); }; /** * listen to logs. * @param cb that is called for each future log() with the Log object * @return a function that can be called to unsubscribe the listener */ const listen = cb => { subscribers.push(cb); return () => { const i = subscribers.indexOf(cb); if (i !== -1) { // equivalent of subscribers.splice(i, 1) // https://twitter.com/Rich_Harris/status/1125850391155965952 subscribers[i] = subscribers[subscribers.length - 1]; subscribers.pop(); } }; }; function dispatch(log) { for (let i = 0; i < subscribers.length; i++) { try { subscribers[i](log); } catch (e) { console.error(e); } } } // for debug purpose if (typeof window !== "undefined") { window.__ledgerLogsListen = listen; } function wrapU2FTransportError(originalError, message, id) { const err = new TransportError(message, id); // $FlowFixMe err.originalError = originalError; return err; } function wrapApdu(apdu, key) { const result = Buffer.alloc(apdu.length); for (let i = 0; i < apdu.length; i++) { result[i] = apdu[i] ^ key[i % key.length]; } return result; } // Convert from normal to web-safe, strip trailing "="s const webSafe64 = base64 => base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); // Convert from web-safe to normal, add trailing "="s const normal64 = base64 => base64.replace(/-/g, "+").replace(/_/g, "/") + "==".substring(0, 3 * base64.length % 4); function attemptExchange(apdu, timeoutMillis, scrambleKey, unwrap) { const keyHandle = wrapApdu(apdu, scrambleKey); const challenge = Buffer.from("0000000000000000000000000000000000000000000000000000000000000000", "hex"); const signRequest = { version: "U2F_V2", keyHandle: webSafe64(keyHandle.toString("base64")), challenge: webSafe64(challenge.toString("base64")), appId: location.origin }; log("apdu", "=> " + apdu.toString("hex")); return u2fApi_2(signRequest, timeoutMillis / 1000).then(response => { const { signatureData } = response; if (typeof signatureData === "string") { const data = Buffer.from(normal64(signatureData), "base64"); let result; if (!unwrap) { result = data; } else { result = data.slice(5); } log("apdu", "<= " + result.toString("hex")); return result; } else { throw response; } }); } let transportInstances = []; function emitDisconnect() { transportInstances.forEach(t => t.emit("disconnect")); transportInstances = []; } function isTimeoutU2FError(u2fError) { return u2fError.metaData.code === 5; } /** * U2F web Transport implementation * @example * import TransportU2F from "@ledgerhq/hw-transport-u2f"; * ... * TransportU2F.create().then(transport => ...) */ class TransportU2F extends Transport { /* */ /* */ /** * static function to create a new Transport from a connected Ledger device discoverable via U2F (browser support) */ static async open(_, _openTimeout = 5000) { return new TransportU2F(); } constructor() { super(); this.scrambleKey = void 0; this.unwrap = true; transportInstances.push(this); } /** * Exchange with the device using APDU protocol. * @param apdu * @returns a promise of apdu response */ async exchange(apdu) { try { return await attemptExchange(apdu, this.exchangeTimeout, this.scrambleKey, this.unwrap); } catch (e) { const isU2FError = typeof e.metaData === "object"; if (isU2FError) { if (isTimeoutU2FError(e)) { emitDisconnect(); } // the wrapping make error more usable and "printable" to the end user. throw wrapU2FTransportError(e, "Failed to sign with Ledger device: U2F " + e.metaData.type, "U2F_" + e.metaData.code); } else { throw e; } } } /** */ setScrambleKey(scrambleKey) { this.scrambleKey = Buffer.from(scrambleKey, "ascii"); } /** */ setUnwrap(unwrap) { this.unwrap = unwrap; } close() { // u2f have no way to clean things up return Promise.resolve(); } } TransportU2F.isSupported = u2fApi_1; TransportU2F.list = () => // this transport is not discoverable but we are going to guess if it is here with isSupported() u2fApi_1().then(supported => supported ? [null] : []); TransportU2F.listen = observer => { let unsubscribed = false; u2fApi_1().then(supported => { if (unsubscribed) return; if (supported) { observer.next({ type: "add", descriptor: null }); observer.complete(); } else { observer.error(new TransportError("U2F browser support is needed for Ledger. " + "Please use Chrome, Opera or Firefox with a U2F extension. " + "Also make sure you're on an HTTPS connection", "U2FNotSupported")); } }); return { unsubscribe: () => { unsubscribed = true; } }; }; "use strict"; const transports = { "u2f": TransportU2F, "default": TransportU2F }; "use strict"; var __awaiter = (window && window.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; const logger = new ethers.utils.Logger(version); const defaultPath = "m/44'/60'/0'/0/0"; function waiter(duration) { return new Promise((resolve) => { setTimeout(resolve, duration); }); } class LedgerSigner extends ethers.Signer { constructor(provider, type, path) { super(); if (path == null) { path = defaultPath; } if (type == null) { type = "default"; } ethers.utils.defineReadOnly(this, "path", path); ethers.utils.defineReadOnly(this, "type", type); ethers.utils.defineReadOnly(this, "provider", provider || null); const transport = transports[type]; if (!transport) { logger.throwArgumentError("unknown or unsupported type", "type", type); } ethers.utils.defineReadOnly(this, "_eth", transport.create().then((transport) => { const eth = new Eth(transport); return eth.getAppConfiguration().then((config) => { return eth; }, (error) => { return Promise.reject(error); }); }, (error) => { return Promise.reject(error); })); } _retry(callback, timeout) { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { if (timeout && timeout > 0) { setTimeout(() => { reject(new Error("timeout")); }, timeout); } const eth = yield this._eth; // Wait up to 5 seconds for (let i = 0; i < 50; i++) { try { const result = yield callback(eth); return resolve(result); } catch (error) { if (error.id !== "TransportLocked") { return reject(error); } } yield waiter(100); } return reject(new Error("timeout")); })); } getAddress() { return __awaiter(this, void 0, void 0, function* () { const account = yield this._retry((eth) => eth.getAddress(this.path)); return ethers.utils.getAddress(account.address); }); } signMessage(message) { return __awaiter(this, void 0, void 0, function* () { if (typeof (message) === 'string') { message = ethers.utils.toUtf8Bytes(message); } const messageHex = ethers.utils.hexlify(message).substring(2); const sig = yield this._retry((eth) => eth.signPersonalMessage(this.path, messageHex)); sig.r = '0x' + sig.r; sig.s = '0x' + sig.s; return ethers.utils.joinSignature(sig); }); } signTransaction(transaction) { return __awaiter(this, void 0, void 0, function* () { const tx = transaction = yield ethers.utils.resolveProperties(transaction); const unsignedTx = ethers.utils.serializeTransaction(tx).substring(2); const sig = yield this._retry((eth) => eth.signTransaction(this.path, unsignedTx)); return ethers.utils.serializeTransaction(tx, { v: sig.v, r: ("0x" + sig.r), s: ("0x" + sig.s), }); }); } connect(provider) { return new LedgerSigner(provider, this.type, this.path); } } "use strict"; export { LedgerSigner };