コード例 #1
0
    def test_recovery_device(self):
        self.client.set_mnemonic(self.mnemonic12)
        with self.client:
            self.client.set_expected_responses(
                [proto.ButtonRequest()]
                + [proto.WordRequest()] * 24
                + [proto.Success(), proto.Features()]
            )

            device.recover(
                self.client,
                12,
                False,
                False,
                "label",
                "english",
                self.client.mnemonic_callback,
            )

        # This must fail, because device is already initialized
        with pytest.raises(RuntimeError):
            device.recover(
                self.client,
                12,
                False,
                False,
                "label",
                "english",
                self.client.mnemonic_callback,
            )
コード例 #2
0
 def test_already_initialized(self):
     self.setup_mnemonic_nopin_nopassphrase()
     with pytest.raises(RuntimeError):
         device.recover(
             self.client,
             12,
             False,
             False,
             "label",
             "english",
             self.client.mnemonic_callback,
         )
def test_wrong_nth_word(client, nth_word):
    debug = client.debug
    share = MNEMONIC_SLIP39_BASIC_20_3of6[0].split(" ")

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        yield  # Homescreen - start process
        debug.press_yes()
        yield  # Enter number of words
        debug.input(str(len(share)))
        yield  # Homescreen - proceed to share entry
        debug.press_yes()
        yield  # Enter first share
        for word in share:
            debug.input(word)

        yield  # Continue to next share
        debug.press_yes()
        yield  # Enter next share
        for i, word in enumerate(share):
            if i < nth_word:
                debug.input(word)
            else:
                debug.input(share[-1])
                break

        code = yield
        assert code == messages.ButtonRequestType.Warning

        client.cancel()

    with client:
        client.set_input_flow(input_flow)
        with pytest.raises(exceptions.Cancelled):
            device.recover(client, pin_protection=False, label="label")
コード例 #4
0
def test_same_share(client):
    debug = client.debug
    first_share = SHARES_20_3of6[0].split(" ")
    # second share is first 4 words of first
    second_share = SHARES_20_3of6[0].split(" ")[:4]

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        yield  # Homescreen - start process
        debug.press_yes()
        yield  # Enter number of words
        debug.input(str(len(first_share)))
        yield  # Homescreen - proceed to share entry
        debug.press_yes()
        yield  # Enter first share
        for word in first_share:
            time.sleep(1)
            debug.input(word)

        yield  # Continue to next share
        debug.press_yes()
        yield  # Enter next share
        for word in second_share:
            time.sleep(1)
            debug.input(word)

        code = yield
        assert code == messages.ButtonRequestType.Warning

        client.cancel()

    with client:
        client.set_input_flow(input_flow)
        with pytest.raises(exceptions.Cancelled):
            device.recover(client, pin_protection=False, label="label")
def test_2of3_invalid_seed_dryrun(client):
    debug = client.debug

    def input_flow():
        yield  # Confirm Dryrun
        debug.press_yes()
        # run recovery flow
        yield from recovery_enter_shares(debug,
                                         INVALID_SHARES_20_2of3_2of3_GROUPS,
                                         groups=True)

    # test fails because of different seed on device
    with client, pytest.raises(
            TrezorFailure,
            match=r"The seed does not match the one in the device"):
        client.set_input_flow(input_flow)
        device.recover(
            client,
            passphrase_protection=False,
            pin_protection=False,
            label="label",
            language="english",
            dry_run=True,
        )
コード例 #6
0
def test_invalid_seed_core(client):
    def input_flow():
        yield
        layout = client.debug.wait_layout()
        assert "check the recovery seed" in layout.text
        client.debug.click(buttons.OK)

        yield
        layout = client.debug.wait_layout()
        assert "Select number of words" in layout.text
        client.debug.click(buttons.OK)

        yield
        layout = client.debug.wait_layout()
        assert layout.text == "WordSelector"
        # select 12 words
        client.debug.click(buttons.grid34(0, 2))

        yield
        layout = client.debug.wait_layout()
        assert "Enter recovery seed" in layout.text
        client.debug.click(buttons.OK)

        yield
        for _ in range(12):
            client.debug.input("stick")

        code = yield
        layout = client.debug.wait_layout()
        assert code == messages.ButtonRequestType.Warning
        assert "invalid recovery seed" in layout.text
        client.debug.click(buttons.OK)

        yield
        # retry screen
        layout = client.debug.wait_layout()
        assert "Select number of words" in layout.text
        client.debug.click(buttons.CANCEL)

        yield
        layout = client.debug.wait_layout()
        assert "abort" in layout.text
        client.debug.click(buttons.OK)

    with client:
        client.set_input_flow(input_flow)
        with pytest.raises(exceptions.Cancelled):
            return device.recover(client, dry_run=True)
