diff --git a/l10n/messages.pot b/l10n/messages.pot index 080ca8a1..b87cb99b 100644 --- a/l10n/messages.pot +++ b/l10n/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: seedsigner 0.8.6\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2025-11-21 14:39-0600\n" +"POT-Creation-Date: 2025-12-14 05:46-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -597,6 +597,10 @@ msgstr "" msgid "Next {}" msgstr "" +#: src/seedsigner/hardware/camera.py +msgid "Camera error. Check camera connections." +msgstr "" + #: src/seedsigner/models/settings_definition.py msgid "Enabled" msgstr "" @@ -613,6 +617,21 @@ msgstr "" msgid "Required" msgstr "" +#. QR code format option; "default" = this is the format most wallets use +#: src/seedsigner/models/settings_definition.py +msgid "Animated (default)" +msgstr "" + +#. QR code format option (static = single frame, not animated) +#: src/seedsigner/models/settings_definition.py +msgid "Static" +msgstr "" + +#. QR code format option: old format that Specter Desktop used to use +#: src/seedsigner/models/settings_definition.py +msgid "Specter legacy" +msgstr "" + #: src/seedsigner/models/settings_definition.py msgid "BTC" msgstr "" @@ -718,10 +737,6 @@ msgstr "" msgid "Persistent settings" msgstr "" -#: src/seedsigner/models/settings_definition.py -msgid "Coordinator software" -msgstr "" - #: src/seedsigner/models/settings_definition.py msgid "Denomination display" msgstr "" @@ -746,6 +761,10 @@ msgstr "" msgid "Script types" msgstr "" +#: src/seedsigner/models/settings_definition.py +msgid "Xpub QR format" +msgstr "" + #: src/seedsigner/models/settings_definition.py msgid "Show xpub details" msgstr "" @@ -853,7 +872,7 @@ msgid "" "addresses." msgstr "" -#: src/seedsigner/views/psbt_views.py +#: src/seedsigner/views/psbt_views.py src/seedsigner/views/view.py msgid "Continue" msgstr "" @@ -1003,9 +1022,8 @@ msgstr "" msgid "QRCode is invalid or is a data format not yet supported." msgstr "" -#: src/seedsigner/views/scan_views.py src/seedsigner/views/seed_views.py -#: src/seedsigner/views/view.py -msgid "Done" +#: src/seedsigner/views/scan_views.py src/seedsigner/views/view.py +msgid "Back to Main Menu" msgstr "" #. This is on the opening splash screen, displayed above the HRF logo @@ -1074,6 +1092,10 @@ msgstr "" msgid "Checksum failure; not a valid seed phrase." msgstr "" +#: src/seedsigner/views/seed_views.py +msgid "Done" +msgstr "" + #: src/seedsigner/views/seed_views.py msgid "Edit passphrase" msgstr "" @@ -1159,6 +1181,10 @@ msgstr "" msgid "Export Xpub" msgstr "" +#: src/seedsigner/views/seed_views.py +msgid "Xpub QR Format" +msgstr "" + #: src/seedsigner/views/seed_views.py msgid "Xpub can be used to view all future transactions." msgstr "" @@ -1321,10 +1347,6 @@ msgstr "" msgid "Cancel" msgstr "" -#: src/seedsigner/views/seed_views.py -msgid "Can't validate a single sig addr without specifying a seed" -msgstr "" - #: src/seedsigner/views/seed_views.py msgid "Return to transaction" msgstr "" @@ -1518,6 +1540,18 @@ msgstr "" msgid "System Error" msgstr "" +#: src/seedsigner/views/view.py +msgid "Hardware Error" +msgstr "" + +#: src/seedsigner/views/view.py +msgid "Cannot access camera" +msgstr "" + +#: src/seedsigner/views/view.py +msgid "Disconnect power and check for a loose camera connection." +msgstr "" + #: src/seedsigner/views/view.py msgid "Update setting" msgstr "" @@ -1532,3 +1566,13 @@ msgstr "" msgid "Option Disabled" msgstr "" +#: src/seedsigner/views/view.py +msgid "Action Required" +msgstr "" + +#: src/seedsigner/views/view.py +msgid "" +"You must remove the\n" +"MicroSD card to continue." +msgstr "" + diff --git a/src/seedsigner/models/encode_qr.py b/src/seedsigner/models/encode_qr.py index 37aeb788..86be8c66 100644 --- a/src/seedsigner/models/encode_qr.py +++ b/src/seedsigner/models/encode_qr.py @@ -238,7 +238,11 @@ class BaseSimpleAnimatedQREncoder(BaseQrEncoder): @dataclass -class SpecterXPubQrEncoder(BaseSimpleAnimatedQREncoder, BaseXpubQrEncoder): +class SpecterLegacyXPubQrEncoder(BaseSimpleAnimatedQREncoder, BaseXpubQrEncoder): + """ + Legacy "pXofY" format. Included here for compatibility with much older versions of + Specter Desktop. Can probably eventually be removed. + """ @property def qr_max_fragment_size(self): density_mapping = { diff --git a/src/seedsigner/models/settings_definition.py b/src/seedsigner/models/settings_definition.py index 2a6a1d7a..42d68666 100644 --- a/src/seedsigner/models/settings_definition.py +++ b/src/seedsigner/models/settings_definition.py @@ -38,17 +38,18 @@ class SettingsConstants: ] # User-facing selection options - COORDINATOR__BLUE_WALLET = "bw" - COORDINATOR__NUNCHUK = "nun" - COORDINATOR__SPARROW = "spa" - COORDINATOR__SPECTER_DESKTOP = "spd" - COORDINATOR__KEEPER = "kpr" - ALL_COORDINATORS = [ - (COORDINATOR__BLUE_WALLET, "BlueWallet"), - (COORDINATOR__NUNCHUK, "Nunchuk"), - (COORDINATOR__SPARROW, "Sparrow"), - (COORDINATOR__SPECTER_DESKTOP, "Specter Desktop"), - (COORDINATOR__KEEPER, "Keeper"), + XPUB_QR_FORMAT__UR_CRYPTO_ACCOUNT = "urca" + XPUB_QR_FORMAT__STATIC = "sta" + XPUB_QR_FORMAT__SPECTER_LEGACY = "spl" + ALL_XPUB_QR_FORMATS = [ + # TRANSLATOR_NOTE: QR code format option; "default" = this is the format most wallets use + (XPUB_QR_FORMAT__UR_CRYPTO_ACCOUNT, _mft("Animated (default)")), + + # TRANSLATOR_NOTE: QR code format option (static = single frame, not animated) + (XPUB_QR_FORMAT__STATIC, _mft("Static")), + + # TRANSLATOR_NOTE: QR code format option: old format that Specter Desktop used to use + (XPUB_QR_FORMAT__SPECTER_LEGACY, _mft("Specter legacy")), ] # Over-specifying current and possible future locales to reduce/eliminate main repo @@ -326,7 +327,7 @@ class SettingsConstants: SETTING__LOCALE = "locale" SETTING__WORDLIST_LANGUAGE = "wordlist_language" SETTING__PERSISTENT_SETTINGS = "persistent_settings" - SETTING__COORDINATORS = "coordinators" + SETTING__XPUB_QR_FORMAT = "xpub_qr" SETTING__BTC_DENOMINATION = "denomination" SETTING__DISPLAY_CONFIGURATION = "display_config" @@ -569,19 +570,6 @@ class SettingsDefinition: help_text=SettingsConstants.PERSISTENT_SETTINGS__SD_INSERTED__HELP_TEXT, default_value=SettingsConstants.OPTION__DISABLED), - SettingsEntry(category=SettingsConstants.CATEGORY__WALLET, - attr_name=SettingsConstants.SETTING__COORDINATORS, - abbreviated_name="coords", - display_name=_mft("Coordinator software"), - type=SettingsConstants.TYPE__MULTISELECT, - selection_options=SettingsConstants.ALL_COORDINATORS, - default_value=[ - SettingsConstants.COORDINATOR__BLUE_WALLET, - SettingsConstants.COORDINATOR__NUNCHUK, - SettingsConstants.COORDINATOR__SPARROW, - SettingsConstants.COORDINATOR__SPECTER_DESKTOP, - ]), - SettingsEntry(category=SettingsConstants.CATEGORY__SYSTEM, attr_name=SettingsConstants.SETTING__BTC_DENOMINATION, abbreviated_name="denom", @@ -632,6 +620,17 @@ class SettingsDefinition: selection_options=SettingsConstants.ALL_SCRIPT_TYPES, default_value=[SettingsConstants.NATIVE_SEGWIT, SettingsConstants.NESTED_SEGWIT, SettingsConstants.TAPROOT]), + SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, + attr_name=SettingsConstants.SETTING__XPUB_QR_FORMAT, + display_name=_mft("Xpub QR format"), + visibility=SettingsConstants.VISIBILITY__ADVANCED, + type=SettingsConstants.TYPE__MULTISELECT, + selection_options=SettingsConstants.ALL_XPUB_QR_FORMATS, + default_value=[ + SettingsConstants.XPUB_QR_FORMAT__UR_CRYPTO_ACCOUNT, + SettingsConstants.XPUB_QR_FORMAT__STATIC, + ]), + SettingsEntry(category=SettingsConstants.CATEGORY__FEATURES, attr_name=SettingsConstants.SETTING__XPUB_DETAILS, display_name=_mft("Show xpub details"), diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index 175bd34c..a977767c 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -11,7 +11,7 @@ from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconCo from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen, WarningScreen, DireWarningScreen, seed_screens) from seedsigner.gui.screens.screen import ButtonOption, ButtonOptionWithoutTranslation -from seedsigner.models.encode_qr import CompactSeedQrEncoder, GenericStaticQrEncoder, SeedQrEncoder, SpecterXPubQrEncoder, StaticXpubQrEncoder, UrXpubQrEncoder +from seedsigner.models.encode_qr import CompactSeedQrEncoder, GenericStaticQrEncoder, SeedQrEncoder, SpecterLegacyXPubQrEncoder, StaticXpubQrEncoder, UrXpubQrEncoder from seedsigner.models.qr_type import QRType from seedsigner.models.seed import Seed from seedsigner.models.settings import Settings, SettingsConstants @@ -720,7 +720,7 @@ class SeedExportXpubScriptTypeView(View): del args["sig_type"] return Destination(ToolsAddressExplorerAddressTypeView, view_args=args, skip_current_view=True) else: - return Destination(SeedExportXpubCoordinatorView, view_args=args, skip_current_view=True) + return Destination(SeedExportXpubQRFormatView, view_args=args, skip_current_view=True) title = _("Export Xpub") if self.controller.resume_main_flow == Controller.FLOW__ADDRESS_EXPLORER: @@ -755,7 +755,7 @@ class SeedExportXpubScriptTypeView(View): del args["sig_type"] return Destination(ToolsAddressExplorerAddressTypeView, view_args=args) else: - return Destination(SeedExportXpubCoordinatorView, view_args=args) + return Destination(SeedExportXpubQRFormatView, view_args=args) @@ -786,7 +786,7 @@ class SeedExportXpubCustomDerivationView(View): return Destination(ToolsAddressExplorerAddressTypeView, view_args=dict(seed_num=self.seed_num, script_type=self.script_type, custom_derivation=custom_derivation)) return Destination( - SeedExportXpubCoordinatorView, + SeedExportXpubQRFormatView, view_args={ "seed_num": self.seed_num, "sig_type": self.sig_type, @@ -797,7 +797,7 @@ class SeedExportXpubCustomDerivationView(View): -class SeedExportXpubCoordinatorView(View): +class SeedExportXpubQRFormatView(View): def __init__(self, seed_num: int, sig_type: str, script_type: str, custom_derivation: str = None): super().__init__() self.seed_num = seed_num @@ -813,41 +813,39 @@ class SeedExportXpubCoordinatorView(View): "script_type": self.script_type, "custom_derivation": self.custom_derivation, } - if len(self.settings.get_value(SettingsConstants.SETTING__COORDINATORS)) == 1: + if len(self.settings.get_value(SettingsConstants.SETTING__XPUB_QR_FORMAT)) == 1: # Nothing to select; skip this screen - args["coordinator"] = self.settings.get_value(SettingsConstants.SETTING__COORDINATORS)[0] + args["xpub_qr_format"] = self.settings.get_value(SettingsConstants.SETTING__XPUB_QR_FORMAT)[0] return Destination(SeedExportXpubWarningView, view_args=args, skip_current_view=True) button_data = [] - for display_name, setting_option in zip(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS), self.settings.get_value(SettingsConstants.SETTING__COORDINATORS)): + for display_name, setting_option in zip(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__XPUB_QR_FORMAT), self.settings.get_value(SettingsConstants.SETTING__XPUB_QR_FORMAT)): button_data.append(ButtonOption(display_name, return_data=setting_option)) selected_menu_num = self.run_screen( ButtonListScreen, - title=_("Export Xpub"), + title=_("Xpub QR Format"), is_button_text_centered=False, button_data=button_data, + is_bottom_list=True, ) if selected_menu_num == RET_CODE__BACK_BUTTON: return Destination(BackStackView) - # coordinators_settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__COORDINATORS) - # selected_display_name = button_data[selected_menu_num] - # args["coordinator"] = coordinators_settings_entry.get_selection_option_value_by_display_name(selected_display_name) - args["coordinator"] = button_data[selected_menu_num].return_data + args["xpub_qr_format"] = button_data[selected_menu_num].return_data return Destination(SeedExportXpubWarningView, view_args=args) class SeedExportXpubWarningView(View): - def __init__(self, seed_num: int, sig_type: str, script_type: str, coordinator: str, custom_derivation: str): + def __init__(self, seed_num: int, sig_type: str, script_type: str, xpub_qr_format: str, custom_derivation: str): super().__init__() self.seed_num = seed_num self.sig_type = sig_type self.script_type = script_type - self.coordinator = coordinator + self.xpub_qr_format = xpub_qr_format self.custom_derivation = custom_derivation @@ -858,7 +856,7 @@ class SeedExportXpubWarningView(View): "seed_num": self.seed_num, "sig_type": self.sig_type, "script_type": self.script_type, - "coordinator": self.coordinator, + "xpub_qr_format": self.xpub_qr_format, "custom_derivation": self.custom_derivation, }, skip_current_view=True, # Prevent going BACK to WarningViews @@ -888,11 +886,11 @@ class SeedExportXpubDetailsView(View): Collects the user input from all the previous screens leading up to this and finally calculates the xpub and displays the summary view to the user. """ - def __init__(self, seed_num: int, sig_type: str, script_type: str, coordinator: str, custom_derivation: str): + def __init__(self, seed_num: int, sig_type: str, script_type: str, xpub_qr_format: str, custom_derivation: str): super().__init__() self.sig_type = sig_type self.script_type = script_type - self.coordinator = coordinator + self.xpub_qr_format = xpub_qr_format self.custom_derivation = custom_derivation self.seed_num = seed_num @@ -955,7 +953,7 @@ class SeedExportXpubDetailsView(View): return Destination( SeedExportXpubQRDisplayView, dict(seed_num=self.seed_num, - coordinator=self.coordinator, + xpub_qr_format=self.xpub_qr_format, derivation_path=derivation_path, sig_type=self.sig_type ) @@ -967,7 +965,7 @@ class SeedExportXpubDetailsView(View): class SeedExportXpubQRDisplayView(View): - def __init__(self, seed_num: int, coordinator: str, derivation_path: str, sig_type: str = SettingsConstants.SINGLE_SIG): + def __init__(self, seed_num: int, xpub_qr_format: str, derivation_path: str, sig_type: str = SettingsConstants.SINGLE_SIG): super().__init__() self.seed = self.controller.get_seed(seed_num) @@ -979,14 +977,14 @@ class SeedExportXpubQRDisplayView(View): sig_type=sig_type ) - if coordinator == SettingsConstants.COORDINATOR__SPECTER_DESKTOP: - self.qr_encoder = SpecterXPubQrEncoder(**encoder_args) - - elif coordinator in [SettingsConstants.COORDINATOR__BLUE_WALLET, - SettingsConstants.COORDINATOR__KEEPER]: + if xpub_qr_format == SettingsConstants.XPUB_QR_FORMAT__STATIC: self.qr_encoder = StaticXpubQrEncoder(**encoder_args) + elif xpub_qr_format == SettingsConstants.XPUB_QR_FORMAT__SPECTER_LEGACY: + self.qr_encoder = SpecterLegacyXPubQrEncoder(**encoder_args) + else: + # Default: UR crypto-address self.qr_encoder = UrXpubQrEncoder(**encoder_args) diff --git a/tests/screenshot_generator/generator.py b/tests/screenshot_generator/generator.py index e45373fc..209fb321 100644 --- a/tests/screenshot_generator/generator.py +++ b/tests/screenshot_generator/generator.py @@ -237,8 +237,8 @@ def generate_screenshots(locale): ) add_settings_entries(SettingsConstants.VISIBILITY__HARDWARE) - settingsqr_data_persistent = f"settings::v1 name=English_noob_mode persistent=E coords=spa,spd denom=thr network=M qr_density=M xpub_export=E sigs=ss scripts=nat xpub_details=E passphrase=E camera=0 compact_seedqr=E bip85=D priv_warn=E dire_warn=E partners=E locale={locale}" - settingsqr_data_not_persistent = f"settings::v1 name=Mode_Ephemeral persistent=D coords=spa,spd denom=thr network=M qr_density=M xpub_export=E sigs=ss scripts=nat xpub_details=E passphrase=E camera=0 compact_seedqr=E bip85=D priv_warn=E dire_warn=E partners=E locale={locale}" + settingsqr_data_persistent = f"settings::v1 name=English_noob_mode persistent=E xpub_qr=urca,sta denom=thr network=M qr_density=M xpub_export=E sigs=ss scripts=nat xpub_details=E passphrase=E camera=0 compact_seedqr=E bip85=D priv_warn=E dire_warn=E partners=E locale={locale}" + settingsqr_data_not_persistent = f"settings::v1 name=Mode_Ephemeral persistent=D xpub_qr=urca,sta denom=thr network=M qr_density=M xpub_export=E sigs=ss scripts=nat xpub_details=E passphrase=E camera=0 compact_seedqr=E bip85=D priv_warn=E dire_warn=E partners=E locale={locale}" # Set up screenshot-specific callbacks to inject data before the View is run and # reset data after the View is run. @@ -334,10 +334,10 @@ def generate_screenshots(locale): ScreenshotConfig(seed_views.SeedExportXpubSigTypeView, dict(seed_num=0)), ScreenshotConfig(seed_views.SeedExportXpubScriptTypeView, dict(seed_num=0, sig_type="msig")), ScreenshotConfig(seed_views.SeedExportXpubCustomDerivationView, dict(seed_num=0, sig_type="ss", script_type="")), - ScreenshotConfig(seed_views.SeedExportXpubCoordinatorView, dict(seed_num=0, sig_type="ss", script_type="nat")), - ScreenshotConfig(seed_views.SeedExportXpubWarningView, dict(seed_num=0, sig_type="msig", script_type="nes", coordinator="spd", custom_derivation="")), - ScreenshotConfig(seed_views.SeedExportXpubDetailsView, dict(seed_num=0, sig_type="ss", script_type="nat", coordinator="bw", custom_derivation="")), - ScreenshotConfig(SeedExportXpubQR_ScreenBrightnessView, dict(seed_num=0, coordinator="bw", derivation_path="m/84'/0'/0'")), + ScreenshotConfig(seed_views.SeedExportXpubQRFormatView, dict(seed_num=0, sig_type="ss", script_type="nat")), + ScreenshotConfig(seed_views.SeedExportXpubWarningView, dict(seed_num=0, sig_type="msig", script_type="nes", xpub_qr_format="urca", custom_derivation="")), + ScreenshotConfig(seed_views.SeedExportXpubDetailsView, dict(seed_num=0, sig_type="ss", script_type="nat", xpub_qr_format="urca", custom_derivation="")), + ScreenshotConfig(SeedExportXpubQR_ScreenBrightnessView, dict(seed_num=0, xpub_qr_format="urca", derivation_path="m/84'/0'/0'")), ScreenshotConfig(seed_views.SeedWordsWarningView, dict(seed_num=0)), ScreenshotConfig(seed_views.SeedWordsView, dict(seed_num=0)), diff --git a/tests/test_controller.py b/tests/test_controller.py index 0be99d0d..f414dc89 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -4,7 +4,6 @@ import pytest from base import BaseTest from seedsigner.controller import Controller -from seedsigner.models.settings_definition import SettingsConstants class TestController(BaseTest): @@ -80,38 +79,3 @@ class TestController(BaseTest): # ...get a new copy of the instance and confirm change controller = Controller.get_instance() assert controller.unverified_address == "123abc" - - - def test_missing_settings_get_defaults(self): - """ Should gracefully handle all missing fields from `settings.json` """ - - controller = Controller.get_instance() - - # Settings defaults - assert controller.settings.get_value(SettingsConstants.SETTING__LOCALE) == SettingsConstants.LOCALE__ENGLISH - assert controller.settings.get_value(SettingsConstants.SETTING__WORDLIST_LANGUAGE) == SettingsConstants.WORDLIST_LANGUAGE__ENGLISH - assert controller.settings.get_value(SettingsConstants.SETTING__PERSISTENT_SETTINGS) == SettingsConstants.OPTION__DISABLED - assert controller.settings.get_value(SettingsConstants.SETTING__COORDINATORS) == [i for i,j in SettingsConstants.ALL_COORDINATORS if i!="kpr"] - assert controller.settings.get_value(SettingsConstants.SETTING__BTC_DENOMINATION) == SettingsConstants.BTC_DENOMINATION__THRESHOLD - - # Advanced Settings defaults - assert controller.settings.get_value(SettingsConstants.SETTING__NETWORK) == SettingsConstants.MAINNET - assert controller.settings.get_value(SettingsConstants.SETTING__QR_DENSITY) == SettingsConstants.DENSITY__MEDIUM - assert controller.settings.get_value(SettingsConstants.SETTING__XPUB_EXPORT) == SettingsConstants.OPTION__ENABLED - assert controller.settings.get_value(SettingsConstants.SETTING__SIG_TYPES) == [i for i,j in SettingsConstants.ALL_SIG_TYPES] - assert controller.settings.get_value(SettingsConstants.SETTING__SCRIPT_TYPES) == [SettingsConstants.NATIVE_SEGWIT, SettingsConstants.NESTED_SEGWIT, SettingsConstants.TAPROOT] - assert controller.settings.get_value(SettingsConstants.SETTING__XPUB_DETAILS) == SettingsConstants.OPTION__ENABLED - assert controller.settings.get_value(SettingsConstants.SETTING__PASSPHRASE) == SettingsConstants.OPTION__ENABLED - assert controller.settings.get_value(SettingsConstants.SETTING__CAMERA_ROTATION) == SettingsConstants.CAMERA_ROTATION__180 - assert controller.settings.get_value(SettingsConstants.SETTING__COMPACT_SEEDQR) == SettingsConstants.OPTION__ENABLED - assert controller.settings.get_value(SettingsConstants.SETTING__BIP85_CHILD_SEEDS) == SettingsConstants.OPTION__DISABLED - assert controller.settings.get_value(SettingsConstants.SETTING__MESSAGE_SIGNING) == SettingsConstants.OPTION__DISABLED - assert controller.settings.get_value(SettingsConstants.SETTING__PRIVACY_WARNINGS) == SettingsConstants.OPTION__ENABLED - assert controller.settings.get_value(SettingsConstants.SETTING__DIRE_WARNINGS) == SettingsConstants.OPTION__ENABLED - assert controller.settings.get_value(SettingsConstants.SETTING__QR_BRIGHTNESS_TIPS) == SettingsConstants.OPTION__ENABLED - assert controller.settings.get_value(SettingsConstants.SETTING__PARTNER_LOGOS) == SettingsConstants.OPTION__ENABLED - assert controller.settings.get_value(SettingsConstants.SETTING__MICROSD_TOAST_TIMER) == SettingsConstants.MICROSD_TOAST_TIMER_FIVE_SECONDS - - # Hidden Settings defaults - assert controller.settings.get_value(SettingsConstants.SETTING__QR_BRIGHTNESS) == 62 - diff --git a/tests/test_encodepsbtqr.py b/tests/test_encodepsbtqr.py index 2d864c12..3b33c0c3 100644 --- a/tests/test_encodepsbtqr.py +++ b/tests/test_encodepsbtqr.py @@ -1,4 +1,4 @@ -from seedsigner.models.encode_qr import CompactSeedQrEncoder, SeedQrEncoder, SpecterXPubQrEncoder, StaticXpubQrEncoder, UrPsbtQrEncoder, UrXpubQrEncoder +from seedsigner.models.encode_qr import CompactSeedQrEncoder, SeedQrEncoder, SpecterLegacyXPubQrEncoder, StaticXpubQrEncoder, UrPsbtQrEncoder, UrXpubQrEncoder from embit import psbt from binascii import a2b_base64 @@ -54,7 +54,7 @@ def test_xpub_qr(): def test_specter_xpub_qr(): mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash" - e = SpecterXPubQrEncoder(seed=Seed(mnemonic.split(" "), passphrase="pass"), network=SettingsConstants.TESTNET, derivation="m/48h/1h/0h/2h", qr_density=SettingsConstants.DENSITY__LOW) + e = SpecterLegacyXPubQrEncoder(seed=Seed(mnemonic.split(" "), passphrase="pass"), network=SettingsConstants.TESTNET, derivation="m/48h/1h/0h/2h", qr_density=SettingsConstants.DENSITY__LOW) assert e.next_part() == "p1of4 [c49122a5/48h/1h/0h/2h]Vpub5mXgECaX5yYDN" assert e.next_part() == "p2of4 c5VnUG4jVNptyEg65qUjuofWchQeuMWWiq8rcPBo" diff --git a/tests/test_flows_seed.py b/tests/test_flows_seed.py index 2b2339f1..29fe379b 100644 --- a/tests/test_flows_seed.py +++ b/tests/test_flows_seed.py @@ -195,7 +195,7 @@ class TestSeedFlows(FlowTest): FlowStep(seed_views.SeedOptionsView, button_data_selection=seed_views.SeedOptionsView.EXPORT_XPUB), FlowStep(seed_views.SeedExportXpubSigTypeView, button_data_selection=sig_selection), FlowStep(seed_views.SeedExportXpubScriptTypeView, button_data_selection=ButtonOption(script_tuple[1], return_data=script_tuple[0])), - FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=ButtonOption(coord_tuple[1], return_data=coord_tuple[0])), + FlowStep(seed_views.SeedExportXpubQRFormatView, button_data_selection=ButtonOption(coord_tuple[1], return_data=coord_tuple[0])), FlowStep(seed_views.SeedExportXpubWarningView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubDetailsView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0), @@ -211,17 +211,17 @@ class TestSeedFlows(FlowTest): # these are lists of (constant_value, display_name) tuples sig_types: list[tuple[str, str]] = SettingsConstants.ALL_SIG_TYPES script_types: list[tuple[str, str]] = SettingsConstants.ALL_SCRIPT_TYPES - coordinators: list[tuple[str, str]] = SettingsConstants.ALL_COORDINATORS + xpub_qr_formats: list[tuple[str, str]] = SettingsConstants.ALL_XPUB_QR_FORMATS # enable non-defaults so they're available in views self.settings.set_value(SettingsConstants.SETTING__SIG_TYPES, [x for x,y in sig_types]) self.settings.set_value(SettingsConstants.SETTING__SCRIPT_TYPES, [x for x,y in script_types]) - self.settings.set_value(SettingsConstants.SETTING__COORDINATORS, [x for x,y in coordinators]) + self.settings.set_value(SettingsConstants.SETTING__XPUB_QR_FORMAT, [x for x,y in xpub_qr_formats]) - # exhaustively test flows thru standard sig_types, script_types, and coordinators + # exhaustively test flows thru standard sig_types, script_types, and xpub_qr_formats for sig_tuple in sig_types: for script_tuple in script_types: - for coord_tuple in coordinators: + for coord_tuple in xpub_qr_formats: # skip custom derivation if script_tuple[0] == SettingsConstants.CUSTOM_DERIVATION: continue @@ -245,17 +245,17 @@ class TestSeedFlows(FlowTest): # these are lists of (constant_value, display_name) tuples sig_types: list[tuple[str, str]] = SettingsConstants.ALL_SIG_TYPES script_types: list[tuple[str, str]] = SettingsConstants.ALL_SCRIPT_TYPES - coordinators: list[tuple[str, str]] = SettingsConstants.ALL_COORDINATORS + xpub_qr_formats: list[tuple[str, str]] = SettingsConstants.ALL_XPUB_QR_FORMATS # these are the disabled types that we will be testing disabled_sig = SettingsConstants.MULTISIG disabled_script = SettingsConstants.TAPROOT - disabled_coord = SettingsConstants.COORDINATOR__NUNCHUK + disabled_xpub_qr_format = SettingsConstants.XPUB_QR_FORMAT__SPECTER_LEGACY # enable all but our target disabled type self.settings.set_value(SettingsConstants.SETTING__SIG_TYPES, [x for x,y in sig_types if x!=disabled_sig]) self.settings.set_value(SettingsConstants.SETTING__SCRIPT_TYPES, [x for x,y in script_types if x!=disabled_script]) - self.settings.set_value(SettingsConstants.SETTING__COORDINATORS, [x for x,y in coordinators if x!=disabled_coord]) + self.settings.set_value(SettingsConstants.SETTING__XPUB_QR_FORMAT, [x for x,y in xpub_qr_formats if x!=disabled_xpub_qr_format]) # If multisig isn't an option, then the sig type selection is skipped altogether self.run_sequence( @@ -286,7 +286,7 @@ class TestSeedFlows(FlowTest): FlowStep(seed_views.SeedOptionsView, button_data_selection=seed_views.SeedOptionsView.EXPORT_XPUB), FlowStep(seed_views.SeedExportXpubSigTypeView, is_redirect=True), FlowStep(seed_views.SeedExportXpubScriptTypeView, screen_return_value=0), - FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=disabled_coord), + FlowStep(seed_views.SeedExportXpubQRFormatView, button_data_selection=disabled_xpub_qr_format), ] ) @@ -307,8 +307,8 @@ class TestSeedFlows(FlowTest): SettingsConstants.CUSTOM_DERIVATION ]) - # Ensure that all coordinators are enabled - self.settings.set_value(SettingsConstants.SETTING__COORDINATORS, [x for x, y in SettingsConstants.ALL_COORDINATORS]) + # Ensure that all xpub_qr_formats are enabled + self.settings.set_value(SettingsConstants.SETTING__XPUB_QR_FORMAT, [x for x, y in SettingsConstants.ALL_XPUB_QR_FORMATS]) # Set up button_data selections sig_type = seed_views.SeedExportXpubSigTypeView.SINGLE_SIG @@ -316,9 +316,9 @@ class TestSeedFlows(FlowTest): custom_derivation = SettingsConstants.CUSTOM_DERIVATION script_type = ButtonOption(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__SCRIPT_TYPES)[2], return_data=custom_derivation) - specter = SettingsConstants.COORDINATOR__SPECTER_DESKTOP - assert SettingsConstants.ALL_COORDINATORS[3][0] == specter - coordinator = ButtonOption(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS)[3], return_data=specter) + specter_legacy = SettingsConstants.XPUB_QR_FORMAT__SPECTER_LEGACY + assert SettingsConstants.ALL_XPUB_QR_FORMATS[2][0] == specter_legacy + xpub_qr_format = ButtonOption(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__XPUB_QR_FORMAT)[2], return_data=specter_legacy) self.run_sequence( initial_destination_view_args=dict(seed_num=0), @@ -327,7 +327,7 @@ class TestSeedFlows(FlowTest): FlowStep(seed_views.SeedExportXpubSigTypeView, button_data_selection=sig_type), FlowStep(seed_views.SeedExportXpubScriptTypeView, button_data_selection=script_type), FlowStep(seed_views.SeedExportXpubCustomDerivationView, screen_return_value="m/0'/0'"), - FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=coordinator), + FlowStep(seed_views.SeedExportXpubQRFormatView, button_data_selection=xpub_qr_format), FlowStep(seed_views.SeedExportXpubWarningView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubDetailsView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0), @@ -338,18 +338,18 @@ class TestSeedFlows(FlowTest): def test_export_xpub_skip_non_option_flow(self): """ - Export XPUB flows w/o user choices when no other options for sig_types, script_types, and/or coordinators + Export XPUB flows w/o user choices when no other options for sig_types, script_types, and/or xpub_qr_formats """ # Load a finalized Seed into the Controller mnemonic = "blush twice taste dawn feed second opinion lazy thumb play neglect impact".split() self.controller.storage.set_pending_seed(Seed(mnemonic=mnemonic)) self.controller.storage.finalize_pending_seed() - # exclusively set only one choice for each of sig_types, script_types and coordinators + # exclusively set only one choice for each of sig_types, script_types and xpub_qr_formats self.settings.update({ SettingsConstants.SETTING__SIG_TYPES: SettingsConstants.MULTISIG, SettingsConstants.SETTING__SCRIPT_TYPES: SettingsConstants.NESTED_SEGWIT, - SettingsConstants.SETTING__COORDINATORS: SettingsConstants.COORDINATOR__SPECTER_DESKTOP, + SettingsConstants.SETTING__XPUB_QR_FORMAT: SettingsConstants.XPUB_QR_FORMAT__UR_CRYPTO_ACCOUNT, }) self.run_sequence( @@ -358,7 +358,7 @@ class TestSeedFlows(FlowTest): FlowStep(seed_views.SeedOptionsView, button_data_selection=seed_views.SeedOptionsView.EXPORT_XPUB), FlowStep(seed_views.SeedExportXpubSigTypeView, is_redirect=True), FlowStep(seed_views.SeedExportXpubScriptTypeView, is_redirect=True), - FlowStep(seed_views.SeedExportXpubCoordinatorView, is_redirect=True), + FlowStep(seed_views.SeedExportXpubQRFormatView, is_redirect=True), FlowStep(seed_views.SeedExportXpubWarningView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubDetailsView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0), @@ -379,7 +379,7 @@ class TestSeedFlows(FlowTest): # Make sure all options are enabled self.settings.set_value(SettingsConstants.SETTING__SIG_TYPES, [x for x,y in SettingsConstants.ALL_SIG_TYPES]) self.settings.set_value(SettingsConstants.SETTING__SCRIPT_TYPES, [x for x,y in SettingsConstants.ALL_SCRIPT_TYPES]) - self.settings.set_value(SettingsConstants.SETTING__COORDINATORS, [x for x,y in SettingsConstants.ALL_COORDINATORS]) + self.settings.set_value(SettingsConstants.SETTING__XPUB_QR_FORMAT, [x for x,y in SettingsConstants.ALL_XPUB_QR_FORMATS]) self.run_sequence( initial_destination_view_args=dict(seed_num=0), @@ -389,7 +389,7 @@ class TestSeedFlows(FlowTest): # Skips past the script type options via redirect FlowStep(seed_views.SeedExportXpubScriptTypeView, is_redirect=True), - FlowStep(seed_views.SeedExportXpubCoordinatorView, button_data_selection=ButtonOption(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__COORDINATORS)[0], return_data=SettingsConstants.ALL_COORDINATORS[0][0])), + FlowStep(seed_views.SeedExportXpubQRFormatView, button_data_selection=ButtonOption(self.settings.get_multiselect_value_display_names(SettingsConstants.SETTING__XPUB_QR_FORMAT)[0], return_data=SettingsConstants.ALL_XPUB_QR_FORMATS[0][0])), FlowStep(seed_views.SeedExportXpubWarningView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubDetailsView, screen_return_value=0), FlowStep(seed_views.SeedExportXpubQRDisplayView, screen_return_value=0), diff --git a/tests/test_flows_settings.py b/tests/test_flows_settings.py index 37adf006..ac2381a2 100644 --- a/tests/test_flows_settings.py +++ b/tests/test_flows_settings.py @@ -39,10 +39,11 @@ class TestSettingsFlows(FlowTest): def test_multiselect(self): """ Multiselect Settings options should stay in-place; requires BACK to exit. """ # Which option are we testing? - settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__COORDINATORS) + settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__XPUB_QR_FORMAT) self.run_sequence([ FlowStep(MainMenuView, button_data_selection=MainMenuView.SETTINGS), + FlowStep(settings_views.SettingsMenuView, button_data_selection=settings_views.SettingsMenuView.ADVANCED), FlowStep(settings_views.SettingsMenuView, button_data_selection=ButtonOption(settings_entry.display_name)), FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=0), # select/deselect first option FlowStep(settings_views.SettingsEntryUpdateSelectionView, screen_return_value=1), # select/deselect second option diff --git a/tests/test_settings.py b/tests/test_settings.py index 94ac626a..7b4a3cfb 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,7 +1,7 @@ import pytest from base import BaseTest from seedsigner.models.settings import InvalidSettingsQRData, Settings -from seedsigner.models.settings_definition import SettingsConstants +from seedsigner.models.settings_definition import SettingsConstants, SettingsDefinition @@ -14,6 +14,10 @@ class TestSettings(BaseTest): def test_reset_settings(self): """ BaseTest.reset_settings() should wipe out any previous Settings changes """ + settings_entry = SettingsDefinition.get_settings_entry(SettingsConstants.SETTING__PERSISTENT_SETTINGS) + assert settings_entry.default_value == SettingsConstants.OPTION__DISABLED + + # Change the setting from its default settings = Settings.get_instance() settings.set_value(SettingsConstants.SETTING__PERSISTENT_SETTINGS, SettingsConstants.OPTION__ENABLED) assert settings.get_value(SettingsConstants.SETTING__PERSISTENT_SETTINGS) == SettingsConstants.OPTION__ENABLED @@ -23,18 +27,26 @@ class TestSettings(BaseTest): assert settings.get_value(SettingsConstants.SETTING__PERSISTENT_SETTINGS) == SettingsConstants.OPTION__DISABLED + def test_settings_defaults(self): + """ Settings should initialize to their default values """ + BaseTest.reset_settings() + settings = Settings.get_instance() + for settings_entry in SettingsDefinition.get_settings_entries(): + assert settings.get_value(settings_entry.attr_name) == settings_entry.default_value + + def test_parse_settingsqr_data(self): """ SettingsQR parser should successfully parse a valid settingsqr input string and return the resulting config_name and formatted settings_update_dict. """ settings_name = "Test SettingsQR" - settingsqr_data = f"""settings::v1 name={ settings_name.replace(" ", "_") } persistent=D coords=spa,spd denom=thr network=M qr_density=M xpub_export=E sigs=ss,ms scripts=nat,nes,tr xpub_details=E passphrase=E camera=180 compact_seedqr=E bip85=D priv_warn=E dire_warn=E partners=E""" + settingsqr_data = f"""settings::v1 name={ settings_name.replace(" ", "_") } persistent=D coords=spa,spd denom=thr network=M qr_density=M xpub_export=E sigs=ss,ms scripts=nat,nes,tr xpub_qr=urca,sta xpub_details=E passphrase=E camera=180 compact_seedqr=E bip85=D priv_warn=E dire_warn=E partners=E""" # First explicitly set settings that differ from the settingsqr_data self.settings.set_value(SettingsConstants.SETTING__COMPACT_SEEDQR, SettingsConstants.OPTION__DISABLED) self.settings.set_value(SettingsConstants.SETTING__DIRE_WARNINGS, SettingsConstants.OPTION__DISABLED) - self.settings.set_value(SettingsConstants.SETTING__COORDINATORS, [SettingsConstants.COORDINATOR__BLUE_WALLET, SettingsConstants.COORDINATOR__SPARROW]) + self.settings.set_value(SettingsConstants.SETTING__XPUB_QR_FORMAT, [SettingsConstants.XPUB_QR_FORMAT__STATIC, SettingsConstants.XPUB_QR_FORMAT__SPECTER_LEGACY]) # Now parse the settingsqr_data config_name, settings_update_dict = Settings.parse_settingsqr(settingsqr_data) @@ -45,10 +57,10 @@ class TestSettings(BaseTest): assert self.settings.get_value(SettingsConstants.SETTING__COMPACT_SEEDQR) == SettingsConstants.OPTION__ENABLED assert self.settings.get_value(SettingsConstants.SETTING__DIRE_WARNINGS) == SettingsConstants.OPTION__ENABLED - coordinators = self.settings.get_value(SettingsConstants.SETTING__COORDINATORS) - assert SettingsConstants.COORDINATOR__BLUE_WALLET not in coordinators - assert SettingsConstants.COORDINATOR__SPARROW in coordinators - assert SettingsConstants.COORDINATOR__SPECTER_DESKTOP in coordinators + xpub_qr_formats = self.settings.get_value(SettingsConstants.SETTING__XPUB_QR_FORMAT) + assert SettingsConstants.XPUB_QR_FORMAT__UR_CRYPTO_ACCOUNT in xpub_qr_formats + assert SettingsConstants.XPUB_QR_FORMAT__STATIC in xpub_qr_formats + assert SettingsConstants.XPUB_QR_FORMAT__SPECTER_LEGACY not in xpub_qr_formats def test_settingsqr_version(self):