updates ledger integration
This commit is contained in:
parent
ccbe715b2a
commit
fe7a628edd
9 changed files with 282 additions and 244 deletions
|
|
@ -117,7 +117,7 @@
|
||||||
<switch id="network-name" name="isTestnet" ng-model="isTestnet" class="green right m5t m10b"></switch>
|
<switch id="network-name" name="isTestnet" ng-model="isTestnet" class="green right m5t m10b"></switch>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="seed" class="oh">
|
<label ng-hide="hwLedger" for="seed" class="oh">
|
||||||
<span translate>Specify your wallet seed</span>
|
<span translate>Specify your wallet seed</span>
|
||||||
<switch id="seed" name="setSeed" ng-model="setSeed" class="green right m5t m10b"></switch>
|
<switch id="seed" name="setSeed" ng-model="setSeed" class="green right m5t m10b"></switch>
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -129,14 +129,14 @@
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="ext-master" class="m10t" ng-show="setSeed">
|
<label for="ext-master" class="m10t" ng-show="setSeed && !hwLedger">
|
||||||
<span translate>Wallet Seed</span>
|
<span translate>Wallet Seed</span>
|
||||||
<small translate>Enter the 12 words seed (BIP39)</small>
|
<small translate>Enter the 12 words seed (BIP39)</small>
|
||||||
<input id="ext-master"
|
<input id="ext-master"
|
||||||
type="text"
|
type="text"
|
||||||
name="privateKey" ng-model="privateKey">
|
name="privateKey" ng-model="privateKey">
|
||||||
</label>
|
</label>
|
||||||
<label for="passphrase" class="line-b oh" ng-show="setSeed"><span translate>Seed Passphrase</span> <small translate>The seed could require a passphrase to be imported</small>
|
<label for="passphrase" class="line-b oh" ng-show="setSeed && !hwLedger"><span translate>Seed Passphrase</span> <small translate>The seed could require a passphrase to be imported</small>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<input type="text" class="form-control" name="passphrase" ng-model="passphrase">
|
<input type="text" class="form-control" name="passphrase" ng-model="passphrase">
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -155,11 +155,11 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<button type="submit" class="button round black expand m0" ng-show="totalCopayers != 1" ng-disabled="setupForm.$invalid || create.loading">
|
<button type="submit" class="button round black expand m0" ng-show="totalCopayers != 1" ng-disabled="setupForm.$invalid || create.loading || create.ledger">
|
||||||
<span translate>Create {{requiredCopayers}}-of-{{totalCopayers}} wallet</span>
|
<span translate>Create {{requiredCopayers}}-of-{{totalCopayers}} wallet</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="submit" class="button round black expand m0" ng-show="totalCopayers == 1" ng-disabled="setupForm.$invalid || create.loading">
|
<button type="submit" class="button round black expand m0" ng-show="totalCopayers == 1" ng-disabled="setupForm.$invalid || create.loading || create.ledger">
|
||||||
<span translate>Create new wallet</span>
|
<span translate>Create new wallet</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -36,19 +36,18 @@
|
||||||
<span ng-style="{'color':index.backgroundColor}">█</span>
|
<span ng-style="{'color':index.backgroundColor}">█</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="line-b p20" ng-hide="index.isPrivKeyExternal">
|
||||||
<li class="line-b p20" ng-hide="preferences.externalIndex >= 0">
|
|
||||||
<span translate>Request Password for Spending Funds</span>
|
<span translate>Request Password for Spending Funds</span>
|
||||||
<switch id="network-name" name="encrypt" ng-model="encrypt" class="green right"></switch>
|
<switch id="network-name" name="encrypt" ng-model="encrypt" class="green right"></switch>
|
||||||
</li>
|
</li>
|
||||||
<li class="line-b p20" ng-show="preferences.externalIndex >= 0">
|
<li class="line-b p20" ng-show="index.isPrivKeyExternal">
|
||||||
<span translate>Hardware wallet</span>
|
<span translate>Hardware wallet</span>
|
||||||
<span class="right text-gray">
|
<span class="right text-gray">
|
||||||
{{preferences.externalSource}}
|
{{preferences.externalSource}}
|
||||||
(index {{preferences.externalIndex}})
|
(index {{preferences.externalIndex}})
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="line-b p20" ng-click="$root.go('backup')" ng-show="preferences.externalIndex >= 0">
|
<li class="line-b p20" ng-click="$root.go('backup')" ng-hide="index.isPrivKeyExternal">
|
||||||
<i class="icon-arrow-right3 size-24 right text-gray"></i>
|
<i class="icon-arrow-right3 size-24 right text-gray"></i>
|
||||||
<span class="text-warning right" ng-show="index.needsBackup">
|
<span class="text-warning right" ng-show="index.needsBackup">
|
||||||
<i class="fi-alert"></i> <span translate> Still not done</span>
|
<i class="fi-alert"></i> <span translate> Still not done</span>
|
||||||
|
|
|
||||||
|
|
@ -125,8 +125,7 @@
|
||||||
<div class="size-12 text-gray">
|
<div class="size-12 text-gray">
|
||||||
<span translate>Multisignature wallet</span>
|
<span translate>Multisignature wallet</span>
|
||||||
(<span translate>{{index.m}}-of-{{index.n}}</span>)
|
(<span translate>{{index.m}}-of-{{index.n}}</span>)
|
||||||
<span ng-if="index.network != 'livenet'">- Testnet</span>
|
<span ng-include="'views/includes/walletInfo.html'"></span>
|
||||||
<span ng-if="!index.canSign"> - <span translate>No Private key</span></span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ng-show="!index.isShared">
|
<div ng-show="!index.isShared">
|
||||||
|
|
@ -134,8 +133,7 @@
|
||||||
{{(index.alias || index.walletName)}}
|
{{(index.alias || index.walletName)}}
|
||||||
</p>
|
</p>
|
||||||
<div class="size-12 text-gray">
|
<div class="size-12 text-gray">
|
||||||
<span ng-if="index.network != 'livenet'"> Testnet </span>
|
<span ng-include="'views/includes/walletInfo.html'"></span>
|
||||||
<span ng-if="!index.canSign" translate>No Private key</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ angular.module('copayApp.controllers').controller('createController',
|
||||||
$scope.requiredCopayers = Math.min(parseInt(n / 2 + 1), maxReq);
|
$scope.requiredCopayers = Math.min(parseInt(n / 2 + 1), maxReq);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.externalIndexValues = lodash.range(0,20);
|
this.externalIndexValues = lodash.range(0,ledger.MAX_SLOT);
|
||||||
$scope.externalIndex = 0;
|
$scope.externalIndex = 0;
|
||||||
this.TCValues = lodash.range(2, defaults.limits.totalCopayers + 1);
|
this.TCValues = lodash.range(2, defaults.limits.totalCopayers + 1);
|
||||||
$scope.totalCopayers = defaults.wallet.totalCopayers;
|
$scope.totalCopayers = defaults.wallet.totalCopayers;
|
||||||
|
|
@ -73,24 +73,17 @@ angular.module('copayApp.controllers').controller('createController',
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.loading = true;
|
|
||||||
|
|
||||||
if (form.hwLedger.$modelValue) {
|
if (form.hwLedger.$modelValue) {
|
||||||
self.ledger = true;
|
self.ledger = true;
|
||||||
ledger.getXPubKey($scope.externalIndex, function(data) {
|
ledger.getInfoForNewWallet($scope.externalIndex, function(err, lopts) {
|
||||||
self.ledger = false;
|
self.ledger = false;
|
||||||
if (data.success) {
|
if (err) {
|
||||||
|
self.error = err;
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
opts.extendedPublicKey = data.xpubkey;
|
return;
|
||||||
opts.externalSource = 'ledger';
|
|
||||||
opts.externalIndex = $scope.externalIndex;
|
|
||||||
self._create(opts);
|
|
||||||
} else {
|
|
||||||
self.loading = false;
|
|
||||||
self.error = data.message;
|
|
||||||
$scope.$apply();
|
|
||||||
$log.debug(data.message);
|
|
||||||
}
|
}
|
||||||
|
opts = lodash.assign(lopts, opts);
|
||||||
|
self._create(opts);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self._create(opts);
|
self._create(opts);
|
||||||
|
|
@ -98,6 +91,7 @@ angular.module('copayApp.controllers').controller('createController',
|
||||||
};
|
};
|
||||||
|
|
||||||
this._create = function (opts) {
|
this._create = function (opts) {
|
||||||
|
self.loading = true;
|
||||||
$timeout(function() {
|
$timeout(function() {
|
||||||
profileService.createWallet(opts, function(err, secret, walletId) {
|
profileService.createWallet(opts, function(err, secret, walletId) {
|
||||||
self.loading = false;
|
self.loading = false;
|
||||||
|
|
@ -105,14 +99,14 @@ angular.module('copayApp.controllers').controller('createController',
|
||||||
if (err == "Error creating wallet" && opts.extendedPublicKey) {
|
if (err == "Error creating wallet" && opts.extendedPublicKey) {
|
||||||
err = gettext("This xpub index is already used by another wallet. Please select another index.");
|
err = gettext("This xpub index is already used by another wallet. Please select another index.");
|
||||||
}
|
}
|
||||||
$log.debug(err);
|
$log.warn(err);
|
||||||
self.error = err;
|
self.error = err;
|
||||||
$timeout(function() {
|
$timeout(function() {
|
||||||
$rootScope.$apply();
|
$rootScope.$apply();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (opts.mnemonic && opts.n==1) {
|
if ( ( opts.mnemonic && opts.n==1) || otps.externalSource ) {
|
||||||
$rootScope.$emit('Local/WalletImported', walletId);
|
$rootScope.$emit('Local/WalletImported', walletId);
|
||||||
} else {
|
} else {
|
||||||
go.walletHome();
|
go.walletHome();
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,8 @@ angular.module('copayApp.controllers').controller('indexController', function($r
|
||||||
self.walletId = fc.credentials.walletId;
|
self.walletId = fc.credentials.walletId;
|
||||||
self.isComplete = fc.isComplete();
|
self.isComplete = fc.isComplete();
|
||||||
self.canSign = fc.canSign();
|
self.canSign = fc.canSign();
|
||||||
|
self.isPrivKeyExternal = fc.isPrivKeyExternal();
|
||||||
|
self.externalSource = fc.getPrivKeyExternalSourceName();
|
||||||
self.txps = [];
|
self.txps = [];
|
||||||
self.copayers = [];
|
self.copayers = [];
|
||||||
self.updateColor();
|
self.updateColor();
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,7 @@ angular.module('copayApp.controllers').controller('joinController',
|
||||||
}
|
}
|
||||||
$timeout(function() {
|
$timeout(function() {
|
||||||
var fc = profileService.focusedClient;
|
var fc = profileService.focusedClient;
|
||||||
if (opts.mnemonic && fc.isComplete()) {
|
if ( ( opts.mnemonic || opts.externalSource ) && fc.isComplete()) {
|
||||||
$rootScope.$emit('Local/WalletImported', fc.credentials.walletId);
|
$rootScope.$emit('Local/WalletImported', fc.credentials.walletId);
|
||||||
} else {
|
} else {
|
||||||
go.walletHome();
|
go.walletHome();
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
|
||||||
$scope.error = null;
|
$scope.error = null;
|
||||||
$scope.copayers = copayers
|
$scope.copayers = copayers
|
||||||
$scope.copayerId = fc.credentials.copayerId;
|
$scope.copayerId = fc.credentials.copayerId;
|
||||||
$scope.canSign = fc.canSign();
|
$scope.canSign = fc.canSign() || fc.isPrivKeyExternal();
|
||||||
$scope.loading = null;
|
$scope.loading = null;
|
||||||
$scope.color = fc.backgroundColor;
|
$scope.color = fc.backgroundColor;
|
||||||
|
|
||||||
|
|
@ -244,7 +244,7 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
|
||||||
$scope.sign = function(txp) {
|
$scope.sign = function(txp) {
|
||||||
var fc = profileService.focusedClient;
|
var fc = profileService.focusedClient;
|
||||||
|
|
||||||
if (!fc.canSign())
|
if (!fc.canSign() && !fc.isPrivKeyExternal())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fc.isPrivKeyEncrypted()) {
|
if (fc.isPrivKeyEncrypted()) {
|
||||||
|
|
@ -801,7 +801,7 @@ angular.module('copayApp.controllers').controller('walletHomeController', functi
|
||||||
return self.setSendError(err);
|
return self.setSendError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fc.canSign()) {
|
if (!fc.canSign() && !fc.isPrivKeyExternal()) {
|
||||||
$log.info('No signing proposal: No private key')
|
$log.info('No signing proposal: No private key')
|
||||||
self.setOngoingProcess();
|
self.setOngoingProcess();
|
||||||
self.resetForm();
|
self.resetForm();
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,82 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('copayApp.services')
|
angular.module('copayApp.services')
|
||||||
.factory('ledger', function(bwcService) {
|
.factory('ledger', function($log, bwcService, gettext) {
|
||||||
var root = {};
|
var root = {};
|
||||||
var LEDGER_CHROME_ID = "kkdpmhnladdopljabkgpacgpliggeeaf";
|
var LEDGER_CHROME_ID = "kkdpmhnladdopljabkgpacgpliggeeaf";
|
||||||
|
root.MAX_SLOT = 20;
|
||||||
|
root.ENTROPY_INDEX_START = 1000;
|
||||||
|
|
||||||
root.callbacks = {};
|
root.callbacks = {};
|
||||||
|
|
||||||
root.hasSession = function() {
|
root.hasSession = function() {
|
||||||
root._message({ command:"has_session" });
|
root._message({
|
||||||
|
command: "has_session"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
root.getXPubKey = function(index, callback) {
|
root.getEntropySource = function(index, callback) {
|
||||||
root.callbacks["get_xpubkey"] = callback;
|
index = index + root.ENTROPY_INDEX_START;
|
||||||
root._messageAfterSession({ command:"get_xpubkey", path:root._getPath(index) })
|
var xpub = root.getXPubKey("m/" + index + "'", function(data) {
|
||||||
|
if (!data.success) {
|
||||||
|
$log.warn(data.message);
|
||||||
|
return callback(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
var b = bwcService.getBitcore();
|
||||||
|
var x = b.HDPublicKey(data.xpubkey);
|
||||||
|
data.entropySource = x.publicKey.toString();
|
||||||
|
return callback(data);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
root.getXPubKeyForAddresses = function(index, callback) {
|
||||||
|
return root.getXPubKey(root._getPath(index), callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
root.getXPubKey = function(path, callback) {
|
||||||
|
root.callbacks["get_xpubkey"] = callback;
|
||||||
|
root._messageAfterSession({
|
||||||
|
command: "get_xpubkey",
|
||||||
|
path: path
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
root.getInfoForNewWallet = function(slot, callback) {
|
||||||
|
var opts = {};
|
||||||
|
root.getEntropySource(slot, function(data) {
|
||||||
|
if (!data.success) {
|
||||||
|
$log.warn(data.message);
|
||||||
|
return callback(data.message);
|
||||||
|
}
|
||||||
|
opts.entropySource = data.entropySource;
|
||||||
|
root.getXPubKeyForAddresses(slot, function(data) {
|
||||||
|
if (!data.success) {
|
||||||
|
$log.warn(data.message);
|
||||||
|
return callback(data);
|
||||||
|
}
|
||||||
|
opts.extendedPublicKey = data.xpubkey;
|
||||||
|
opts.externalSource = 'ledger';
|
||||||
|
opts.externalIndex = slot;
|
||||||
|
return callback(null, opts);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
root.signTx = function(txp, index, callback) {
|
root.signTx = function(txp, index, callback) {
|
||||||
root.callbacks["sign_p2sh"] = callback;
|
root.callbacks["sign_p2sh"] = callback;
|
||||||
var redeemScripts = [];
|
var redeemScripts = [];
|
||||||
var paths = [];
|
var paths = [];
|
||||||
var tx = bwcService.getUtils().buildTx(txp);
|
var tx = bwcService.getUtils().buildTx(txp);
|
||||||
for (var i=0; i<tx.inputs.length; i++) {
|
for (var i = 0; i < tx.inputs.length; i++) {
|
||||||
redeemScripts.push(new ByteString(tx.inputs[i].redeemScript.toBuffer().toString('hex'), GP.HEX).toString());
|
redeemScripts.push(new ByteString(tx.inputs[i].redeemScript.toBuffer().toString('hex'), GP.HEX).toString());
|
||||||
paths.push(root._getPath(index) + txp.inputs[i].path.substring(1));
|
paths.push(root._getPath(index) + txp.inputs[i].path.substring(1));
|
||||||
}
|
}
|
||||||
var splitTransaction = root._splitTransaction(new ByteString(tx.toString(), GP.HEX));
|
var splitTransaction = root._splitTransaction(new ByteString(tx.toString(), GP.HEX));
|
||||||
var inputs = [];
|
var inputs = [];
|
||||||
for (var i=0; i<splitTransaction.inputs.length; i++) {
|
for (var i = 0; i < splitTransaction.inputs.length; i++) {
|
||||||
var input = splitTransaction.inputs[i];
|
var input = splitTransaction.inputs[i];
|
||||||
inputs.push([
|
inputs.push([
|
||||||
root._reverseBytestring(input.prevout.bytes(0, 32)).toString(),
|
root._reverseBytestring(input.prevout.bytes(0, 32)).toString(),
|
||||||
|
|
@ -35,18 +84,20 @@ angular.module('copayApp.services')
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
root._messageAfterSession({
|
root._messageAfterSession({
|
||||||
command:"sign_p2sh",
|
command: "sign_p2sh",
|
||||||
inputs: inputs,
|
inputs: inputs,
|
||||||
scripts: redeemScripts,
|
scripts: redeemScripts,
|
||||||
outputs_number: splitTransaction.outputs.length,
|
outputs_number: splitTransaction.outputs.length,
|
||||||
outputs_script: splitTransaction.outputScript.toString(),
|
outputs_script: splitTransaction.outputScript.toString(),
|
||||||
paths: paths });
|
paths: paths
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
root._message = function(data) {
|
root._message = function(data) {
|
||||||
chrome.runtime.sendMessage(
|
chrome.runtime.sendMessage(
|
||||||
LEDGER_CHROME_ID,
|
LEDGER_CHROME_ID, {
|
||||||
{ request: data },
|
request: data
|
||||||
|
},
|
||||||
function(response) {
|
function(response) {
|
||||||
root._callback(response);
|
root._callback(response);
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +106,9 @@ angular.module('copayApp.services')
|
||||||
|
|
||||||
root._messageAfterSession = function(data) {
|
root._messageAfterSession = function(data) {
|
||||||
root._after_session = data;
|
root._after_session = data;
|
||||||
root._message({ command:"launch" });
|
root._message({
|
||||||
|
command: "launch"
|
||||||
|
});
|
||||||
root._should_poll_session = true;
|
root._should_poll_session = true;
|
||||||
root._do_poll_session();
|
root._do_poll_session();
|
||||||
}
|
}
|
||||||
|
|
@ -78,8 +131,11 @@ angular.module('copayApp.services')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
root._should_poll_session = false;
|
root._should_poll_session = false;
|
||||||
Object.keys(root.callbacks).forEach(function (key) {
|
Object.keys(root.callbacks).forEach(function(key) {
|
||||||
root.callbacks[key]({ success: false, message: "The Ledger Chrome application is not installed" });
|
root.callbacks[key]({
|
||||||
|
success: false,
|
||||||
|
message: gettext("The Ledger Chrome application is not installed"),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +154,7 @@ angular.module('copayApp.services')
|
||||||
var varint = root._getVarint(transaction, offset);
|
var varint = root._getVarint(transaction, offset);
|
||||||
var numberInputs = varint[0];
|
var numberInputs = varint[0];
|
||||||
offset += varint[1];
|
offset += varint[1];
|
||||||
for (var i=0; i<numberInputs; i++) {
|
for (var i = 0; i < numberInputs; i++) {
|
||||||
var input = {};
|
var input = {};
|
||||||
input['prevout'] = transaction.bytes(offset, 36);
|
input['prevout'] = transaction.bytes(offset, 36);
|
||||||
offset += 36;
|
offset += 36;
|
||||||
|
|
@ -114,7 +170,7 @@ angular.module('copayApp.services')
|
||||||
var numberOutputs = varint[0];
|
var numberOutputs = varint[0];
|
||||||
offset += varint[1];
|
offset += varint[1];
|
||||||
var outputStartOffset = offset;
|
var outputStartOffset = offset;
|
||||||
for (var i=0; i<numberOutputs; i++) {
|
for (var i = 0; i < numberOutputs; i++) {
|
||||||
var output = {};
|
var output = {};
|
||||||
output['amount'] = transaction.bytes(offset, 8);
|
output['amount'] = transaction.bytes(offset, 8);
|
||||||
offset += 8;
|
offset += 8;
|
||||||
|
|
@ -135,20 +191,20 @@ angular.module('copayApp.services')
|
||||||
|
|
||||||
root._getVarint = function(data, offset) {
|
root._getVarint = function(data, offset) {
|
||||||
if (data.byteAt(offset) < 0xfd) {
|
if (data.byteAt(offset) < 0xfd) {
|
||||||
return [ data.byteAt(offset), 1 ];
|
return [data.byteAt(offset), 1];
|
||||||
}
|
}
|
||||||
if (data.byteAt(offset) == 0xfd) {
|
if (data.byteAt(offset) == 0xfd) {
|
||||||
return [ ((data.byteAt(offset + 2) << 8) + data.byteAt(offset + 1)), 3 ];
|
return [((data.byteAt(offset + 2) << 8) + data.byteAt(offset + 1)), 3];
|
||||||
}
|
}
|
||||||
if (data.byteAt(offset) == 0xfe) {
|
if (data.byteAt(offset) == 0xfe) {
|
||||||
return [ ((data.byteAt(offset + 4) << 24) + (data.byteAt(offset + 3) << 16) +
|
return [((data.byteAt(offset + 4) << 24) + (data.byteAt(offset + 3) << 16) +
|
||||||
(data.byteAt(offset + 2) << 8) + data.byteAt(offset + 1)), 5 ];
|
(data.byteAt(offset + 2) << 8) + data.byteAt(offset + 1)), 5];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root._reverseBytestring = function(x) {
|
root._reverseBytestring = function(x) {
|
||||||
var res = "";
|
var res = "";
|
||||||
for (var i=x.length - 1; i>=0; i--) {
|
for (var i = x.length - 1; i >= 0; i--) {
|
||||||
res += Convert.toHexByte(x.byteAt(i));
|
res += Convert.toHexByte(x.byteAt(i));
|
||||||
}
|
}
|
||||||
return new ByteString(res, GP.HEX);
|
return new ByteString(res, GP.HEX);
|
||||||
|
|
@ -167,8 +223,10 @@ var Convert = {};
|
||||||
*/
|
*/
|
||||||
Convert.stringToHex = function(src) {
|
Convert.stringToHex = function(src) {
|
||||||
var r = "";
|
var r = "";
|
||||||
var hexes = new Array ("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");
|
var hexes = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f");
|
||||||
for (var i=0; i<src.length; i++) {r += hexes [src.charCodeAt(i) >> 4] + hexes [src.charCodeAt(i) & 0xf];}
|
for (var i = 0; i < src.length; i++) {
|
||||||
|
r += hexes[src.charCodeAt(i) >> 4] + hexes[src.charCodeAt(i) & 0xf];
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,24 +238,24 @@ Convert.stringToHex = function(src) {
|
||||||
* @throws {InvalidString} if the string isn't properly formatted
|
* @throws {InvalidString} if the string isn't properly formatted
|
||||||
*/
|
*/
|
||||||
Convert.hexToBin = function(src) {
|
Convert.hexToBin = function(src) {
|
||||||
var result = "";
|
var result = "";
|
||||||
var digits = "0123456789ABCDEF";
|
var digits = "0123456789ABCDEF";
|
||||||
if ((src.length % 2) != 0) {
|
if ((src.length % 2) != 0) {
|
||||||
throw "Invalid string";
|
throw "Invalid string";
|
||||||
}
|
|
||||||
src = src.toUpperCase();
|
|
||||||
for (var i=0; i<src.length; i+=2) {
|
|
||||||
var x1 = digits.indexOf(src.charAt(i));
|
|
||||||
if (x1 < 0) {
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
var x2 = digits.indexOf(src.charAt(i + 1));
|
src = src.toUpperCase();
|
||||||
if (x2 < 0) {
|
for (var i = 0; i < src.length; i += 2) {
|
||||||
return "";
|
var x1 = digits.indexOf(src.charAt(i));
|
||||||
|
if (x1 < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
var x2 = digits.indexOf(src.charAt(i + 1));
|
||||||
|
if (x2 < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
result += String.fromCharCode((x1 << 4) + x2);
|
||||||
}
|
}
|
||||||
result += String.fromCharCode((x1 << 4) + x2);
|
return result;
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -266,7 +324,7 @@ Convert.toHexShort = function(number) {
|
||||||
*/
|
*/
|
||||||
Convert.toHexInt = function(number) {
|
Convert.toHexInt = function(number) {
|
||||||
return Convert.toHexDigit((number >> 24) & 0xff) + Convert.toHexDigit((number >> 16) & 0xff) +
|
return Convert.toHexDigit((number >> 24) & 0xff) + Convert.toHexDigit((number >> 16) & 0xff) +
|
||||||
Convert.toHexDigit((number >> 8) & 0xff) + Convert.toHexDigit(number & 0xff);
|
Convert.toHexDigit((number >> 8) & 0xff) + Convert.toHexDigit(number & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -275,67 +333,63 @@ GP.ASCII = 1;
|
||||||
GP.HEX = 5;
|
GP.HEX = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class GPScript ByteString implementation
|
* @class GPScript ByteString implementation
|
||||||
* @param {String} value initial value
|
* @param {String} value initial value
|
||||||
* @param {HEX|ASCII} encoding encoding to use
|
* @param {HEX|ASCII} encoding encoding to use
|
||||||
* @property {Number} length length of the ByteString
|
* @property {Number} length length of the ByteString
|
||||||
* @constructs
|
* @constructs
|
||||||
*/
|
*/
|
||||||
var ByteString = function(value, encoding) {
|
var ByteString = function(value, encoding) {
|
||||||
this.encoding = encoding;
|
this.encoding = encoding;
|
||||||
this.hasBuffer = (typeof Buffer != 'undefined');
|
this.hasBuffer = (typeof Buffer != 'undefined');
|
||||||
if (this.hasBuffer && (value instanceof Buffer)) {
|
if (this.hasBuffer && (value instanceof Buffer)) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.encoding = GP.HEX;
|
this.encoding = GP.HEX;
|
||||||
}
|
} else {
|
||||||
else {
|
switch (encoding) {
|
||||||
switch(encoding) {
|
case GP.HEX:
|
||||||
case GP.HEX:
|
if (!this.hasBuffer) {
|
||||||
if (!this.hasBuffer) {
|
this.value = Convert.hexToBin(value);
|
||||||
this.value = Convert.hexToBin(value);
|
} else {
|
||||||
}
|
this.value = new Buffer(value, 'hex');
|
||||||
else {
|
}
|
||||||
this.value = new Buffer(value, 'hex');
|
break;
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GP.ASCII:
|
case GP.ASCII:
|
||||||
if (!this.hasBuffer) {
|
if (!this.hasBuffer) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
} else {
|
||||||
else {
|
this.value = new Buffer(value, 'ascii');
|
||||||
this.value = new Buffer(value, 'ascii');
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw "Invalid arguments";
|
throw "Invalid arguments";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.length = this.value.length;
|
}
|
||||||
|
this.length = this.value.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the byte value at the given index
|
* Retrieve the byte value at the given index
|
||||||
* @param {Number} index index
|
* @param {Number} index index
|
||||||
* @returns {Number} byte value
|
* @returns {Number} byte value
|
||||||
*/
|
*/
|
||||||
ByteString.prototype.byteAt = function(index) {
|
ByteString.prototype.byteAt = function(index) {
|
||||||
if (arguments.length < 1) {
|
if (arguments.length < 1) {
|
||||||
throw "Argument missing";
|
throw "Argument missing";
|
||||||
}
|
}
|
||||||
if (typeof index != "number") {
|
if (typeof index != "number") {
|
||||||
throw "Invalid index";
|
throw "Invalid index";
|
||||||
}
|
}
|
||||||
if ((index < 0) || (index >= this.value.length)) {
|
if ((index < 0) || (index >= this.value.length)) {
|
||||||
throw "Invalid index offset";
|
throw "Invalid index offset";
|
||||||
}
|
}
|
||||||
if (!this.hasBuffer) {
|
if (!this.hasBuffer) {
|
||||||
return Convert.readHexDigit(Convert.stringToHex(this.value.substring(index, index + 1)));
|
return Convert.readHexDigit(Convert.stringToHex(this.value.substring(index, index + 1)));
|
||||||
}
|
} else {
|
||||||
else {
|
return this.value[index];
|
||||||
return this.value[index];
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -343,95 +397,88 @@ ByteString.prototype.byteAt = function(index) {
|
||||||
* @param {Number} offset offset to start at
|
* @param {Number} offset offset to start at
|
||||||
* @param {Number} [count] size of the target ByteString (default : use the remaining length)
|
* @param {Number} [count] size of the target ByteString (default : use the remaining length)
|
||||||
* @returns {ByteString} subset of the original ByteString
|
* @returns {ByteString} subset of the original ByteString
|
||||||
*/
|
*/
|
||||||
ByteString.prototype.bytes = function(offset, count) {
|
ByteString.prototype.bytes = function(offset, count) {
|
||||||
var result;
|
var result;
|
||||||
if (arguments.length < 1) {
|
if (arguments.length < 1) {
|
||||||
throw "Argument missing";
|
throw "Argument missing";
|
||||||
}
|
}
|
||||||
if (typeof offset != "number") {
|
if (typeof offset != "number") {
|
||||||
throw "Invalid offset";
|
throw "Invalid offset";
|
||||||
}
|
}
|
||||||
//if ((offset < 0) || (offset >= this.value.length)) {
|
//if ((offset < 0) || (offset >= this.value.length)) {
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
throw "Invalid offset";
|
throw "Invalid offset";
|
||||||
}
|
}
|
||||||
if (typeof count == "number") {
|
if (typeof count == "number") {
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
throw "Invalid count";
|
|
||||||
}
|
|
||||||
if (!this.hasBuffer) {
|
|
||||||
result = new ByteString(this.value.substring(offset, offset + count), GP.ASCII);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = new Buffer(count);
|
|
||||||
this.value.copy(result, 0, offset, offset + count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (typeof count == "undefined") {
|
|
||||||
if (!this.hasBuffer) {
|
|
||||||
result = new ByteString(this.value.substring(offset), GP.ASCII);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = new Buffer(this.value.length - offset);
|
|
||||||
this.value.copy(result, 0, offset, this.value.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw "Invalid count";
|
throw "Invalid count";
|
||||||
}
|
}
|
||||||
if (!this.hasBuffer) {
|
if (!this.hasBuffer) {
|
||||||
result.encoding = this.encoding;
|
result = new ByteString(this.value.substring(offset, offset + count), GP.ASCII);
|
||||||
return result;
|
} else {
|
||||||
|
result = new Buffer(count);
|
||||||
|
this.value.copy(result, 0, offset, offset + count);
|
||||||
}
|
}
|
||||||
else {
|
} else
|
||||||
return new ByteString(result, GP.HEX);
|
if (typeof count == "undefined") {
|
||||||
|
if (!this.hasBuffer) {
|
||||||
|
result = new ByteString(this.value.substring(offset), GP.ASCII);
|
||||||
|
} else {
|
||||||
|
result = new Buffer(this.value.length - offset);
|
||||||
|
this.value.copy(result, 0, offset, this.value.length);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw "Invalid count";
|
||||||
|
}
|
||||||
|
if (!this.hasBuffer) {
|
||||||
|
result.encoding = this.encoding;
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return new ByteString(result, GP.HEX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends two ByteString
|
* Appends two ByteString
|
||||||
* @param {ByteString} target ByteString to append
|
* @param {ByteString} target ByteString to append
|
||||||
* @returns {ByteString} result of the concatenation
|
* @returns {ByteString} result of the concatenation
|
||||||
*/
|
*/
|
||||||
ByteString.prototype.concat = function(target) {
|
ByteString.prototype.concat = function(target) {
|
||||||
if (arguments.length < 1) {
|
if (arguments.length < 1) {
|
||||||
throw "Not enough arguments";
|
throw "Not enough arguments";
|
||||||
}
|
}
|
||||||
if (!(target instanceof ByteString)) {
|
if (!(target instanceof ByteString)) {
|
||||||
throw "Invalid argument";
|
throw "Invalid argument";
|
||||||
}
|
}
|
||||||
if (!this.hasBuffer) {
|
if (!this.hasBuffer) {
|
||||||
var result = this.value + target.value;
|
var result = this.value + target.value;
|
||||||
var x = new ByteString(result, GP.ASCII);
|
var x = new ByteString(result, GP.ASCII);
|
||||||
x.encoding = this.encoding;
|
x.encoding = this.encoding;
|
||||||
return x;
|
return x;
|
||||||
}
|
} else {
|
||||||
else {
|
var result = Buffer.concat([this.value, target.value]);
|
||||||
var result = Buffer.concat([this.value, target.value]);
|
return new ByteString(result, GP.HEX);
|
||||||
return new ByteString(result, GP.HEX);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if two ByteString are equal
|
* Check if two ByteString are equal
|
||||||
* @param {ByteString} target ByteString to check against
|
* @param {ByteString} target ByteString to check against
|
||||||
* @returns {Boolean} true if the two ByteString are equal
|
* @returns {Boolean} true if the two ByteString are equal
|
||||||
*/
|
*/
|
||||||
ByteString.prototype.equals = function(target) {
|
ByteString.prototype.equals = function(target) {
|
||||||
if (arguments.length < 1) {
|
if (arguments.length < 1) {
|
||||||
throw "Not enough arguments";
|
throw "Not enough arguments";
|
||||||
}
|
}
|
||||||
if (!(target instanceof ByteString)) {
|
if (!(target instanceof ByteString)) {
|
||||||
throw "Invalid argument";
|
throw "Invalid argument";
|
||||||
}
|
}
|
||||||
if (!this.hasBuffer) {
|
if (!this.hasBuffer) {
|
||||||
return (this.value == target.value);
|
return (this.value == target.value);
|
||||||
}
|
} else {
|
||||||
else {
|
return Buffer.equals(this.value, target.value);
|
||||||
return Buffer.equals(this.value, target.value);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -439,45 +486,43 @@ ByteString.prototype.equals = function(target) {
|
||||||
* Convert the ByteString to a String using the given encoding
|
* Convert the ByteString to a String using the given encoding
|
||||||
* @param {HEX|ASCII|UTF8|BASE64|CN} encoding encoding to use
|
* @param {HEX|ASCII|UTF8|BASE64|CN} encoding encoding to use
|
||||||
* @return {String} converted content
|
* @return {String} converted content
|
||||||
*/
|
*/
|
||||||
ByteString.prototype.toString = function(encoding) {
|
ByteString.prototype.toString = function(encoding) {
|
||||||
var targetEncoding = this.encoding;
|
var targetEncoding = this.encoding;
|
||||||
if (arguments.length >= 1) {
|
if (arguments.length >= 1) {
|
||||||
if (typeof encoding != "number") {
|
if (typeof encoding != "number") {
|
||||||
throw "Invalid encoding";
|
throw "Invalid encoding";
|
||||||
}
|
|
||||||
switch(encoding) {
|
|
||||||
case GP.HEX:
|
|
||||||
case GP.ASCII:
|
|
||||||
targetEncoding = encoding;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw "Unsupported arguments";
|
|
||||||
}
|
|
||||||
targetEncoding = encoding;
|
|
||||||
}
|
}
|
||||||
switch(targetEncoding) {
|
switch (encoding) {
|
||||||
case GP.HEX:
|
case GP.HEX:
|
||||||
if (!this.hasBuffer) {
|
|
||||||
return Convert.stringToHex(this.value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return this.value.toString('hex');
|
|
||||||
}
|
|
||||||
case GP.ASCII:
|
case GP.ASCII:
|
||||||
if (!this.hasBuffer) {
|
targetEncoding = encoding;
|
||||||
return this.value;
|
break;
|
||||||
}
|
|
||||||
else {
|
|
||||||
return this.value.toString();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw "Unsupported";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteString.prototype.toStringIE = function(encoding) {
|
default:
|
||||||
|
throw "Unsupported arguments";
|
||||||
|
}
|
||||||
|
targetEncoding = encoding;
|
||||||
|
}
|
||||||
|
switch (targetEncoding) {
|
||||||
|
case GP.HEX:
|
||||||
|
if (!this.hasBuffer) {
|
||||||
|
return Convert.stringToHex(this.value);
|
||||||
|
} else {
|
||||||
|
return this.value.toString('hex');
|
||||||
|
}
|
||||||
|
case GP.ASCII:
|
||||||
|
if (!this.hasBuffer) {
|
||||||
|
return this.value;
|
||||||
|
} else {
|
||||||
|
return this.value.toString();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw "Unsupported";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteString.prototype.toStringIE = function(encoding) {
|
||||||
return this.toString(encoding);
|
return this.toString(encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
angular.module('copayApp.services')
|
angular.module('copayApp.services')
|
||||||
.factory('profileService', function profileServiceFactory($rootScope, $location, $timeout, $filter, $log, lodash, storageService, bwcService, configService, notificationService, isChromeApp, isCordova, gettext, nodeWebkit, bwsError, ledger, uxLanguage) {
|
.factory('profileService', function profileServiceFactory($rootScope, $location, $timeout, $filter, $log, lodash, storageService, bwcService, configService, notificationService, isChromeApp, isCordova, gettext, nodeWebkit, bwsError, uxLanguage, ledger) {
|
||||||
|
|
||||||
var root = {};
|
var root = {};
|
||||||
|
|
||||||
|
|
@ -179,7 +179,7 @@ angular.module('copayApp.services')
|
||||||
}
|
}
|
||||||
} else if (opts.extendedPublicKey) {
|
} else if (opts.extendedPublicKey) {
|
||||||
try {
|
try {
|
||||||
walletClient.seedFromExternalWalletPublicKey(opts.extendedPublicKey, opts.externalSource, opts.externalIndex);
|
walletClient.seedFromExternalWalletPublicKey(opts.extendedPublicKey, opts.externalSource, opts.externalIndex, opts.entropySource);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
return cb(gettext('Could not create using the specified extended public key'));
|
return cb(gettext('Could not create using the specified extended public key'));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue