|
26 | 26 | using namespace hw::trezor::messages; |
27 | 27 |
|
28 | 28 | namespace { |
| 29 | + const auto kModel1 = "1"; |
| 30 | + const auto kModelT = "T"; |
| 31 | + |
| 32 | + const std::map<std::string, std::array<unsigned, 3>> kMinVersion = { |
| 33 | + { kModel1, { 1, 9, 1 } }, |
| 34 | + { kModelT, { 2, 3, 1 } } |
| 35 | + }; |
| 36 | + |
29 | 37 | // Trezor package rule (source - https://github.com/trezor/trezord-go) |
30 | 38 | int getMessageType(const google::protobuf::Message &msg) |
31 | 39 | { |
@@ -128,6 +136,13 @@ void TrezorDevice::getPublicKey(AsyncCallBackCall&& cb) |
128 | 136 | awaitingWalletInfo_.info_.deviceId = features_.device_id(); |
129 | 137 | awaitingWalletInfo_.info_.vendor = features_.vendor(); |
130 | 138 |
|
| 139 | + awaitingWalletInfo_.isFirmwareSupported_ = isFirmwareSupported(); |
| 140 | + if (!awaitingWalletInfo_.isFirmwareSupported_) { |
| 141 | + awaitingWalletInfo_.firmwareSupportedMsg_ = firmwareSupportedVersion(); |
| 142 | + cb(QVariant::fromValue<>(awaitingWalletInfo_)); |
| 143 | + return; |
| 144 | + } |
| 145 | + |
131 | 146 | // We cannot get all data from one call so we make four calls: |
132 | 147 | // fetching first address for "m/0'" as wallet id |
133 | 148 | // fetching first address for "m/84'" as native segwit xpub |
@@ -215,11 +230,15 @@ void TrezorDevice::setMatrixPin(const std::string& pin) |
215 | 230 | makeCall(message); |
216 | 231 | } |
217 | 232 |
|
218 | | -void TrezorDevice::setPassword(const std::string& password) |
| 233 | +void TrezorDevice::setPassword(const std::string& password, bool enterOnDevice) |
219 | 234 | { |
220 | 235 | connectionManager_->GetLogger()->debug("[TrezorDevice] setPassword - send passphrase response"); |
221 | 236 | common::PassphraseAck message; |
222 | | - message.set_passphrase(password); |
| 237 | + if (enterOnDevice) { |
| 238 | + message.set_on_device(true); |
| 239 | + } else { |
| 240 | + message.set_passphrase(password); |
| 241 | + } |
223 | 242 | makeCall(message); |
224 | 243 | } |
225 | 244 |
|
@@ -308,7 +327,8 @@ void TrezorDevice::handleMessage(const MessageData& data) |
308 | 327 | case MessageType_Features: |
309 | 328 | { |
310 | 329 | if (parseResponse(features_, data)) { |
311 | | - connectionManager_->GetLogger()->debug("[TrezorDevice] handleMessage Features "); |
| 330 | + connectionManager_->GetLogger()->debug("[TrezorDevice] handleMessage Features, model: '{}' - {}.{}.{} ({})" |
| 331 | + , features_.model(), features_.major_version(), features_.minor_version(), features_.patch_version(), features_.revision()); |
312 | 332 | // + getJSONReadableMessage(features_)); |
313 | 333 | } |
314 | 334 | } |
@@ -339,7 +359,7 @@ void TrezorDevice::handleMessage(const MessageData& data) |
339 | 359 | { |
340 | 360 | common::PassphraseRequest request; |
341 | 361 | if (parseResponse(request, data)) { |
342 | | - emit requestHWPass(); |
| 362 | + emit requestHWPass(hasCapability(management::Features_Capability_Capability_PassphraseEntry)); |
343 | 363 | sendTxMessage(HWInfoStatus::kRequestPassphrase); |
344 | 364 | } |
345 | 365 | } |
@@ -398,7 +418,6 @@ void TrezorDevice::resetCaches() |
398 | 418 | currentTxSignReq_.reset(nullptr); |
399 | 419 | awaitingTransaction_ = {}; |
400 | 420 | awaitingWalletInfo_ = {}; |
401 | | - prevTxs_.clear(); |
402 | 421 | } |
403 | 422 |
|
404 | 423 | void TrezorDevice::setCallbackNoData(MessageType type, AsyncCallBack&& cb) |
@@ -449,16 +468,17 @@ void TrezorDevice::handleTxRequest(const MessageData& data) |
449 | 468 | { |
450 | 469 | case bitcoin::TxRequest_RequestType_TXINPUT: |
451 | 470 | { |
452 | | - // Legacy inputs support |
453 | 471 | if (!txRequest.details().tx_hash().empty()) { |
454 | | - auto tx = prevTx(txRequest); |
455 | | - auto txIn = tx.getTxInCopy(txRequest.details().request_index()); |
456 | | - |
457 | 472 | auto input = txAck.mutable_tx()->add_inputs(); |
458 | | - input->set_prev_hash(txIn.getOutPoint().getTxHash().copySwapEndian().toBinStr()); |
459 | | - input->set_prev_index(txIn.getOutPoint().getTxOutIndex()); |
460 | | - input->set_sequence(txIn.getSequence()); |
461 | | - input->set_script_sig(txIn.getScript().toBinStr()); |
| 473 | + |
| 474 | + auto tx = prevTx(txRequest); |
| 475 | + if (tx.isInitialized()) { |
| 476 | + auto txIn = tx.getTxInCopy(txRequest.details().request_index()); |
| 477 | + input->set_prev_hash(txIn.getOutPoint().getTxHash().copySwapEndian().toBinStr()); |
| 478 | + input->set_prev_index(txIn.getOutPoint().getTxOutIndex()); |
| 479 | + input->set_sequence(txIn.getSequence()); |
| 480 | + input->set_script_sig(txIn.getScript().toBinStr()); |
| 481 | + } |
462 | 482 |
|
463 | 483 | connectionManager_->GetLogger()->debug("[TrezorDevice] handleTxRequest TXINPUT for prev hash" |
464 | 484 | + getJSONReadableMessage(txAck)); |
@@ -520,11 +540,12 @@ void TrezorDevice::handleTxRequest(const MessageData& data) |
520 | 540 | // Legacy inputs support |
521 | 541 | if (!txRequest.details().tx_hash().empty()) { |
522 | 542 | auto tx = prevTx(txRequest); |
523 | | - auto txOut = tx.getTxOutCopy(txRequest.details().request_index()); |
524 | | - |
525 | 543 | auto binOutput = txAck.mutable_tx()->add_bin_outputs(); |
526 | | - binOutput->set_amount(txOut.getValue()); |
527 | | - binOutput->set_script_pubkey(txOut.getScript().toBinStr()); |
| 544 | + if (tx.isInitialized()) { |
| 545 | + auto txOut = tx.getTxOutCopy(txRequest.details().request_index()); |
| 546 | + binOutput->set_amount(txOut.getValue()); |
| 547 | + binOutput->set_script_pubkey(txOut.getScript().toBinStr()); |
| 548 | + } |
528 | 549 |
|
529 | 550 | connectionManager_->GetLogger()->debug("[TrezorDevice] handleTxRequest TXOUTPUT for prev hash" |
530 | 551 | + getJSONReadableMessage(txAck)); |
@@ -593,12 +614,13 @@ void TrezorDevice::handleTxRequest(const MessageData& data) |
593 | 614 | // Return previous tx details for legacy inputs |
594 | 615 | // See https://wiki.trezor.io/Developers_guide:Message_Workflows |
595 | 616 | auto tx = prevTx(txRequest); |
596 | | - |
597 | 617 | auto data = txAck.mutable_tx(); |
598 | | - data->set_version(tx.getVersion()); |
599 | | - data->set_lock_time(tx.getLockTime()); |
600 | | - data->set_inputs_cnt(tx.getNumTxIn()); |
601 | | - data->set_outputs_cnt(tx.getNumTxOut()); |
| 618 | + if (tx.isInitialized()) { |
| 619 | + data->set_version(tx.getVersion()); |
| 620 | + data->set_lock_time(tx.getLockTime()); |
| 621 | + data->set_inputs_cnt(tx.getNumTxIn()); |
| 622 | + data->set_outputs_cnt(tx.getNumTxOut()); |
| 623 | + } |
602 | 624 |
|
603 | 625 | connectionManager_->GetLogger()->debug("[TrezorDevice] handleTxRequest TXMETA" |
604 | 626 | + getJSONReadableMessage(txAck)); |
@@ -627,13 +649,53 @@ void TrezorDevice::sendTxMessage(const QString& status) |
627 | 649 | emit deviceTxStatusChanged(status); |
628 | 650 | } |
629 | 651 |
|
630 | | -const Tx &TrezorDevice::prevTx(const bitcoin::TxRequest &txRequest) |
| 652 | +Tx TrezorDevice::prevTx(const bitcoin::TxRequest &txRequest) |
631 | 653 | { |
632 | 654 | auto txHash = BinaryData::fromString(txRequest.details().tx_hash()).swapEndian(); |
633 | | - auto &tx = prevTxs_[txHash]; |
634 | | - if (!tx.isInitialized()) { |
635 | | - auto txRaw = currentTxSignReq_->supportingTXs.at(txHash); |
636 | | - tx = Tx(txRaw); |
| 655 | + auto supportingTxIt = currentTxSignReq_->supportingTXs.find(txHash); |
| 656 | + if (supportingTxIt == currentTxSignReq_->supportingTXs.end()) { |
| 657 | + SPDLOG_LOGGER_ERROR(connectionManager_->GetLogger(), "can't find prev TX {}", txHash.toHexStr(1)); |
| 658 | + return {}; |
| 659 | + } |
| 660 | + return Tx(supportingTxIt->second); |
| 661 | +} |
| 662 | + |
| 663 | +bool TrezorDevice::hasCapability(management::Features::Capability cap) const |
| 664 | +{ |
| 665 | + return std::find(features_.capabilities().begin(), features_.capabilities().end(), cap) |
| 666 | + != features_.capabilities().end(); |
| 667 | +} |
| 668 | + |
| 669 | +bool TrezorDevice::isFirmwareSupported() const |
| 670 | +{ |
| 671 | + auto verIt = kMinVersion.find(features_.model()); |
| 672 | + if (verIt == kMinVersion.end()) { |
| 673 | + return false; |
| 674 | + } |
| 675 | + |
| 676 | + const auto &minVer = verIt->second; |
| 677 | + if (features_.major_version() > minVer[0]) { |
| 678 | + return true; |
| 679 | + } |
| 680 | + if (features_.major_version() < minVer[0]) { |
| 681 | + return false; |
| 682 | + } |
| 683 | + if (features_.minor_version() > minVer[1]) { |
| 684 | + return true; |
| 685 | + } |
| 686 | + if (features_.minor_version() < minVer[1]) { |
| 687 | + return false; |
| 688 | + } |
| 689 | + return features_.patch_version() >= minVer[2]; |
| 690 | +} |
| 691 | + |
| 692 | +std::string TrezorDevice::firmwareSupportedVersion() const |
| 693 | +{ |
| 694 | + auto verIt = kMinVersion.find(features_.model()); |
| 695 | + if (verIt == kMinVersion.end()) { |
| 696 | + return fmt::format("Unknown model: {}", features_.model()); |
637 | 697 | } |
638 | | - return tx; |
| 698 | + const auto &minVer = verIt->second; |
| 699 | + return fmt::format("Please update wallet firmware to version {}.{}.{} or later" |
| 700 | + , minVer[0], minVer[1], minVer[2]); |
639 | 701 | } |
0 commit comments