def recover(client, shares):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        # run recovery flow
        yield from recovery_enter_shares(debug, shares, groups=True)

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(client, pin_protection=False, label="label")

    # Workflow successfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.pin_protection is False
    assert client.features.passphrase_protection is False
コード例 #8
0
def do_recover_legacy(client, mnemonic, **kwargs):
    def input_callback(_):
        word, pos = client.debug.read_recovery_word()
        if pos != 0:
            word = mnemonic[pos - 1]
            mnemonic[pos - 1] = None
            assert word is not None

        return word

    ret = device.recover(client,
                         dry_run=True,
                         word_count=len(mnemonic),
                         type=messages.RecoveryDeviceType.ScrambledWords,
                         input_callback=input_callback,
                         **kwargs)
    # if the call succeeded, check that all words have been used
    assert all(m is None for m in mnemonic)
    return ret
コード例 #9
0
def test_secret(client, shares, secret):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        # run recovery flow
        yield from enter_all_shares(debug, shares)

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(client, pin_protection=False, label="label")

    # Workflow succesfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.pin_protection is False
    assert client.features.passphrase_protection is False

    # Check mnemonic
    assert debug.read_mnemonic_secret().hex() == secret
def test_recover_no_pin_no_passphrase(client):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        # Proceed with recovery
        yield from enter_all_shares(debug, SHARES_20_2of3_2of3_GROUPS)

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(
            client, pin_protection=False, passphrase_protection=False, label="label"
        )

    # Workflow succesfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.initialized is True
    assert client.features.pin_protection is False
    assert client.features.passphrase_protection is False
コード例 #11
0
def test_secret(client: Client, shares, secret):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        # run recovery flow
        yield from recovery_enter_shares(debug, shares)

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(client, pin_protection=False, label="label")

    # Workflow succesfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.pin_protection is False
    assert client.features.passphrase_protection is False
    assert client.features.backup_type is messages.BackupType.Slip39_Basic

    # Check mnemonic
    assert debug.state().mnemonic_secret.hex() == secret
コード例 #12
0
def recover(client: Client, mnemonic):
    debug = client.debug
    words = mnemonic.split(" ")

    def input_flow():
        yield  # Confirm recovery
        debug.press_yes()
        yield  # Homescreen
        debug.press_yes()

        yield  # Enter word count
        debug.input(str(len(words)))

        yield  # Homescreen
        debug.press_yes()
        yield  # Enter words
        for word in words:
            debug.input(word)

        yield  # confirm success
        debug.press_yes()

    with client:
        client.set_input_flow(input_flow)
        client.set_expected_responses([
            messages.ButtonRequest(code=B.ProtectCall),
            messages.ButtonRequest(code=B.RecoveryHomepage),
            messages.ButtonRequest(code=B.MnemonicWordCount),
            messages.ButtonRequest(code=B.RecoveryHomepage),
            messages.ButtonRequest(code=B.MnemonicInput),
            messages.ButtonRequest(code=B.Success),
            messages.Success,
            messages.Features,
        ])
        ret = device.recover(client, pin_protection=False, label="label")

    # Workflow successfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.pin_protection is False
    assert client.features.passphrase_protection is False
