SFT-3834: removed unused security_menu and sign_text_file_flow
What changed, and why it matters
This commit simply removes an unused feature that let users sign a text file from a microSD card. There is no indication of a security bug being fixed; it appears to be dead-code cleanup.
No security action required. Treat as routine code cleanup. If the feature is reintroduced later, review input validation and file handling in the restored flow.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change deletes sign_text_file_flow.py and removes references to it from the firmware manifest, flows package init, and a security_menu() function that is also removed. The removed flow allowed selecting a text file from microSD, validating its length and contents, signing it, and writing a signed output file. No vulnerability is described or evident in the diff.
Changed components
ports/stm32/boards/Passport/modules/flows/sign_text_file_flow.pyports/stm32/boards/Passport/manifest.pyports/stm32/boards/Passport/modules/flows/__init__.pyports/stm32/boards/Passport/modules/menus.pyInspect captured patch +0 / −126
diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py
index ee1ddb5..b3ab807 100644
--- a/ports/stm32/boards/Passport/manifest.py
+++ b/ports/stm32/boards/Passport/manifest.py
@@ -151,7 +151,6 @@ freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules',
'flows/sign_psbt_common_flow.py',
'flows/sign_psbt_microsd_flow.py',
'flows/sign_psbt_qr_flow.py',
- 'flows/sign_text_file_flow.py',
'flows/temporary_seed_flow.py',
'flows/terms_of_use_flow.py',
'flows/update_firmware_flow.py',
diff --git a/ports/stm32/boards/Passport/modules/flows/__init__.py b/ports/stm32/boards/Passport/modules/flows/__init__.py
index dc94e86..767b466 100644
--- a/ports/stm32/boards/Passport/modules/flows/__init__.py
+++ b/ports/stm32/boards/Passport/modules/flows/__init__.py
@@ -67,7 +67,6 @@ from .set_chain_flow import *
from .set_initial_pin_flow import *
from .show_security_words_setting_flow import *
from .sign_electrum_message_flow import *
-from .sign_text_file_flow import *
from .sign_psbt_common_flow import *
from .sign_psbt_microsd_flow import *
from .sign_psbt_qr_flow import *
diff --git a/ports/stm32/boards/Passport/modules/flows/sign_text_file_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_text_file_flow.py
deleted file mode 100644
index 0c600e4..0000000
--- a/ports/stm32/boards/Passport/modules/flows/sign_text_file_flow.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. <hello@foundation.xyz>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# sign_text_file_flow.py - Ask user to choose a file from microSD and then sign it.
-
-from files import CardMissingError, CardSlot
-from flows import Flow, FilePickerFlow
-from pages import SuccessPage, ErrorPage, InsertMicroSDPage
-from tasks import sign_text_file_task
-from utils import spinner_task, validate_sign_text
-from translations import t, T
-from public_constants import AF_CLASSIC, MSG_SIGNING_MAX_LENGTH, RFC_SIGNATURE_TEMPLATE
-import sys
-
-
-def is_signable(filename, path=None):
- # print('is_signable: {}'.format(filename))
- if '-signed' in filename.lower():
- return False
-
- return True
- # with open(filename, 'rt') as fd:
- # lines = fd.readlines()
- # print('len(lines) = {}'.format(len(lines)))
- # return (1 <= len(lines) <= 5)
-
-
-class SignTextFileFlow(Flow):
- def __init__(self):
- super().__init__(initial_state=self.select_file, name='SignTextFileFlow')
-
- async def select_file(self):
- result = await FilePickerFlow(filter_fn=is_signable, show_folders=True).run()
- if result is None:
- self.set_result(False)
- return
-
- _filename, full_path, is_folder = result
- if not is_folder:
- self.file_path = full_path
- self.goto(self.validate_file)
-
- async def validate_file(self):
- from common import system
-
- with CardSlot() as card:
- with open(self.file_path, 'rb') as fd:
- import os
-
- s = os.stat(self.file_path)
- self.size = s[6]
-
- # Check length
- if self.size < 2:
- await ErrorPage(
- 'File is too short. Must be at least 2 bytes.'.format(MSG_SIGNING_MAX_LENGTH)).show()
- self.set_result(False)
- return
-
- if self.size > MSG_SIGNING_MAX_LENGTH:
- await ErrorPage(
- 'File is too long. Max. length is {} bytes.'.format(MSG_SIGNING_MAX_LENGTH)).show()
- self.set_result(False)
- return
-
- # Read the file
- self.text = fd.readline().strip().decode('utf-8')
-
- self.subpath = fd.readline().strip().decode('utf-8')
-
- # Validate
- (subpath, error) = validate_sign_text(self.text, self.subpath)
- if error is not None:
- await ErrorPage(text=error).show()
- self.set_result(False)
- return
-
- self.subpath = subpath
-
- # All looks good so far, so try to sign it
- self.goto(self.do_sign)
-
- async def do_sign(self):
- (signature, address, error) = await spinner_task('Signing File', sign_text_file_task,
- args=[self.text, self.subpath, AF_CLASSIC])
- if error is None:
- self.signature = signature
- self.address = address
- self.goto(self.write_signed_file)
- else:
- # TODO: Refactor this to a simpler, common error handler page?
- await ErrorPage(text='Error while signing file: {}'.format(error)).show()
- self.set_result(False)
- return
-
- async def write_signed_file(self):
- # complete. write out result
- from ubinascii import b2a_base64
- from flows import SaveToMicroSDFlow
- from public_constants import RFC_SIGNATURE_TEMPLATE
-
- orig_path, basename = self.file_path.rsplit('/', 1)
- base, ext = basename.rsplit('.', 1)
- filename = base + '-signed' + '.' + ext
- sig = b2a_base64(self.signature).decode('ascii').strip()
- data = RFC_SIGNATURE_TEMPLATE.format(addr=self.address, msg=self.text, blockchain='BITCOIN', sig=sig)
- result = await SaveToMicroSDFlow(filename=filename,
- data=data,
- success_text="signed file",
- path=orig_path,
- mode='t').run()
- self.set_result(result)
diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py
index cbb1d40..cf3c1a8 100644
--- a/ports/stm32/boards/Passport/modules/menus.py
+++ b/ports/stm32/boards/Passport/modules/menus.py
@@ -317,18 +317,6 @@ def bitcoin_menu():
]
-def security_menu():
- from flows import ChangePINFlow, SignTextFileFlow, NewSeedFlow, RestoreSeedFlow
-
- return [
- {'icon': 'ICON_SEED', 'label': 'Restore Seed', 'flow': RestoreSeedFlow, 'is_visible': lambda: not has_seed(),
- 'args': {'refresh_cards_when_done': True}},
- {'icon': 'ICON_SEED', 'label': 'New Seed', 'flow': NewSeedFlow, 'is_visible': lambda: not has_seed(),
- 'args': {'refresh_cards_when_done': True}},
- {'icon': 'ICON_SIGN', 'label': 'Sign Text File', 'flow': SignTextFileFlow, 'is_visible': has_seed},
- ]
-
-
def update_menu():
from flows import UpdateFirmwareFlow, ViewCurrentFirmwareFlow
from utils import is_logged_in
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.