Exemple #1
0
def main():
    parser = ArgumentParser()
    parser.add_argument("-m", dest="mnemonic", help="Set mnemonic", type=str)
    parser.add_argument("-p", dest="pin", help="Set pin", type=str)
    parser.add_argument("--passphrase",
                        dest="passphrase",
                        help="Enable passphrase",
                        action="store_true")
    parser.add_argument("--no-passphrase",
                        dest="passphrase",
                        help="Enable passphrase",
                        action="store_false")
    parser.set_defaults(passphrase=True)

    args = parser.parse_args()

    # Setup link
    wirelink = get_device()
    client = TrezorClientDebugLink(wirelink)
    client.open()
    device.wipe(client)

    debuglink.load_device_by_mnemonic(client,
                                      mnemonic=args.mnemonic,
                                      pin=args.pin,
                                      passphrase_protection=args.passphrase,
                                      label='test')

    print(args.mnemonic)
    print(client.features)
    client.close()
Exemple #2
0
def apply_settings(
    language: Optional[str] = None,
    label: Optional[str] = None,
    use_passphrase: Optional[bool] = None,
    homescreen: Optional[str] = None,
    auto_lock_delay_ms: Optional[int] = None,
    display_rotation: Optional[int] = None,
    passphrase_always_on_device: Optional[bool] = None,
    safety_checks: Optional[int] = None,
) -> None:
    """Forwards settings fields to be applied on a device.

    NOTE: does not handle the experimental_features argument,
      seems that it is not yet supported in latest trezorlib
    """
    # Homescreen needs to be bytes object, so if there,
    #   it should be encoded from the received string
    homescreen_bytes = homescreen.encode() if homescreen else None

    client = TrezorClientDebugLink(get_device())
    client.open()
    time.sleep(SLEEP)
    device.apply_settings(
        client,
        label=label,
        language=language,
        use_passphrase=use_passphrase,
        homescreen=homescreen_bytes,
        passphrase_always_on_device=passphrase_always_on_device,
        auto_lock_delay_ms=auto_lock_delay_ms,
        display_rotation=display_rotation,
        safety_checks=safety_checks,
    )
    client.close()
Exemple #3
0
def allow_unsafe() -> None:
    client = TrezorClientDebugLink(get_device())
    client.open()
    time.sleep(SLEEP)

    # T1 does not support PromptAlways
    if client.features.major_version == 1:
        safety_checks = messages.SafetyCheckLevel.PromptTemporarily
    else:
        safety_checks = messages.SafetyCheckLevel.PromptAlways

    # Some older devices do not support safety checks, so we know
    # the command will fail with a specific error message
    # T1 supports safety checks from 1.10.1 and T2 from 2.3.2
    try:
        device.apply_settings(client, safety_checks=safety_checks)
    except TrezorFailure as err:
        # Catching only specific error message, otherwise reraising the exception
        if "No setting provided" in str(err):
            log(
                f"Could not allow unsafe. Device does not support safety checks. Err: {err}",
                "red",
            )
        else:
            raise
    client.close()
Exemple #4
0
def client():
    wirelink = get_device()
    client = TrezorClientDebugLink(wirelink)
    wipe_device(client)

    client.open()
    yield client
    client.close()
def allow_unsafe():
    client = TrezorClientDebugLink(get_device())
    # ignore for Legacy firmware, there is no such setting
    if client.features.major_version == 1:
        return
    client.open()
    time.sleep(SLEEP)
    device.apply_settings(client, safety_checks=1)  # TODO
    client.close()
Exemple #6
0
def apply_settings(passphrase_always_on_device=None):
    client = TrezorClientDebugLink(get_device())
    client.open()
    time.sleep(SLEEP)
    device.apply_settings(
        client,
        passphrase_always_on_device=bool(passphrase_always_on_device),
    )
    client.close()
