From b40125284480073f45a4c9073368027b42a8b536 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 8 Jun 2026 17:07:09 -0400 Subject: [PATCH 1/2] SFT-7112: handled signing the single-lign message format, fixed message parser sensitivity to trailing newlines --- .../modules/flows/health_check_common_flow.py | 38 +++++++++++++------ .../flows/health_check_microsd_flow.py | 2 +- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py b/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py index 8c43ff0fb..388093a4c 100644 --- a/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py @@ -4,7 +4,7 @@ # health_check_common_flow.py - Scan and process a health check QR code in `crypto-request` format from flows import Flow -from wallets.utils import get_addr_type_from_string +from wallets.utils import get_addr_type_from_deriv, get_addr_type_from_string from public_constants import AF_CLASSIC @@ -20,19 +20,33 @@ def __init__(self, lines, normal_signing=False): async def validate_lines(self): from pages import ErrorPage from utils import validate_sign_text - if len(self.lines) not in [2, 3]: - await ErrorPage('{} format is invalid.'.format('Message' if self.normal_signing else 'Health check')).show() - self.set_result(None) - return + err_label = 'Message' if self.normal_signing else 'Health check' + + if self.lines and self.lines[0].startswith('signmessage '): + raw = '\n'.join(self.lines) + parts = raw.split(' ', 2) + if len(parts) != 3 or not parts[2].startswith('ascii:'): + await ErrorPage('{} format is invalid.'.format(err_label)).show() + self.set_result(None) + return + + self.subpath = parts[1] + self.text = parts[2][len('ascii:'):] + + derived = get_addr_type_from_deriv(self.subpath) + if derived is not None: + self.addr_type = derived + else: + if len(self.lines) not in [2, 3]: + await ErrorPage('{} format is invalid.'.format(err_label)).show() + self.set_result(None) + return - # Common function to validate the message - self.text = self.lines[0] - self.subpath = self.lines[1] + self.text = self.lines[0] + self.subpath = self.lines[1] - if len(self.lines) == 3: - self.addr_type = get_addr_type_from_string(self.lines[2]) - # print('text={}'.format(self.text)) - # print('subpath={}'.format(self.subpath)) + if len(self.lines) == 3: + self.addr_type = get_addr_type_from_string(self.lines[2]) # Validate (subpath, error) = validate_sign_text(self.text, self.subpath) diff --git a/ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.py index 241df459f..40f00f82c 100644 --- a/ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.py @@ -91,7 +91,7 @@ async def parse_message(self): self.set_result(False) return - self.lines = data.split('\n') + self.lines = data.splitlines() self.goto(self.common_flow) async def common_flow(self): From 4157518eea19e5f20b15adef74bcea9ded0ce9e2 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 10 Jun 2026 15:08:20 -0400 Subject: [PATCH 2/2] SFT-7112: moved message signing subpath cleaning up in the process to prevent deriving address types from malformed paths, added comments and spacing --- .../modules/flows/health_check_common_flow.py | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py b/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py index 388093a4c..7e993f2ae 100644 --- a/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/health_check_common_flow.py @@ -20,11 +20,15 @@ def __init__(self, lines, normal_signing=False): async def validate_lines(self): from pages import ErrorPage from utils import validate_sign_text + err_label = 'Message' if self.normal_signing else 'Health check' + # single-line `signmessage ascii:` (Envoy export) + # Multiline messages are preserved by joining lines back before splitting. if self.lines and self.lines[0].startswith('signmessage '): raw = '\n'.join(self.lines) parts = raw.split(' ', 2) + if len(parts) != 3 or not parts[2].startswith('ascii:'): await ErrorPage('{} format is invalid.'.format(err_label)).show() self.set_result(None) @@ -33,7 +37,17 @@ async def validate_lines(self): self.subpath = parts[1] self.text = parts[2][len('ascii:'):] + (subpath, error) = validate_sign_text(self.text, self.subpath) + + if error is not None: + await ErrorPage(text=error).show() + self.set_result(None) + return + + self.subpath = subpath + derived = get_addr_type_from_deriv(self.subpath) + if derived is not None: self.addr_type = derived else: @@ -48,14 +62,14 @@ async def validate_lines(self): if len(self.lines) == 3: self.addr_type = get_addr_type_from_string(self.lines[2]) - # Validate - (subpath, error) = validate_sign_text(self.text, self.subpath) - if error is not None: - await ErrorPage(text=error).show() - self.set_result(None) - return + (subpath, error) = validate_sign_text(self.text, self.subpath) + + if error is not None: + await ErrorPage(text=error).show() + self.set_result(None) + return - self.subpath = subpath + self.subpath = subpath # User Interaction for non-health check signing if self.normal_signing: