Browse Source

Merge branch 'dev-v1.0.7' into PASS1-67

PASS1-67
Corey Lakey 3 years ago
committed by GitHub
parent
commit
6aa2b968e4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .gitignore
  2. 32
      Dockerfile
  3. 8
      README.md
  4. 46
      justfile
  5. 13
      ports/stm32/boards/Passport/modules/actions.py
  6. 5
      ports/stm32/boards/Passport/modules/constants.py
  7. 10
      ports/stm32/boards/Passport/modules/display.py
  8. 21
      ports/stm32/boards/Passport/modules/new_wallet.py
  9. 2
      ports/stm32/boards/Passport/modules/wallets/casa.py
  10. 4
      ports/stm32/boards/Passport/modules/wallets/specter.py
  11. 2
      ports/stm32/boards/Passport/modules/wallets/sw_wallets.py
  12. 2
      py/dynruntime.mk
  13. 2
      py/mkenv.mk
  14. 2
      py/mkrules.mk
  15. 2
      tools/makemanifest.py

2
.gitignore

@ -55,3 +55,5 @@ ports/stm32/secrets*
ports/stm32/boards/Passport/bootloader/version_info.c
ports/stm32/boards/Passport/bootloader/secrets*
*.pem

32
Dockerfile

@ -0,0 +1,32 @@
FROM ubuntu:18.04 AS cross_build
RUN apt-get update && \
apt-get install -y git make gcc-arm-none-eabi python3 gcc && \
rm -rf /var/lib/apt/lists/*
COPY docs /workspace/passport-firmware/docs
COPY extmod /workspace/passport-firmware/extmod
COPY lib /workspace/passport-firmware/lib
COPY mpy-cross /workspace/passport-firmware/mpy-cross
COPY py /workspace/passport-firmware/py
WORKDIR /workspace/passport-firmware/mpy-cross
RUN make
FROM ubuntu:18.04 AS cosign_build
WORKDIR /workspace
RUN apt-get update && \
apt-get install -y git make libssl-dev gcc && \
rm -rf /var/lib/apt/lists/*
COPY ports/stm32/boards/Passport/tools/cosign /workspace/passport-firmware/ports/stm32/boards/Passport/tools/cosign
COPY ports/stm32/boards/Passport/include /workspace/passport-firmware/ports/stm32/boards/Passport/include
COPY lib /workspace/passport-firmware/lib
COPY ports/stm32/boards/Passport/common /workspace/passport-firmware/ports/stm32/boards/Passport/common
WORKDIR /workspace/passport-firmware/ports/stm32/boards/Passport/tools/cosign
RUN make
FROM ubuntu:18.04 AS firmware_builder
COPY --from=cosign_build \
/workspace/passport-firmware/ports/stm32/boards/Passport/tools/cosign/x86/release/cosign /usr/bin/cosign
COPY --from=cross_build \
/workspace/passport-firmware/mpy-cross/mpy-cross /usr/bin/mpy-cross
RUN apt-get update && \
apt-get install -y make gcc-arm-none-eabi autotools-dev automake libtool python3 && \
rm -rf /var/lib/apt/lists/*

8
README.md

@ -32,6 +32,14 @@ Code specific to Passport is included in the following folders:
Please see [`DEVELOPMENT.md`](https://github.com/Foundation-Devices/passport/blob/main/DEVELOPMENT.md) for information on developing for Passport.
## Verifying Firmware SHA Sums
To make building and verifying the firmware a simple process, there is a Dockerfile in the project that builds an image to be used to build the firmware. Using [`just`](https://github.com/casey/just), the following command can be used to verify the reproducability of the firmware. Make sure to substitute `<the sha sum>` for the SHA string to verify.
```shell
just verify-sha <the-sha-sum>
```
## Open Source Components
Passport's firmware incorporates open-source software from several third-party projects, as well as other first-party work we open-sourced.

46
justfile

@ -0,0 +1,46 @@
commit_sha := `git rev-parse HEAD`
base_path := 'ports/stm32'
firmware_path := base_path + '/build-Passport/firmware.bin'
# build the firmware inside docker
docker-build:
#!/usr/bin/env bash
set -euxo pipefail
docker build -t foundation-devices/firmware-builder:{{ commit_sha }} .
docker run -it --rm -v "$PWD":/workspace \
-w /workspace/{{ base_path }} \
--entrypoint bash \
foundation-devices/firmware-builder:{{ commit_sha }} \
-c 'make BOARD=Passport MPY_CROSS=/usr/bin/mpy-cross'
# run the built firmware through SHA256
verify-sha sha: docker-build
#!/usr/bin/env bash
sha=$(shasum -a 256 {{ firmware_path }} | awk '{print $1}')
echo -e "Expected SHA:\t{{ sha }}"
echo -e "Actual SHA:\t${sha}"
if [ "$sha" = "{{ sha }}" ]; then
echo "Hashes match!"
else
echo "ERROR: Hashes DO NOT match!"
fi
# sign the built firmware using a private key and the cosign tool
sign keypath version filepath=firmware_path: docker-build
#!/usr/bin/env bash
set -euxo pipefail
docker run -it --rm -v "$PWD":/workspace \
-w /workspace \
--entrypoint bash \
foundation-devices/firmware-builder:{{ commit_sha }} \
-c "cosign -f {{ filepath }} -k {{ keypath }} -v {{ version }}"
# clean firmware build
clean:
docker run -it --rm -v "$PWD":/workspace \
-w /workspace/{{ base_path }} \
--entrypoint bash \
foundation-devices/firmware-builder:{{ commit_sha }} \
-c "make clean BOARD=Passport"

13
ports/stm32/boards/Passport/modules/actions.py

@ -1402,11 +1402,18 @@ async def enter_passphrase(menu, label, item):
title = item.arg
passphrase = await ux_enter_text(title, label="Enter Passphrase", max_length=MAX_PASSPHRASE_LENGTH)
# print("Chosen passphrase = {}".format(passphrase))
if not await ux_confirm('Are you sure you want to apply the passphrase:\n\n{}'.format(passphrase)):
# None is passed back when user chose "back"
if passphrase == None:
return
# print("Chosen passphrase = {}".format(passphrase))
if passphrase == '':
if not await ux_confirm('Are you sure you want to clear the passphrase?'):
return
else:
if not await ux_confirm('Are you sure you want to apply the passphrase:\n\n{}'.format(passphrase)):
return
# Applying the passphrase takes a bit of time so show message
dis.fullscreen("Applying Passphrase...")

5
ports/stm32/boards/Passport/modules/constants.py

@ -42,4 +42,7 @@ DEFAULT_ACCOUNT_ENTRY = {'name': 'Primary', 'acct_num': 0}
# Unit types for labeling conversions
UNIT_TYPE_BTC = 0
UNIT_TYPE_SATS = 1
UNIT_TYPE_SATS = 1
# Maximum amount of characters in a text entry screen
MAX_MESSAGE_LEN = 64

10
ports/stm32/boards/Passport/modules/display.py

@ -195,7 +195,12 @@ class Display:
def text_input(self, x, y, msg, font=FontSmall, invert=0, cursor_pos=None, visible_spaces=False, fixed_spacing=None, cursor_shape='line'):
from ux import word_wrap
from utils import split_by_char_size
from constants import MAX_MESSAGE_LEN
# Maximum message size is MAX_MESSAGE_LEN (64) characters
if len(msg) >= MAX_MESSAGE_LEN:
msg = msg[:MAX_MESSAGE_LEN]
if hasattr(msg, 'readline'):
lines = split_by_char_size(msg.getvalue(), font)
else:
@ -209,7 +214,8 @@ class Display:
for line in lines:
self.text(x, y, line, font, invert, cursor_pos,
visible_spaces, fixed_spacing, cursor_shape, True)
y += font.leading
# move the y down enough to make room for 7 lines of text (hence the -2)
y += font.leading - 2
cursor_pos -= len(line)
def text(self, x, y, msg, font=FontSmall, invert=0, cursor_pos=None, visible_spaces=False, fixed_spacing=None, cursor_shape='line', scrollbar_visible=False):

21
ports/stm32/boards/Passport/modules/new_wallet.py

@ -391,6 +391,17 @@ class NewWalletUX(UXStateMachine):
elif method == 'show_addresses':
self.goto(self.SHOW_RX_ADDRESSES_VERIFICATION_INTRO, save_curr=save_curr)
def choose_multisig_import_mode(self):
if 'mulitsig_import_mode' in self.export_mode:
if self.export_mode['mulitsig_import_mode'] == EXPORT_MODE_QR:
self.goto(self.IMPORT_MULTISIG_CONFIG_FROM_QR, save_curr=False)
else:
self.goto(self.IMPORT_MULTISIG_CONFIG_FROM_MICROSD, save_curr=False)
elif self.export_mode['id'] == EXPORT_MODE_QR:
self.goto(self.IMPORT_MULTISIG_CONFIG_FROM_QR, save_curr=False)
else:
self.goto(self.IMPORT_MULTISIG_CONFIG_FROM_MICROSD, save_curr=False)
async def show(self):
while True:
# print('show: state={}'.format(self.state))
@ -541,7 +552,7 @@ class NewWalletUX(UXStateMachine):
# If multisig, we need to import the quorum/config info first, else go right to validating the first
# receive address from the wallet.
if self.is_multisig():
self.goto(self.IMPORT_MULTISIG_CONFIG_FROM_QR, save_curr=False)
self.choose_multisig_import_mode()
else:
self.goto_address_verification_method(save_curr=False)
@ -598,11 +609,10 @@ class NewWalletUX(UXStateMachine):
# If multisig, we need to import the quorum/config info first, else go right to validating the first
# receive address from the wallet.
if self.is_multisig():
self.goto(self.IMPORT_MULTISIG_CONFIG_FROM_MICROSD, save_curr=False)
self.choose_multisig_import_mode()
else:
self.goto_address_verification_method(save_curr=False)
elif self.state == self.IMPORT_MULTISIG_CONFIG_FROM_QR:
while True:
msg = self.get_custom_text('multisig_import_qr', 'Next, import the multisig configuration from {} via QR code.'.format(self.sw_wallet['label']))
@ -831,10 +841,7 @@ Compare them with the addresses shown on the next screen to make sure they match
if self.is_multisig():
if not self.multisig_wallet:
# Need to import the multisig wallet
if self.export_mode['id'] == 'qr':
self.goto(self.IMPORT_MULTISIG_CONFIG_FROM_QR)
else:
self.goto(self.IMPORT_MULTISIG_CONFIG_FROM_MICROSD)
self.choose_multisig_import_mode()
continue
if not self.verified:

2
ports/stm32/boards/Passport/modules/wallets/casa.py

@ -55,6 +55,6 @@ CasaWallet = {
],
'export_modes': [
{'id': 'microsd', 'label': 'microSD', 'filename_pattern': '{sd}/{xfp}-casa.txt', 'ext': '.txt',
'filename_pattern_multisig': '{sd}/{xfp}-casa-multisig.json', 'ext_multisig': '.txt',}
'filename_pattern_multisig': '{sd}/{xfp}-casa-multisig.json', 'ext_multisig': '.txt'}
]
}

4
ports/stm32/boards/Passport/modules/wallets/specter.py

@ -18,7 +18,7 @@ SpecterWallet = {
'import_qr': read_multisig_config_from_qr, 'import_microsd': read_multisig_config_from_microsd}
],
'export_modes': [
# {'id': 'qr', 'label': 'QR Code', 'qr_type': QRType.UR1},
{'id': 'microsd', 'label': 'microSD', 'filename_pattern': '{sd}/{xfp}-specter.json', 'filename_pattern_multisig': '{sd}/{xfp}-specter-multisig.json'}
{'id': 'qr', 'label': 'QR Code', 'qr_type': QRType.UR2},
{'id': 'microsd', 'label': 'microSD', 'filename_pattern': '{sd}/{xfp}-specter.json', 'filename_pattern_multisig': '{sd}/{xfp}-specter-multisig.json', 'mulitsig_import_mode': 'qr'}
]
}

2
ports/stm32/boards/Passport/modules/wallets/sw_wallets.py

@ -32,6 +32,6 @@ supported_software_wallets = [
# GordianWallet,
# LilyWallet,
SparrowWallet,
# SpecterWallet,
SpecterWallet,
WasabiWallet,
]

2
py/dynruntime.mk

@ -7,7 +7,7 @@ ECHO = @echo
RM = /bin/rm
MKDIR = /bin/mkdir
PYTHON = python3
MPY_CROSS = $(MPY_DIR)/mpy-cross/mpy-cross
MPY_CROSS ?= $(MPY_DIR)/mpy-cross/mpy-cross
MPY_TOOL = $(PYTHON) $(MPY_DIR)/tools/mpy-tool.py
MPY_LD = $(PYTHON) $(MPY_DIR)/tools/mpy_ld.py

2
py/mkenv.mk

@ -63,7 +63,7 @@ endif
MAKE_MANIFEST = $(PYTHON) $(TOP)/tools/makemanifest.py
MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py
MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
MPY_CROSS ?= $(TOP)/mpy-cross/mpy-cross
MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py
MPY_LIB_DIR = $(TOP)/../micropython-lib

2
py/mkrules.mk

@ -100,7 +100,7 @@ $(HEADER_BUILD):
ifneq ($(FROZEN_MANIFEST),)
# to build frozen_content.c from a manifest
$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) $(FROZEN_MANIFEST)
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "MPY_CROSS=$(MPY_CROSS)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) $(FROZEN_MANIFEST)
ifneq ($(FROZEN_DIR),)
$(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST)

2
tools/makemanifest.py

@ -216,7 +216,7 @@ def main():
# Get paths to tools
MAKE_FROZEN = VARS['MPY_DIR'] + '/tools/make-frozen.py'
MPY_CROSS = VARS['MPY_DIR'] + '/mpy-cross/mpy-cross'
MPY_CROSS = VARS['MPY_CROSS']
MPY_TOOL = VARS['MPY_DIR'] + '/tools/mpy-tool.py'
# Ensure mpy-cross is built

Loading…
Cancel
Save