コード例 #13
0
def do_recover_core(client, mnemonic, **kwargs):
    def input_flow():
        yield
        layout = client.debug.wait_layout()
        assert "check the recovery seed" in layout.text.replace("\n", " ")
        client.debug.click(buttons.OK)

        yield
        layout = client.debug.wait_layout()
        assert "Select number of words" in layout.text
        client.debug.click(buttons.OK)

        yield
        layout = client.debug.wait_layout()
        assert layout.text == "WordSelector"
        # click the number
        word_option_offset = 6
        word_options = (12, 18, 20, 24, 33)
        index = word_option_offset + word_options.index(len(mnemonic))
        client.debug.click(buttons.grid34(index % 3, index // 3))

        yield
        layout = client.debug.wait_layout()
        assert "Enter recovery seed" in layout.text
        client.debug.click(buttons.OK)

        yield
        for word in mnemonic:
            client.debug.wait_layout()
            client.debug.input(word)

        yield
        client.debug.wait_layout()
        client.debug.click(buttons.OK)

    with client:
        client.watch_layout()
        client.set_input_flow(input_flow)
        return device.recover(client, dry_run=True, **kwargs)
コード例 #14
0
def test_secret(client, shares, secret):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        # Proceed with recovery
        yield from recovery_enter_shares(debug, shares, groups=True)

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(client,
                             pin_protection=False,
                             passphrase_protection=False,
                             label="label")

    # Workflow succesfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.initialized is True
    assert client.features.pin_protection is False
    assert client.features.passphrase_protection is False
    assert client.features.backup_type is messages.BackupType.Slip39_Advanced
    assert debug.state().mnemonic_secret.hex() == secret
def test_2of3_dryrun(client):
    debug = client.debug

    def input_flow():
        yield  # Confirm Dryrun
        debug.press_yes()
        # run recovery flow
        yield from recovery_enter_shares(debug, SHARES_20_2of3[1:3])

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(
            client,
            passphrase_protection=False,
            pin_protection=False,
            label="label",
            language="english",
            dry_run=True,
        )

    # Dry run was successful
    assert ret == messages.Success(
        message="The seed is valid and matches the one in the device")
コード例 #16
0
def test_1of1(client):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        # Proceed with recovery
        yield from recovery_enter_shares(
            debug, MNEMONIC_SLIP39_BASIC_20_1of1, groups=False
        )

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(
            client, pin_protection=False, passphrase_protection=False, label="label"
        )

    # Workflow succesfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.initialized is True
    assert client.features.pin_protection is False
    assert client.features.passphrase_protection is False
    assert client.features.backup_type is messages.BackupType.Slip39_Basic
コード例 #17
0
def test_recover_with_pin_passphrase(client):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        yield  # Enter PIN
        debug.input("654")
        yield  # Enter PIN again
        debug.input("654")
        # Proceed with recovery
        yield from enter_all_shares(debug, SHARES_20_3of6)

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(client,
                             pin_protection=True,
                             passphrase_protection=True,
                             label="label")

    # Workflow succesfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.pin_protection is True
    assert client.features.passphrase_protection is True
コード例 #18
0
def test_recover_with_pin_passphrase(client):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        yield  # Enter PIN
        debug.input("654")
        yield  # Enter PIN again
        debug.input("654")
        # Proceed with recovery
        yield from recovery_enter_shares(debug, MNEMONIC_SLIP39_BASIC_20_3of6)

    with client:
        client.set_input_flow(input_flow)
        ret = device.recover(
            client, pin_protection=True, passphrase_protection=True, label="label"
        )

    # Workflow succesfully ended
    assert ret == messages.Success(message="Device recovered")
    assert client.features.pin_protection is True
    assert client.features.passphrase_protection is True
    assert client.features.backup_type is messages.BackupType.Slip39_Basic
コード例 #19
0
def test_already_initialized(client):
    with pytest.raises(RuntimeError):
        device.recover(client)

    with pytest.raises(exceptions.TrezorFailure, match="Already initialized"):
        client.call(messages.RecoveryDevice())
コード例 #20
0
 def test_already_initialized(self):
     self.setup_mnemonic_nopin_nopassphrase()
     with pytest.raises(Exception):
         device.recover(self.client, 12, False, False, "label", "english")
コード例 #21
0
def test_ask_word_number(client):
    debug = client.debug

    def input_flow_retry_first():
        yield  # Confirm Recovery
        debug.press_yes()
        yield  # Homescreen - start process
        debug.press_yes()
        yield  # Enter number of words
        debug.input("20")
        yield  # Homescreen - proceed to share entry
        debug.press_yes()
        yield  # Enter first share
        for _ in range(20):
            debug.input("slush")

        br = yield  # Invalid share
        assert br.code == messages.ButtonRequestType.Warning
        debug.press_yes()

        yield  # Homescreen - start process
        debug.press_yes()
        yield  # Enter number of words
        debug.input("33")
        yield  # Homescreen - proceed to share entry
        debug.press_yes()
        yield  # Enter first share
        for _ in range(33):
            debug.input("slush")

        br = yield  # Invalid share
        assert br.code == messages.ButtonRequestType.Warning
        debug.press_yes()

        yield  # Homescreen
        debug.press_no()
        yield  # Confirm abort
        debug.press_yes()

    with client:
        client.set_input_flow(input_flow_retry_first)
        with pytest.raises(exceptions.Cancelled):
            device.recover(client, pin_protection=False, label="label")
        client.init_device()
        assert client.features.initialized is False

    def input_flow_retry_second():
        yield  # Confirm Recovery
        debug.press_yes()
        yield  # Homescreen - start process
        debug.press_yes()
        yield  # Enter number of words
        debug.input("20")
        yield  # Homescreen - proceed to share entry
        debug.press_yes()
        yield  # Enter first share
        share = MNEMONIC_SLIP39_BASIC_20_3of6[0].split(" ")
        for word in share:
            debug.input(word)

        yield  # More shares needed
        debug.press_yes()

        yield  # Enter another share
        share = share[:3] + ["slush"] * 17
        for word in share:
            debug.input(word)

        br = yield  # Invalid share
        assert br.code == messages.ButtonRequestType.Warning
        debug.press_yes()

        yield  # Proceed to next share
        share = MNEMONIC_SLIP39_BASIC_20_3of6[1].split(" ")
        for word in share:
            debug.input(word)

        yield  # More shares needed
        debug.press_no()
        yield  # Confirm abort
        debug.press_yes()

    with client:
        client.set_input_flow(input_flow_retry_second)
        with pytest.raises(exceptions.Cancelled):
            device.recover(client, pin_protection=False, label="label")
        client.init_device()
        assert client.features.initialized is False
 def test_already_initialized(self, client):
     with pytest.raises(RuntimeError):
         device.recover(client, 12, False, False, "label", "english",
                        client.mnemonic_callback)
コード例 #23
0
def recover_device(hw_device_id: str,
                   hw_device_transport_id: Any,
                   hw_client: Any,
                   word_count: int,
                   passphrase_enabled: bool,
                   pin_enabled: bool,
                   hw_label: str,
                   input_type: Literal["scrambled_words", "matrix"],
                   parent_window: Optional[QWidget] = None) -> Optional[str]:
    mnem = Mnemonic('english')
    type = {
        "scrambled_words": messages.RecoveryDeviceType.ScrambledWords
    }.get(input_type, messages.RecoveryDeviceType.Matrix)

    def ask_for_word(_type):
        nonlocal mnem
        if _type == 0:
            msg = "Enter one word of mnemonic: "
            word = ask_for_word_callback(msg, mnem.wordlist, parent_window)
            if not word:
                raise exceptions.Cancelled
            return word
        elif _type in (1, 2):
            # _type
            # 1: matrix has three columns
            # 2: matrix has two columns
            element = hw_common.ask_for_martix_element_callback(
                "<span>Select the matrix element that corresponds<br>"
                "to the part of the word displayed on<br>"
                "the device screen</span>",
                columns=3 if _type == 1 else 2,
                parent_window=parent_window)
            if element:
                return element
            else:
                raise exceptions.Cancelled
        else:
            raise exceptions.Cancelled

    client = None
    try:
        if not hw_client:
            client = open_session(hw_device_id, hw_device_transport_id)
        else:
            client = hw_client

        if client:
            if client.features.initialized:
                device.wipe(client)
                hw_device_id = client.features.device_id

            device.recover(client,
                           word_count,
                           passphrase_enabled,
                           pin_enabled,
                           hw_label,
                           input_callback=ask_for_word,
                           type=type)
            return hw_device_id
        else:
            raise Exception('Couldn\'t connect to Trezor device.')

    except exceptions.Cancelled:
        raise CancelException
    except exceptions.TrezorFailure as e:
        if e.failure.message == 'Device not initialized':
            raise HwNotInitialized(e.failure.message)
        else:
            raise
    finally:
        if client and hw_client != client:
            client.close()