Exemple #7
0
class TrezorTest:
    # fmt: off
    #                1      2     3    4      5      6      7     8      9    10    11    12
    mnemonic12 = "alcohol woman abuse must during monitor noble actual mixed trade anger aisle"
    mnemonic18 = "owner little vague addict embark decide pink prosper true fork panda embody mixture exchange choose canoe electric jewel"
    mnemonic24 = "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic"
    mnemonic_all = " ".join(["all"] * 12)
    # fmt: on

    pin4 = "1234"
    pin6 = "789456"
    pin8 = "45678978"

    def setup_method(self, method):
        wirelink = conftest.get_device()
        self.client = TrezorClientDebugLink(wirelink)
        # self.client.set_buttonwait(3)

        device.wipe(self.client)
        self.client.open()

    def teardown_method(self, method):
        self.client.close()

    def _setup_mnemonic(self, mnemonic=None, pin="", passphrase=False):
        if mnemonic is None:
            mnemonic = TrezorTest.mnemonic12
        debuglink.load_device_by_mnemonic(
            self.client,
            mnemonic=mnemonic,
            pin=pin,
            passphrase_protection=passphrase,
            label="test",
            language="english",
        )
        if conftest.TREZOR_VERSION == 1:
            # remove cached PIN (introduced via load_device)
            self.client.clear_session()
        if conftest.TREZOR_VERSION > 1 and passphrase:
            device.apply_settings(self.client,
                                  passphrase_source=PASSPHRASE_ON_HOST)

    def setup_mnemonic_allallall(self):
        self._setup_mnemonic(mnemonic=TrezorTest.mnemonic_all)

    def setup_mnemonic_nopin_nopassphrase(self):
        self._setup_mnemonic()

    def setup_mnemonic_nopin_passphrase(self):
        self._setup_mnemonic(passphrase=True)

    def setup_mnemonic_pin_nopassphrase(self):
        self._setup_mnemonic(pin=TrezorTest.pin4)

    def setup_mnemonic_pin_passphrase(self):
        self._setup_mnemonic(pin=TrezorTest.pin4, passphrase=True)
class EmulatorWrapper:
    def __init__(self, gen, tag, storage=None):
        self.gen = gen
        self.tag = tag
        self.workdir = tempfile.TemporaryDirectory()
        if storage:
            open(self._storage_file(), "wb").write(storage)

    def __enter__(self):
        if self.tag.startswith("/"):  # full path+filename provided
            args = [self.tag]
        else:  # only gen+tag provided
            args = ["%s/trezor-emu-%s-%s" % (BINDIR, self.gen, self.tag)]
        env = ENV
        if self.gen == "core":
            args += ["-m", "main"]
            env["TREZOR_PROFILE_DIR"] = self.workdir.name
        self.process = subprocess.Popen(args,
                                        cwd=self.workdir.name,
                                        env=ENV,
                                        stdout=open(os.devnull, "w"))
        # wait until emulator is started
        while True:
            try:
                self.transport = get_transport("udp:127.0.0.1:21324")
            except TransportException:
                time.sleep(0.1)
                continue
            break
        self.client = TrezorClientDebugLink(self.transport)
        self.client.open()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.client.close()
        self.process.terminate()
        try:
            self.process.wait(1)
        except subprocess.TimeoutExpired:
            self.process.kill()
        self.workdir.cleanup()

    def _storage_file(self):
        if self.gen == "legacy":
            return self.workdir.name + "/emulator.img"
        elif self.gen == "core":
            return self.workdir.name + "/trezor.flash"
        else:
            raise ValueError("Unknown gen")

    def storage(self):
        return open(self._storage_file(), "rb").read()
Exemple #9
0
def client():
    wirelink = get_device()
    client = TrezorClientDebugLink(wirelink)
    wipe_device(client)
    client.transport.session_begin()

    yield client

    client.transport.session_end()

    # XXX debuglink session must also be closed
    # client.close accomplishes that for now; going forward, there should
    # also be proper session handling for debuglink
    client.close()
Exemple #10
0
def setup_device(mnemonic,
                 pin,
                 passphrase_protection,
                 label,
                 needs_backup=None):
    # TODO:
    # - check if device is acquired otherwise throws "wrong previous session" from bridge
    client = TrezorClientDebugLink(get_device())
    client.open()
    debuglink.load_device(client,
                          mnemonic,
                          pin,
                          passphrase_protection,
                          label,
                          needs_backup=bool(needs_backup))
    client.close()
Exemple #11
0
def setup_device(
    mnemonic: str,
    pin: str,
    passphrase_protection: bool,
    label: str,
    needs_backup: bool = False,
) -> None:
    # TODO: check if device is acquired, otherwise throws
    #   "wrong previous session" from bridge
    client = TrezorClientDebugLink(get_device())
    client.open()
    time.sleep(SLEEP)
    debuglink.load_device(
        client,
        mnemonic,
        pin,
        passphrase_protection,
        label,
        needs_backup=needs_backup,
    )
    client.close()
