mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-05 15:08:25 +00:00
Merge branch 'dev' into 2026-04-22_CI_hardening
This commit is contained in:
@@ -43,9 +43,12 @@ jobs:
|
|||||||
tests/requirements.txt
|
tests/requirements.txt
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install -y --no-install-recommends libzbar0
|
sudo apt-get install libzbar0
|
||||||
pip install -r requirements.txt -r tests/requirements.txt
|
python -m pip install --upgrade pip
|
||||||
pip install .
|
pip install -r requirements.txt -r tests/requirements.txt -r l10n/requirements-l10n.txt
|
||||||
|
pip install -e .
|
||||||
|
- name: Compile translations
|
||||||
|
run: python setup.py compile_catalog
|
||||||
- name: Test with pytest
|
- name: Test with pytest
|
||||||
run: |
|
run: |
|
||||||
mkdir -p artifacts
|
mkdir -p artifacts
|
||||||
|
|||||||
@@ -112,23 +112,23 @@ Instructions to build a SeedSigner OS image (using precisely the same process th
|
|||||||
## Downloading the Software
|
## Downloading the Software
|
||||||
|
|
||||||
|
|
||||||
Download the current Version (0.8.6) software image that is compatible with your Raspberry Pi Hardware. The Pi Zero 1.3 is the most common and recommended board.
|
Download the current Version (0.8.7) software image that is compatible with your Raspberry Pi Hardware. The Pi Zero 1.3 is the most common and recommended board.
|
||||||
| Board | Download Image Link/Name |
|
| Board | Download Image Link/Name |
|
||||||
| --------------------- | --------------------------------- |
|
| --------------------- | --------------------------------- |
|
||||||
|**[Raspberry Pi Zero 1.3](https://www.raspberrypi.com/products/raspberry-pi-zero/)** |[`seedsigner_os.0.8.6.pi0.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner_os.0.8.6.pi0.img) |
|
|**[Raspberry Pi Zero 1.3](https://www.raspberrypi.com/products/raspberry-pi-zero/)** |[`seedsigner_os.0.8.7.pi0.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner_os.0.8.7.pi0.img) |
|
||||||
|[Raspberry Pi Zero W](https://www.raspberrypi.com/products/raspberry-pi-zero-w/) |[`seedsigner_os.0.8.6.pi0.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner_os.0.8.6.pi0.img) |
|
|[Raspberry Pi Zero W](https://www.raspberrypi.com/products/raspberry-pi-zero-w/) |[`seedsigner_os.0.8.7.pi0.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner_os.0.8.7.pi0.img) |
|
||||||
|[Raspberry Pi Zero 2 W](https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/) |[`seedsigner_os.0.8.6.pi02w.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner_os.0.8.6.pi02w.img) |
|
|[Raspberry Pi Zero 2 W](https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/) |[`seedsigner_os.0.8.7.pi02w.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner_os.0.8.7.pi02w.img) |
|
||||||
|[Raspberry Pi 1 Model B/B+](https://www.raspberrypi.com/products/raspberry-pi-1-model-b-plus/) |[`seedsigner_os.0.8.6.pi0.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner_os.0.8.6.pi0.img) |
|
|[Raspberry Pi 1 Model B/B+](https://www.raspberrypi.com/products/raspberry-pi-1-model-b-plus/) |[`seedsigner_os.0.8.7.pi0.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner_os.0.8.7.pi0.img) |
|
||||||
|[Raspberry Pi 2 Model B](https://www.raspberrypi.com/products/raspberry-pi-2-model-b/) |[`seedsigner_os.0.8.6.pi2.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner_os.0.8.6.pi2.img) |
|
|[Raspberry Pi 2 Model B](https://www.raspberrypi.com/products/raspberry-pi-2-model-b/) |[`seedsigner_os.0.8.7.pi2.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner_os.0.8.7.pi2.img) |
|
||||||
|[Raspberry Pi 3 Model B](https://www.raspberrypi.com/products/raspberry-pi-3-model-b/) |[`seedsigner_os.0.8.6.pi02w.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner_os.0.8.6.pi02w.img) |
|
|[Raspberry Pi 3 Model B](https://www.raspberrypi.com/products/raspberry-pi-3-model-b/) |[`seedsigner_os.0.8.7.pi02w.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner_os.0.8.7.pi02w.img) |
|
||||||
|[Raspberry Pi 4 Model B](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) |[`seedsigner_os.0.8.6.pi4.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner_os.0.8.6.pi4.img) |
|
|[Raspberry Pi 4 Model B](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) |[`seedsigner_os.0.8.7.pi4.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner_os.0.8.7.pi4.img) |
|
||||||
|[Raspberry Pi 400](https://www.raspberrypi.com/products/raspberry-pi-400-unit/) |[`seedsigner_os.0.8.6.pi4.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner_os.0.8.6.pi4.img) |
|
|[Raspberry Pi 400](https://www.raspberrypi.com/products/raspberry-pi-400-unit/) |[`seedsigner_os.0.8.7.pi4.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner_os.0.8.7.pi4.img) |
|
||||||
|
|
||||||
Note: If you have physically removed the WiFi component from your board, you will still use the image file of the original (un-modified) hardware. (Our files are compiled/based on the *processor* architecture). Although it is better to spend a few minutes upfront to determine which specific Pi hardware/model you have, if you are still unsure which hardware you have, you can try using the pi0.img file. Making an incorrect choice here will not ruin your board, because this is software, not firmware.
|
Note: If you have physically removed the WiFi component from your board, you will still use the image file of the original (un-modified) hardware. (Our files are compiled/based on the *processor* architecture). Although it is better to spend a few minutes upfront to determine which specific Pi hardware/model you have, if you are still unsure which hardware you have, you can try using the pi0.img file. Making an incorrect choice here will not ruin your board, because this is software, not firmware.
|
||||||
|
|
||||||
**Also download** these 2 signature verification files to the same folder
|
**Also download** these 2 signature verification files to the same folder
|
||||||
[The Plaintext manifest file](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner.0.8.6.sha256.txt)
|
[The Plaintext manifest file](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner.0.8.7.sha256.txt)
|
||||||
[The Signature of the manifest file](https://github.com/SeedSigner/seedsigner/releases/download/0.8.6/seedsigner.0.8.6.sha256.txt.sig)
|
[The Signature of the manifest file](https://github.com/SeedSigner/seedsigner/releases/download/0.8.7/seedsigner.0.8.7.sha256.txt.sig)
|
||||||
|
|
||||||
|
|
||||||
Users familiar with older versions of the SeedSigner software might be surprised with how fast their software downloads now are, because since version 0.6.0 the software image files are now 100x smaller! Each image file is now under 42 Megabytes so your downloads and verifications will be very quick now (and might even seem *too* quick)!
|
Users familiar with older versions of the SeedSigner software might be surprised with how fast their software downloads now are, because since version 0.6.0 the software image files are now 100x smaller! Each image file is now under 42 Megabytes so your downloads and verifications will be very quick now (and might even seem *too* quick)!
|
||||||
@@ -160,7 +160,7 @@ The result should confirm that 1 key was *either* imported or updated. *Ignore*
|
|||||||
|
|
||||||
Next, you will run the *verify* command on the signature (.sig) file. (*Verify* must be run from inside the same folder that you downloaded the files into earlier.)
|
Next, you will run the *verify* command on the signature (.sig) file. (*Verify* must be run from inside the same folder that you downloaded the files into earlier.)
|
||||||
```
|
```
|
||||||
gpg --verify seedsigner.0.8.6.sha256.txt.sig
|
gpg --verify seedsigner.0.8.7.sha256.txt.sig
|
||||||
```
|
```
|
||||||
|
|
||||||
When the verify command completes successfully, it should display output like this:
|
When the verify command completes successfully, it should display output like this:
|
||||||
@@ -230,22 +230,22 @@ Now that you have confirmed that you do have the real SeedSigner Project's Publi
|
|||||||
|
|
||||||
**On Linux or OSX:** Run this command
|
**On Linux or OSX:** Run this command
|
||||||
```
|
```
|
||||||
shasum -a 256 --ignore-missing --check seedsigner.0.8.6.sha256.txt
|
shasum -a 256 --ignore-missing --check seedsigner.0.8.7.sha256.txt
|
||||||
```
|
```
|
||||||
Note: macOS versions earlier than v11 (Big Sur) do not support the `--ignore-missing` flag. You can omit it and disregard any missing file warnings.
|
Note: macOS versions earlier than v11 (Big Sur) do not support the `--ignore-missing` flag. You can omit it and disregard any missing file warnings.
|
||||||
|
|
||||||
**On Windows (inside Powershell):** Run this command
|
**On Windows (inside Powershell):** Run this command
|
||||||
```
|
```
|
||||||
CertUtil -hashfile seedsigner_os.0.8.6.Insert_Your_Pi_Models_binary_here_For_Example_pi02w.img SHA256
|
CertUtil -hashfile seedsigner_os.0.8.7.Insert_Your_Pi_Models_binary_here_For_Example_pi02w.img SHA256
|
||||||
```
|
```
|
||||||
On Windows, you must then manually compare the resulting file hash value to the corresponding hash value shown inside the .SHA256 cleartext file.
|
On Windows, you must then manually compare the resulting file hash value to the corresponding hash value shown inside the .SHA256 cleartext file.
|
||||||
<BR>
|
<BR>
|
||||||
|
|
||||||
Wait up to 30 seconds for the command to complete, and it should display:
|
Wait up to 30 seconds for the command to complete, and it should display:
|
||||||
```
|
```
|
||||||
seedsigner_os.0.8.6.[Your_Pi_Model_For_Example:pi02w].img: OK
|
seedsigner_os.0.8.7.[Your_Pi_Model_For_Example:pi02w].img: OK
|
||||||
```
|
```
|
||||||
**If you receive the "OK" message** for your **seedsigner_os.0.8.6.[Your_Pi_Model_For_Example:pi02w].img file**, as shown above, then your verification is fully complete!
|
**If you receive the "OK" message** for your **seedsigner_os.0.8.7.[Your_Pi_Model_For_Example:pi02w].img file**, as shown above, then your verification is fully complete!
|
||||||
**All of your downloaded files have now been confirmed as both authentic and unaltered!** You can proceed to create/write your MicroSD card😄😄 !!
|
**All of your downloaded files have now been confirmed as both authentic and unaltered!** You can proceed to create/write your MicroSD card😄😄 !!
|
||||||
|
|
||||||
If your file result shows "FAILED", then you must stop here immediately. Do not continue. Contact us for assistance at the Telegram group address above.
|
If your file result shows "FAILED", then you must stop here immediately. Do not continue. Contact us for assistance at the Telegram group address above.
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
Babel==2.16.0
|
Babel==2.16.0
|
||||||
|
setuptools>=82.0.0
|
||||||
|
|||||||
Submodule src/seedsigner/resources/seedsigner-translations updated: 6b911be2da...708961a416
@@ -226,11 +226,13 @@ class SeedMnemonicEntryView(View):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if ret == RET_CODE__BACK_BUTTON:
|
if ret == RET_CODE__BACK_BUTTON:
|
||||||
if self.cur_word_index > 0:
|
# This handles two possible scenarios:
|
||||||
return Destination(BackStackView)
|
# 1. Backing out of the first word cancels the mnemonic entry process;
|
||||||
else:
|
# return to whichever `View` routed us here initially.
|
||||||
|
# 2. Backing out of the current word returns to the previous word.
|
||||||
|
if self.cur_word_index == 0:
|
||||||
self.controller.storage.discard_pending_mnemonic()
|
self.controller.storage.discard_pending_mnemonic()
|
||||||
return Destination(MainMenuView)
|
return Destination(BackStackView)
|
||||||
|
|
||||||
# ret will be our new mnemonic word
|
# ret will be our new mnemonic word
|
||||||
self.controller.storage.update_pending_mnemonic(ret, self.cur_word_index)
|
self.controller.storage.update_pending_mnemonic(ret, self.cur_word_index)
|
||||||
@@ -339,9 +341,6 @@ class SeedFinalizeView(View):
|
|||||||
elif button_data[selected_menu_num] == self.PASSPHRASE:
|
elif button_data[selected_menu_num] == self.PASSPHRASE:
|
||||||
return Destination(SeedAddPassphraseView)
|
return Destination(SeedAddPassphraseView)
|
||||||
|
|
||||||
elif selected_menu_num == RET_CODE__BACK_BUTTON:
|
|
||||||
return Destination(BackStackView)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SeedAddPassphraseView(View):
|
class SeedAddPassphraseView(View):
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
@@ -148,9 +147,12 @@ class ToolsImageEntropyMnemonicLengthView(View):
|
|||||||
|
|
||||||
# Build in some hardware-level uniqueness via CPU unique Serial num
|
# Build in some hardware-level uniqueness via CPU unique Serial num
|
||||||
try:
|
try:
|
||||||
stream = os.popen("cat /proc/cpuinfo | grep Serial")
|
serial_num = b''
|
||||||
output = stream.read()
|
with open("/proc/cpuinfo", "r") as f:
|
||||||
serial_num = output.split(":")[-1].strip().encode('utf-8')
|
for line in f:
|
||||||
|
if "Serial" in line:
|
||||||
|
serial_num = line.split(":")[-1].strip().encode('utf-8')
|
||||||
|
break
|
||||||
serial_hash = hashlib.sha256(serial_num)
|
serial_hash = hashlib.sha256(serial_num)
|
||||||
hash_bytes = serial_hash.digest()
|
hash_bytes = serial_hash.digest()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -495,6 +495,79 @@ class TestSeedFlows(FlowTest):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestSeedEntryBackFlows(FlowTest):
|
||||||
|
"""
|
||||||
|
Tests for every BACK exit scenario from SeedMnemonicEntryView and related views.
|
||||||
|
|
||||||
|
A naive BackStackView swap can leave resume_main_flow dangling, causing
|
||||||
|
auto-redirects on stale flow state. These tests verify that BACK navigation
|
||||||
|
returns to the correct parent view AND that no flow state leaks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_back_from_seed_entry_first_word(self):
|
||||||
|
"""
|
||||||
|
Pressing BACK on the first word of mnemonic entry should return to
|
||||||
|
the View that initiated the mnemonic entry process.
|
||||||
|
"""
|
||||||
|
for seed_type in [seed_views.LoadSeedView.TYPE_12WORD, seed_views.LoadSeedView.TYPE_24WORD]:
|
||||||
|
self.run_sequence([
|
||||||
|
FlowStep(MainMenuView, button_data_selection=MainMenuView.SEEDS),
|
||||||
|
FlowStep(seed_views.SeedsMenuView, is_redirect=True), # No seeds loaded; auto-redirects to LoadSeedView
|
||||||
|
FlowStep(seed_views.LoadSeedView, button_data_selection=seed_type),
|
||||||
|
FlowStep(seed_views.SeedMnemonicEntryView, screen_return_value=RET_CODE__BACK_BUTTON),
|
||||||
|
FlowStep(seed_views.LoadSeedView), # Should land here, NOT MainMenuView
|
||||||
|
])
|
||||||
|
BaseTest.reset_controller()
|
||||||
|
|
||||||
|
|
||||||
|
def test_back_from_seed_entry_mid_word(self):
|
||||||
|
"""
|
||||||
|
Pressing BACK from a middle word (eg. word #2) should return to the
|
||||||
|
previous SeedMnemonicEntryView (eg. word #1) via the back stack.
|
||||||
|
"""
|
||||||
|
self.run_sequence([
|
||||||
|
FlowStep(MainMenuView, button_data_selection=MainMenuView.SEEDS),
|
||||||
|
FlowStep(seed_views.SeedsMenuView, is_redirect=True),
|
||||||
|
FlowStep(seed_views.LoadSeedView, button_data_selection=seed_views.LoadSeedView.TYPE_12WORD),
|
||||||
|
FlowStep(seed_views.SeedMnemonicEntryView, screen_return_value="abandon"), # word #1
|
||||||
|
FlowStep(seed_views.SeedMnemonicEntryView, screen_return_value=RET_CODE__BACK_BUTTON), # BACK from word #2
|
||||||
|
FlowStep(seed_views.SeedMnemonicEntryView), # Returns to word #1
|
||||||
|
])
|
||||||
|
|
||||||
|
# Verify we're back on word #1: word at index 0 should still be set
|
||||||
|
# from the previous entry, while word at index 1 should be unset.
|
||||||
|
assert self.controller.storage.get_pending_mnemonic_word(0) == "abandon"
|
||||||
|
assert self.controller.storage.get_pending_mnemonic_word(1) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_back_from_seed_entry_via_seed_select(self):
|
||||||
|
"""
|
||||||
|
Backing out of mnemonic entry during an active flow must preserve
|
||||||
|
`resume_main_flow` so the user remains within that flow.
|
||||||
|
"""
|
||||||
|
from seedsigner.controller import Controller
|
||||||
|
from seedsigner.models.settings import SettingsConstants
|
||||||
|
|
||||||
|
self.settings.set_value(SettingsConstants.SETTING__MESSAGE_SIGNING, SettingsConstants.OPTION__ENABLED)
|
||||||
|
|
||||||
|
def load_signmessage_into_decoder(view):
|
||||||
|
view.decoder.add_data("signmessage m/84h/0h/0h/0/0 ascii:test message")
|
||||||
|
|
||||||
|
self.run_sequence([
|
||||||
|
FlowStep(MainMenuView, button_data_selection=MainMenuView.SCAN),
|
||||||
|
FlowStep(scan_views.ScanView, before_run=load_signmessage_into_decoder),
|
||||||
|
FlowStep(seed_views.SeedSignMessageStartView, is_redirect=True),
|
||||||
|
FlowStep(seed_views.SeedSelectSeedView, button_data_selection=seed_views.SeedSelectSeedView.TYPE_12WORD),
|
||||||
|
FlowStep(seed_views.SeedMnemonicEntryView, screen_return_value=RET_CODE__BACK_BUTTON), # BACK on first word
|
||||||
|
FlowStep(seed_views.SeedSelectSeedView), # Should return here, in the sign message flow
|
||||||
|
])
|
||||||
|
|
||||||
|
# Verify resume_main_flow is still set — user is still in the sign message flow
|
||||||
|
assert self.controller.resume_main_flow == Controller.FLOW__SIGN_MESSAGE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestMessageSigningFlows(FlowTest):
|
class TestMessageSigningFlows(FlowTest):
|
||||||
MAINNET_DERIVATION_PATH = "m/84h/0h/0h/0/0"
|
MAINNET_DERIVATION_PATH = "m/84h/0h/0h/0/0"
|
||||||
TESTNET_DERIVATION_PATH = "m/84h/1h/0h/0/0"
|
TESTNET_DERIVATION_PATH = "m/84h/1h/0h/0/0"
|
||||||
|
|||||||
Reference in New Issue
Block a user