Skip to content

Commit 6407310

Browse files
authored
Merge pull request #657 from kdmukai/decodeqr_bytes_fix_v2
[bugfix] `DecodeQR`: handle Compact SeedQR byte data that can be decoded to `str`
2 parents 9bfb7b2 + cf83ebe commit 6407310

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

src/seedsigner/models/decode_qr.py

+8
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,14 @@ def detect_segment_type(s, wordlist_language_code=None):
414414
pass
415415

416416
# Is it byte data?
417+
if not isinstance(s, bytes):
418+
try:
419+
# TODO: remove this check & conversion once above cast to str is removed
420+
s = s.encode()
421+
except UnicodeError:
422+
# Couldn't convert back to bytes; shouldn't happen
423+
raise Exception("Conversion to bytes failed")
424+
417425
# 32 bytes for 24-word CompactSeedQR; 16 bytes for 12-word CompactSeedQR
418426
if len(s) == 32 or len(s) == 16:
419427
try:

tests/test_seedqr.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from seedsigner.models.decode_qr import DecodeQR, DecodeQRStatus
55
from seedsigner.models.encode_qr import SeedQrEncoder, CompactSeedQrEncoder
66
from seedsigner.models.qr_type import QRType
7-
from seedsigner.models.seed import Seed
87

98

109

@@ -104,3 +103,28 @@ def test_compact_seedqr_handles_null_bytes():
104103
# 12-word seed, multiple null bytes in a row
105104
entropy = os.urandom(10) + b'\x00\x00' + os.urandom(4)
106105
run_encode_decode_test(entropy, mnemonic_length=12, qr_type=QRType.SEED__COMPACTSEEDQR)
106+
107+
108+
def test_compact_seedqr_bytes_interpretable_as_str():
109+
"""
110+
Should successfully decode a Compact SeedQR whose bytes can be interpreted as a valid
111+
string. Most Compact SeedQR byte data will raise a UnicodeDecodeError when attempting to
112+
interpret it as a string, but edge cases are possible.
113+
114+
see: Issue #656
115+
"""
116+
# Randomly generated to pass the str.decode() step; 12- and 24-word entropy.
117+
entropy_bytes_tests = [
118+
b'\x00' * 16, # abandon * 11 + about
119+
b'\x12\x15\\1j`3\x0bkL}f\x00ZYK',
120+
b'tv\x1bZjmqN@t\x13\x1aK\\v)',
121+
b'|9\x05\x1aHF9j\xda\xb6v\x05\x08#\x12=',
122+
b"iHK`4\x1a5\xd3\xaf\xd3\xb47htJ.}<\xea\xbf\x88Xh\x01.?R2^\xc2\xb1'",
123+
b'|Z\x11\x1dt\xdd\x97~t&f &G$H|^[\xd3\x9d<q]z\x14.\x11`!\xd1\x91',
124+
b'0\xd4\xb3\\,\xcd\x8d7c/Rp\x0e\xc2\xbb\xe4\x99\xa3=j5,\xcc\x9a[>\x19Z{\ng^',
125+
]
126+
127+
for entropy_bytes in entropy_bytes_tests:
128+
entropy_bytes.decode() # should not raise an exception
129+
mnemonic_length = 12 if len(entropy_bytes) == 16 else 24
130+
run_encode_decode_test(entropy_bytes, mnemonic_length=mnemonic_length, qr_type=QRType.SEED__COMPACTSEEDQR)

0 commit comments

Comments
 (0)