class EmulatorWrapper:
    def __init__(self, gen, tag=None, executable=None, storage=None):
        self.gen = gen
        self.tag = tag

        if executable is not None:
            self.executable = executable
        elif tag is not None:
            self.executable = filename_from_tag(gen, tag)
        else:
            self.executable = LOCAL_BUILD_PATHS[gen]

        if not os.path.exists(self.executable):
            raise ValueError(
                f"emulator executable not found: {self.executable}")

        self.workdir = tempfile.TemporaryDirectory()
        if storage:
            open(self._storage_file(), "wb").write(storage)

        with gzip.open(SD_CARD_GZ, "rb") as gz:
            with open(self.workdir.name + "/trezor.sdcard", "wb") as sd:
                sd.write(gz.read())

        self.client = None

    def _get_params_core(self):
        env = ENV.copy()
        args = [self.executable, "-m", "main"]
        # for firmware 2.1.2 and newer
        env["TREZOR_PROFILE_DIR"] = self.workdir.name
        # for firmware 2.1.1 and older
        env["TREZOR_PROFILE"] = self.workdir.name

        if self.executable == LOCAL_BUILD_PATHS["core"]:
            cwd = ROOT + "/core/src"
        else:
            cwd = self.workdir.name

        return env, args, cwd

    def _get_params_legacy(self):
        env = ENV.copy()
        args = [self.executable]
        cwd = self.workdir.name
        return env, args, cwd

    def _get_params(self):
        if self.gen == "core":
            return self._get_params_core()
        elif self.gen == "legacy":
            return self._get_params_legacy()
        else:
            raise ValueError("Unknown gen")

    def start(self):
        env, args, cwd = self._get_params()
        self.process = subprocess.Popen(args,
                                        cwd=cwd,
                                        env=env,
                                        stdout=open(os.devnull, "w"))

        # wait until emulator is listening
        transport = UdpTransport("127.0.0.1:21324")
        transport.open()
        for _ in range(300):
            if transport._ping():
                break
            if self.process.poll() is not None:
                self._cleanup()
                raise RuntimeError("Emulator proces died")
            time.sleep(0.1)
        else:
            # could not connect after 300 attempts * 0.1s = 30s of waiting
            self._cleanup()
            raise RuntimeError("Can't connect to emulator")
        transport.close()

        self.client = TrezorClientDebugLink(transport)
        self.client.open()
        check_version(self.tag, self.client.version)

    def stop(self):
        if self.client:
            self.client.close()
        self.process.terminate()
        try:
            self.process.wait(1)
        except subprocess.TimeoutExpired:
            self.process.kill()

    def restart(self):
        self.stop()
        self.start()

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self._cleanup()

    def _cleanup(self):
        self.stop()
        self.workdir.cleanup()

    def _storage_file(self):
        if self.gen == "legacy":
            return self.workdir.name + "/emulator.img"
        elif self.gen == "core":
            return self.workdir.name + "/trezor.flash"
        else:
            raise ValueError("Unknown gen")

    def storage(self):
        return open(self._storage_file(), "rb").read()
Exemple #13
0
def wipe_device():
    client = TrezorClientDebugLink(get_device())
    client.open()
    wipe(client)
    client.close()
Exemple #14
0
def reset_device():
    client = TrezorClientDebugLink(get_device())
    client.open()
    reset(client, skip_backup=True, pin_protection=False)
    client.close()
Exemple #15
0
class EmulatorWrapper:
    def __init__(self, gen, tag=None, executable=None, storage=None):
        self.gen = gen
        self.tag = tag

        if executable is not None:
            self.executable = executable
        elif tag is not None:
            self.executable = filename_from_tag(gen, tag)
        else:
            self.executable = LOCAL_BUILD_PATHS[gen]

        if not os.path.exists(self.executable):
            raise ValueError(
                f"emulator executable not found: {self.executable}")

        self.workdir = tempfile.TemporaryDirectory()
        if storage:
            open(self._storage_file(), "wb").write(storage)

        self.client = None

    def __enter__(self):
        args = [self.executable]
        env = ENV
        if self.gen == "core":
            args += ["-m", "main"]
            # for firmware 2.1.2 and newer
            env["TREZOR_PROFILE_DIR"] = self.workdir.name
            # for firmware 2.1.1 and older
            env["TREZOR_PROFILE"] = self.workdir.name
        self.process = subprocess.Popen(args,
                                        cwd=self.workdir.name,
                                        env=env,
                                        stdout=open(os.devnull, "w"))
        # wait until emulator is listening
        for _ in range(300):
            try:
                time.sleep(0.1)
                transport = get_transport("udp:127.0.0.1:21324")
                break
            except TransportException:
                pass
            if self.process.poll() is not None:
                self._cleanup()
                raise RuntimeError("Emulator proces died")
        else:
            # could not connect after 300 attempts * 0.1s = 30s of waiting
            self._cleanup()
            raise RuntimeError("Can't connect to emulator")

        self.client = TrezorClientDebugLink(transport)
        self.client.open()
        check_version(self.tag, self.client.version)
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self._cleanup()
        return False

    def _cleanup(self):
        if self.client:
            self.client.close()
        self.process.terminate()
        try:
            self.process.wait(1)
        except subprocess.TimeoutExpired:
            self.process.kill()
        self.workdir.cleanup()

    def _storage_file(self):
        if self.gen == "legacy":
            return self.workdir.name + "/emulator.img"
        elif self.gen == "core":
            return self.workdir.name + "/trezor.flash"
        else:
            raise ValueError("Unknown gen")

    def storage(self):
        return open(self._storage_file(), "rb").read()
Exemple #16
0
def reset_device() -> None:
    client = TrezorClientDebugLink(get_device())
    client.open()
    time.sleep(SLEEP)
    device.reset(client, skip_backup=True, pin_protection=False)
    client.close()
Exemple #17
0
def wipe_device() -> None:
    client = TrezorClientDebugLink(get_device())
    client.open()
    time.sleep(SLEEP)
    device.wipe(client)
    client.close()
Exemple #18
0
class Emulator:
    STORAGE_FILENAME = None

    def __init__(self,
                 executable,
                 profile_dir,
                 *,
                 logfile=None,
                 storage=None,
                 headless=False,
                 debug=True,
                 extra_args=()):
        self.executable = Path(executable).resolve()
        if not executable.exists():
            raise ValueError("emulator executable not found: {}".format(
                self.executable))

        self.profile_dir = Path(profile_dir).resolve()
        if not self.profile_dir.exists():
            self.profile_dir.mkdir(parents=True)
        elif not self.profile_dir.is_dir():
            raise ValueError("profile_dir is not a directory")

        self.workdir = self.profile_dir

        self.storage = self.profile_dir / self.STORAGE_FILENAME
        if storage:
            self.storage.write_bytes(storage)

        if logfile:
            self.logfile = logfile
        else:
            self.logfile = self.profile_dir / "trezor.log"

        self.client = None
        self.process = None

        self.port = 21324
        self.headless = headless
        self.debug = debug
        self.extra_args = list(extra_args)

    def make_args(self):
        return []

    def make_env(self):
        return os.environ.copy()

    def _get_transport(self):
        return UdpTransport("127.0.0.1:{}".format(self.port))

    def wait_until_ready(self, timeout=30):
        transport = self._get_transport()
        transport.open()
        start = time.monotonic()
        try:
            while True:
                if transport._ping():
                    break
                if self.process.poll() is not None:
                    raise RuntimeError("Emulator proces died")

                elapsed = time.monotonic() - start
                if elapsed >= timeout:
                    raise TimeoutError("Can't connect to emulator")

                time.sleep(0.1)
        finally:
            transport.close()

    def wait(self, timeout=None):
        ret = self.process.wait(timeout=None)
        self.stop()
        return ret

    def launch_process(self):
        args = self.make_args()
        env = self.make_env()

        if hasattr(self.logfile, "write"):
            output = self.logfile
        else:
            output = open(self.logfile, "w")

        return subprocess.Popen(
            [self.executable] + args + self.extra_args,
            cwd=self.workdir,
            stdout=output,
            stderr=subprocess.STDOUT,
            env=env,
        )

    def start(self):
        if self.process:
            if self.process.poll() is not None:
                # process has died, stop and start again
                self.stop()
            else:
                # process is running, no need to start again
                return

        self.process = self.launch_process()
        try:
            self.wait_until_ready()
        except TimeoutError:
            # Assuming that after the default 30-second timeout, the process is stuck
            self.process.kill()
            raise

        (self.profile_dir /
         "trezor.pid").write_text(str(self.process.pid) + "\n")
        (self.profile_dir / "trezor.port").write_text(str(self.port) + "\n")

        transport = self._get_transport()
        self.client = TrezorClientDebugLink(transport,
                                            auto_interact=self.debug)

        self.client.open()

    def stop(self):
        if self.client:
            self.client.close()
        self.client = None

        if self.process:
            self.process.terminate()
            try:
                self.process.wait(1)
            except subprocess.TimeoutExpired:
                self.process.kill()

        _rm_f(self.profile_dir / "trezor.pid")
        _rm_f(self.profile_dir / "trezor.port")
        self.process = None

    def restart(self):
        self.stop()
        self.start()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.stop()

    def get_storage(self):
        return self.storage.read_bytes()
Exemple #19
0
def client(request: pytest.FixtureRequest,
           _raw_client: Client) -> Generator[Client, None, None]:
    """Client fixture.

    Every test function that requires a client instance will get it from here.
    If we can't connect to a debuggable device, the test will fail.
    If 'skip_t2' is used and TT is connected, the test is skipped. Vice versa with T1
    and 'skip_t1'.

    The client instance is wiped and preconfigured with "all all all..." mnemonic, no
    password and no pin. It is possible to customize this with the `setup_client`
    marker.

    To specify a custom mnemonic and/or custom pin and/or enable passphrase:

    @pytest.mark.setup_client(mnemonic=MY_MNEMONIC, pin="9999", passphrase=True)

    To receive a client instance that was not initialized:

    @pytest.mark.setup_client(uninitialized=True)
    """
    if request.node.get_closest_marker(
            "skip_t2") and _raw_client.features.model == "T":
        pytest.skip("Test excluded on Trezor T")
    if request.node.get_closest_marker(
            "skip_t1") and _raw_client.features.model == "1":
        pytest.skip("Test excluded on Trezor 1")

    sd_marker = request.node.get_closest_marker("sd_card")
    if sd_marker and not _raw_client.features.sd_card_present:
        raise RuntimeError("This test requires SD card.\n"
                           "To skip all such tests, run:\n"
                           "  pytest -m 'not sd_card' <test path>")

    test_ui = request.config.getoption("ui")

    _raw_client.reset_debug_features()
    _raw_client.open()
    try:
        _raw_client.init_device()
    except Exception:
        request.session.shouldstop = "Failed to communicate with Trezor"
        pytest.fail("Failed to communicate with Trezor")

    if test_ui:
        # we need to reseed before the wipe
        _raw_client.debug.reseed(0)

    if sd_marker:
        should_format = sd_marker.kwargs.get("formatted", True)
        _raw_client.debug.erase_sd_card(format=should_format)

    wipe_device(_raw_client)

    setup_params = dict(
        uninitialized=False,
        mnemonic=" ".join(["all"] * 12),
        pin=None,
        passphrase=False,
        needs_backup=False,
        no_backup=False,
    )

    marker = request.node.get_closest_marker("setup_client")
    if marker:
        setup_params.update(marker.kwargs)

    use_passphrase = setup_params["passphrase"] is True or isinstance(
        setup_params["passphrase"], str)

    if not setup_params["uninitialized"]:
        debuglink.load_device(
            _raw_client,
            mnemonic=setup_params["mnemonic"],
            pin=setup_params["pin"],
            passphrase_protection=use_passphrase,
            label="test",
            language="en-US",
            needs_backup=setup_params["needs_backup"],
            no_backup=setup_params["no_backup"],
        )

        if _raw_client.features.model == "T":
            apply_settings(_raw_client, experimental_features=True)

        if use_passphrase and isinstance(setup_params["passphrase"], str):
            _raw_client.use_passphrase(setup_params["passphrase"])

        _raw_client.clear_session()

    if test_ui:
        with ui_tests.screen_recording(_raw_client, request):
            yield _raw_client
    else:
        yield _raw_client

    _raw_client.close()