@ledgerhq/hw-app-btc
Advanced tools
Comparing version 1.2.0-beta.10b44916 to 1.2.0-beta.5f7fbb68
121
lib/Btc.js
@@ -9,22 +9,9 @@ "use strict"; | ||
const MAX_SCRIPT_BLOCK = 50; /******************************************************************************** | ||
* 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. | ||
********************************************************************************/ | ||
const MAX_SCRIPT_BLOCK = 50; | ||
// TODO future refactoring | ||
// - drop utils.js & refactoring with async/await style | ||
// - try to avoid every place we do hex<>Buffer conversion. also accept Buffer as func parameters (could accept both a string or a Buffer in the API) | ||
// - there are redundant code across apps (see Eth vs Btc). we might want to factorize it somewhere. also each app apdu call should be abstracted it out as an api | ||
// FIXME drop: | ||
const DEFAULT_LOCKTIME = 0; | ||
@@ -55,14 +42,8 @@ const DEFAULT_SEQUENCE = 0xffffffff; | ||
const paths = (0, _utils.splitPath)(path); | ||
const buffer = Buffer.alloc(5 + 1 + paths.length * 4); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x40; | ||
buffer[2] = 0x00; | ||
buffer[3] = 0x00; | ||
buffer[4] = 1 + paths.length * 4; | ||
buffer[5] = paths.length; | ||
const buffer = Buffer.alloc(1 + paths.length * 4); | ||
buffer[0] = paths.length; | ||
paths.forEach((element, index) => { | ||
buffer.writeUInt32BE(element, 6 + 4 * index); | ||
buffer.writeUInt32BE(element, 1 + 4 * index); | ||
}); | ||
return this.transport.exchange(buffer.toString("hex"), [0x9000]).then(responseHex => { | ||
const response = Buffer.from(responseHex, "hex"); | ||
return this.transport.send(0xe0, 0x40, 0x00, 0x00, buffer).then(response => { | ||
const publicKeyLength = response[0]; | ||
@@ -88,10 +69,3 @@ const addressLength = response[1 + publicKeyLength]; | ||
} | ||
let buffer = Buffer.alloc(5); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x42; | ||
buffer[2] = firstRound ? 0x00 : 0x80; | ||
buffer[3] = 0x00; | ||
buffer[4] = data.length; | ||
buffer = Buffer.concat([buffer, data], 5 + data.length); | ||
return this.transport.exchange(buffer.toString("hex"), [0x9000]).then(trustedInput => trustedInput.substring(0, trustedInput.length - 4)); | ||
return this.transport.send(0xe0, 0x42, firstRound ? 0x00 : 0x80, 0x00, data).then(trustedInput => trustedInput.slice(0, trustedInput.length - 2).toString("hex")); | ||
} | ||
@@ -163,10 +137,3 @@ | ||
startUntrustedHashTransactionInputRaw(newTransaction, firstRound, transactionData) { | ||
let buffer = Buffer.alloc(5); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x44; | ||
buffer[2] = firstRound ? 0x00 : 0x80; | ||
buffer[3] = newTransaction ? 0x00 : 0x80; | ||
buffer[4] = transactionData.length; | ||
buffer = Buffer.concat([buffer, transactionData], 5 + transactionData.length); | ||
return this.transport.exchange(buffer.toString("hex"), [0x9000]); | ||
return this.transport.send(0xe0, 0x44, firstRound ? 0x00 : 0x80, newTransaction ? 0x00 : 0x80, transactionData); | ||
} | ||
@@ -218,13 +185,8 @@ | ||
let paths = (0, _utils.splitPath)(path); | ||
let buffer = Buffer.alloc(5 + 1 + paths.length * 4); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x4a; | ||
buffer[2] = 0xff; | ||
buffer[3] = 0x00; | ||
buffer[4] = 1 + paths.length * 4; | ||
buffer[5] = paths.length; | ||
let buffer = Buffer.alloc(1 + paths.length * 4); | ||
buffer[0] = paths.length; | ||
paths.forEach((element, index) => { | ||
buffer.writeUInt32BE(element, 6 + 4 * index); | ||
buffer.writeUInt32BE(element, 1 + 4 * index); | ||
}); | ||
return this.transport.exchange(buffer.toString("hex"), [0x9000]); | ||
return this.transport.send(0xe0, 0x4a, 0xff, 0x00, buffer); | ||
} | ||
@@ -237,10 +199,4 @@ | ||
let p1 = offset + blockSize === outputScript.length ? 0x80 : 0x00; | ||
let prefix = Buffer.alloc(5); | ||
prefix[0] = 0xe0; | ||
prefix[1] = 0x4a; | ||
prefix[2] = p1; | ||
prefix[3] = 0x00; | ||
prefix[4] = blockSize; | ||
let data = Buffer.concat([prefix, outputScript.slice(offset, offset + blockSize)]); | ||
return this.transport.exchange(data.toString("hex"), [0x9000]).then(() => { | ||
let data = outputScript.slice(offset, offset + blockSize); | ||
return this.transport.send(0xe0, 0x4a, p1, 0x00, data).then(() => { | ||
offset += blockSize; | ||
@@ -255,9 +211,4 @@ }); | ||
const paths = (0, _utils.splitPath)(path); | ||
const buffer = Buffer.alloc(5 + 1 + paths.length * 4 + 1 + 4 + 1); | ||
const buffer = Buffer.alloc(1 + paths.length * 4 + 1 + 4 + 1); // TODO shouldn't have to calc that, just use buffer concat all the way down | ||
let offset = 0; | ||
buffer[offset++] = 0xe0; | ||
buffer[offset++] = 0x48; | ||
buffer[offset++] = 0x00; | ||
buffer[offset++] = 0x00; | ||
buffer[offset++] = 1 + paths.length * 4 + 1 + 4 + 1; | ||
buffer[offset++] = paths.length; | ||
@@ -272,4 +223,3 @@ paths.forEach(element => { | ||
buffer[offset++] = sigHashType; | ||
return this.transport.exchange(buffer.toString("hex"), [0x9000]).then(signature => { | ||
const result = Buffer.from(signature, "hex"); | ||
return this.transport.send(0xe0, 0x48, 0x00, 0x00, buffer).then(result => { | ||
result[0] = 0x30; | ||
@@ -293,35 +243,22 @@ return result.slice(0, result.length - 2); | ||
let offset = 0; | ||
const apdus = []; | ||
const toSend = []; | ||
while (offset !== message.length) { | ||
let maxChunkSize = offset === 0 ? MAX_SCRIPT_BLOCK - 1 - paths.length * 4 - 4 : MAX_SCRIPT_BLOCK; | ||
let chunkSize = offset + maxChunkSize > message.length ? message.length - offset : maxChunkSize; | ||
const buffer = new Buffer(offset === 0 ? 5 + 1 + paths.length * 4 + 2 + chunkSize : 5 + chunkSize); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x4e; | ||
buffer[2] = 0x00; | ||
buffer[3] = offset === 0 ? 0x01 : 0x80; | ||
buffer[4] = offset === 0 ? 1 + paths.length * 4 + 2 + chunkSize : chunkSize; | ||
const buffer = new Buffer(offset === 0 ? 1 + paths.length * 4 + 2 + chunkSize : chunkSize); | ||
if (offset === 0) { | ||
buffer[5] = paths.length; | ||
buffer[0] = paths.length; | ||
paths.forEach((element, index) => { | ||
buffer.writeUInt32BE(element, 6 + 4 * index); | ||
buffer.writeUInt32BE(element, 1 + 4 * index); | ||
}); | ||
buffer.writeUInt16BE(message.length, 6 + 4 * paths.length); | ||
message.copy(buffer, 6 + 4 * paths.length + 2, offset, offset + chunkSize); | ||
buffer.writeUInt16BE(message.length, 1 + 4 * paths.length); | ||
message.copy(buffer, 1 + 4 * paths.length + 2, offset, offset + chunkSize); | ||
} else { | ||
message.copy(buffer, 5, offset, offset + chunkSize); | ||
message.copy(buffer, 0, offset, offset + chunkSize); | ||
} | ||
apdus.push(buffer.toString("hex")); | ||
toSend.push(buffer); | ||
offset += chunkSize; | ||
} | ||
return (0, _utils.foreach)(apdus, apdu => this.transport.exchange(apdu, [0x9000])).then(() => { | ||
const buffer = Buffer.alloc(6); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x4e; | ||
buffer[2] = 0x80; | ||
buffer[3] = 0x00; | ||
buffer[4] = 0x01; | ||
buffer[5] = 0x00; | ||
return this.transport.exchange(buffer.toString("hex"), [0x9000]).then(apduResponse => { | ||
const response = Buffer.from(apduResponse, "hex"); | ||
return (0, _utils.foreach)(toSend, (data, i) => this.transport.send(0xe0, 0x4e, 0x00, i === 0 ? 0x01 : 0x80, data)).then(() => { | ||
return this.transport.send(0xe0, 0x4e, 0x80, 0x00, Buffer.from([0x00])).then(response => { | ||
const v = response[0] - 0x30; | ||
@@ -328,0 +265,0 @@ let r = response.slice(4, 4 + response[3]); |
{ | ||
"name": "@ledgerhq/hw-app-btc", | ||
"version": "1.2.0-beta.10b44916", | ||
"version": "1.2.0-beta.5f7fbb68", | ||
"description": "Ledger Hardware Wallet Bitcoin Application API", | ||
@@ -28,3 +28,3 @@ "keywords": [ | ||
"dependencies": { | ||
"@ledgerhq/hw-transport": "^1.2.0-beta.10b44916" | ||
"@ledgerhq/hw-transport": "^1.2.0-beta.5f7fbb68" | ||
}, | ||
@@ -31,0 +31,0 @@ "devDependencies": { |
188
src/Btc.js
@@ -1,20 +0,7 @@ | ||
/******************************************************************************** | ||
* 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. | ||
********************************************************************************/ | ||
//@flow | ||
// FIXME drop: | ||
// TODO future refactoring | ||
// - drop utils.js & refactoring with async/await style | ||
// - try to avoid every place we do hex<>Buffer conversion. also accept Buffer as func parameters (could accept both a string or a Buffer in the API) | ||
// - there are redundant code across apps (see Eth vs Btc). we might want to factorize it somewhere. also each app apdu call should be abstracted it out as an api | ||
import { foreach, doIf, asyncWhile, splitPath, eachSeries } from "./utils"; | ||
@@ -73,16 +60,10 @@ import type Transport from "@ledgerhq/hw-transport"; | ||
const paths = splitPath(path); | ||
const buffer = Buffer.alloc(5 + 1 + paths.length * 4); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x40; | ||
buffer[2] = 0x00; | ||
buffer[3] = 0x00; | ||
buffer[4] = 1 + paths.length * 4; | ||
buffer[5] = paths.length; | ||
const buffer = Buffer.alloc(1 + paths.length * 4); | ||
buffer[0] = paths.length; | ||
paths.forEach((element, index) => { | ||
buffer.writeUInt32BE(element, 6 + 4 * index); | ||
buffer.writeUInt32BE(element, 1 + 4 * index); | ||
}); | ||
return this.transport | ||
.exchange(buffer.toString("hex"), [0x9000]) | ||
.then(responseHex => { | ||
const response = Buffer.from(responseHex, "hex"); | ||
.send(0xe0, 0x40, 0x00, 0x00, buffer) | ||
.then(response => { | ||
const publicKeyLength = response[0]; | ||
@@ -126,12 +107,7 @@ const addressLength = response[1 + publicKeyLength]; | ||
} | ||
let buffer = Buffer.alloc(5); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x42; | ||
buffer[2] = firstRound ? 0x00 : 0x80; | ||
buffer[3] = 0x00; | ||
buffer[4] = data.length; | ||
buffer = Buffer.concat([buffer, data], 5 + data.length); | ||
return this.transport | ||
.exchange(buffer.toString("hex"), [0x9000]) | ||
.then(trustedInput => trustedInput.substring(0, trustedInput.length - 4)); | ||
.send(0xe0, 0x42, firstRound ? 0x00 : 0x80, 0x00, data) | ||
.then(trustedInput => | ||
trustedInput.slice(0, trustedInput.length - 2).toString("hex") | ||
); | ||
} | ||
@@ -237,13 +213,9 @@ | ||
) { | ||
let buffer = Buffer.alloc(5); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x44; | ||
buffer[2] = firstRound ? 0x00 : 0x80; | ||
buffer[3] = newTransaction ? 0x00 : 0x80; | ||
buffer[4] = transactionData.length; | ||
buffer = Buffer.concat( | ||
[buffer, transactionData], | ||
5 + transactionData.length | ||
return this.transport.send( | ||
0xe0, | ||
0x44, | ||
firstRound ? 0x00 : 0x80, | ||
newTransaction ? 0x00 : 0x80, | ||
transactionData | ||
); | ||
return this.transport.exchange(buffer.toString("hex"), [0x9000]); | ||
} | ||
@@ -328,13 +300,8 @@ | ||
let paths = splitPath(path); | ||
let buffer = Buffer.alloc(5 + 1 + paths.length * 4); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x4a; | ||
buffer[2] = 0xff; | ||
buffer[3] = 0x00; | ||
buffer[4] = 1 + paths.length * 4; | ||
buffer[5] = paths.length; | ||
let buffer = Buffer.alloc(1 + paths.length * 4); | ||
buffer[0] = paths.length; | ||
paths.forEach((element, index) => { | ||
buffer.writeUInt32BE(element, 6 + 4 * index); | ||
buffer.writeUInt32BE(element, 1 + 4 * index); | ||
}); | ||
return this.transport.exchange(buffer.toString("hex"), [0x9000]); | ||
return this.transport.send(0xe0, 0x4a, 0xff, 0x00, buffer); | ||
} | ||
@@ -352,17 +319,6 @@ | ||
let p1 = offset + blockSize === outputScript.length ? 0x80 : 0x00; | ||
let prefix = Buffer.alloc(5); | ||
prefix[0] = 0xe0; | ||
prefix[1] = 0x4a; | ||
prefix[2] = p1; | ||
prefix[3] = 0x00; | ||
prefix[4] = blockSize; | ||
let data = Buffer.concat([ | ||
prefix, | ||
outputScript.slice(offset, offset + blockSize) | ||
]); | ||
return this.transport | ||
.exchange(data.toString("hex"), [0x9000]) | ||
.then(() => { | ||
offset += blockSize; | ||
}); | ||
let data = outputScript.slice(offset, offset + blockSize); | ||
return this.transport.send(0xe0, 0x4a, p1, 0x00, data).then(() => { | ||
offset += blockSize; | ||
}); | ||
} | ||
@@ -380,9 +336,4 @@ ); | ||
const paths = splitPath(path); | ||
const buffer = Buffer.alloc(5 + 1 + paths.length * 4 + 1 + 4 + 1); | ||
const buffer = Buffer.alloc(1 + paths.length * 4 + 1 + 4 + 1); // TODO shouldn't have to calc that, just use buffer concat all the way down | ||
let offset = 0; | ||
buffer[offset++] = 0xe0; | ||
buffer[offset++] = 0x48; | ||
buffer[offset++] = 0x00; | ||
buffer[offset++] = 0x00; | ||
buffer[offset++] = 1 + paths.length * 4 + 1 + 4 + 1; | ||
buffer[offset++] = paths.length; | ||
@@ -397,9 +348,6 @@ paths.forEach(element => { | ||
buffer[offset++] = sigHashType; | ||
return this.transport | ||
.exchange(buffer.toString("hex"), [0x9000]) | ||
.then(signature => { | ||
const result = Buffer.from(signature, "hex"); | ||
result[0] = 0x30; | ||
return result.slice(0, result.length - 2); | ||
}); | ||
return this.transport.send(0xe0, 0x48, 0x00, 0x00, buffer).then(result => { | ||
result[0] = 0x30; | ||
return result.slice(0, result.length - 2); | ||
}); | ||
} | ||
@@ -423,3 +371,3 @@ | ||
let offset = 0; | ||
const apdus = []; | ||
const toSend = []; | ||
while (offset !== message.length) { | ||
@@ -435,19 +383,13 @@ let maxChunkSize = | ||
const buffer = new Buffer( | ||
offset === 0 ? 5 + 1 + paths.length * 4 + 2 + chunkSize : 5 + chunkSize | ||
offset === 0 ? 1 + paths.length * 4 + 2 + chunkSize : chunkSize | ||
); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x4e; | ||
buffer[2] = 0x00; | ||
buffer[3] = offset === 0 ? 0x01 : 0x80; | ||
buffer[4] = | ||
offset === 0 ? 1 + paths.length * 4 + 2 + chunkSize : chunkSize; | ||
if (offset === 0) { | ||
buffer[5] = paths.length; | ||
buffer[0] = paths.length; | ||
paths.forEach((element, index) => { | ||
buffer.writeUInt32BE(element, 6 + 4 * index); | ||
buffer.writeUInt32BE(element, 1 + 4 * index); | ||
}); | ||
buffer.writeUInt16BE(message.length, 6 + 4 * paths.length); | ||
buffer.writeUInt16BE(message.length, 1 + 4 * paths.length); | ||
message.copy( | ||
buffer, | ||
6 + 4 * paths.length + 2, | ||
1 + 4 * paths.length + 2, | ||
offset, | ||
@@ -457,36 +399,28 @@ offset + chunkSize | ||
} else { | ||
message.copy(buffer, 5, offset, offset + chunkSize); | ||
message.copy(buffer, 0, offset, offset + chunkSize); | ||
} | ||
apdus.push(buffer.toString("hex")); | ||
toSend.push(buffer); | ||
offset += chunkSize; | ||
} | ||
return foreach(apdus, apdu => this.transport.exchange(apdu, [0x9000])).then( | ||
() => { | ||
const buffer = Buffer.alloc(6); | ||
buffer[0] = 0xe0; | ||
buffer[1] = 0x4e; | ||
buffer[2] = 0x80; | ||
buffer[3] = 0x00; | ||
buffer[4] = 0x01; | ||
buffer[5] = 0x00; | ||
return this.transport | ||
.exchange(buffer.toString("hex"), [0x9000]) | ||
.then(apduResponse => { | ||
const response = Buffer.from(apduResponse, "hex"); | ||
const v = response[0] - 0x30; | ||
let r = response.slice(4, 4 + response[3]); | ||
if (r[0] === 0) { | ||
r = r.slice(1); | ||
} | ||
r = r.toString("hex"); | ||
let offset = 4 + response[3] + 2; | ||
let s = response.slice(offset, offset + response[offset - 1]); | ||
if (s[0] === 0) { | ||
s = s.slice(1); | ||
} | ||
s = s.toString("hex"); | ||
return { v, r, s }; | ||
}); | ||
} | ||
); | ||
return foreach(toSend, (data, i) => | ||
this.transport.send(0xe0, 0x4e, 0x00, i === 0 ? 0x01 : 0x80, data) | ||
).then(() => { | ||
return this.transport | ||
.send(0xe0, 0x4e, 0x80, 0x00, Buffer.from([0x00])) | ||
.then(response => { | ||
const v = response[0] - 0x30; | ||
let r = response.slice(4, 4 + response[3]); | ||
if (r[0] === 0) { | ||
r = r.slice(1); | ||
} | ||
r = r.toString("hex"); | ||
let offset = 4 + response[3] + 2; | ||
let s = response.slice(offset, offset + response[offset - 1]); | ||
if (s[0] === 0) { | ||
s = s.slice(1); | ||
} | ||
s = s.toString("hex"); | ||
return { v, r, s }; | ||
}); | ||
}); | ||
} | ||
@@ -493,0 +427,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
14710
47
155751
1712