From 525491361949bc1e761de998b95806b196dce1c6 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Fri, 13 Jan 2023 01:18:15 -0600 Subject: [PATCH 001/156] PASS1-584: improved page with sd card error handling, reduced FE file display limit --- .../boards/Passport/modules/pages/file_picker_page.py | 3 ++- ports/stm32/boards/Passport/modules/utils.py | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/pages/file_picker_page.py b/ports/stm32/boards/Passport/modules/pages/file_picker_page.py index 9dace71cc..bfbe0fe99 100644 --- a/ports/stm32/boards/Passport/modules/pages/file_picker_page.py +++ b/ports/stm32/boards/Passport/modules/pages/file_picker_page.py @@ -11,8 +11,9 @@ from pages import Page from views import FileItem, View from micropython import const +import passport -MAX_FILE_DISPLAY = const(15) +MAX_FILE_DISPLAY = const(15) if passport.IS_COLOR else const(10) class FilePickerPage(Page): diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 5471df96a..c8c4bce08 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -1101,6 +1101,7 @@ async def show_page_with_sd_card(page, on_sd_card_change, on_result, on_exceptio :return: None """ from files import CardMissingError + from pages import ErrorPage sd_card_change = False prev_sd_card_cb = None @@ -1120,7 +1121,14 @@ def restore_sd_cb(): prev_sd_card_cb = CardSlot.get_sd_card_change_cb() CardSlot.set_sd_card_change_cb(sd_card_cb) - await page.display() + try: + await page.display() + except Exception as e: + page.unmount() + restore_sd_cb() + on_result(None) + await ErrorPage(text='Unable to display page.').show() + return g = page.poll_for_done() while True: From 8c83eefc7beb57f7e1313f49f81f4b6d872740c3 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 12 Jan 2023 19:40:27 -0600 Subject: [PATCH 002/156] PASS1-593: added success pages --- .../modules/flows/import_multisig_wallet_from_microsd_flow.py | 3 +++ .../modules/flows/import_multisig_wallet_from_qr_flow.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_microsd_flow.py index b21e3439e..4548806c6 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_microsd_flow.py @@ -59,9 +59,12 @@ async def choose_wallet_file(self): async def do_import(self): from flows import ImportMultisigWalletFlow + from pages import SuccessPage # Show the wallet to the user for import result = await ImportMultisigWalletFlow(self.ms).run() + if result: + await SuccessPage(text='Multisig config imported').show() self.set_result(result) async def show_error(self): diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py index cf0f5b41d..45b1e15db 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py @@ -40,9 +40,12 @@ async def scan_qr_code(self): async def do_import(self): from flows import ImportMultisigWalletFlow + from pages import SuccessPage # Show the wallet to the user for import result = await ImportMultisigWalletFlow(self.ms).run() + if result: + await SuccessPage(text='Multisig config imported').show() self.set_result(result) async def show_error(self): From 062bbb24d1fbef283fa2164623eac1416651edd4 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 11 Jan 2023 11:19:43 -0600 Subject: [PATCH 003/156] PASS1-605: added hash files to "just hash" command --- ports/stm32/Justfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/stm32/Justfile b/ports/stm32/Justfile index 647c75914..8945f9585 100644 --- a/ports/stm32/Justfile +++ b/ports/stm32/Justfile @@ -283,21 +283,26 @@ hash filepath: #!/usr/bin/env bash set -e filename=`basename {{filepath}}` + directory=`dirname {{filepath}}` + release_name=${filename::-13} # SHA256 sha=`shasum -b -a 256 {{filepath}} | sed -rn 's/^(.*) .*$/\1/p'` echo -e "\n\`SHA256: $sha\`" echo -e "\`(shasum -b -a 256 $filename)\`\n" + echo "$sha" > ${directory}/${release_name}-sha256 # MD5 md5=`mdsum {{filepath}} | sed -rn 's/^(.*) .*$/\1/p'` echo "\`MD5: $md5\`" echo -e "\`(md5 $filename or mdsum $filename)\`\n" + echo "$md5" > ${directory}/${release_name}-md5 # Build Hash build_hash=`cosign -t color -p -f {{filepath}} | sed -rn 's/^FW Build Hash: (.*)$/\1/p'` echo -e "\`Build Hash: $build_hash\`" echo -e "\`(Developers Only)\`\n" + echo "$build_hash" > ${directory}/${release_name}-build-hash # Format the project's .py files under boards/Passport/modules fmt-py: From 9a1548df795894ced9b0c3564e81a47e03dbf026 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 11 Jan 2023 17:35:20 -0600 Subject: [PATCH 004/156] PASS1-605: generated release notes hash text block --- ports/stm32/Justfile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ports/stm32/Justfile b/ports/stm32/Justfile index 8945f9585..b74c9936e 100644 --- a/ports/stm32/Justfile +++ b/ports/stm32/Justfile @@ -288,22 +288,21 @@ hash filepath: # SHA256 sha=`shasum -b -a 256 {{filepath}} | sed -rn 's/^(.*) .*$/\1/p'` - echo -e "\n\`SHA256: $sha\`" - echo -e "\`(shasum -b -a 256 $filename)\`\n" echo "$sha" > ${directory}/${release_name}-sha256 # MD5 md5=`mdsum {{filepath}} | sed -rn 's/^(.*) .*$/\1/p'` - echo "\`MD5: $md5\`" - echo -e "\`(md5 $filename or mdsum $filename)\`\n" + md5=${md5::-1} echo "$md5" > ${directory}/${release_name}-md5 # Build Hash build_hash=`cosign -t color -p -f {{filepath}} | sed -rn 's/^FW Build Hash: (.*)$/\1/p'` - echo -e "\`Build Hash: $build_hash\`" - echo -e "\`(Developers Only)\`\n" echo "$build_hash" > ${directory}/${release_name}-build-hash + echo -e "## RELEASE HASHES\n\nSHA256: \`$sha\`\nMD5: \`$md5\`\n\nYou can check these hashes with the following commands on most operating systems:\n" + echo -e "SHA256: \`shasum -b -a 256 $filename\`\nMD5: \`md5 $filename\` or \`mdsum v2.0.5-passport.bin\` or \`md5sum v2.0.5-passport.bin\`\n" + echo -e "### DEVELOPERS ONLY\n\nBuild Hash: \`$build_hash\`" + # Format the project's .py files under boards/Passport/modules fmt-py: #!/usr/bin/env bash From f6deff9f53bf222580f7b80097818827e1073152 Mon Sep 17 00:00:00 2001 From: Ken Carpenter Date: Wed, 4 Jan 2023 23:07:46 -0800 Subject: [PATCH 005/156] PASS1-576: Render camera image direct to LCD Instead of letting LVGL render pixel-by-pixel from the camera image downsampled to 1 bit-per-pixel, we now render directly to the LCD driver buffer and update just the modified lines. In addition, the LVGL `_lcd_rounder` callback was always setting the fully display to be updated (in addition to setting `direct_mode=1`, which ended up doing the same thing). Change it so that only the dirty lines are push to the display. Also optimized the bit calculation of `_lcd_set_px()` to be a table lookup instead for a small LVGL performance boost. --- .../Passport/common/lcd-sharp-ls018b7dh02.c | 45 +++++++++++++++++++ ports/stm32/boards/Passport/framebuffer.c | 32 ++++++++----- .../Passport/include/lcd-sharp-ls018b7dh02.h | 19 ++++---- .../boards/Passport/modpassport_lv-lcd.h | 21 +++++++++ .../Passport/modules/pages/scan_qr_page.py | 5 ++- .../boards/Passport/modules/views/camera.py | 11 +++-- 6 files changed, 110 insertions(+), 23 deletions(-) diff --git a/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c b/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c index add29efbb..e6b2f7c56 100644 --- a/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c +++ b/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c @@ -224,6 +224,51 @@ void lcd_update_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* da HAL_SPI_Transmit(lcd.spi, (uint8_t*)&screen.lines[y], sizeof(ScreenLine) * h, 1000); } +#define VIEWFINDER_WIDTH 180 +#define VIEWFINDER_HEIGHT 180 +#define VIEWFINDER_Y_START 52 + +// A very hard-coded function to resize the grayscale camera image to the viewfinder size, and convert from +// grayscle to mono as quickly as possible. +static void _lcd_resize_and_render_viewfinder_direct(uint8_t* grayscale, uint32_t gray_hor_res, uint32_t gray_ver_res) { + float scale = (float)gray_ver_res / (float)VIEWFINDER_HEIGHT; + uint32_t x_offset = (SCREEN_WIDTH - VIEWFINDER_WIDTH) / 2; + + // printf("hor_res=%lu ver_res=%lu scale=%f\n", gray_hor_res, gray_ver_res, (double)scale); + // printf("x_offset=%lu\n", x_offset); + + for (uint32_t y = 0; y < VIEWFINDER_HEIGHT; y++) { + for (uint32_t x = 0; x < VIEWFINDER_WIDTH; x++) { + uint32_t offset = ((uint32_t)((float)(x)*scale) * (uint32_t)gray_hor_res) + (uint32_t)((float)(y)*scale); + uint8_t gray = grayscale[offset]; + + // Mask the value in it + uint32_t flipped_x = VIEWFINDER_WIDTH - x; + uint32_t mono_offset = (x_offset + flipped_x) >> 3; + uint8_t bit = (x_offset + flipped_x) % 8; + uint8_t* p_byte = &screen.lines[y + VIEWFINDER_Y_START].pixels[mono_offset]; + if (gray > 64) { + // Set the bit + *p_byte |= 1 << (7 - bit); + } else { + // Clear the bit + *p_byte &= ~(1 << (7 - bit)); + } + } + } +} + +// Given a full grayscale camera image buffer, resize it to fit in a +void lcd_update_viewfinder(uint8_t* grayscale, uint16_t gray_hor_res, uint16_t gray_ver_res) { + // Grayscale buffer is 396*330 pixels, and we need to scale down to 180x180 size of the viewfiender, + // and position it at the right place on the display, then write the corresponding lines. + _lcd_resize_and_render_viewfinder_direct(grayscale, gray_hor_res, gray_ver_res); + + // Send the lines of the viewfinder to the display + HAL_SPI_Transmit(lcd.spi, (uint8_t*)&screen.lines[VIEWFINDER_Y_START], sizeof(ScreenLine) * VIEWFINDER_HEIGHT, + 1000); +} + void lcd_draw_image(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* image) { for (uint32_t cy = 0; cy < h; cy++) { for (uint32_t cx = 0; cx < w; cx++) { diff --git a/ports/stm32/boards/Passport/framebuffer.c b/ports/stm32/boards/Passport/framebuffer.c index 4768e3432..242f83392 100644 --- a/ports/stm32/boards/Passport/framebuffer.c +++ b/ports/stm32/boards/Passport/framebuffer.c @@ -89,11 +89,10 @@ void framebuffer_init() { #endif // SCREEN_MODE_MONO lv_disp_drv_init(disp_drv); - disp_drv->hor_res = LCD_HOR_RES; - disp_drv->ver_res = LCD_VER_RES; - disp_drv->draw_buf = draw_buf; - disp_drv->flush_cb = _lcd_flush; - disp_drv->direct_mode = 1; + disp_drv->hor_res = LCD_HOR_RES; + disp_drv->ver_res = LCD_VER_RES; + disp_drv->draw_buf = draw_buf; + disp_drv->flush_cb = _lcd_flush; #ifdef SCREEN_MODE_COLOR memcpy(&_small_lcd_disp_drv, &_big_lcd_disp_drv, sizeof(lv_disp_drv_t)); _small_lcd_disp_drv.draw_buf = &_small_lcd_draw_buf; @@ -161,13 +160,24 @@ static void _lcd_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_ } #ifdef SCREEN_MODE_MONO + static void _lcd_rounder(lv_disp_drv_t* disp_drv, lv_area_t* area) { + // The Sharp display only allows writing whole lines, so expand the rectangle to cover the + // full width of the screen. area->x1 = 0; area->x2 = 229; - area->y1 = 0; - area->y2 = 302; } +uint8_t byte_lookup_table[] = { + 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, + 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, + 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, + 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, + 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, + 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, + 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, 128, 64, 32, 16, 8, 4, 2, 1, + 128, 64, 32, 16, 8, 4}; + static void _lcd_set_px(lv_disp_drv_t* disp_drv, uint8_t* buf, lv_coord_t buf_w, @@ -177,10 +187,12 @@ static void _lcd_set_px(lv_disp_drv_t* disp_drv, lv_opa_t opa) { buf += 30 * y; buf += x >> 3; - if (lv_color_brightness(color) > 128) { - (*buf) |= (1 << (7 - (x & 0x07))); + uint8_t byte_value = byte_lookup_table[x]; + + if (lv_color_brightness(color) > 96) { + (*buf) |= byte_value; } else { - (*buf) &= ~(1 << (7 - (x & 0x07))); + (*buf) &= ~byte_value; } } #endif // SCREEN_MODE_MONO diff --git a/ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h b/ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h index 3a8541c1a..b22550423 100644 --- a/ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h +++ b/ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h @@ -48,16 +48,17 @@ typedef struct _LCDTestScreen { #define COLOR_BLACK 0 #define COLOR_WHITE 1 -void lcd_init(bool clear); -void lcd_deinit(void); -void lcd_fill(uint16_t color); -void lcd_clear(uint16_t color); -void lcd_update(bool invert); -void lcd_update_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* data); -void lcd_draw_glyph(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* glyph, uint16_t color); -void lcd_draw_image(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* image); +void lcd_init(bool clear); +void lcd_deinit(void); +void lcd_fill(uint16_t color); +void lcd_clear(uint16_t color); +void lcd_update(bool invert); +void lcd_update_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* data); +void lcd_update_viewfinder(uint8_t* grayscale, uint16_t gray_hor_res, uint16_t gray_ver_res); +void lcd_draw_glyph(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* glyph, uint16_t color); +void lcd_draw_image(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* image); uint16_t lcd_get_glyph_pixel(int16_t x, int16_t y, uint16_t w, uint16_t h, uint8_t* image); uint16_t lcd_get_image_pixel(int16_t x, int16_t y, uint16_t w, uint16_t h, uint8_t* image, uint16_t default_color); -void lcd_set_pixel(int16_t x, int16_t y, uint16_t color); +void lcd_set_pixel(int16_t x, int16_t y, uint16_t color); #endif /* __LCD_SHARP_H__ */ diff --git a/ports/stm32/boards/Passport/modpassport_lv-lcd.h b/ports/stm32/boards/Passport/modpassport_lv-lcd.h index 5c2eb61f2..2510467d8 100644 --- a/ports/stm32/boards/Passport/modpassport_lv-lcd.h +++ b/ports/stm32/boards/Passport/modpassport_lv-lcd.h @@ -20,8 +20,29 @@ STATIC mp_obj_t mod_passport_lv_lcd_init(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_passport_lv_lcd_init_obj, mod_passport_lv_lcd_init); +#ifdef SCREEN_MODE_MONO +STATIC mp_obj_t mod_passport_lv_lcd_update_viewfinder_direct(size_t n_args, const mp_obj_t* args) { + mp_buffer_info_t grayscale_info; + mp_get_buffer_raise(args[0], &grayscale_info, MP_BUFFER_READ); + + mp_int_t hor_res = mp_obj_get_int(args[1]); + mp_int_t ver_res = mp_obj_get_int(args[2]); + + lcd_update_viewfinder(grayscale_info.buf, hor_res, ver_res); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_passport_lv_lcd_update_viewfinder_direct_obj, + 3, + 3, + mod_passport_lv_lcd_update_viewfinder_direct); +#endif + STATIC const mp_rom_map_elem_t mod_passport_lv_lcd_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mod_passport_lv_lcd_init_obj)}, +#ifdef SCREEN_MODE_MONO + {MP_ROM_QSTR(MP_QSTR_update_viewfinder_direct), MP_ROM_PTR(&mod_passport_lv_lcd_update_viewfinder_direct_obj)}, +#endif }; STATIC MP_DEFINE_CONST_DICT(mod_passport_lv_lcd_globals, mod_passport_lv_lcd_globals_table); diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index b55003ba8..a083d536d 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -70,7 +70,10 @@ def __init__(self, self.progress_label = Label(text=progress_text(0), color=TEXT_GREY) with Stylize(self.progress_label) as default: default.align(lv.ALIGN.BOTTOM_MID) - default.pad(bottom=8) + if passport.IS_COLOR: + default.pad(bottom=8) + else: + default.pad(bottom=2) self.set_children([self.camera, self.progress_label]) def attach(self, group): diff --git a/ports/stm32/boards/Passport/modules/views/camera.py b/ports/stm32/boards/Passport/modules/views/camera.py index acba1bac7..52007d98d 100644 --- a/ports/stm32/boards/Passport/modules/views/camera.py +++ b/ports/stm32/boards/Passport/modules/views/camera.py @@ -72,9 +72,14 @@ def update(self): # full access to the buffer. self.hook() - # Resize the framebuffer and invalidate the widget contents, so it gets redrawn. - camera.resize(self.content_width, self.content_height) - self.lvgl_root.invalidate() + if passport.IS_COLOR or passport.IS_SIMULATOR: + # Resize the framebuffer and invalidate the widget contents, so it gets redrawn. + camera.resize(self.content_width, self.content_height) + self.lvgl_root.invalidate() + else: # MONO device + # Update the viewfinder using the grayscale image in the QR framebuffer + import passport_lv + passport_lv.lcd.update_viewfinder_direct(qr.framebuffer, self.HOR_RES, self.VER_RES) def enable(self): """Enable the camera""" From d6f3483baff2419fae15923299037a682169fd6b Mon Sep 17 00:00:00 2001 From: Ken Carpenter Date: Wed, 4 Jan 2023 23:10:41 -0800 Subject: [PATCH 006/156] PASS1-576: Round corners of viewfinder and adjust position --- .../Passport/common/lcd-sharp-ls018b7dh02.c | 47 +++++++++++++++---- ports/stm32/boards/Passport/framebuffer.c | 7 ++- .../boards/Passport/modules/constants.py | 2 +- .../stm32/boards/Passport/modules/display.py | 2 +- .../Passport/modules/pages/scan_qr_page.py | 14 ++++-- .../boards/Passport/modules/views/camera.py | 21 +++++++-- 6 files changed, 73 insertions(+), 20 deletions(-) diff --git a/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c b/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c index e6b2f7c56..ce1caadca 100644 --- a/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c +++ b/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c @@ -224,18 +224,27 @@ void lcd_update_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t* da HAL_SPI_Transmit(lcd.spi, (uint8_t*)&screen.lines[y], sizeof(ScreenLine) * h, 1000); } -#define VIEWFINDER_WIDTH 180 -#define VIEWFINDER_HEIGHT 180 -#define VIEWFINDER_Y_START 52 +#define VIEWFINDER_WIDTH 188 +#define VIEWFINDER_HEIGHT 188 +#define VIEWFINDER_Y_START 49 +#define VIEWFINDER_X_OFFSET (SCREEN_WIDTH - VIEWFINDER_WIDTH) / 2 + +// Force the specified pixel to white +static void _lcd_set_pixel(uint32_t x, uint32_t y) { + uint32_t mono_offset = x >> 3; + uint8_t bit = x % 8; + uint8_t* p_byte = &screen.lines[y].pixels[mono_offset]; + + // Set the bit + *p_byte |= 1 << (7 - bit); +} // A very hard-coded function to resize the grayscale camera image to the viewfinder size, and convert from // grayscle to mono as quickly as possible. static void _lcd_resize_and_render_viewfinder_direct(uint8_t* grayscale, uint32_t gray_hor_res, uint32_t gray_ver_res) { - float scale = (float)gray_ver_res / (float)VIEWFINDER_HEIGHT; - uint32_t x_offset = (SCREEN_WIDTH - VIEWFINDER_WIDTH) / 2; + float scale = (float)gray_ver_res / (float)VIEWFINDER_HEIGHT; // printf("hor_res=%lu ver_res=%lu scale=%f\n", gray_hor_res, gray_ver_res, (double)scale); - // printf("x_offset=%lu\n", x_offset); for (uint32_t y = 0; y < VIEWFINDER_HEIGHT; y++) { for (uint32_t x = 0; x < VIEWFINDER_WIDTH; x++) { @@ -244,9 +253,10 @@ static void _lcd_resize_and_render_viewfinder_direct(uint8_t* grayscale, uint32_ // Mask the value in it uint32_t flipped_x = VIEWFINDER_WIDTH - x; - uint32_t mono_offset = (x_offset + flipped_x) >> 3; - uint8_t bit = (x_offset + flipped_x) % 8; - uint8_t* p_byte = &screen.lines[y + VIEWFINDER_Y_START].pixels[mono_offset]; + uint32_t mono_offset = (VIEWFINDER_X_OFFSET + flipped_x) >> 3; + uint8_t bit = (VIEWFINDER_X_OFFSET + flipped_x) % 8; + uint8_t* p_byte = &screen.lines[VIEWFINDER_Y_START + y].pixels[mono_offset]; + if (gray > 64) { // Set the bit *p_byte |= 1 << (7 - bit); @@ -256,6 +266,25 @@ static void _lcd_resize_and_render_viewfinder_direct(uint8_t* grayscale, uint32_ } } } + + // Force the corners to be white to "round" the viewfinder + uint32_t corner_lines[] = {8, 6, 5, 3, 3, 2, 1, 1}; + uint32_t num_lines = sizeof(corner_lines) / sizeof(uint32_t); + for (uint32_t x = 0; x < num_lines; x++) { + for (uint32_t y = 0; y < corner_lines[x]; y++) { + // Upper-left + _lcd_set_pixel(VIEWFINDER_X_OFFSET + x, VIEWFINDER_Y_START + y); + + // Upper-right + _lcd_set_pixel(VIEWFINDER_X_OFFSET + VIEWFINDER_WIDTH - x, VIEWFINDER_Y_START + y); + + // Lower-left + _lcd_set_pixel(VIEWFINDER_X_OFFSET + x, VIEWFINDER_Y_START + VIEWFINDER_HEIGHT - y); + + // Lower-right + _lcd_set_pixel(VIEWFINDER_X_OFFSET + VIEWFINDER_WIDTH - x, VIEWFINDER_Y_START + VIEWFINDER_HEIGHT - y); + } + } } // Given a full grayscale camera image buffer, resize it to fit in a diff --git a/ports/stm32/boards/Passport/framebuffer.c b/ports/stm32/boards/Passport/framebuffer.c index 242f83392..fabf8bfd9 100644 --- a/ports/stm32/boards/Passport/framebuffer.c +++ b/ports/stm32/boards/Passport/framebuffer.c @@ -165,7 +165,12 @@ static void _lcd_rounder(lv_disp_drv_t* disp_drv, lv_area_t* area) { // The Sharp display only allows writing whole lines, so expand the rectangle to cover the // full width of the screen. area->x1 = 0; - area->x2 = 229; + area->x2 = LCD_HOR_RES - 1; + + // LVGL sometimes miscalculates the update region by 1 pixel on the bottom, so we expand the region + // It's possible we might expand it more than once when coalescing multiple regions, but this is not + // going to affect performance in a noticeable way. + area->y2 = MIN(area->y2 + 1, LCD_VER_RES - 1); } uint8_t byte_lookup_table[] = { diff --git a/ports/stm32/boards/Passport/modules/constants.py b/ports/stm32/boards/Passport/modules/constants.py index 09dccdf40..2ea12aa59 100644 --- a/ports/stm32/boards/Passport/modules/constants.py +++ b/ports/stm32/boards/Passport/modules/constants.py @@ -140,7 +140,7 @@ def set_gen1_constants(): # Display constants # TODO: Can we reference Display.HEIGHT here instead of 303? STATUSBAR_HEIGHT = 40 - CARD_PAD_BOTTOM = 28 + CARD_PAD_BOTTOM = 26 CARD_PAD_LEFT = 4 CARD_PAD_RIGHT = 4 OUTER_CORNER_RADIUS = 16 diff --git a/ports/stm32/boards/Passport/modules/display.py b/ports/stm32/boards/Passport/modules/display.py index be5e83531..ef99c1d2e 100644 --- a/ports/stm32/boards/Passport/modules/display.py +++ b/ports/stm32/boards/Passport/modules/display.py @@ -44,7 +44,7 @@ class Display: HALF_WIDTH = WIDTH // 2 HEIGHT = 303 HALF_HEIGHT = HEIGHT // 2 - HEADER_HEIGHT = 40 + HEADER_HEIGHT = 38 FOOTER_HEIGHT = 32 SCROLLBAR_WIDTH = 8 NUM_LVGL_BUF_LINES = HEIGHT diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index a083d536d..7849f1f56 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -58,9 +58,13 @@ def __init__(self, else: # Camera needs to be a square on Founders Edition so that the rotation # works properly. - self.camera.set_width(180) - self.camera.set_height(180) - self.camera.set_y(-22) + self.camera.set_width(188) + self.camera.set_height(188) + + if passport.IS_COLOR: + self.camera.set_y(-22) + else: + self.camera.set_y(-12) self.set_scroll_dir(dir=lv.DIR.NONE) with Stylize(self.camera) as default: default.align(lv.ALIGN.CENTER) @@ -73,7 +77,9 @@ def __init__(self, if passport.IS_COLOR: default.pad(bottom=8) else: - default.pad(bottom=2) + # self.progress_label.set_y(0) + default.pad(bottom=0) + self.set_children([self.camera, self.progress_label]) def attach(self, group): diff --git a/ports/stm32/boards/Passport/modules/views/camera.py b/ports/stm32/boards/Passport/modules/views/camera.py index 52007d98d..fccc897e9 100644 --- a/ports/stm32/boards/Passport/modules/views/camera.py +++ b/ports/stm32/boards/Passport/modules/views/camera.py @@ -9,6 +9,8 @@ from foundation import qr from passport import camera from views import View +from styles import Stylize +from styles.colors import WHITE from data_codecs.qr_factory import get_qr_decoder_for_data @@ -42,8 +44,16 @@ def __init__(self): self.content_height = None self.img_dsc = None + if not passport.IS_COLOR and not passport.IS_SIMULATOR: + with Stylize(self) as default: + default.bg_color(WHITE) + default.border_width(0) + def create_lvgl_root(self, lvgl_parent): # noqa - return lv.img(lvgl_parent) + if passport.IS_COLOR or passport.IS_SIMULATOR: + return lv.img(lvgl_parent) + else: + return lv.obj(lvgl_parent) def hook(self): pass @@ -97,7 +107,13 @@ def enable(self): # complete area). The pixel format of the camera is the same one as the # LVGL format. self._framebuffer = camera.framebuffer() + + # Nothing else to do on device since viewfinder is hard-wired at the lower level + if not passport.IS_COLOR and not passport.IS_SIMULATOR: + return + self.lvgl_root.refr_size() + self.content_width = min(self.content_width, self.HOR_RES) self.content_height = min(self.content_height, self.VER_RES) self.img_dsc = lv.img_dsc_t({ @@ -109,9 +125,6 @@ def enable(self): 'data': self._framebuffer, }) self.lvgl_root.set_src(self.img_dsc) - if not passport.IS_COLOR and not passport.IS_SIMULATOR: - self.lvgl_root.set_pivot(self.content_width // 2, self.content_height // 2) - self.lvgl_root.set_angle(900) else: self.content_width = None self.content_height = None From f4642f69e9b663cf896b1d4a1a70aafa5a6de9f1 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 16 Jan 2023 19:00:08 +0100 Subject: [PATCH 007/156] PASS1-621: Remove duplicated QRType. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/data_codecs/data_format.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_format.py b/ports/stm32/boards/Passport/modules/data_codecs/data_format.py index 7b6b13137..38c186aba 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_format.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_format.py @@ -18,12 +18,6 @@ MagicScanValidateAddressFlow) -class QRType: - QR = 0 # Standard QR code with no additional encoding - UR1 = 1 # UR 1.0 pre-standard from Blockchain Commons - UR2 = 2 # UR 2.0 standard from Blockchain Commons - - samplers = [ {'name': 'psbt', 'sampler': PsbtTxnSampler, 'flow': MagicScanSignPsbtFlow}, {'name': 'multisig', 'sampler': MultisigConfigSampler, 'flow': MagicScanImportMultisigFlow}, From 462bffc563b1e05af3fa533dc3f4622f0d5284d0 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 16 Jan 2023 15:20:59 -0600 Subject: [PATCH 008/156] PASS1-535: added function to remove settings based on regex --- ports/stm32/boards/Passport/modules/ext_settings.py | 6 ++++++ .../boards/Passport/modules/tasks/erase_passport_task.py | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/ext_settings.py b/ports/stm32/boards/Passport/modules/ext_settings.py index f8610522a..7ea45b1bc 100644 --- a/ports/stm32/boards/Passport/modules/ext_settings.py +++ b/ports/stm32/boards/Passport/modules/ext_settings.py @@ -254,6 +254,12 @@ def remove(self, kn): self.current.pop(kn, None) self.changed() + def remove_regex(self, pattern): + import re + matches = [k for k in self.current if re.search(pattern, k)] + for k in matches: + self.remove(k) + def clear(self): # print('clear() called!') # could be just: diff --git a/ports/stm32/boards/Passport/modules/tasks/erase_passport_task.py b/ports/stm32/boards/Passport/modules/tasks/erase_passport_task.py index 14a582781..f4423f597 100644 --- a/ports/stm32/boards/Passport/modules/tasks/erase_passport_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/erase_passport_task.py @@ -30,8 +30,7 @@ async def erase_passport_task(on_done, full_reset): settings.remove('enable_passphrase') settings.remove('envoy_setup') settings.remove('manual_setup') - settings.remove('ext.casa.enabled') - settings.remove('ext.postmix.enabled') + settings.remove_regex("^ext\\.*") settings.remove('next_addrs') await sleep_ms(1) From 1002c44324bcf186160fade50d324c3bb507563b Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 17 Jan 2023 18:14:35 -0600 Subject: [PATCH 009/156] PASS1-535: pre-compiled regex --- ports/stm32/boards/Passport/modules/ext_settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/ext_settings.py b/ports/stm32/boards/Passport/modules/ext_settings.py index 7ea45b1bc..73f2b88e4 100644 --- a/ports/stm32/boards/Passport/modules/ext_settings.py +++ b/ports/stm32/boards/Passport/modules/ext_settings.py @@ -256,7 +256,8 @@ def remove(self, kn): def remove_regex(self, pattern): import re - matches = [k for k in self.current if re.search(pattern, k)] + pattern = re.compile(pattern) + matches = [k for k in self.current if pattern.search(k)] for k in matches: self.remove(k) From 379192f87a421568a5144111e4c091aa1eebd6dd Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 25 Jan 2023 18:49:58 +0100 Subject: [PATCH 010/156] PASS1-557: Use format for string creation Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index c8c4bce08..cfe39e851 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -272,7 +272,7 @@ def get_file_list(path=None, include_folders=False, include_parent=False, suffix if not is_folder and filter_fn is not None and not filter_fn(filename): continue - full_path = path + '/' + filename + full_path = "{}/{}".format(path, filename) file_list.append((filename, full_path, is_folder)) @@ -557,9 +557,9 @@ def cleanup_deriv_path(bin_path, allow_star=False): ip = int(p, 10) except Exception: ip = -1 - assert 0 <= ip < 0x80000000 and p == str(ip), "bad component: " + p + assert 0 <= ip < 0x80000000 and p == str(ip), "bad component: {}".format(p) - return 'm/' + '/'.join(parts) + return 'm/{}'.format('/'.join(parts)) def keypath_to_str(bin_path, prefix='m/', skip=1): From 2970a667b4d82d00e4cdb5917f063280c10724fb Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 25 Jan 2023 18:23:36 +0100 Subject: [PATCH 011/156] PASS1-643: Add alphanumeric support to widget This adds alphanumeric support to the LVGL QR code widget by checking at the update function if the input is alphanumeric. Previously it would encode everything as binary. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../lvgl/src/extra/libs/qrcode/lv_qrcode.c | 26 +++++----- .../lvgl/src/extra/libs/qrcode/lv_qrcode.h | 2 +- .../lvgl/src/extra/libs/qrcode/qrcodegen.c | 47 ++++++++++++------- .../lvgl/src/extra/libs/qrcode/qrcodegen.h | 12 ++--- 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/lib/lv_bindings/lvgl/src/extra/libs/qrcode/lv_qrcode.c b/lib/lv_bindings/lvgl/src/extra/libs/qrcode/lv_qrcode.c index dc72f9522..a283f74cb 100644 --- a/lib/lv_bindings/lvgl/src/extra/libs/qrcode/lv_qrcode.c +++ b/lib/lv_bindings/lvgl/src/extra/libs/qrcode/lv_qrcode.c @@ -62,8 +62,6 @@ void lv_qrcode_set_buffer(lv_obj_t * obj, void * img_buf, lv_coord_t hor_res, lv qrcode->modules_buf = modules_buf; qrcode->max_version = max_version; - // printf("modules buf %p\n", qrcode->modules_buf); - lv_canvas_set_buffer(obj, img_buf, hor_res, ver_res, LV_IMG_CF_INDEXED_1BIT); lv_canvas_set_palette(obj, 0, dark_color); lv_canvas_set_palette(obj, 1, light_color); @@ -89,7 +87,7 @@ int32_t lv_qrcode_get_last_version(lv_obj_t * obj) int32_t lv_qrcode_get_min_fit_version(lv_obj_t * obj, uint32_t data_len) { LV_UNUSED(obj); - return qrcodegen_getMinFitVersion(qrcodegen_Ecc_LOW, data_len); + return qrcodegen_getMinFitVersion(qrcodegen_Ecc_LOW, qrcodegen_Mode_BYTE, data_len); } lv_res_t lv_qrcode_update(lv_obj_t * obj, const void * data, uint32_t data_len, int32_t min_version) @@ -105,7 +103,13 @@ lv_res_t lv_qrcode_update(lv_obj_t * obj, const void * data, uint32_t data_len, lv_img_dsc_t * imgdsc = lv_canvas_get_img(obj); lv_coord_t res = LV_MIN(imgdsc->header.w, imgdsc->header.h); - int32_t qr_version = qrcodegen_getMinFitVersion(qrcodegen_Ecc_LOW, data_len); + int32_t qr_version; + if (qrcodegen_isAlphanumeric((const char*)data, data_len)) { + qr_version = qrcodegen_getMinFitVersion(qrcodegen_Ecc_LOW, qrcodegen_Mode_ALPHANUMERIC, data_len); + } else { + qr_version = qrcodegen_getMinFitVersion(qrcodegen_Ecc_LOW, qrcodegen_Mode_BYTE, data_len); + } + if(qr_version <= 0) return LV_RES_INV; if(qr_version > qrcode->max_version) return LV_RES_INV; if(qr_version < min_version) qr_version = min_version; @@ -123,16 +127,10 @@ lv_res_t lv_qrcode_update(lv_obj_t * obj, const void * data, uint32_t data_len, } qrcode->last_version = qr_version; - if (data_len > sizeof(qrcode->data_and_tmp)) { - return LV_RES_INV; - } - - lv_memcpy(qrcode->data_and_tmp, data, data_len); - - bool ok = qrcodegen_encodeBinary(qrcode->data_and_tmp, data_len, - qrcode->modules_buf, qrcodegen_Ecc_LOW, - qr_version, qr_version, - qrcodegen_Mask_AUTO, true); + bool ok = qrcodegen_encodeText((const char*)data, data_len, qrcode->tmp, + qrcode->modules_buf, qrcodegen_Ecc_LOW, + qr_version, qr_version, + qrcodegen_Mask_AUTO, true); if (!ok) { return LV_RES_INV; } diff --git a/lib/lv_bindings/lvgl/src/extra/libs/qrcode/lv_qrcode.h b/lib/lv_bindings/lvgl/src/extra/libs/qrcode/lv_qrcode.h index 34ae0fdc1..25c57896c 100644 --- a/lib/lv_bindings/lvgl/src/extra/libs/qrcode/lv_qrcode.h +++ b/lib/lv_bindings/lvgl/src/extra/libs/qrcode/lv_qrcode.h @@ -37,7 +37,7 @@ extern "C" { void *modules_buf; int32_t max_version; int32_t last_version; - uint8_t data_and_tmp[650]; + uint8_t tmp[LV_QRCODE_MODULES_BUF_SIZE(40)]; } lv_qrcode_t; /********************** diff --git a/lib/lv_bindings/lvgl/src/extra/libs/qrcode/qrcodegen.c b/lib/lv_bindings/lvgl/src/extra/libs/qrcode/qrcodegen.c index 27cd91852..ff0989d42 100644 --- a/lib/lv_bindings/lvgl/src/extra/libs/qrcode/qrcodegen.c +++ b/lib/lv_bindings/lvgl/src/extra/libs/qrcode/qrcodegen.c @@ -125,23 +125,22 @@ static const int PENALTY_N4 = 10; /*---- High-level QR Code encoding functions ----*/ // Public function - see documentation comment in header file. -bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], +bool qrcodegen_encodeText(const char *text, size_t textLen, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { - size_t textLen = strlen(text); if (textLen == 0) return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); size_t bufLen = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion); struct qrcodegen_Segment seg; - if (qrcodegen_isNumeric(text)) { + if (qrcodegen_isNumeric(text, textLen)) { if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) goto fail; - seg = qrcodegen_makeNumeric(text, tempBuffer); - } else if (qrcodegen_isAlphanumeric(text)) { + seg = qrcodegen_makeNumeric(text, textLen, tempBuffer); + } else if (qrcodegen_isAlphanumeric(text, textLen)) { if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen) goto fail; - seg = qrcodegen_makeAlphanumeric(text, tempBuffer); + seg = qrcodegen_makeAlphanumeric(text, textLen, tempBuffer); } else { if (textLen > bufLen) goto fail; @@ -794,22 +793,29 @@ static bool getBit(int x, int i) { /*---- Segment handling ----*/ // Public function - see documentation comment in header file. -bool qrcodegen_isAlphanumeric(const char *text) { +bool qrcodegen_isAlphanumeric(const char *text, size_t textLen) { assert(text != NULL); - for (; *text != '\0'; text++) { + while (textLen) { if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) return false; + + text++; + textLen--; } + return true; } // Public function - see documentation comment in header file. -bool qrcodegen_isNumeric(const char *text) { +bool qrcodegen_isNumeric(const char *text, size_t textLen) { assert(text != NULL); - for (; *text != '\0'; text++) { + while (textLen) { if (*text < '0' || *text > '9') return false; + + text++; + textLen--; } return true; } @@ -875,10 +881,9 @@ struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, u // Public function - see documentation comment in header file. -struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) { +struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, size_t len, uint8_t buf[]) { assert(digits != NULL); struct qrcodegen_Segment result; - size_t len = strlen(digits); result.mode = qrcodegen_Mode_NUMERIC; int bitLen = calcSegmentBitLength(result.mode, len); assert(bitLen != -1); @@ -889,7 +894,7 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] unsigned int accumData = 0; int accumCount = 0; - for (; *digits != '\0'; digits++) { + while (len) { char c = *digits; assert('0' <= c && c <= '9'); accumData = accumData * 10 + (unsigned int)(c - '0'); @@ -899,7 +904,10 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] accumData = 0; accumCount = 0; } + digits++; + len--; } + if (accumCount > 0) // 1 or 2 digits remaining appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength); assert(result.bitLength == bitLen); @@ -909,10 +917,9 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] // Public function - see documentation comment in header file. -struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) { +struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, size_t len, uint8_t buf[]) { assert(text != NULL); struct qrcodegen_Segment result; - size_t len = strlen(text); result.mode = qrcodegen_Mode_ALPHANUMERIC; int bitLen = calcSegmentBitLength(result.mode, len); assert(bitLen != -1); @@ -923,7 +930,7 @@ struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t bu unsigned int accumData = 0; int accumCount = 0; - for (; *text != '\0'; text++) { + while (len) { const char *temp = strchr(ALPHANUMERIC_CHARSET, *text); assert(temp != NULL); accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET); @@ -933,7 +940,11 @@ struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t bu accumData = 0; accumCount = 0; } + + text++; + len--; } + if (accumCount > 0) // 1 character remaining appendBitsToBuffer(accumData, 6, buf, &result.bitLength); assert(result.bitLength == bitLen); @@ -1009,10 +1020,10 @@ static int numCharCountBits(enum qrcodegen_Mode mode, int version) { } } -int qrcodegen_getMinFitVersion(enum qrcodegen_Ecc ecl, size_t dataLen) +int qrcodegen_getMinFitVersion(enum qrcodegen_Ecc ecl, enum qrcodegen_Mode mode, size_t dataLen) { struct qrcodegen_Segment seg; - seg.mode = qrcodegen_Mode_BYTE; + seg.mode = mode; seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); seg.numChars = (int)dataLen; diff --git a/lib/lv_bindings/lvgl/src/extra/libs/qrcode/qrcodegen.h b/lib/lv_bindings/lvgl/src/extra/libs/qrcode/qrcodegen.h index dceddf605..cfc6622a2 100644 --- a/lib/lv_bindings/lvgl/src/extra/libs/qrcode/qrcodegen.h +++ b/lib/lv_bindings/lvgl/src/extra/libs/qrcode/qrcodegen.h @@ -166,7 +166,7 @@ struct qrcodegen_Segment { * - Please consult the QR Code specification for information on * data capacities per version, ECC level, and text encoding mode. */ -bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], +bool qrcodegen_encodeText(const char *text, size_t textLen, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); @@ -234,14 +234,14 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz * A string is encodable iff each character is in the following set: 0 to 9, A to Z * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. */ -bool qrcodegen_isAlphanumeric(const char *text); +bool qrcodegen_isAlphanumeric(const char *text, size_t textLen); /* * Tests whether the given string can be encoded as a segment in numeric mode. * A string is encodable iff each character is in the range 0 to 9. */ -bool qrcodegen_isNumeric(const char *text); +bool qrcodegen_isNumeric(const char *text, size_t textLen); /* @@ -269,7 +269,7 @@ struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, u /* * Returns a segment representing the given string of decimal digits encoded in numeric mode. */ -struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]); +struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, size_t len, uint8_t buf[]); /* @@ -277,7 +277,7 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] * The characters allowed are: 0 to 9, A to Z (uppercase only), space, * dollar, percent, asterisk, plus, hyphen, period, slash, colon. */ -struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]); +struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, size_t len, uint8_t buf[]); /* @@ -312,7 +312,7 @@ int qrcodegen_version2size(int version); /* * Returns the min version of the data that can be stored. Returns -1 on failure */ -int qrcodegen_getMinFitVersion(enum qrcodegen_Ecc ecl, size_t dataLen); +int qrcodegen_getMinFitVersion(enum qrcodegen_Ecc ecl, enum qrcodegen_Mode mode, size_t dataLen); #ifdef __cplusplus } From 62eeaf2224c6681de42232099396ea19ded7a039 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 25 Jan 2023 18:27:42 +0100 Subject: [PATCH 012/156] PASS1-642: Use version for QR code sizes. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../modules/data_codecs/data_encoder.py | 6 ----- .../Passport/modules/data_codecs/qr_codec.py | 6 ----- .../Passport/modules/data_codecs/ur1_codec.py | 9 ------- .../Passport/modules/data_codecs/ur2_codec.py | 25 ++++++++++++------- .../Passport/modules/pages/show_qr_page.py | 22 ++++++++++++---- 5 files changed, 33 insertions(+), 35 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py b/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py index 18acefdfe..52f625e7a 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py @@ -13,12 +13,6 @@ class DataEncoder: def __init__(self): pass - def get_num_supported_sizes(self): - return 1 - - def get_max_len(self, index): - return 0 - def encode(self, data, is_binary=False, max_fragment_len=None): pass diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index 5d4610bf8..36405778b 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -45,12 +45,6 @@ class QREncoder(DataEncoder): def __init__(self, _args): self.data = None - # def get_num_supported_sizes(self): - # return 1 - - def get_max_len(self, index): - return 300 - def encode(self, data, is_binary=False, max_fragment_len=None): self.data = data diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index ffca8a6a5..72d862d55 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -71,15 +71,6 @@ class UR1Encoder(DataEncoder): def __init__(self, _args): self.parts = [] self.next_index = 0 - self.qr_sizes = [500, 200, 60] - - # def get_num_supported_sizes(self): - # return len(self.qr_sizes) - - def get_max_len(self, index): - if index < 0 or index >= len(self.qr_sizes): - return 0 - return self.qr_sizes[index] # Encode the given data def encode(self, data, is_binary=False, max_fragment_len=500): diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index 2afc65981..d88541e85 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -74,21 +74,12 @@ def get_data_format(self): class UR2Encoder(DataEncoder): def __init__(self, args): self.ur_encoder = None - self.qr_sizes = [140, 70, 25] self.type = None if isinstance(args, dict): self.prefix = args['prefix'] or 'bytes' else: self.prefix = 'bytes' - # def get_num_supported_sizes(self): - # return len(self.qr_sizes) - - def get_max_len(self, index): - if index < 0 or index >= len(self.qr_sizes): - return 0 - return self.qr_sizes[index] - # Encode the given data def encode(self, data, is_binary=False, max_fragment_len=200): # print('UR2Encoder: data="{}"'.format(data)) @@ -101,6 +92,22 @@ def encode(self, data, is_binary=False, max_fragment_len=200): else: ur_obj = data + # CBOR length of a UR2 part. Excluding the data itself on bytes which + # must be of the resulting `max_fragment_len`. + # + # 85 # array(5) + # 1A FFFFFFFF # unsigned(0xFFFFFFFF) + # 1B FFFFFFFFFFFFFFFF # unsigned(0xFFFFFFFFFFFFFFFF) + # 1B FFFFFFFFFFFFFFFF # unsigned(0xFFFFFFFFFFFFFFFF) + # 1A FFFFFFFF # unsigned(0xFFFFFFFF) + # 5B FFFFFFFFFFFFFFFF # bytes(0xFFFFFFFFFFFFFFFF) + max_fragment_cbor = 1 + 5 + 9 + 9 + 5 + 2 + + # "ur:" + prefix + "/99-999/" + max-fragment-cbor + CRC + reserved_len = 3 + len(self.prefix) + len("/99-9999/") + max_fragment_cbor + (4 * 2) + + # Divide in half the maximum fragment length as each byteword encoded byte takes two characters. + max_fragment_len = (max_fragment_len - reserved_len) // 2 self.ur_encoder = UREncoder(ur_obj, max_fragment_len) # UR2.0's next_part() returns the initial pieces split into max_fragment_len bytes, but then switches over to diff --git a/ports/stm32/boards/Passport/modules/pages/show_qr_page.py b/ports/stm32/boards/Passport/modules/pages/show_qr_page.py index dde83f759..0bcbbc83e 100644 --- a/ports/stm32/boards/Passport/modules/pages/show_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/show_qr_page.py @@ -17,6 +17,15 @@ _FRAME_TIME = const(300) +# Supported QR code versions. +# +# Assumes ECC L for alphanumeric and binary capacity. +_VERSIONS = [ + {'alphanumeric': 154, 'binary': 106}, # Version 5 + {'alphanumeric': 279, 'binary': 192}, # Version 8 + {'alphanumeric': 535, 'binary': 367}, # Version 12 +] + brightness_levels = [5, 25, 50, 75, 100] @@ -185,18 +194,21 @@ def update(self): if self.is_attached(): if self.qr_encoder is None: self.qr_encoder = make_qr_encoder(self.qr_type, self.qr_args) - # print('qr_size_idx={}'.format(self.qr_size_idx)) - self.curr_fragment_len = self.qr_encoder.get_max_len(self.qr_size_idx) - # print('curr_fragment_len={}'.format(self.curr_fragment_len)) + + if self.qr_type == QRType.UR2: + self.curr_fragment_len = _VERSIONS[self.qr_size_idx]['alphanumeric'] + else: + self.curr_fragment_len = _VERSIONS[self.qr_size_idx]['binary'] + self.qr_encoder.encode(self.qr_data, max_fragment_len=self.curr_fragment_len) self.qrcode.reset_sizing() part = self.qr_encoder.next_part() - if part is None: return - if self.qr_type != QRType.QR: + # URs are always alphanumeric, but they might be in lowercase. + if self.qr_type == QRType.UR2: part = part.upper() # TODO: Optimization: Don't update if the fragment is the From 1a69c3bb73b4f83a1ab1699b349b791b8d02ee6d Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 24 Jan 2023 16:17:52 -0600 Subject: [PATCH 013/156] PASS1-631: added menu entries for multisig export --- ports/stm32/boards/Passport/manifest.py | 2 + .../boards/Passport/modules/flows/__init__.py | 2 + .../flows/export_multisig_microsd_flow.py | 76 +++++++++++++++++++ .../modules/flows/export_multisig_qr_flow.py | 57 ++++++++++++++ ports/stm32/boards/Passport/modules/menus.py | 5 +- 5 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py create mode 100644 ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index 286384498..35e936a1b 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -85,6 +85,8 @@ 'flows/envoy_setup_flow.py', 'flows/erase_passport_flow.py', + 'flows/export_multisig_microsd_flow.py', + 'flows/export_multisig_qr_flow.py', 'flows/export_summary_flow.py', # 'flows/fcc_test_flow.py', 'flows/file_picker_flow.py', diff --git a/ports/stm32/boards/Passport/modules/flows/__init__.py b/ports/stm32/boards/Passport/modules/flows/__init__.py index 5cc7063b4..09ca01d8e 100644 --- a/ports/stm32/boards/Passport/modules/flows/__init__.py +++ b/ports/stm32/boards/Passport/modules/flows/__init__.py @@ -28,6 +28,8 @@ from .delete_multisig_flow import * from .developer_functions_flow import * from .erase_passport_flow import * +from .export_multisig_microsd_flow import * +from .export_multisig_qr_flow import * from .export_summary_flow import * # from .fcc_test_flow import * from .file_picker_flow import * diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py new file mode 100644 index 000000000..ca244a1f0 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py @@ -0,0 +1,76 @@ +# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# export_multisig_microsd_flow.py - Export a multisig wallet via microSD + +from flows import Flow + + +class ExportMultisigMicrosdFlow(Flow): + def __init__(self, context=None): + from multisig_wallet import MultisigWallet + super().__init__(initial_state=self.choose_wallet_file, name='ExportMultisigMicrosdFlow') + + self.storage_idx = context + self.ms = MultisigWallet.get_by_idx(self.storage_idx) + + async def choose_wallet_file(self): + from flows import FilePickerFlow + from files import CardSlot + from pages import InsertMicroSDPage, ErrorPage + from tasks import read_file_task + from utils import spinner_task + from errors import Error + from multisig_wallet import MultisigWallet + + root_path = CardSlot.get_sd_root() + + result = await FilePickerFlow(initial_path=root_path, show_folders=True).run() + if result is None: + self.set_result(False) + return + + _filename, full_path, is_folder = result + if not is_folder: + result = await spinner_task( + 'Reading File', + read_file_task, + args=[full_path]) + (data, error) = result + if error is None: + try: + self.ms = await MultisigWallet.from_file(data) + except BaseException as e: + if e.args is None or len(e.args) == 0: + self.error = "Multisig Import Error" + else: + self.error = e.args[0] + self.goto(self.show_error) + return + # print('New MS: {}'.format(self.ms.serialize())) + + self.goto(self.do_import) + elif error is Error.MICROSD_CARD_MISSING: + result = await InsertMicroSDPage().show() + if not result: + self.set_result(False) + return + elif error is Error.FILE_WRITE_ERROR: + await ErrorPage(text='Unable to read multisig config file from microSD card.').show() + self.set_result(False) + + async def do_import(self): + from flows import ImportMultisigWalletFlow + from pages import SuccessPage + + # Show the wallet to the user for import + result = await ImportMultisigWalletFlow(self.ms).run() + if result: + await SuccessPage(text='Multisig config imported').show() + self.set_result(result) + + async def show_error(self): + from pages import ErrorPage + await ErrorPage(text=self.error).show() + self.error = None + self.reset(self.choose_wallet_file) diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py new file mode 100644 index 000000000..11a990e0a --- /dev/null +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# export_multisig_qr_flow.py - Export a multisig wallet via QR code + +from flows import Flow + + +class ExportMultisigQRFlow(Flow): + def __init__(self, context=None): + from multisig_wallet import MultisigWallet + super().__init__(initial_state=self.scan_qr_code, name='ExportMultisigQRFlow') + + self.storage_idx = context + self.ms = MultisigWallet.get_by_idx(self.storage_idx) + + async def scan_qr_code(self): + from pages import ScanQRPage + from multisig_wallet import MultisigWallet + + result = await ScanQRPage(decode_cbor_bytes=True).show() + if result is None or result.error is not None: + self.set_result(False) + return + + data = result.data + if isinstance(data, (bytes, bytearray)): + data = data.decode('utf-8') + + try: + self.ms = await MultisigWallet.from_file(data) + except BaseException as e: + if e.args is None or len(e.args) == 0: + self.error = "Multisig Import Error" + else: + self.error = e.args[0] + self.goto(self.show_error) + return + # print('New MS: {}'.format(self.ms.serialize())) + + self.goto(self.do_import) + + async def do_import(self): + from flows import ImportMultisigWalletFlow + from pages import SuccessPage + + # Show the wallet to the user for import + result = await ImportMultisigWalletFlow(self.ms).run() + if result: + await SuccessPage(text='Multisig config imported').show() + self.set_result(result) + + async def show_error(self): + from pages import ErrorPage + await ErrorPage(text=self.error).show() + self.error = None + self.reset(self.scan_qr_code) diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index 8bcb1fa79..96f712758 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -150,10 +150,13 @@ def microsd_menu(): def multisig_item_menu(): - from flows import RenameMultisigFlow, DeleteMultisigFlow, ViewMultisigDetailsFlow + from flows import (RenameMultisigFlow, DeleteMultisigFlow, ViewMultisigDetailsFlow, + ExportMultisigQRFlow, ExportMultisigMicrosdFlow) return [ {'icon': lv.ICON_TWO_KEYS, 'label': 'View Details', 'flow': ViewMultisigDetailsFlow}, + {'icon': lv.ICON_SCAN_QR, 'label': 'Export via QR', 'flow': ExportMultisigQRFlow}, + {'icon': lv.ICON_MICROSD, 'label': 'Export via microSD', 'flow': ExportMultisigMicrosdFlow}, {'icon': lv.ICON_TWO_KEYS, 'label': 'Rename', 'flow': RenameMultisigFlow}, {'icon': lv.ICON_TWO_KEYS, 'label': 'Delete', 'flow': DeleteMultisigFlow}, ] From 87386e27317f98282553a49fe10131849d4f92cd Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 25 Jan 2023 16:28:11 -0600 Subject: [PATCH 014/156] PASS1-631: keeper multisig QR export working --- .../modules/flows/export_multisig_qr_flow.py | 47 +++---------------- .../import_multisig_wallet_from_qr_flow.py | 1 + .../Passport/modules/multisig_wallet.py | 13 +++++ .../Passport/modules/public_constants.py | 12 +++++ 4 files changed, 33 insertions(+), 40 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py index 11a990e0a..ae16b58b0 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py @@ -9,49 +9,16 @@ class ExportMultisigQRFlow(Flow): def __init__(self, context=None): from multisig_wallet import MultisigWallet - super().__init__(initial_state=self.scan_qr_code, name='ExportMultisigQRFlow') + super().__init__(initial_state=self.show_qr_code, name='ExportMultisigQRFlow') self.storage_idx = context self.ms = MultisigWallet.get_by_idx(self.storage_idx) + self.ms_text = self.ms.to_file() - async def scan_qr_code(self): - from pages import ScanQRPage + async def show_qr_code(self): + from pages import ShowQRPage + from data_codecs.qr_type import QRType from multisig_wallet import MultisigWallet - result = await ScanQRPage(decode_cbor_bytes=True).show() - if result is None or result.error is not None: - self.set_result(False) - return - - data = result.data - if isinstance(data, (bytes, bytearray)): - data = data.decode('utf-8') - - try: - self.ms = await MultisigWallet.from_file(data) - except BaseException as e: - if e.args is None or len(e.args) == 0: - self.error = "Multisig Import Error" - else: - self.error = e.args[0] - self.goto(self.show_error) - return - # print('New MS: {}'.format(self.ms.serialize())) - - self.goto(self.do_import) - - async def do_import(self): - from flows import ImportMultisigWalletFlow - from pages import SuccessPage - - # Show the wallet to the user for import - result = await ImportMultisigWalletFlow(self.ms).run() - if result: - await SuccessPage(text='Multisig config imported').show() - self.set_result(result) - - async def show_error(self): - from pages import ErrorPage - await ErrorPage(text=self.error).show() - self.error = None - self.reset(self.scan_qr_code) + await ShowQRPage(qr_type=QRType.UR2, qr_data=self.ms_text).show() + self.set_result(True) diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py index 45b1e15db..1e913a445 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py @@ -24,6 +24,7 @@ async def scan_qr_code(self): data = result.data if isinstance(data, (bytes, bytearray)): data = data.decode('utf-8') + print(data) try: self.ms = await MultisigWallet.from_file(data) diff --git a/ports/stm32/boards/Passport/modules/multisig_wallet.py b/ports/stm32/boards/Passport/modules/multisig_wallet.py index d09188b01..2bfa26b29 100644 --- a/ports/stm32/boards/Passport/modules/multisig_wallet.py +++ b/ports/stm32/boards/Passport/modules/multisig_wallet.py @@ -720,6 +720,19 @@ def from_file(cls, config, name=None): # done. have all the parts return cls(name, (M, N), xpubs, unique_id, addr_fmt=addr_fmt, chain_type=expect_chain, deriv=my_deriv) + def to_file(self): + from public_constants import MULTISIG_EXPORT_TEMPLATE, MULTISIG_DERIV_TEMPLATE + file_string = MULTISIG_EXPORT_TEMPLATE.format(self.name, + self.M, + self.N, + self.render_addr_fmt(self.addr_fmt)) + + for xfp, deriv, xpub in self.xpubs: + file_string += MULTISIG_DERIV_TEMPLATE.format(deriv, xfp2str(xfp), xpub) + + print(file_string) + return file_string + @classmethod def check_xpub(cls, xfp, xpub, deriv, expect_chain, my_xfp, xpubs): # Shared code: consider an xpub for inclusion into a wallet, if ok, append diff --git a/ports/stm32/boards/Passport/modules/public_constants.py b/ports/stm32/boards/Passport/modules/public_constants.py index f7bd10fee..662af48f7 100644 --- a/ports/stm32/boards/Passport/modules/public_constants.py +++ b/ports/stm32/boards/Passport/modules/public_constants.py @@ -103,5 +103,17 @@ -----END {blockchain} SIGNED MESSAGE----- ''' +MULTISIG_EXPORT_TEMPLATE = '''\ +Name: {} +Policy: {} of {} +Format: {} +''' + +MULTISIG_DERIV_TEMPLATE = '''\ + +Derivation: {} +{}: {} +''' + # EOF From 956d24f6f10764d64e6de0eba3f0564fa1d6c4bb Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 25 Jan 2023 18:44:16 -0600 Subject: [PATCH 015/156] PASS1-631: added multisig microsd export flow --- .../flows/export_multisig_microsd_flow.py | 99 +++++++++---------- .../Passport/modules/multisig_wallet.py | 1 - 2 files changed, 45 insertions(+), 55 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py index ca244a1f0..46d28c26c 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py @@ -9,68 +9,59 @@ class ExportMultisigMicrosdFlow(Flow): def __init__(self, context=None): from multisig_wallet import MultisigWallet - super().__init__(initial_state=self.choose_wallet_file, name='ExportMultisigMicrosdFlow') + super().__init__(initial_state=self.create_file, name='ExportMultisigMicrosdFlow') self.storage_idx = context self.ms = MultisigWallet.get_by_idx(self.storage_idx) + self.ms_text = self.ms.to_file() + self.fname = None - async def choose_wallet_file(self): - from flows import FilePickerFlow - from files import CardSlot - from pages import InsertMicroSDPage, ErrorPage - from tasks import read_file_task - from utils import spinner_task - from errors import Error - from multisig_wallet import MultisigWallet + async def create_file(self): + from files import CardSlot, CardMissingError + from pages import ErrorPage + from utils import file_exists - root_path = CardSlot.get_sd_root() + multisig_num = 1 - result = await FilePickerFlow(initial_path=root_path, show_folders=True).run() - if result is None: - self.set_result(False) - return + while True: + try: + with CardSlot() as card: + path = card.get_sd_root() + # Make a unique filename + while True: + self.file_path = '{}/{}-multisig-{}.txt'.format(path, + self.ms.name, + multisig_num) + self.file_path = self.file_path.replace(' ', '_') + # Ensure filename doesn't already exist + if not file_exists(self.file_path): + break - _filename, full_path, is_folder = result - if not is_folder: - result = await spinner_task( - 'Reading File', - read_file_task, - args=[full_path]) - (data, error) = result - if error is None: - try: - self.ms = await MultisigWallet.from_file(data) - except BaseException as e: - if e.args is None or len(e.args) == 0: - self.error = "Multisig Import Error" - else: - self.error = e.args[0] - self.goto(self.show_error) - return - # print('New MS: {}'.format(self.ms.serialize())) + # Ooops...that exists, so increment and try again + multisig_num += 1 - self.goto(self.do_import) - elif error is Error.MICROSD_CARD_MISSING: - result = await InsertMicroSDPage().show() - if not result: - self.set_result(False) - return - elif error is Error.FILE_WRITE_ERROR: - await ErrorPage(text='Unable to read multisig config file from microSD card.').show() - self.set_result(False) + # Do actual write + with open(self.file_path, 'w') as fd: + fd.write(self.ms_text) + self.goto(self.show_success) + return - async def do_import(self): - from flows import ImportMultisigWalletFlow - from pages import SuccessPage + except CardMissingError: + self.goto(self.show_insert_microsd_error) + return + except Exception as e: + self.error = e.args[0] + await ErrorPage(text=self.error).show() + self.set_result(False) + return - # Show the wallet to the user for import - result = await ImportMultisigWalletFlow(self.ms).run() - if result: - await SuccessPage(text='Multisig config imported').show() - self.set_result(result) + async def show_insert_microsd_error(self): + result = await InsertMicroSDPage().show() + if not result: + self.set_result(False) + else: + self.goto(self.create_file) - async def show_error(self): - from pages import ErrorPage - await ErrorPage(text=self.error).show() - self.error = None - self.reset(self.choose_wallet_file) + async def show_success(self): + from pages import SuccessPage + await SuccessPage(text='Saved multisig config as {}.'.format(self.file_path)).show() diff --git a/ports/stm32/boards/Passport/modules/multisig_wallet.py b/ports/stm32/boards/Passport/modules/multisig_wallet.py index 2bfa26b29..0464df97b 100644 --- a/ports/stm32/boards/Passport/modules/multisig_wallet.py +++ b/ports/stm32/boards/Passport/modules/multisig_wallet.py @@ -730,7 +730,6 @@ def to_file(self): for xfp, deriv, xpub in self.xpubs: file_string += MULTISIG_DERIV_TEMPLATE.format(deriv, xfp2str(xfp), xpub) - print(file_string) return file_string @classmethod From adcc69bca85c819b7170ae336741e14a182e1acb Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 25 Jan 2023 18:50:12 -0600 Subject: [PATCH 016/156] PASS1-631: refined microsd export --- .../Passport/modules/flows/export_multisig_microsd_flow.py | 1 + ports/stm32/boards/Passport/modules/menus.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py index 46d28c26c..76cf5f070 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py @@ -65,3 +65,4 @@ async def show_insert_microsd_error(self): async def show_success(self): from pages import SuccessPage await SuccessPage(text='Saved multisig config as {}.'.format(self.file_path)).show() + self.set_result(True) diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index 96f712758..7fb6311d0 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -156,7 +156,7 @@ def multisig_item_menu(): return [ {'icon': lv.ICON_TWO_KEYS, 'label': 'View Details', 'flow': ViewMultisigDetailsFlow}, {'icon': lv.ICON_SCAN_QR, 'label': 'Export via QR', 'flow': ExportMultisigQRFlow}, - {'icon': lv.ICON_MICROSD, 'label': 'Export via microSD', 'flow': ExportMultisigMicrosdFlow}, + {'icon': lv.ICON_MICROSD, 'label': 'Export via SD', 'flow': ExportMultisigMicrosdFlow}, {'icon': lv.ICON_TWO_KEYS, 'label': 'Rename', 'flow': RenameMultisigFlow}, {'icon': lv.ICON_TWO_KEYS, 'label': 'Delete', 'flow': DeleteMultisigFlow}, ] From 4f7ea9e67c4f1ef142ca8131bb826f566325efd8 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 25 Jan 2023 18:52:10 -0600 Subject: [PATCH 017/156] PASS1-631: removed debug --- .../modules/flows/import_multisig_wallet_from_qr_flow.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py index 1e913a445..45b1e15db 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py @@ -24,7 +24,6 @@ async def scan_qr_code(self): data = result.data if isinstance(data, (bytes, bytearray)): data = data.decode('utf-8') - print(data) try: self.ms = await MultisigWallet.from_file(data) From c2b8863784d5e6f7f77117720edee4857e358231 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 23 Jan 2023 15:14:29 -0600 Subject: [PATCH 018/156] PASS1-595: added microsd health check menu item --- ports/stm32/boards/Passport/manifest.py | 3 +- .../boards/Passport/modules/flows/__init__.py | 3 +- .../flows/casa_health_check_microsd_flow.py | 93 +++++++++++++++++++ ...k_flow.py => casa_health_check_qr_flow.py} | 2 +- ports/stm32/boards/Passport/modules/menus.py | 15 ++- 5 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py rename ports/stm32/boards/Passport/modules/flows/{casa_health_check_flow.py => casa_health_check_qr_flow.py} (99%) diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index 35e936a1b..7fec70c59 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -77,7 +77,8 @@ 'flows/apply_passphrase_flow.py', 'flows/auto_backup_flow.py', 'flows/backup_flow.py', - 'flows/casa_health_check_flow.py', + 'flows/casa_health_check_qr_flow.py', + 'flows/casa_health_check_microsd_flow.py', 'flows/change_pin_flow.py', 'flows/delete_account_flow.py', 'flows/delete_multisig_flow.py', diff --git a/ports/stm32/boards/Passport/modules/flows/__init__.py b/ports/stm32/boards/Passport/modules/flows/__init__.py index 09ca01d8e..3f7e36443 100644 --- a/ports/stm32/boards/Passport/modules/flows/__init__.py +++ b/ports/stm32/boards/Passport/modules/flows/__init__.py @@ -22,7 +22,8 @@ from .apply_passphrase_flow import * from .auto_backup_flow import * from .backup_flow import * -from .casa_health_check_flow import * +from .casa_health_check_qr_flow import * +from .casa_health_check_microsd_flow import * from .change_pin_flow import * from .delete_account_flow import * from .delete_multisig_flow import * diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py new file mode 100644 index 000000000..4fb6788c5 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py @@ -0,0 +1,93 @@ +# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format + +from flows import Flow +from pages import ErrorPage, SuccessPage +from pages.show_qr_page import ShowQRPage +from utils import validate_sign_text, spinner_task +from tasks import sign_text_file_task +from public_constants import AF_CLASSIC, RFC_SIGNATURE_TEMPLATE + + +class CasaHealthCheckMicrosdFlow(Flow): + def __init__(self): + super().__init__(initial_state=self.scan_qr, name='SignPsbtQRFlow') + self.psbt = None + + async def scan_qr(self): + from pages import ScanQRPage, ErrorPage + import microns + + result = await ScanQRPage(right_micron=microns.Checkmark, decode_cbor_bytes=True).show() + + if result is None: + # User canceled the scan + self.set_result(False) + else: + # Got a scan result (aka QRScanResult): good data or error + if result.error is not None: + # Unable to scan QR code - show error? + await ErrorPage(text='Unable to scan QR code.'.show()) + self.set_result(False) + else: + # print('result.data={}'.format(result.data)) + try: + lines = result.data.decode('utf-8').split('\n') + except Exception as e: + await ErrorPage('Health check format is invalid.').show() + return + if len(lines) != 2: + await ErrorPage('Health check format is invalid.').show() + self.set_result(False) + return + + # Common function to validate the message + self.text = lines[0] + self.subpath = lines[1] + # print('text={}'.format(self.text)) + # print('subpath={}'.format(self.subpath)) + + # 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 + + self.qr_type = result.qr_type + self.goto(self.sign_health_check) + + async def sign_health_check(self): + (signature, address, error) = await spinner_task('Performing Health Check', sign_text_file_task, + args=[self.text, self.subpath, AF_CLASSIC]) + if error is None: + self.signature = signature + self.address = address + self.goto(self.show_signed_message, save_curr=False) + else: + await ErrorPage(text='Error while signing file: {}'.format(error)).show() + self.set_result(False) + return + + async def show_signed_message(self): + from ubinascii import b2a_base64 + from data_codecs.qr_type import QRType + + sig = b2a_base64(self.signature).decode('ascii').strip() + + signed_message = RFC_SIGNATURE_TEMPLATE.format(addr=self.address, msg=self.text, blockchain='BITCOIN', sig=sig) + + result = await ShowQRPage( + qr_type=QRType.UR2, + qr_args={'prefix': 'bytes'}, + qr_data=signed_message, + caption='Signed Health Check' + ).show() + if not result: + self.back() + else: + self.set_result(True) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py similarity index 99% rename from ports/stm32/boards/Passport/modules/flows/casa_health_check_flow.py rename to ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index 5356ed19a..a7da96bd2 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -11,7 +11,7 @@ from public_constants import AF_CLASSIC, RFC_SIGNATURE_TEMPLATE -class CasaHealthCheckFlow(Flow): +class CasaHealthCheckQRFlow(Flow): def __init__(self): super().__init__(initial_state=self.scan_qr, name='SignPsbtQRFlow') self.psbt = None diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index 7fb6311d0..ace179097 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -34,8 +34,19 @@ def account_menu(): ] +def health_check_submenu(): + from flows import CasaHealthCheckQRFlow, CasaHealthCheckMicrosdFlow + + return [ + {'icon': lv.ICON_SCAN_QR, 'label': 'Sign with QR Code', 'flow': CasaHealthCheckQRFlow, + 'statusbar': {'title': 'SIGN'}}, + {'icon': lv.ICON_MICROSD, 'label': 'Sign with microSD', 'flow': CasaHealthCheckMicrosdFlow, + 'statusbar': {'title': 'SIGN'}}, + ] + + def casa_menu(): - from flows import CasaHealthCheckFlow, VerifyAddressFlow, SignPsbtQRFlow, SignPsbtMicroSDFlow, ConnectWalletFlow + from flows import VerifyAddressFlow, SignPsbtQRFlow, SignPsbtMicroSDFlow, ConnectWalletFlow return [ {'icon': lv.ICON_SCAN_QR, 'label': 'Sign with QR Code', 'flow': SignPsbtQRFlow, @@ -43,7 +54,7 @@ def casa_menu(): {'icon': lv.ICON_MICROSD, 'label': 'Sign with microSD', 'flow': SignPsbtMicroSDFlow, 'statusbar': {'title': 'SIGN'}}, {'icon': lv.ICON_VERIFY_ADDRESS, 'label': 'Verify Address', 'flow': VerifyAddressFlow}, - {'icon': lv.ICON_HEALTH_CHECK, 'label': 'Health Check', 'flow': CasaHealthCheckFlow}, + {'icon': lv.ICON_HEALTH_CHECK, 'label': 'Health Check', 'submenu': health_check_submenu}, {'icon': lv.ICON_CONNECT, 'label': 'Connect to Casa', 'flow': ConnectWalletFlow, 'statusbar': {'title': 'CONNECT'}, 'args': {'sw_wallet': 'Casa'}}, ] From f5165cccfaef5ddfc75cdb87746fb515bfef41be Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 23 Jan 2023 16:49:58 -0600 Subject: [PATCH 019/156] PASS1-595: first pass microsd flow --- ports/stm32/boards/Passport/manifest.py | 3 +- .../boards/Passport/modules/flows/__init__.py | 3 +- .../flows/casa_health_check_common_flow.py | 61 +++++++ .../flows/casa_health_check_microsd_flow.py | 163 +++++++++++------- .../flows/casa_health_check_qr_flow.py | 6 +- 5 files changed, 164 insertions(+), 72 deletions(-) create mode 100644 ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index 7fec70c59..c5c61d623 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -77,8 +77,9 @@ 'flows/apply_passphrase_flow.py', 'flows/auto_backup_flow.py', 'flows/backup_flow.py', - 'flows/casa_health_check_qr_flow.py', + 'flows/casa_health_check_common_flow.py', 'flows/casa_health_check_microsd_flow.py', + 'flows/casa_health_check_qr_flow.py', 'flows/change_pin_flow.py', 'flows/delete_account_flow.py', 'flows/delete_multisig_flow.py', diff --git a/ports/stm32/boards/Passport/modules/flows/__init__.py b/ports/stm32/boards/Passport/modules/flows/__init__.py index 3f7e36443..ca47aa300 100644 --- a/ports/stm32/boards/Passport/modules/flows/__init__.py +++ b/ports/stm32/boards/Passport/modules/flows/__init__.py @@ -22,8 +22,9 @@ from .apply_passphrase_flow import * from .auto_backup_flow import * from .backup_flow import * -from .casa_health_check_qr_flow import * +from .casa_health_check_common_flow import * from .casa_health_check_microsd_flow import * +from .casa_health_check_qr_flow import * from .change_pin_flow import * from .delete_account_flow import * from .delete_multisig_flow import * diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py new file mode 100644 index 000000000..b525e1791 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py @@ -0,0 +1,61 @@ +# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format + +from flows import Flow +from pages import ErrorPage +from utils import validate_sign_text, spinner_task +from tasks import sign_text_file_task +from public_constants import AF_CLASSIC, RFC_SIGNATURE_TEMPLATE + + +class CasaHealthCheckCommonFlow(Flow): + def __init__(self, lines): + super().__init__(initial_state=self.validate_lines, name='CasaHealthCheckQRFlow') + self.lines = lines + self.text = None + self.subpath = None + + async def validate_lines(self): + if len(self.lines) != 2: + await ErrorPage('Health check format is invalid.').show() + self.set_result(None) + return + + # Common function to validate the message + self.text = self.lines[0] + self.subpath = self.lines[1] + # print('text={}'.format(self.text)) + # print('subpath={}'.format(self.subpath)) + + # 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 + + self.subpath = subpath + self.goto(self.sign_health_check) + + async def sign_health_check(self): + (signature, address, error) = await spinner_task('Performing Health Check', sign_text_file_task, + args=[self.text, self.subpath, AF_CLASSIC]) + if error is None: + self.signature = signature + self.address = address + # TODO: do we need save_curr? + self.goto(self.format_signature, save_curr=False) + else: + await ErrorPage(text='Error while signing file: {}'.format(error)).show() + self.set_result(None) + return + + async def format_signature(self): + from ubinascii import b2a_base64 + + sig = b2a_base64(self.signature).decode('ascii').strip() + + signed_message = RFC_SIGNATURE_TEMPLATE.format(addr=self.address, msg=self.text, blockchain='BITCOIN', sig=sig) + self.set_result(signed_message) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py index 4fb6788c5..d91a9bbba 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py @@ -1,93 +1,122 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format from flows import Flow from pages import ErrorPage, SuccessPage -from pages.show_qr_page import ShowQRPage from utils import validate_sign_text, spinner_task from tasks import sign_text_file_task from public_constants import AF_CLASSIC, RFC_SIGNATURE_TEMPLATE +def is_health_check(filename): + from files import CardSlot + + # print('filenmame={}'.format(filename)) + if '-signed' in filename.lower(): + return False + + if '-hc' in filename.lower(): + return True + return False + + class CasaHealthCheckMicrosdFlow(Flow): def __init__(self): - super().__init__(initial_state=self.scan_qr, name='SignPsbtQRFlow') - self.psbt = None + super().__init__(initial_state=self.choose_file, name='CasaHealthCheckMicrosdFlow') + self.file_path = None + self.lines = None + self.signed_message = None - async def scan_qr(self): - from pages import ScanQRPage, ErrorPage - import microns + async def choose_file(self): + from flows import FilePickerFlow + from files import CardSlot - result = await ScanQRPage(right_micron=microns.Checkmark, decode_cbor_bytes=True).show() + root_path = CardSlot.get_sd_root() + result = await FilePickerFlow( + initial_path=root_path, show_folders=True, filter_fn=is_health_check).run() if result is None: - # User canceled the scan self.set_result(False) - else: - # Got a scan result (aka QRScanResult): good data or error - if result.error is not None: - # Unable to scan QR code - show error? - await ErrorPage(text='Unable to scan QR code.'.show()) + return + + _filename, full_path, is_folder = result + if not is_folder: + self.file_path = full_path + self.goto(self.parse_message) + + async def parse_message(self): + from files import CardSlot + from pages import ErrorPage + + with open(self.file_path, 'r') as fd: + try: + self.lines = fd.read().split('\n') + except Exception as e: + await ErrorPage(text='Health check format is invalid.').show() self.set_result(False) - else: - # print('result.data={}'.format(result.data)) - try: - lines = result.data.decode('utf-8').split('\n') - except Exception as e: - await ErrorPage('Health check format is invalid.').show() - return - if len(lines) != 2: - await ErrorPage('Health check format is invalid.').show() - self.set_result(False) - return - - # Common function to validate the message - self.text = lines[0] - self.subpath = lines[1] - # print('text={}'.format(self.text)) - # print('subpath={}'.format(self.subpath)) - - # 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 - - self.qr_type = result.qr_type - self.goto(self.sign_health_check) - - async def sign_health_check(self): - (signature, address, error) = await spinner_task('Performing Health Check', sign_text_file_task, - args=[self.text, self.subpath, AF_CLASSIC]) - if error is None: - self.signature = signature - self.address = address - self.goto(self.show_signed_message, save_curr=False) - else: - await ErrorPage(text='Error while signing file: {}'.format(error)).show() + return + self.goto(self.common_flow) + + async def common_flow(self): + from flows import CasaHealthCheckCommonFlow + + self.signed_message = await CasaHealthCheckCommonFlow(self.lines).run() + if self.signed_message is None: self.set_result(False) return + self.goto(self.write_signed_file) - async def show_signed_message(self): - from ubinascii import b2a_base64 - from data_codecs.qr_type import QRType + async def write_signed_file(self): + from files import CardSlot, CardMissingError + from pages import ErrorPage - sig = b2a_base64(self.signature).decode('ascii').strip() + orig_path, basename = self.file_path.rsplit('/', 1) + orig_path += '/' + base = basename.rsplit('.', 1)[0] + self.out_fn = None - signed_message = RFC_SIGNATURE_TEMPLATE.format(addr=self.address, msg=self.text, blockchain='BITCOIN', sig=sig) + # Add -signed to end. We won't offer to sign again. + target_fname = base + '-signed.txt' - result = await ShowQRPage( - qr_type=QRType.UR2, - qr_args={'prefix': 'bytes'}, - qr_data=signed_message, - caption='Signed Health Check' - ).show() - if not result: - self.back() + for path in [orig_path, None]: + try: + with CardSlot() as card: + out_full, self.out_fn = card.pick_filename( + target_fname, path) + if out_full: + break + except CardMissingError: + self.goto(self.show_card_missing) + return + + if not self.out_fn: + self.goto(self.show_card_missing) + return else: - self.set_result(True) + print(self.signed_message) + # Attempt to write-out the transaction + try: + with open(out_full, 'w') as fd: + fd.write(self.signed_message) + except OSError as exc: + result = await ErrorPage(text='Unable to write!\n\n%s\n\n' % exc).show() + # sys.print_exception(exc) + # fall thru to try again + + # Success and done! + self.goto(self.show_success) + return + + async def show_success(self): + import microns + from lvgl import LARGE_ICON_SUCCESS + from styles.colors import DEFAULT_LARGE_ICON_COLOR + from pages import LongTextPage + msg = "Updated Health Check is:\n\n%s" % self.out_fn + + await LongTextPage(text=msg, centered=True, left_micron=None, + right_micron=microns.Checkmark, icon=LARGE_ICON_SUCCESS, + icon_color=DEFAULT_LARGE_ICON_COLOR,).show() + self.set_result(True) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index a7da96bd2..c80d6d757 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -13,8 +13,8 @@ class CasaHealthCheckQRFlow(Flow): def __init__(self): - super().__init__(initial_state=self.scan_qr, name='SignPsbtQRFlow') - self.psbt = None + super().__init__(initial_state=self.scan_qr, name='CasaHealthCheckQRFlow') + self.lines = None async def scan_qr(self): from pages import ScanQRPage, ErrorPage @@ -34,7 +34,7 @@ async def scan_qr(self): else: # print('result.data={}'.format(result.data)) try: - lines = result.data.decode('utf-8').split('\n') + self.lines = result.data.decode('utf-8').split('\n') except Exception as e: await ErrorPage('Health check format is invalid.').show() return From 3a64af41b64cbf692ededb314dbc9b83da7c3294 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 23 Jan 2023 16:57:21 -0600 Subject: [PATCH 020/156] PASS1-595: cleaned up new code --- .../modules/flows/casa_health_check_common_flow.py | 11 +++++++---- .../modules/flows/casa_health_check_microsd_flow.py | 5 ----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py index b525e1791..7a064e466 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py @@ -4,10 +4,6 @@ # casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format from flows import Flow -from pages import ErrorPage -from utils import validate_sign_text, spinner_task -from tasks import sign_text_file_task -from public_constants import AF_CLASSIC, RFC_SIGNATURE_TEMPLATE class CasaHealthCheckCommonFlow(Flow): @@ -18,6 +14,8 @@ def __init__(self, lines): self.subpath = None async def validate_lines(self): + from pages import ErrorPage + from utils import validate_sign_text if len(self.lines) != 2: await ErrorPage('Health check format is invalid.').show() self.set_result(None) @@ -40,6 +38,10 @@ async def validate_lines(self): self.goto(self.sign_health_check) async def sign_health_check(self): + from pages import ErrorPage + from tasks import sign_text_file_task + from utils import spinner_task + from public_constants import AF_CLASSIC (signature, address, error) = await spinner_task('Performing Health Check', sign_text_file_task, args=[self.text, self.subpath, AF_CLASSIC]) if error is None: @@ -54,6 +56,7 @@ async def sign_health_check(self): async def format_signature(self): from ubinascii import b2a_base64 + from public_constants import RFC_SIGNATURE_TEMPLATE sig = b2a_base64(self.signature).decode('ascii').strip() diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py index d91a9bbba..a306d305c 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py @@ -4,10 +4,6 @@ # casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format from flows import Flow -from pages import ErrorPage, SuccessPage -from utils import validate_sign_text, spinner_task -from tasks import sign_text_file_task -from public_constants import AF_CLASSIC, RFC_SIGNATURE_TEMPLATE def is_health_check(filename): @@ -95,7 +91,6 @@ async def write_signed_file(self): self.goto(self.show_card_missing) return else: - print(self.signed_message) # Attempt to write-out the transaction try: with open(out_full, 'w') as fd: From 08b77e72508782693e4283f651cf5b1d822f2754 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 24 Jan 2023 08:52:16 -0600 Subject: [PATCH 021/156] PASS1-595: fixed lines error --- .../Passport/modules/flows/casa_health_check_qr_flow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index c80d6d757..b74b7081e 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -38,14 +38,14 @@ async def scan_qr(self): except Exception as e: await ErrorPage('Health check format is invalid.').show() return - if len(lines) != 2: + if len(self.lines) != 2: await ErrorPage('Health check format is invalid.').show() self.set_result(False) return # Common function to validate the message - self.text = lines[0] - self.subpath = lines[1] + self.text = self.lines[0] + self.subpath = self.lines[1] # print('text={}'.format(self.text)) # print('subpath={}'.format(self.subpath)) From 0d9351fbba914e4376467aca08e4b0049ebc778d Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Fri, 27 Jan 2023 13:14:26 -0600 Subject: [PATCH 022/156] PASS1-595: changed from "sign" to "check" --- ports/stm32/boards/Passport/modules/menus.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index ace179097..64a97683e 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -38,9 +38,9 @@ def health_check_submenu(): from flows import CasaHealthCheckQRFlow, CasaHealthCheckMicrosdFlow return [ - {'icon': lv.ICON_SCAN_QR, 'label': 'Sign with QR Code', 'flow': CasaHealthCheckQRFlow, + {'icon': lv.ICON_SCAN_QR, 'label': 'Check with QR Code', 'flow': CasaHealthCheckQRFlow, 'statusbar': {'title': 'SIGN'}}, - {'icon': lv.ICON_MICROSD, 'label': 'Sign with microSD', 'flow': CasaHealthCheckMicrosdFlow, + {'icon': lv.ICON_MICROSD, 'label': 'Check with microSD', 'flow': CasaHealthCheckMicrosdFlow, 'statusbar': {'title': 'SIGN'}}, ] From f968dc29991bd8bf2de8367e877a316d5869daf6 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 2 Feb 2023 17:27:44 -0600 Subject: [PATCH 023/156] PASS1-643: fixed multisig info formatting --- .../modules/flows/view_multisig_details_flow.py | 2 +- .../stm32/boards/Passport/modules/multisig_wallet.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/view_multisig_details_flow.py b/ports/stm32/boards/Passport/modules/flows/view_multisig_details_flow.py index 0eadeea4d..decd80899 100644 --- a/ports/stm32/boards/Passport/modules/flows/view_multisig_details_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/view_multisig_details_flow.py @@ -17,7 +17,7 @@ def __init__(self, context=None): self.ms = MultisigWallet.get_by_idx(self.storage_idx) async def show_overview(self): - msg, _ = self.ms.format_overview() + msg, _ = self.ms.format_overview(importing=False) result = await LongTextPage(card_header={'title': self.ms.name}, text=msg, centered=True).show() if not result: diff --git a/ports/stm32/boards/Passport/modules/multisig_wallet.py b/ports/stm32/boards/Passport/modules/multisig_wallet.py index 0464df97b..b25026074 100644 --- a/ports/stm32/boards/Passport/modules/multisig_wallet.py +++ b/ports/stm32/boards/Passport/modules/multisig_wallet.py @@ -942,7 +942,7 @@ def get_deriv_paths(self): return derivs, dsum - def format_overview(self): + def format_overview(self, importing=True): from utils import recolor from styles.colors import HIGHLIGHT_TEXT_HEX, COPPER_HEX @@ -973,16 +973,20 @@ def format_overview(self): {} This new wallet is similar to an existing wallet, but will NOT replace it. Consider deleting previous \ wallet first. Differences: '''.format(recolor(COPPER_HEX, 'WARNING:')) + ', '.join(diff_items) is_dup = True - elif num_dups: + elif importing and num_dups: msg = 'Duplicate wallet. All details are the same as an existing wallet, so it will not be added.' is_dup = True + elif not importing: + msg = '' else: msg = 'Create new multisig wallet?' derivs, dsum = self.get_deriv_paths() - msg += '''\n -{name_title} + if importing: + msg += '\n\n' + + msg += '''{name_title} {name} {policy_title} {M} of {N} From ed9fcd4b5bd9077bc900f59d36dee38d618595c1 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 26 Jan 2023 13:39:51 +0100 Subject: [PATCH 024/156] PASS1-553: Remove get_error from DataEncoder. Not used and saves 160 bytes from `.text`. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../stm32/boards/Passport/modules/data_codecs/data_encoder.py | 4 ---- ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py | 3 --- ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py | 3 --- ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py | 3 --- 4 files changed, 13 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py b/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py index 52f625e7a..59a9e0c23 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py @@ -18,7 +18,3 @@ def encode(self, data, is_binary=False, max_fragment_len=None): def next_part(self): return None - - # Return any error message if decoding or adding data failed for some reason - def get_error(self): - return None diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index 36405778b..8293921c4 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -51,9 +51,6 @@ def encode(self, data, is_binary=False, max_fragment_len=None): def next_part(self): return self.data - def get_error(self): - return None - class QRSampler(DataSampler): # Any data can be accepted diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index 72d862d55..0bbe8c21b 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -96,9 +96,6 @@ def next_part(self): # print('UR1: part={}'.format(to_str(part))) return part.upper() - # Return any error info - def get_error(self): - return None class UR1Sampler(DataSampler): diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index d88541e85..d7f9f3472 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -115,9 +115,6 @@ def encode(self, data, is_binary=False, max_fragment_len=200): def next_part(self): return self.ur_encoder.next_part() - # Return any error message if decoding or adding data failed for some reason - def get_error(self): - return None class UR2Sampler(DataSampler): From 1d05d27419504779cd79a551240ca3dbe95bde5e Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 26 Jan 2023 13:43:52 +0100 Subject: [PATCH 025/156] PASS1-553: Rename get_data_format to qr_type. The documentation was a bit outdated and the name didn't suit the type returned. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../Passport/modules/data_codecs/data_decoder.py | 10 +++++----- .../boards/Passport/modules/data_codecs/qr_codec.py | 2 +- .../boards/Passport/modules/data_codecs/ur1_codec.py | 2 +- .../boards/Passport/modules/data_codecs/ur2_codec.py | 2 +- .../boards/Passport/modules/pages/scan_qr_page.py | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py b/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py index e4a041088..51c76003a 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py @@ -36,10 +36,10 @@ def get_ur_prefix(self): def decode(self): pass - # Return what type of data this is: - # - Multisig Quorum info - # - Spending transaction - # - Wallet seed + # Return what type of QR this is: + # + # - Normal QR. + # - UR2. # - etc. - def get_data_format(self): + def qr_type(self): pass diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index 8293921c4..eb4070c33 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -37,7 +37,7 @@ def get_ur_prefix(self): def decode(self, **kwargs): return self.data - def get_data_format(self): + def qr_type(self): return QRType.QR diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index 0bbe8c21b..d0bd60b48 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -63,7 +63,7 @@ def decode(self, **kwargs): # print('UR1Decoder.decode() ERROR: {}'.format(e)) return None - def get_data_format(self): + def qr_type(self): return QRType.UR1 diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index d7f9f3472..989cdcdae 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -67,7 +67,7 @@ def decode(self, decode_cbor_bytes=False): # print('CBOR decode error: {}'.format(e)) return None - def get_data_format(self): + def qr_type(self): return QRType.UR2 diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index 7849f1f56..dc19bb0a9 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -118,8 +118,8 @@ def right_action(self, is_pressed): self.set_result(None) def complete(self, qr_decoder): - qr_type = qr_decoder.get_data_format() - self.set_result(QRScanResult(data=qr_decoder.decode(decode_cbor_bytes=self.decode_cbor_bytes), qr_type=qr_type)) + self.set_result(QRScanResult(data=qr_decoder.decode(decode_cbor_bytes=self.decode_cbor_bytes), + qr_type=qr_decoder.qr_type())) def progress(self, qr_decoder): # print('Updating progress label...') From 5f05e8d0054776238b4802af136a5a57dbd4a55d Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 26 Jan 2023 13:57:55 +0100 Subject: [PATCH 026/156] PASS1-553: Remove get_ur_prefix from DataDecoder. Saves 312 bytes from .text. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/data_codecs/data_decoder.py | 7 ------- .../stm32/boards/Passport/modules/data_codecs/qr_codec.py | 3 --- .../stm32/boards/Passport/modules/data_codecs/ur1_codec.py | 3 --- .../stm32/boards/Passport/modules/data_codecs/ur2_codec.py | 3 --- ports/stm32/boards/Passport/modules/ur2/ur_decoder.py | 3 --- 5 files changed, 19 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py b/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py index 51c76003a..30516046c 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py @@ -26,13 +26,6 @@ def total_parts(self): def is_complete(self): return False - # Return any error message if decoding or adding data failed for some reason - def get_error(self): - return None - - def get_ur_prefix(self): - return None - def decode(self): pass diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index eb4070c33..b5a3eca68 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -31,9 +31,6 @@ def is_complete(self): def get_error(self): return None - def get_ur_prefix(self): - return None - def decode(self, **kwargs): return self.data diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index d0bd60b48..2647e1cc1 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -45,9 +45,6 @@ def is_complete(self): def get_error(self): return self.error - def get_ur_prefix(self): - return 'bytes' # TODO: Get the type from the UR1 decoder - def decode(self, **kwargs): from common import system try: diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index 989cdcdae..e64caa93c 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -50,9 +50,6 @@ def get_error(self): else: return None - def get_ur_prefix(self): - return self.decoder.expected_type() - def decode(self, decode_cbor_bytes=False): try: message = self.decoder.result_message() diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py index 521ea7d7e..32a1863d5 100644 --- a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py @@ -147,9 +147,6 @@ def receive_part(self, str): # print('ur_decoder.receive_part() err={}'.format(err)) return False - def expected_type(self): - return self._expected_type - def expected_part_count(self): return self.fountain_decoder.expected_part_count() From d6e8f2e8c73400297f42c40fa763c351b05fb4b3 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 26 Jan 2023 22:01:59 +0100 Subject: [PATCH 027/156] PASS1-553: Remove comments from codec files. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../Passport/modules/data_codecs/ur1_codec.py | 5 ---- .../Passport/modules/data_codecs/ur2_codec.py | 4 --- .../Passport/modules/pages/scan_qr_page.py | 2 -- .../Passport/modules/ur2/fountain_decoder.py | 30 +++++++------------ .../boards/Passport/modules/views/camera.py | 1 - 5 files changed, 11 insertions(+), 31 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index 2647e1cc1..422aa3617 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -79,22 +79,17 @@ def encode(self, data, is_binary=False, max_fragment_len=500): if not is_binary: data = hexlify(data) - # print('UR1: hex data={}'.format(data)) data = data.decode('utf8') - # print('UR1: data={}'.format(data)) - self.parts = encode_ur(data, fragment_capacity=max_fragment_len) def next_part(self): from utils import to_str part = self.parts[self.next_index] self.next_index = (self.next_index + 1) % len(self.parts) - # print('UR1: part={}'.format(to_str(part))) return part.upper() - class UR1Sampler(DataSampler): # Check if the given bytes look like UR1 data # Return True if it matches or False if not diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index e64caa93c..2aa5c611f 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -32,7 +32,6 @@ def add_data(self, data): try: return self.decoder.receive_part(data) except Exception as e: - # print('EXCEPTION: {}'.format(e)) return False def received_parts(self): @@ -54,14 +53,12 @@ def decode(self, decode_cbor_bytes=False): try: message = self.decoder.result_message() if decode_cbor_bytes: - # print('UR2: message={}'.format(message.cbor)) cbor_decoder = CBORDecoder(message.cbor) (message, length) = cbor_decoder.decodeBytes() return message except Exception as e: self.error = '{}'.format(e) - # print('CBOR decode error: {}'.format(e)) return None def qr_type(self): @@ -113,7 +110,6 @@ def next_part(self): return self.ur_encoder.next_part() - class UR2Sampler(DataSampler): # Check if the given bytes look like UR1 data # Return True if it matches or False if not diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index dc19bb0a9..3a24ab75d 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -15,7 +15,6 @@ def progress_text(p): label = 'Scanning...' if p == 0 else '{}%'.format(p) - # print('label={}'.format(label)) return label @@ -122,7 +121,6 @@ def complete(self, qr_decoder): qr_type=qr_decoder.qr_type())) def progress(self, qr_decoder): - # print('Updating progress label...') n = qr_decoder.received_parts() m = qr_decoder.total_parts() p = int((n * 100) / m) diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py index 1365c9c22..772d10c75 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py @@ -91,7 +91,6 @@ def receive_part(self, encoder_part): # Don't continue if this part doesn't validate if not self.validate_part(encoder_part): - # print('INVALID PART!') return False # Add this part to the queue @@ -103,11 +102,10 @@ def receive_part(self, encoder_part): while not self.is_complete() and len(self.queued_parts) != 0: self.process_queue_item() - # # Keep track of how many parts we've processed - # # NOTE: We should only increment this if we haven't processed this part before - # print('encoder_part.seq_num={} .seq_len={} received_part_indexes={}'.format(encoder_part.seq_num, - # encoder_part.seq_len, - # self.received_part_indexes)) + # Keep track of how many parts we've processed + # + # NOTE: We should only increment this if we haven't processed this part + # before. if encoder_part.seq_num - 1 not in self.received_part_indexes: self.processed_parts_count += 1 @@ -162,7 +160,7 @@ def reduce_part_by_part(self, a, b): new_data = xor_with(bytearray(a.data), b.data) return self.Part(new_indexes, new_data) else: - # `a` is not reducable by `b`, so return a + # `a` is not reducible by `b`, so return a return a def process_simple_part(self, p): @@ -208,7 +206,6 @@ def process_mixed_part(self, p): # Don't process duplicate parts for r in self.mixed_parts.values(): if r == p.indexes: - # print('Already processed/duplicate?') return # Reduce this part by all the others @@ -260,19 +257,14 @@ def indexes_to_string(self, indexes): s = [str(j) for j in i] return '[{}]'.format(', '.join(s)) - def result_description(self): - if self.result is None: - return 'None' - - if self.is_success(): - return '{} bytes'.format(len(self.result)) - elif self.is_failure(): - return 'Exception: {}'.format(self.result) - else: - assert(False) - # DEBUG CODE # + # def result_description(self): + # if self.result is None: + # return 'None' + # + # return '{} bytes'.format(len(self.result)) + # # def print_part(self, p): # print('part indexes: {}'.format(self.indexes_to_string(p.indexes))) # diff --git a/ports/stm32/boards/Passport/modules/views/camera.py b/ports/stm32/boards/Passport/modules/views/camera.py index fccc897e9..b0ebde459 100644 --- a/ports/stm32/boards/Passport/modules/views/camera.py +++ b/ports/stm32/boards/Passport/modules/views/camera.py @@ -72,7 +72,6 @@ def update(self): if self.content_width is None or self.content_height is None: self.enable() if self.content_width is None or self.content_height is None: - print('Not enabled') return # Take the camera image. From 1a7a82c79e7e5ea74282dc21e13e72efa79e68f7 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 26 Jan 2023 22:07:43 +0100 Subject: [PATCH 028/156] PASS1-553: Remove last_part_indexes from UR codec. Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py | 2 -- ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py | 3 --- ports/stm32/boards/Passport/modules/ur2/ur_encoder.py | 3 --- 3 files changed, 8 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py index 772d10c75..fc49576c2 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py @@ -43,7 +43,6 @@ def index(self): # FountainDecoder def __init__(self): self.received_part_indexes = set() - self.last_part_indexes = None self.processed_parts_count = 0 self.result = None self.expected_part_indexes = None @@ -95,7 +94,6 @@ def receive_part(self, encoder_part): # Add this part to the queue p = FountainDecoder.Part.from_encoder_part(encoder_part) - self.last_part_indexes = p.indexes self.enqueue(p) # Process the queue until we're done or the queue is empty diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py index 2f9151b3c..a20fbbbd5 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py @@ -125,9 +125,6 @@ def partition_message(message, fragment_len): return fragments - def last_part_indexes(self): - return self.last_part_indexes - def seq_len(self): return len(self.fragments) diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py index 2178c13c7..abb6d3433 100644 --- a/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py @@ -21,9 +21,6 @@ def encode(ur): body = Bytewords.encode(Bytewords_Style_minimal, ur.cbor) return UREncoder.encode_ur([ur.type, body]) - def last_part_indexes(self): - return self.fountain_encoder.last_part_indexes() - # `True` if the minimal number of parts to transmit the message have been # generated. Parts generated when this is `true` will be fountain codes # containing various mixes of the part data. From 5ea4e25f3a061fd5ea6a06f9280815d774da19cd Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 27 Jan 2023 00:02:00 +0100 Subject: [PATCH 029/156] PASS1-553: More accurate scan progress. Signed-off-by: Jean-Pierre De Jesus DIAZ --- CHANGELOG.md | 1 + .../modules/data_codecs/data_decoder.py | 9 +++++---- .../Passport/modules/data_codecs/qr_codec.py | 7 ++----- .../Passport/modules/data_codecs/ur1_codec.py | 4 ++-- .../Passport/modules/data_codecs/ur2_codec.py | 7 ++----- .../Passport/modules/pages/scan_qr_page.py | 5 +---- .../boards/Passport/modules/views/camera.py | 17 +++++++---------- 7 files changed, 20 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 359972dbf..2ece04fed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ SPDX-License-Identifier: GPL-3.0-or-later --> ## Head +- Perform more accurate calculation of scan progress. (PASS1-553) ## 2.0.6 - Fixed alphanumeric pin entry timing (PASS1-655) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py b/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py index 30516046c..182e7a48d 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py @@ -7,6 +7,10 @@ # +class DecodeError(Exception): + pass + + # Collects data segments, indicates when the data is complete, and decodes it to a common # format for the specified data category class DataDecoder: @@ -17,12 +21,9 @@ def __init__(self): def add_data(self, data): pass - def received_parts(self): + def estimated_percent_complete(self): return 0 - def total_parts(self): - return 1 - def is_complete(self): return False diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index b5a3eca68..d9f7cf550 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -19,11 +19,8 @@ def __init__(self): def add_data(self, data): self.data = data - def received_parts(self): - return 0 if self.data is None else 1 - - def total_parts(self): - return 1 + def estimated_percent_complete(self): + return 1 if self.data is not None else 0 def is_complete(self): return self.data is not None diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index 422aa3617..9171aa3f6 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -36,8 +36,8 @@ def add_data(self, data): def received_parts(self): return self._received_parts - def total_parts(self): - return self._total_parts + def estimated_percent_complete(self): + return int((self._received_parts * 100) / self._total_parts) def is_complete(self): return self.workloads.is_complete() diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index 2aa5c611f..44b4bdb97 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -34,11 +34,8 @@ def add_data(self, data): except Exception as e: return False - def received_parts(self): - return len(self.decoder.received_part_indexes()) - - def total_parts(self): - return self.decoder.expected_part_count() + def estimated_percent_complete(self): + return self.decoder.estimated_percent_complete() def is_complete(self): return self.decoder.is_complete() diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index 3a24ab75d..2ea585b5b 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -121,10 +121,7 @@ def complete(self, qr_decoder): qr_type=qr_decoder.qr_type())) def progress(self, qr_decoder): - n = qr_decoder.received_parts() - m = qr_decoder.total_parts() - p = int((n * 100) / m) - self.progress_label.set_text(progress_text(p)) + self.progress_label.set_text(progress_text(self.camera.estimated_percent_complete())) def error(self, error): self.set_result(QRScanResult(error=error)) diff --git a/ports/stm32/boards/Passport/modules/views/camera.py b/ports/stm32/boards/Passport/modules/views/camera.py index b0ebde459..0f6e42e74 100644 --- a/ports/stm32/boards/Passport/modules/views/camera.py +++ b/ports/stm32/boards/Passport/modules/views/camera.py @@ -167,25 +167,16 @@ def update(self): super().update() - # print('update') - - # Do not scan anything if we are completed decoding. + # Do not scan anything if decoding is complete. if self.qr_decoder is not None: if self.qr_decoder.is_complete(): return - # print('decoding') - # Find QR codes in the QR framebuffer, and return early if no data found. data = qr.scan() - if data is None: - # print('None') return - # print('============================================================') - # print('data {}'.format(data)) - # print('============================================================') try: if self.qr_decoder is None: @@ -209,3 +200,9 @@ def update(self): except Exception as e: # noqa # print('Exception in CameraQRScanner: {}'.format(e)) pass + + def estimated_percent_complete(self): + """Returns an integer from 0-100 representing the estimated percentage of completion""" + if self.qr_decoder is None: + return 0 + return self.qr_decoder.estimated_percent_complete() From a033271821ffddf313a837a0af94a4cf1eb946f1 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 27 Jan 2023 00:07:33 +0100 Subject: [PATCH 030/156] PASS1-553: Report non PSBT QRs as such. Signed-off-by: Jean-Pierre De Jesus DIAZ --- CHANGELOG.md | 1 + .../Passport/modules/flows/sign_psbt_qr_flow.py | 17 +++++++---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ece04fed..a35b8657e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ SPDX-License-Identifier: GPL-3.0-or-later ## Head - Perform more accurate calculation of scan progress. (PASS1-553) +- Report to the user when the data contained in a QR code is not a PSBT. (PASS1-553) ## 2.0.6 - Fixed alphanumeric pin entry timing (PASS1-655) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index 5937e729f..cb2d7f3ac 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -27,9 +27,13 @@ async def scan_transaction(self): await ErrorPage(text='Unable to scan QR code.').show() self.set_result(False) else: - self.raw_psbt = result.data - self.qr_type = result.qr_type - self.goto(self.copy_to_flash) + if isinstance(result.data, str): + await ErrorPage(text='The QR code does not contain a transaction.').show() + self.set_result(False) + else: + self.raw_psbt = result.data + self.qr_type = result.qr_type + self.goto(self.copy_to_flash) async def copy_to_flash(self): import gc @@ -38,13 +42,6 @@ async def copy_to_flash(self): from pages import ErrorPage from public_constants import TXN_INPUT_OFFSET - # TODO: I think this is always a bytes object -- can probably remove this check - # The data can be a string or may already be a bytes object - # if isinstance(self.raw_psbt, bytes): - # data_buf = self.raw_psbt - # else: - # data_buf = bytes(self.raw_psbt, 'utf-8') - gc.collect() # Try to avoid excessive fragmentation # TODO: Pass on_progress function as the first argument if we want progress or remove it From ff8f31e0fab5ceb34935a7012f7d7b984ccbfa7b Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 27 Jan 2023 00:09:56 +0100 Subject: [PATCH 031/156] PASS1-553: Add is_failure to QRScanResult Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../Passport/modules/flows/casa_health_check_qr_flow.py | 5 ++--- .../stm32/boards/Passport/modules/flows/fcc_test_flow.py | 2 +- .../modules/flows/import_multisig_wallet_from_qr_flow.py | 6 +++++- .../boards/Passport/modules/flows/sign_psbt_qr_flow.py | 6 +++--- .../Passport/modules/flows/system_test_camera_flow.py | 2 +- .../boards/Passport/modules/flows/verify_address_flow.py | 8 ++++++-- ports/stm32/boards/Passport/modules/pages/scan_qr_page.py | 3 +++ 7 files changed, 21 insertions(+), 11 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index b74b7081e..7f74a0b64 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -26,9 +26,8 @@ async def scan_qr(self): # User canceled the scan self.set_result(False) else: - # Got a scan result (aka QRScanResult): good data or error - if result.error is not None: - # Unable to scan QR code - show error? + # Got a scan result (aka QRScanResult). + if result.is_failure(): await ErrorPage(text='Unable to scan QR code.'.show()) self.set_result(False) else: diff --git a/ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py b/ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py index 3592ab300..144785b3d 100644 --- a/ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py @@ -27,7 +27,7 @@ def __init__(self): async def show_camera(self): result = await ScanQRPage().show(auto_close_timeout=_CAMERA_DISPLAY_DURATION_SECS) - if result is not None: + if result is None: # User used a button to back out self.set_result(False) return diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py index 45b1e15db..15cce73b0 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py @@ -17,9 +17,13 @@ async def scan_qr_code(self): from multisig_wallet import MultisigWallet result = await ScanQRPage(decode_cbor_bytes=True).show() - if result is None or result.error is not None: + if result is None: self.set_result(False) return + elif result.is_failure(): + self.set_result(False) + await ErrorPage(text='Unable to scan QR code.').show() + return data = result.data if isinstance(data, (bytes, bytearray)): diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index cb2d7f3ac..f0d175b8f 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -21,10 +21,10 @@ async def scan_transaction(self): # User canceled the scan self.set_result(False) else: - # Got a scan result (aka QRScanResult): good data or error - if result.error is not None: + # Got a scan result (aka QRScanResult). + if result.is_failure(): # Unable to scan QR code - show error? - await ErrorPage(text='Unable to scan QR code.').show() + await ErrorPage(text='Unable to scan QR code.\n\n{}'.format(result.error)).show() self.set_result(False) else: if isinstance(result.data, str): diff --git a/ports/stm32/boards/Passport/modules/flows/system_test_camera_flow.py b/ports/stm32/boards/Passport/modules/flows/system_test_camera_flow.py index c577253d9..0f8fb3953 100644 --- a/ports/stm32/boards/Passport/modules/flows/system_test_camera_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/system_test_camera_flow.py @@ -23,7 +23,7 @@ async def scan_qr(self): self.set_result(skip) else: # Got a scan result (aka QRScanResult): good data or error - if result.error is not None: + if result.is_failure(): # Unable to scan QR code - show error? await ErrorPage(text='Unable to scan QR code.').show() self.set_result(False) diff --git a/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py b/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py index 91d308a59..305801e65 100644 --- a/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py @@ -74,10 +74,14 @@ async def scan_address(self): result = await ScanQRPage( left_micron=microns.Back, right_micron=None).show() - if result is None or result.error is not None: - # User canceled the scan or bad QR code + + if result is None: if not self.back(): self.set_result(False) + return + elif result.is_failure(): + await ErrorPage(text='Unable to scan QR code.').show() + self.set_result(False) return # print('result={}'.format(result)) diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index 2ea585b5b..a55de8266 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -139,3 +139,6 @@ def __init__(self, data=None, error=None, qr_type=None): self.data = data self.error = error self.qr_type = qr_type + + def is_failure(self): + self.error is not None From dd0b6c1a56df9e535229b01c5a56afd8e2da59c0 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 27 Jan 2023 00:27:10 +0100 Subject: [PATCH 032/156] PASS1-553: Improve QR code error reporting. Signed-off-by: Jean-Pierre De Jesus DIAZ --- CHANGELOG.md | 1 + .../Passport/modules/data_codecs/qr_codec.py | 3 - .../Passport/modules/data_codecs/ur1_codec.py | 33 +---- .../Passport/modules/data_codecs/ur2_codec.py | 29 ++-- .../Passport/modules/pages/scan_qr_page.py | 29 ++-- .../Passport/modules/ur2/fountain_decoder.py | 24 +-- .../boards/Passport/modules/ur2/ur_decoder.py | 139 ++++++------------ .../boards/Passport/modules/views/camera.py | 39 ++--- 8 files changed, 96 insertions(+), 201 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a35b8657e..420663b72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ SPDX-License-Identifier: GPL-3.0-or-later ## Head - Perform more accurate calculation of scan progress. (PASS1-553) - Report to the user when the data contained in a QR code is not a PSBT. (PASS1-553) +- Improved the QR code scan error reporting. (PASS1-553) ## 2.0.6 - Fixed alphanumeric pin entry timing (PASS1-655) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index d9f7cf550..70e2f7800 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -25,9 +25,6 @@ def estimated_percent_complete(self): def is_complete(self): return self.data is not None - def get_error(self): - return None - def decode(self, **kwargs): return self.data diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index 9171aa3f6..ac508d851 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -9,7 +9,7 @@ from ubinascii import unhexlify from .data_encoder import DataEncoder -from .data_decoder import DataDecoder +from .data_decoder import DataDecoder, DecodeError from .data_sampler import DataSampler from .qr_type import QRType from ur1.decode_ur import decode_ur, extract_single_workload, Workloads @@ -23,18 +23,13 @@ def __init__(self): self._total_parts = 0 self.error = None - # Decode the given data into the expected format def add_data(self, data): try: self.workloads.add(data) - self._received_parts, self._total_parts = self.workloads.get_progress() - return True - except Exception as e: - self.error = '{}'.format(e) - return False + except ValueError as exc: + raise DecodeError from exc - def received_parts(self): - return self._received_parts + self._received_parts, self._total_parts = self.workloads.get_progress() def estimated_percent_complete(self): return int((self._received_parts * 100) / self._total_parts) @@ -42,23 +37,11 @@ def estimated_percent_complete(self): def is_complete(self): return self.workloads.is_complete() - def get_error(self): - return self.error - def decode(self, **kwargs): - from common import system - try: - # system.show_busy_bar() - encoded_data = decode_ur(self.workloads.workloads) - # system.hide_busy_bar() - # print('UR1: encoded_data={}'.format(encoded_data)) - data = unhexlify(encoded_data) # TODO: Should this be optional (e.g., PSBT in binary)? - # print('UR1: data={}'.format(data)) - return data - except Exception as e: - self.error = '{}'.format(e) - # print('UR1Decoder.decode() ERROR: {}'.format(e)) - return None + # XXX: This should be optional (e.g., PSBT in binary). + # + # But the UR1 standard is deprecated. + return unhexlify(decode_ur(self.workloads.workloads)) def qr_type(self): return QRType.UR1 diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index 44b4bdb97..ef28b9807 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -9,11 +9,11 @@ import re from .data_encoder import DataEncoder -from .data_decoder import DataDecoder +from .data_decoder import DataDecoder, DecodeError from .data_sampler import DataSampler from .qr_type import QRType -from ur2.ur_decoder import URDecoder +from ur2.ur_decoder import URDecoder, URError from ur2.ur_encoder import UREncoder from ur2.cbor_lite import CBORDecoder @@ -24,15 +24,14 @@ class UR2Decoder(DataDecoder): def __init__(self): - self.error = None self.decoder = URDecoder() # Decode the given data into the expected format def add_data(self, data): try: return self.decoder.receive_part(data) - except Exception as e: - return False + except URError as exc: + raise DecodeError from exc def estimated_percent_complete(self): return self.decoder.estimated_percent_complete() @@ -40,23 +39,13 @@ def estimated_percent_complete(self): def is_complete(self): return self.decoder.is_complete() - def get_error(self): - if self.decoder.is_failure(): - return self.decoder.result_error() - else: - return None - def decode(self, decode_cbor_bytes=False): - try: - message = self.decoder.result_message() - if decode_cbor_bytes: - cbor_decoder = CBORDecoder(message.cbor) - (message, length) = cbor_decoder.decodeBytes() + message = self.decoder.result() + if decode_cbor_bytes: + cbor_decoder = CBORDecoder(message.cbor) + (message, length) = cbor_decoder.decodeBytes() - return message - except Exception as e: - self.error = '{}'.format(e) - return None + return message def qr_type(self): return QRType.UR2 diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index a55de8266..4680b569e 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -3,6 +3,7 @@ # import lvgl as lv +from data_codecs.data_decoder import DecodeError from pages import Page from styles.colors import TEXT_GREY from styles.style import Stylize @@ -38,9 +39,8 @@ def __init__(self, self.decode_cbor_bytes = decode_cbor_bytes self.prev_card_header = None self.timer = None - self.camera = CameraQRScanner(result_cb=self.complete, - progress_cb=self.progress, - error_cb=self.error) + self.camera = CameraQRScanner() + # TODO: # lv.pct(100) just makes the widget inside the camera view to return # invalid values for it's content width. @@ -104,7 +104,18 @@ def detach(self): def update(self): if self.is_attached(): - self.camera.update() + try: + self.camera.update() + + self.progress_label.set_text(progress_text(self.camera.estimated_percent_complete())) + if self.camera.is_complete(): + data = self.camera.qr_decoder.decode(decode_cbor_bytes=self.decode_cbor_bytes) + qr_type = self.camera.qr_decoder.qr_type() + + self.set_result(QRScanResult(data=data, qr_type=qr_type)) + except DecodeError as exc: + message = DecodeError.args[0] + self.set_result(QRScanResult(error='Scan Failed: {}'.format(message))) # Just return None. def left_action(self, is_pressed): @@ -116,16 +127,6 @@ def right_action(self, is_pressed): if not is_pressed: self.set_result(None) - def complete(self, qr_decoder): - self.set_result(QRScanResult(data=qr_decoder.decode(decode_cbor_bytes=self.decode_cbor_bytes), - qr_type=qr_decoder.qr_type())) - - def progress(self, qr_decoder): - self.progress_label.set_text(progress_text(self.camera.estimated_percent_complete())) - - def error(self, error): - self.set_result(QRScanResult(error=error)) - class QRScanResult: """ diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py index fc49576c2..014e42218 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py @@ -9,11 +9,7 @@ from utils import bytes_to_hex_str -class InvalidPart(Exception): - pass - - -class InvalidChecksum(Exception): +class FountainError(Exception): pass @@ -58,21 +54,10 @@ def expected_part_count(self): return 0 return len(self.expected_part_indexes) - def is_success(self): - result = self.result - return result if not isinstance(result, Exception) else False - - def is_failure(self): - result = self.result - return result if isinstance(result, Exception) else False - def is_complete(self): return self.result is not None - def result_message(self): - return self.result - - def result_error(self): + def result(self): return self.result def estimated_percent_complete(self): @@ -90,7 +75,7 @@ def receive_part(self, encoder_part): # Don't continue if this part doesn't validate if not self.validate_part(encoder_part): - return False + raise FountainError('Invalid part') # Add this part to the queue p = FountainDecoder.Part.from_encoder_part(encoder_part) @@ -194,8 +179,7 @@ def process_simple_part(self, p): result = bytes(message) self.result = result else: - self.result = InvalidChecksum() - + raise FountainError('Invalid part checksum') else: # Reduce all the mixed parts by this part self.reduce_mixed_by(p) diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py index 32a1863d5..68f83982e 100644 --- a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py @@ -6,28 +6,12 @@ from .ur import UR from .fountain_encoder import FountainEncoder, Part as FountainEncoderPart -from .fountain_decoder import FountainDecoder +from .fountain_decoder import FountainDecoder, FountainError from .bytewords import * from .utils import drop_first, is_ur_type -class InvalidScheme(Exception): - pass - - -class InvalidType(Exception): - pass - - -class InvalidPathLength(Exception): - pass - - -class InvalidSequenceComponent(Exception): - pass - - -class InvalidFragment(Exception): +class URError(Exception): pass @@ -41,7 +25,7 @@ def __init__(self): def decode(str): (type, components) = URDecoder.parse(str) if len(components) == 0: - raise InvalidPathLength() + raise URError('invalid path length') body = components[0] return URDecoder.decode_by_type(type, body) @@ -58,7 +42,7 @@ def parse(str): # Validate URI scheme if not lowered.startswith('ur:'): - raise InvalidScheme() + raise URError('Invalid scheme') path = drop_first(lowered, 3) @@ -67,30 +51,27 @@ def parse(str): # Make sure there are at least two path components if len(components) < 2: - raise InvalidPathLength() + raise URError('malformed UR path components') # Validate the type type = components[0] if not is_ur_type(type): - raise InvalidType() + raise URError('invalid UR type') comps = components[1:] # Don't include the ur type return (type, comps) @staticmethod def parse_sequence_component(str): - try: - comps = str.split('-') - if len(comps) != 2: - raise InvalidSequenceComponent() - seq_num = int(comps[0]) - seq_len = int(comps[1]) - # print('seq_num={} seq_len={}'.format(seq_num, seq_len)) - if seq_num < 1 or seq_len < 1: - raise InvalidSequenceComponent() - return (seq_num, seq_len) - except BaseException: - raise InvalidSequenceComponent() + comps = str.split('-') + if len(comps) != 2: + raise URError('invalid sequence component') + seq_num = int(comps[0]) + seq_len = int(comps[1]) + # print('seq_num={} seq_len={}'.format(seq_num, seq_len)) + if seq_num < 1 or seq_len < 1: + raise URError('invalid sequence numbers') + return (seq_num, seq_len) def validate_part(self, type): if self._expected_type is None: @@ -102,77 +83,49 @@ def validate_part(self, type): return type == self._expected_type def receive_part(self, str): - try: - # Don't process the part if we're already done - if self.result is not None: - return False - - # Don't continue if this part doesn't validate - (type, components) = URDecoder.parse(str) - if not self.validate_part(type): - return False - - # If this is a single-part UR then we're done - if len(components) == 1: - body = components[0] - self.result = self.decode_by_type(type, body) - return True - - # Multi-part URs must have two path components: seq/fragment - if len(components) != 2: - raise InvalidPathLength() - seq = components[0] - fragment = components[1] - - # Parse the sequence component and the fragment, and make sure they agree. - (seq_num, seq_len) = URDecoder.parse_sequence_component(seq) - cbor = Bytewords.decode(Bytewords_Style_minimal, fragment) - part = FountainEncoderPart.from_cbor(cbor) - if seq_num != part.seq_num or seq_len != part.seq_len: - # print('seq num mismatch') - return False - - # Process the part - if not self.fountain_decoder.receive_part(part): - # print('Error in foundation_decoder.receive_part(): part={}'.format(part)) - return False + # Don't process the part if we're already done + if self.result is not None: + return False - if self.fountain_decoder.is_success(): - self.result = UR(type, self.fountain_decoder.result_message()) - elif self.fountain_decoder.is_failure(): - self.result = self.fountain_decoder.result_error() + # Don't continue if this part doesn't validate + (type, components) = URDecoder.parse(str) + if not self.validate_part(type): + return False + # If this is a single-part UR then we're done + if len(components) == 1: + body = components[0] + self.result = self.decode_by_type(type, body) return True - except Exception as err: - # print('ur_decoder.receive_part() err={}'.format(err)) - return False - def expected_part_count(self): - return self.fountain_decoder.expected_part_count() + # Multi-part URs must have two path components: seq/fragment + if len(components) != 2: + raise InvalidPathLength() + seq = components[0] + fragment = components[1] - def received_part_indexes(self): - return self.fountain_decoder.received_part_indexes + # Parse the sequence component and the fragment, and make sure they agree. + (seq_num, seq_len) = URDecoder.parse_sequence_component(seq) + cbor = Bytewords.decode(Bytewords_Style_minimal, fragment) + part = FountainEncoderPart.from_cbor(cbor) + if seq_num != part.seq_num or seq_len != part.seq_len: + raise URError('sequence numbers mismatch') - def last_part_indexes(self): - return self.fountain_decoder.last_part_indexes + # Process the part + try: + self.fountain_decoder.receive_part(part) + if self.fountain_decoder.is_complete(): + self.result = UR(type, self.fountain_decoder.result_message()) + except FountainError as exc: + raise URError('failed to receive part') from exc - def processed_parts_count(self): - return self.fountain_decoder.processed_parts_count + return True def estimated_percent_complete(self): return self.fountain_decoder.estimated_percent_complete() - def is_success(self): - return self.result is not None and not isinstance(self.result, Exception) - - def is_failure(self): - return self.result is not None and isinstance(self.result, Exception) - def is_complete(self): return self.result is not None - def result_message(self): - return self.result - - def result_error(self): + def result(self): return self.result diff --git a/ports/stm32/boards/Passport/modules/views/camera.py b/ports/stm32/boards/Passport/modules/views/camera.py index 0f6e42e74..9606f7b04 100644 --- a/ports/stm32/boards/Passport/modules/views/camera.py +++ b/ports/stm32/boards/Passport/modules/views/camera.py @@ -143,12 +143,9 @@ def framebuffer(self): class CameraQRScanner(Camera): """Camera QR code scanner and decoder""" - def __init__(self, result_cb=None, progress_cb=None, error_cb=None): + def __init__(self): super().__init__() self.qr_decoder = None - self.result_cb = result_cb - self.progress_cb = progress_cb - self.error_cb = error_cb qr.init(self.HOR_RES, self.VER_RES) def hook(self): @@ -177,32 +174,22 @@ def update(self): if data is None: return + if self.qr_decoder is None: + self.qr_decoder = get_qr_decoder_for_data(data) - try: - if self.qr_decoder is None: - self.qr_decoder = get_qr_decoder_for_data(data) - - self.qr_decoder.add_data(data) - - error = self.qr_decoder.get_error() - if error is not None: - if callable(self.error_cb): - self.error_cb(error) - return - - if self.qr_decoder.is_complete(): - if callable(self.result_cb): - self.result_cb(self.qr_decoder) - return - - if callable(self.progress_cb): - self.progress_cb(self.qr_decoder) - except Exception as e: # noqa - # print('Exception in CameraQRScanner: {}'.format(e)) - pass + self.qr_decoder.add_data(data) def estimated_percent_complete(self): """Returns an integer from 0-100 representing the estimated percentage of completion""" + if self.qr_decoder is None: return 0 + return self.qr_decoder.estimated_percent_complete() + + def is_complete(self): + """Returns true if the scan is complete""" + + if self.qr_decoder is not None: + return self.qr_decoder.is_complete() + return False From 866a3eba87dca039be5c326d44040fd9f6973288 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 27 Jan 2023 19:19:02 +0100 Subject: [PATCH 033/156] PASS1-553: Scale and use integer for percentage Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py index 014e42218..b939dc437 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py @@ -66,7 +66,7 @@ def estimated_percent_complete(self): if self.expected_part_indexes is None: return 0 estimated_input_parts = self.expected_part_count() * 1.75 - return min(0.99, self.processed_parts_count / estimated_input_parts) + return int(min(0.99, self.processed_parts_count / estimated_input_parts) * 100) def receive_part(self, encoder_part): # Don't process the part if we're already done From fcbd18c1b8cacf9f066cd9252ef21cdefbefbd41 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 27 Jan 2023 20:05:34 +0100 Subject: [PATCH 034/156] PASS1-553: Fix leftovers Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../Passport/modules/data_codecs/ur2_codec.py | 12 ++-- .../Passport/modules/pages/scan_qr_page.py | 5 +- .../boards/Passport/modules/ur2/cbor_lite.py | 58 ++++++++++--------- .../Passport/modules/ur2/fountain_decoder.py | 5 +- .../boards/Passport/modules/ur2/ur_decoder.py | 12 ++-- 5 files changed, 48 insertions(+), 44 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index ef28b9807..ff7fc4d0b 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -16,8 +16,7 @@ from ur2.ur_decoder import URDecoder, URError from ur2.ur_encoder import UREncoder -from ur2.cbor_lite import CBORDecoder -from ur2.cbor_lite import CBOREncoder +from ur2.cbor_lite import CBORDecoder, CBOREncoder, CBORError from ur2.ur import UR @@ -40,10 +39,13 @@ def is_complete(self): return self.decoder.is_complete() def decode(self, decode_cbor_bytes=False): - message = self.decoder.result() + message = self.decoder.result if decode_cbor_bytes: - cbor_decoder = CBORDecoder(message.cbor) - (message, length) = cbor_decoder.decodeBytes() + try: + cbor_decoder = CBORDecoder(message.cbor) + (message, length) = cbor_decoder.decodeBytes() + except CBORError as exc: + raise DecodeError from exc return message diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index 4680b569e..d76b835fe 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -114,8 +114,7 @@ def update(self): self.set_result(QRScanResult(data=data, qr_type=qr_type)) except DecodeError as exc: - message = DecodeError.args[0] - self.set_result(QRScanResult(error='Scan Failed: {}'.format(message))) + self.set_result(QRScanResult(error=exc)) # Just return None. def left_action(self, is_pressed): @@ -142,4 +141,4 @@ def __init__(self, data=None, error=None, qr_type=None): self.qr_type = qr_type def is_failure(self): - self.error is not None + return self.error is not None diff --git a/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py b/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py index bc773b99d..901e386fa 100644 --- a/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py +++ b/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py @@ -14,6 +14,10 @@ from micropython import const +class CBORError(Exception): + pass + + def bit_length(n): return len(bin(abs(n))) - 2 @@ -120,7 +124,7 @@ def encodeTagAndValue(self, tag, value): self.encodeTagAndAdditional(tag, value) else: - raise Exception( + raise CBORError( "Unsupported byte length of {} for value in encodeTagAndValue()".format(length)) encoded_size = 1 + length @@ -188,7 +192,7 @@ def __init__(self, buf): def decodeTagAndAdditional(self, flags=Flag_None): if self.pos == len(self.buf): - raise Exception("Not enough input") + raise CBORError("Not enough input") octet = self.buf[self.pos] self.pos += 1 tag = octet & Tag_Major_mask @@ -199,7 +203,7 @@ def decodeTagAndValue(self, flags): end = len(self.buf) if self.pos == end: - raise Exception("Not enough input") + raise CBORError("Not enough input") (tag, additional, length) = self.decodeTagAndAdditional(flags) if additional < Tag_Minor_length1: @@ -209,66 +213,66 @@ def decodeTagAndValue(self, flags): value = 0 if additional == Tag_Minor_length8: if end - self.pos < 8: - raise Exception("Not enough input") + raise CBORError("Not enough input") for shift in [56, 48, 40, 32, 24, 16, 8, 0]: value |= self.buf[self.pos] << shift self.pos += 1 if ((flags & Flag_Require_Minimal_Encoding) and value == 0): - raise Exception("Encoding not minimal") + raise CBORError("Encoding not minimal") return (tag, value, self.pos) elif additional == Tag_Minor_length4: if end - self.pos < 4: - raise Exception("Not enough input") + raise CBORError("Not enough input") for shift in [24, 16, 8, 0]: value |= self.buf[self.pos] << shift self.pos += 1 if ((flags & Flag_Require_Minimal_Encoding) and value == 0): - raise Exception("Encoding not minimal") + raise CBORError("Encoding not minimal") return (tag, value, self.pos) elif additional == Tag_Minor_length2: if end - self.pos < 2: - raise Exception("Not enough input") + raise CBORError("Not enough input") for shift in [8, 0]: value |= self.buf[self.pos] << shift self.pos += 1 if ((flags & Flag_Require_Minimal_Encoding) and value == 0): - raise Exception("Encoding not minimal") + raise CBORError("Encoding not minimal") return (tag, value, self.pos) elif additional == Tag_Minor_length1: if end - self.pos < 1: - raise Exception("Not enough input") + raise CBORError("Not enough input") value |= self.buf[self.pos] self.pos += 1 if ((flags & Flag_Require_Minimal_Encoding) and value == 0): - raise Exception("Encoding not minimal") + raise CBORError("Encoding not minimal") return (tag, value, self.pos) - raise Exception("Bad additional value") + raise CBORError("Bad additional value") def decodeTagSemantic(self, flags=Flag_None): (tag, value, length) = self.decodeTagAndValue(flags) if tag != Tag_Major_semantic: - raise Exception("Expected Tag_Major_semantic, but found {}".format(tag)) + raise CBORError("Expected Tag_Major_semantic, but found {}".format(tag)) return (value, length) def decodeUndefined(self, flags=Flag_None): (tag, value, length) = self.decodeTagAndValue(flags) if tag != Tag_Major_semantic: - raise Exception("Expected Tag_Major_semantic ({}), but found {}".format( + raise CBORError("Expected Tag_Major_semantic ({}), but found {}".format( Tag_Major_semantic, tag)) return (value, length) def decodeUnsigned(self, flags=Flag_None): (tag, value, length) = self.decodeTagAndValue(flags) if tag != Tag_Major_unsignedInteger: - raise Exception("Expected Tag_Major_unsignedInteger ({}), but found {}".format( + raise CBORError("Expected Tag_Major_unsignedInteger ({}), but found {}".format( Tag_Major_unsignedInteger, tag)) return (value, length) def decodeNegative(self, flags=Flag_None): (tag, value, length) = self.decodeTagAndValue(flags) if tag != Tag_Major_negativeInteger: - raise Exception( + raise CBORError( "Expected Tag_Major_negativeInteger, but found {}".format(tag)) return (value, length) @@ -287,18 +291,18 @@ def decodeBool(self, flags=Flag_None): return (True, length) elif value == Tag_Minor_false: return (False, length) - raise Exception("Not a Boolean") - raise Exception("Not Simple/Boolean") + raise CBORError("Not a Boolean") + raise CBORError("Not Simple/Boolean") def decodeBytes(self, flags=Flag_None): # First value is the length of the bytes that follow (tag, byte_length, size_length) = self.decodeTagAndValue(flags) if tag != Tag_Major_byteString: - raise Exception("Not a byteString") + raise CBORError("Not a byteString") end = len(self.buf) if end - self.pos < byte_length: - raise Exception("Not enough input") + raise CBORError("Not enough input") value = bytes(self.buf[self.pos: self.pos + byte_length]) self.pos += byte_length @@ -307,18 +311,18 @@ def decodeBytes(self, flags=Flag_None): def decodeEncodedBytesPrefix(self, flags=Flag_None): (tag, value, length1) = self.decodeTagAndValue(flags) if tag != Tag_Major_semantic or value != Tag_Minor_cborEncodedData: - raise Exception("Not CBOR Encoded Data") + raise CBORError("Not CBOR Encoded Data") (tag, value, length2) = self.decodeTagAndValue(flags) if tag != Tag_Major_byteString: - raise Exception("Not byteString") + raise CBORError("Not byteString") return (tag, value, length1 + length2) def decodeEncodedBytes(self, flags=Flag_None): (tag, minor_tag, tag_length) = self.decodeTagAndValue(flags) if tag != Tag_Major_semantic or minor_tag != Tag_Minor_cborEncodedData: - raise Exception("Not CBOR Encoded Data") + raise CBORError("Not CBOR Encoded Data") (value, length) = self.decodeBytes(flags) return (value, tag_length + length) @@ -327,11 +331,11 @@ def decodeText(self, flags=Flag_None): # First value is the length of the bytes that follow (tag, byte_length, size_length) = self.decodeTagAndValue(flags) if tag != Tag_Major_textString: - raise Exception("Not a textString") + raise CBORError("Not a textString") end = len(self.buf) if end - self.pos < byte_length: - raise Exception("Not enough input") + raise CBORError("Not enough input") value = bytes(self.buf[self.pos: self.pos + byte_length]) self.pos += byte_length @@ -341,12 +345,12 @@ def decodeArraySize(self, flags=Flag_None): (tag, value, length) = self.decodeTagAndValue(flags) if tag != Tag_Major_array: - raise Exception( + raise CBORError( "Expected Tag_Major_array, but found {}".format(tag)) return (value, length) def decodeMapSize(self, flags=Flag_None): (tag, value, length) = self.decodeTagAndValue(flags) if tag != Tag_Major_map: - raise Exception("Expected Tag_Major_map, but found {}".format(tag)) + raise CBORError("Expected Tag_Major_map, but found {}".format(tag)) return (value, length) diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py index b939dc437..35849570a 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py @@ -57,12 +57,9 @@ def expected_part_count(self): def is_complete(self): return self.result is not None - def result(self): - return self.result - def estimated_percent_complete(self): if self.is_complete(): - return 1 + return 100 if self.expected_part_indexes is None: return 0 estimated_input_parts = self.expected_part_count() * 1.75 diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py index 68f83982e..64351f85c 100644 --- a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py @@ -106,7 +106,12 @@ def receive_part(self, str): # Parse the sequence component and the fragment, and make sure they agree. (seq_num, seq_len) = URDecoder.parse_sequence_component(seq) - cbor = Bytewords.decode(Bytewords_Style_minimal, fragment) + + try: + cbor = Bytewords.decode(Bytewords_Style_minimal, fragment) + except ValueError as exc: + raise URError from exc + part = FountainEncoderPart.from_cbor(cbor) if seq_num != part.seq_num or seq_len != part.seq_len: raise URError('sequence numbers mismatch') @@ -115,7 +120,7 @@ def receive_part(self, str): try: self.fountain_decoder.receive_part(part) if self.fountain_decoder.is_complete(): - self.result = UR(type, self.fountain_decoder.result_message()) + self.result = UR(type, self.fountain_decoder.result) except FountainError as exc: raise URError('failed to receive part') from exc @@ -126,6 +131,3 @@ def estimated_percent_complete(self): def is_complete(self): return self.result is not None - - def result(self): - return self.result From 065df5a524ef5542d060801a91415940eee600c7 Mon Sep 17 00:00:00 2001 From: Ken Carpenter <62639971+FoundationKen@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:15:48 -0800 Subject: [PATCH 035/156] Make URError() text more consistent Capitalization --- ports/stm32/boards/Passport/modules/ur2/ur_decoder.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py index 64351f85c..47f2ca529 100644 --- a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py @@ -65,12 +65,12 @@ def parse(str): def parse_sequence_component(str): comps = str.split('-') if len(comps) != 2: - raise URError('invalid sequence component') + raise URError('Invalid sequence component') seq_num = int(comps[0]) seq_len = int(comps[1]) # print('seq_num={} seq_len={}'.format(seq_num, seq_len)) if seq_num < 1 or seq_len < 1: - raise URError('invalid sequence numbers') + raise URError('Invalid sequence numbers') return (seq_num, seq_len) def validate_part(self, type): @@ -114,7 +114,7 @@ def receive_part(self, str): part = FountainEncoderPart.from_cbor(cbor) if seq_num != part.seq_num or seq_len != part.seq_len: - raise URError('sequence numbers mismatch') + raise URError('Sequence number mismatch') # Process the part try: @@ -122,7 +122,7 @@ def receive_part(self, str): if self.fountain_decoder.is_complete(): self.result = UR(type, self.fountain_decoder.result) except FountainError as exc: - raise URError('failed to receive part') from exc + raise URError('Invalid part data') from exc return True From ebf88f0a47e18283ebbb49f53c1753302e384e47 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Fri, 30 Dec 2022 16:58:39 -0600 Subject: [PATCH 036/156] PASS1-345: cleared PSBT from flash in QR flow --- ports/stm32/boards/Passport/manifest.py | 1 + .../modules/flows/sign_psbt_qr_flow.py | 5 +++++ .../boards/Passport/modules/tasks/__init__.py | 1 + .../clear_psbt_from_external_flash_task.py | 21 +++++++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index c5c61d623..216d252da 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -227,6 +227,7 @@ 'tasks/change_pin_task.py', 'tasks/copy_psbt_file_to_external_flash_task.py', 'tasks/copy_psbt_to_external_flash_task.py', + 'tasks/clear_psbt_from_external_flash_task.py', 'tasks/double_check_psbt_change_task.py', 'tasks/create_wallet_export_task.py', 'tasks/copy_firmware_to_spi_flash_task.py', diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index f0d175b8f..a286eeebc 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -59,9 +59,14 @@ async def copy_to_flash(self): async def common_flow(self): from flows import SignPsbtCommonFlow + from tasks import clear_psbt_from_external_flash_task + from utils import spinner_task + from public_constants import TXN_INPUT_OFFSET # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, + args=[None, self.psbt_len, TXN_INPUT_OFFSET]) if result is None: self.set_result(False) else: diff --git a/ports/stm32/boards/Passport/modules/tasks/__init__.py b/ports/stm32/boards/Passport/modules/tasks/__init__.py index da89511d8..7c90c69c3 100644 --- a/ports/stm32/boards/Passport/modules/tasks/__init__.py +++ b/ports/stm32/boards/Passport/modules/tasks/__init__.py @@ -16,6 +16,7 @@ from .copy_firmware_to_spi_flash_task import copy_firmware_to_spi_flash_task from .copy_psbt_file_to_external_flash_task import copy_psbt_file_to_external_flash_task from .copy_psbt_to_external_flash_task import copy_psbt_to_external_flash_task +from .clear_psbt_from_external_flash_task import clear_psbt_from_external_flash_task from .create_wallet_export_task import create_wallet_export_task from .delete_account_task import delete_account_task from .delay_task import delay_task diff --git a/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py new file mode 100644 index 000000000..3fa8f7790 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# SPDX-FileCopyrightText: 2018 Coinkite, Inc. +# SPDX-License-Identifier: GPL-3.0-only +# +# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard +# and is covered by GPLv3 license found in COPYING. +# +# clear_psbt_from_external_flash_task.py - Task to clear a psbt from external flash after signing for security purposes + +from public_constants import MAX_TXN_LEN + + +async def clear_psbt_from_external_flash_task(on_done, on_progress, psbt_len, offset): + from sffile import SFFile + + with SFFile(offset, max_size=psbt_len) as out: + # blank flash + await out.erase() + await on_done() From e3a284e33695e66d32293cd62e3264448870a694 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 2 Jan 2023 13:48:59 -0600 Subject: [PATCH 037/156] PASS1-345: fixed erase from external flash for microsd flow --- .../modules/flows/sign_psbt_microsd_flow.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py index 6f34670ef..776f1743a 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py @@ -54,6 +54,7 @@ async def copy_file_to_flash(self): from pages import ErrorPage from public_constants import TXN_INPUT_OFFSET from tasks import copy_psbt_file_to_external_flash_task + from tasks import clear_psbt_from_external_flash_task # TODO: I think this is always a bytes object -- can probably remove this check # The data can be a string or may already be a bytes object @@ -70,6 +71,8 @@ async def copy_file_to_flash(self): copy_psbt_file_to_external_flash_task, args=[None, self.file_path, TXN_INPUT_OFFSET]) if error is not None: + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, + args=[None, self.psbt_len, TXN_INPUT_OFFSET]) await ErrorPage(text='Invalid PSBT (copying microSD)').show() self.set_result(False) return @@ -81,20 +84,31 @@ async def copy_file_to_flash(self): async def common_flow(self): from flows import SignPsbtCommonFlow + from tasks import clear_psbt_from_external_flash_task + from utils import spinner_task + from public_constants import TXN_INPUT_OFFSET # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() if result is None: + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, + args=[None, self.psbt_len, TXN_INPUT_OFFSET]) self.set_result(False) else: self.psbt = result self.goto(self.write_signed_transaction) async def show_card_missing(self): + from tasks import clear_psbt_from_external_flash_task + from utils import spinner_task + from public_constants import TXN_INPUT_OFFSET + result = await InsertMicroSDPage().show() if not result: result = QuestionPage(text='Cancel signing this transaction?').show() if result: + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, + args=[None, self.psbt_len, TXN_INPUT_OFFSET]) self.set_result(None) self.goto(self.write_signed_transaction) @@ -103,6 +117,9 @@ async def write_signed_transaction(self): from files import CardSlot, CardMissingError, securely_blank_file from utils import HexWriter from pages import ErrorPage + from tasks import clear_psbt_from_external_flash_task + from utils import spinner_task + from public_constants import TXN_INPUT_OFFSET orig_path, basename = self.file_path.rsplit('/', 1) orig_path += '/' @@ -151,12 +168,16 @@ async def write_signed_transaction(self): self.txid = self.psbt.finalize(fd) securely_blank_file(self.file_path) + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, + args=[None, self.psbt_len, TXN_INPUT_OFFSET]) # Success and done! self.goto(self.show_success) return except OSError as exc: + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, + args=[None, self.psbt_len, TXN_INPUT_OFFSET]) result = await ErrorPage(text='Unable to write!\n\n%s\n\n' % exc).show() # sys.print_exception(exc) # fall thru to try again From 74802c26ef54cb34d0ec371bf30e868298934c06 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 16 Jan 2023 11:40:56 -0600 Subject: [PATCH 038/156] PASS1-345: refactored clear flash code --- .../modules/flows/sign_psbt_microsd_flow.py | 30 +++++++------------ .../modules/flows/sign_psbt_qr_flow.py | 10 +++---- ports/stm32/boards/Passport/modules/utils.py | 9 ++++++ 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py index 776f1743a..d47d4d586 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py @@ -54,7 +54,7 @@ async def copy_file_to_flash(self): from pages import ErrorPage from public_constants import TXN_INPUT_OFFSET from tasks import copy_psbt_file_to_external_flash_task - from tasks import clear_psbt_from_external_flash_task + from utils import clear_psbt_flash # TODO: I think this is always a bytes object -- can probably remove this check # The data can be a string or may already be a bytes object @@ -71,8 +71,7 @@ async def copy_file_to_flash(self): copy_psbt_file_to_external_flash_task, args=[None, self.file_path, TXN_INPUT_OFFSET]) if error is not None: - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, - args=[None, self.psbt_len, TXN_INPUT_OFFSET]) + await clear_psbt_flash(self.psbt_len) await ErrorPage(text='Invalid PSBT (copying microSD)').show() self.set_result(False) return @@ -84,31 +83,25 @@ async def copy_file_to_flash(self): async def common_flow(self): from flows import SignPsbtCommonFlow - from tasks import clear_psbt_from_external_flash_task - from utils import spinner_task - from public_constants import TXN_INPUT_OFFSET + from utils import clear_psbt_flash # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() if result is None: - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, - args=[None, self.psbt_len, TXN_INPUT_OFFSET]) + await clear_psbt_flash(self.psbt_len) self.set_result(False) else: self.psbt = result self.goto(self.write_signed_transaction) async def show_card_missing(self): - from tasks import clear_psbt_from_external_flash_task - from utils import spinner_task - from public_constants import TXN_INPUT_OFFSET + from utils import clear_psbt_flash result = await InsertMicroSDPage().show() if not result: result = QuestionPage(text='Cancel signing this transaction?').show() if result: - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, - args=[None, self.psbt_len, TXN_INPUT_OFFSET]) + await clear_psbt_flash(self.psbt_len) self.set_result(None) self.goto(self.write_signed_transaction) @@ -117,9 +110,7 @@ async def write_signed_transaction(self): from files import CardSlot, CardMissingError, securely_blank_file from utils import HexWriter from pages import ErrorPage - from tasks import clear_psbt_from_external_flash_task - from utils import spinner_task - from public_constants import TXN_INPUT_OFFSET + from utils import clear_psbt_flash orig_path, basename = self.file_path.rsplit('/', 1) orig_path += '/' @@ -168,16 +159,15 @@ async def write_signed_transaction(self): self.txid = self.psbt.finalize(fd) securely_blank_file(self.file_path) - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, - args=[None, self.psbt_len, TXN_INPUT_OFFSET]) + await clear_psbt_flash(self.psbt_len) # Success and done! self.goto(self.show_success) return except OSError as exc: - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, - args=[None, self.psbt_len, TXN_INPUT_OFFSET]) + # If this ever changes to not fall through, clear the flash + # await clear_psbt_flash(self.psbt_len) result = await ErrorPage(text='Unable to write!\n\n%s\n\n' % exc).show() # sys.print_exception(exc) # fall thru to try again diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index a286eeebc..c428d4031 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -41,6 +41,7 @@ async def copy_to_flash(self): from tasks import copy_psbt_to_external_flash_task from pages import ErrorPage from public_constants import TXN_INPUT_OFFSET + from utils import clear_psbt_flash gc.collect() # Try to avoid excessive fragmentation @@ -48,6 +49,7 @@ async def copy_to_flash(self): (self.psbt_len, self.output_encoder, error) = await spinner_task( 'Parsing transaction', copy_psbt_to_external_flash_task, args=[None, self.raw_psbt, TXN_INPUT_OFFSET]) if error is not None: + await clear_psbt_flash(self.psbt_len) await ErrorPage(text='Invalid PSBT (copying QR)').show() self.set_result(False) return @@ -59,14 +61,12 @@ async def copy_to_flash(self): async def common_flow(self): from flows import SignPsbtCommonFlow - from tasks import clear_psbt_from_external_flash_task - from utils import spinner_task - from public_constants import TXN_INPUT_OFFSET + from utils import clear_psbt_flash # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, - args=[None, self.psbt_len, TXN_INPUT_OFFSET]) + await clear_psbt_flash(self.psbt_len) + if result is None: self.set_result(False) else: diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index cfe39e851..2d58e3f3e 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -1239,4 +1239,13 @@ def set_screen_brightness(value): else: common.settings.set('screen_brightness', value) + +async def clear_psbt_flash(psbt_len): + from utils import spinner_task + from tasks import clear_psbt_from_external_flash_task + from public_constants import TXN_INPUT_OFFSET + + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, + args=[None, psbt_len, TXN_INPUT_OFFSET]) + # EOF From ea758b9c6aa5087cf22c7e489e9b34119dc51769 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 23 Jan 2023 12:49:06 -0600 Subject: [PATCH 039/156] PASS1-345: added bounds check on PSBTs, and erased full PSBT area of flash --- .../Passport/modules/flows/sign_psbt_microsd_flow.py | 10 +++++----- .../boards/Passport/modules/flows/sign_psbt_qr_flow.py | 4 ++-- .../tasks/clear_psbt_from_external_flash_task.py | 7 ++++--- .../tasks/copy_psbt_file_to_external_flash_task.py | 4 ++++ .../modules/tasks/copy_psbt_to_external_flash_task.py | 4 ++++ ports/stm32/boards/Passport/modules/utils.py | 6 ++---- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py index d47d4d586..a924e1e03 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py @@ -71,7 +71,7 @@ async def copy_file_to_flash(self): copy_psbt_file_to_external_flash_task, args=[None, self.file_path, TXN_INPUT_OFFSET]) if error is not None: - await clear_psbt_flash(self.psbt_len) + await clear_psbt_flash() await ErrorPage(text='Invalid PSBT (copying microSD)').show() self.set_result(False) return @@ -88,7 +88,7 @@ async def common_flow(self): # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() if result is None: - await clear_psbt_flash(self.psbt_len) + await clear_psbt_flash() self.set_result(False) else: self.psbt = result @@ -101,7 +101,7 @@ async def show_card_missing(self): if not result: result = QuestionPage(text='Cancel signing this transaction?').show() if result: - await clear_psbt_flash(self.psbt_len) + await clear_psbt_flash() self.set_result(None) self.goto(self.write_signed_transaction) @@ -159,7 +159,7 @@ async def write_signed_transaction(self): self.txid = self.psbt.finalize(fd) securely_blank_file(self.file_path) - await clear_psbt_flash(self.psbt_len) + await clear_psbt_flash() # Success and done! self.goto(self.show_success) @@ -167,7 +167,7 @@ async def write_signed_transaction(self): except OSError as exc: # If this ever changes to not fall through, clear the flash - # await clear_psbt_flash(self.psbt_len) + # await clear_psbt_flash() result = await ErrorPage(text='Unable to write!\n\n%s\n\n' % exc).show() # sys.print_exception(exc) # fall thru to try again diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index c428d4031..79c5e909b 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -49,7 +49,7 @@ async def copy_to_flash(self): (self.psbt_len, self.output_encoder, error) = await spinner_task( 'Parsing transaction', copy_psbt_to_external_flash_task, args=[None, self.raw_psbt, TXN_INPUT_OFFSET]) if error is not None: - await clear_psbt_flash(self.psbt_len) + await clear_psbt_flash() await ErrorPage(text='Invalid PSBT (copying QR)').show() self.set_result(False) return @@ -65,7 +65,7 @@ async def common_flow(self): # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() - await clear_psbt_flash(self.psbt_len) + await clear_psbt_flash() if result is None: self.set_result(False) diff --git a/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py index 3fa8f7790..a3f875ddf 100644 --- a/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py @@ -9,13 +9,14 @@ # # clear_psbt_from_external_flash_task.py - Task to clear a psbt from external flash after signing for security purposes -from public_constants import MAX_TXN_LEN +from constants import PSBT_MAX_SIZE +from public_constants import TXN_INPUT_OFFSET -async def clear_psbt_from_external_flash_task(on_done, on_progress, psbt_len, offset): +async def clear_psbt_from_external_flash_task(on_done): from sffile import SFFile - with SFFile(offset, max_size=psbt_len) as out: + with SFFile(start=TXN_INPUT_OFFSET, max_size=PSBT_MAX_SIZE) as out: # blank flash await out.erase() await on_done() diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py index f625f9ead..42726e84e 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py @@ -34,6 +34,10 @@ async def copy_psbt_file_to_external_flash_task(on_done, on_progress, filename, psbt_len = fd.seek(0, 2) fd.seek(0) + if psbt_len > MAX_TXN_LEN: + await on_done(0, None, Error.PSBT_INVALID) + return + # determine encoding used, although we prefer binary taste = fd.read(10) fd.seek(0) diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py index 07b765900..c70fb0b38 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py @@ -26,6 +26,10 @@ async def copy_psbt_to_external_flash_task(on_done, on_progress, data, offset): # See how long it is -- This version of seek returns the final offset psbt_len = len(data) + if psbt_len > MAX_TXN_LEN: + await on_done(0, None, Error.PSBT_INVALID) + return + # determine encoding used, although we prefer binary taste = fd.read(10) fd.seek(0) diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 2d58e3f3e..9618c767f 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -1240,12 +1240,10 @@ def set_screen_brightness(value): common.settings.set('screen_brightness', value) -async def clear_psbt_flash(psbt_len): +async def clear_psbt_flash(): from utils import spinner_task from tasks import clear_psbt_from_external_flash_task - from public_constants import TXN_INPUT_OFFSET - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, - args=[None, psbt_len, TXN_INPUT_OFFSET]) + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task) # EOF From b9c43c08059d23ca941c0b39109078791ececf8a Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 26 Jan 2023 12:40:37 -0600 Subject: [PATCH 040/156] PASS1-345: added PSBT_TOO_LARGE error --- ports/stm32/boards/Passport/modules/errors.py | 1 + .../boards/Passport/modules/flows/sign_psbt_microsd_flow.py | 6 +++++- .../boards/Passport/modules/flows/sign_psbt_qr_flow.py | 6 +++++- .../modules/tasks/copy_psbt_file_to_external_flash_task.py | 2 +- .../modules/tasks/copy_psbt_to_external_flash_task.py | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/errors.py b/ports/stm32/boards/Passport/modules/errors.py index db13d08bd..416241af6 100644 --- a/ports/stm32/boards/Passport/modules/errors.py +++ b/ports/stm32/boards/Passport/modules/errors.py @@ -23,4 +23,5 @@ 'PSBT_INVALID', 'SECURE_ELEMENT_ERROR', 'USER_SETTINGS_FULL', + 'PSBT_TOO_LARGE', ) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py index a924e1e03..aac7b63e5 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py @@ -55,6 +55,7 @@ async def copy_file_to_flash(self): from public_constants import TXN_INPUT_OFFSET from tasks import copy_psbt_file_to_external_flash_task from utils import clear_psbt_flash + from errors import Error # TODO: I think this is always a bytes object -- can probably remove this check # The data can be a string or may already be a bytes object @@ -72,7 +73,10 @@ async def copy_file_to_flash(self): args=[None, self.file_path, TXN_INPUT_OFFSET]) if error is not None: await clear_psbt_flash() - await ErrorPage(text='Invalid PSBT (copying microSD)').show() + if error == Error.PSBT_TOO_LARGE: + await ErrorPage(text='PSBT too large').show() + else: + await ErrorPage(text='Invalid PSBT (copying microSD)').show() self.set_result(False) return diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index 79c5e909b..2b5bbeb54 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -42,6 +42,7 @@ async def copy_to_flash(self): from pages import ErrorPage from public_constants import TXN_INPUT_OFFSET from utils import clear_psbt_flash + from errors import Error gc.collect() # Try to avoid excessive fragmentation @@ -50,7 +51,10 @@ async def copy_to_flash(self): 'Parsing transaction', copy_psbt_to_external_flash_task, args=[None, self.raw_psbt, TXN_INPUT_OFFSET]) if error is not None: await clear_psbt_flash() - await ErrorPage(text='Invalid PSBT (copying QR)').show() + if error == Error.PSBT_TOO_LARGE: + await ErrorPage(text='PSBT too large').show() + else: + await ErrorPage(text='Invalid PSBT (copying QR)').show() self.set_result(False) return diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py index 42726e84e..a4add503b 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py @@ -35,7 +35,7 @@ async def copy_psbt_file_to_external_flash_task(on_done, on_progress, filename, fd.seek(0) if psbt_len > MAX_TXN_LEN: - await on_done(0, None, Error.PSBT_INVALID) + await on_done(0, None, Error.PSBT_TOO_LARGE) return # determine encoding used, although we prefer binary diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py index c70fb0b38..3c558c28c 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py @@ -27,7 +27,7 @@ async def copy_psbt_to_external_flash_task(on_done, on_progress, data, offset): psbt_len = len(data) if psbt_len > MAX_TXN_LEN: - await on_done(0, None, Error.PSBT_INVALID) + await on_done(0, None, Error.PSBT_TOO_LARGE) return # determine encoding used, although we prefer binary From d95cd2ad3a61c8c77bfbf560db2fdf447da0f997 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 30 Jan 2023 09:58:02 -0600 Subject: [PATCH 041/156] PASS1-345: reverted to only clearing the psbt length --- .../Passport/modules/flows/sign_psbt_microsd_flow.py | 10 +++++----- .../boards/Passport/modules/flows/sign_psbt_qr_flow.py | 4 ++-- .../tasks/clear_psbt_from_external_flash_task.py | 5 ++--- ports/stm32/boards/Passport/modules/utils.py | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py index aac7b63e5..a515f044f 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py @@ -72,7 +72,7 @@ async def copy_file_to_flash(self): copy_psbt_file_to_external_flash_task, args=[None, self.file_path, TXN_INPUT_OFFSET]) if error is not None: - await clear_psbt_flash() + await clear_psbt_flash(self.psbt_len) if error == Error.PSBT_TOO_LARGE: await ErrorPage(text='PSBT too large').show() else: @@ -92,7 +92,7 @@ async def common_flow(self): # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() if result is None: - await clear_psbt_flash() + await clear_psbt_flash(self.psbt_len) self.set_result(False) else: self.psbt = result @@ -105,7 +105,7 @@ async def show_card_missing(self): if not result: result = QuestionPage(text='Cancel signing this transaction?').show() if result: - await clear_psbt_flash() + await clear_psbt_flash(self.psbt_len) self.set_result(None) self.goto(self.write_signed_transaction) @@ -163,7 +163,7 @@ async def write_signed_transaction(self): self.txid = self.psbt.finalize(fd) securely_blank_file(self.file_path) - await clear_psbt_flash() + await clear_psbt_flash(self.psbt_len) # Success and done! self.goto(self.show_success) @@ -171,7 +171,7 @@ async def write_signed_transaction(self): except OSError as exc: # If this ever changes to not fall through, clear the flash - # await clear_psbt_flash() + # await clear_psbt_flash(self.psbt_len) result = await ErrorPage(text='Unable to write!\n\n%s\n\n' % exc).show() # sys.print_exception(exc) # fall thru to try again diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index 2b5bbeb54..492353631 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -50,7 +50,7 @@ async def copy_to_flash(self): (self.psbt_len, self.output_encoder, error) = await spinner_task( 'Parsing transaction', copy_psbt_to_external_flash_task, args=[None, self.raw_psbt, TXN_INPUT_OFFSET]) if error is not None: - await clear_psbt_flash() + await clear_psbt_flash(self.psbt_len) if error == Error.PSBT_TOO_LARGE: await ErrorPage(text='PSBT too large').show() else: @@ -69,7 +69,7 @@ async def common_flow(self): # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() - await clear_psbt_flash() + await clear_psbt_flash(self.psbt_len) if result is None: self.set_result(False) diff --git a/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py index a3f875ddf..734f09b8d 100644 --- a/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py @@ -9,14 +9,13 @@ # # clear_psbt_from_external_flash_task.py - Task to clear a psbt from external flash after signing for security purposes -from constants import PSBT_MAX_SIZE from public_constants import TXN_INPUT_OFFSET -async def clear_psbt_from_external_flash_task(on_done): +async def clear_psbt_from_external_flash_task(on_done, psbt_len): from sffile import SFFile - with SFFile(start=TXN_INPUT_OFFSET, max_size=PSBT_MAX_SIZE) as out: + with SFFile(start=TXN_INPUT_OFFSET, max_size=psbt_len) as out: # blank flash await out.erase() await on_done() diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 9618c767f..58fb2b41f 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -1240,10 +1240,10 @@ def set_screen_brightness(value): common.settings.set('screen_brightness', value) -async def clear_psbt_flash(): +async def clear_psbt_flash(psbt_len): from utils import spinner_task from tasks import clear_psbt_from_external_flash_task - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task) + await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, args=[psbt_len]) # EOF From bdf7ae62c88ca1b3b7f2834849aa01f9204c410f Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 30 Jan 2023 16:15:20 -0600 Subject: [PATCH 042/156] PASS1-345: removed message from clearing psbt spinner --- ports/stm32/boards/Passport/modules/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 58fb2b41f..6ad6ef21e 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -1244,6 +1244,6 @@ async def clear_psbt_flash(psbt_len): from utils import spinner_task from tasks import clear_psbt_from_external_flash_task - await spinner_task('Clearing transaction from flash', clear_psbt_from_external_flash_task, args=[psbt_len]) + await spinner_task(None, clear_psbt_from_external_flash_task, args=[psbt_len]) # EOF From c647e744787d2212b27aafa25a4bf516946dceb4 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 6 Feb 2023 14:42:18 +0100 Subject: [PATCH 043/156] PASS1-651: Cleanup gitignore. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .gitignore | 35 ++++++------------ .../boards/Passport/bootloader/.gitignore | 1 - .../boards/Passport/tools/cosign/.gitignore | 1 - .../tools/word_list_gen/word_list_gen | Bin 101384 -> 0 bytes 4 files changed, 12 insertions(+), 25 deletions(-) delete mode 100644 ports/stm32/boards/Passport/bootloader/.gitignore delete mode 100644 ports/stm32/boards/Passport/tools/cosign/.gitignore delete mode 100755 ports/stm32/boards/Passport/tools/word_list_gen/word_list_gen diff --git a/.gitignore b/.gitignore index 79ab2b284..86f93757d 100644 --- a/.gitignore +++ b/.gitignore @@ -71,34 +71,23 @@ genrst/ ###################### .DS_Store - - - -ports/stm32/boards/Passport/tools/add-secrets/x86/release/ - -ports/stm32/secrets* - +# Passport +###################### +ports/stm32/boards/Passport/tools/add-secrets/x86 +ports/stm32/boards/Passport/bootloader/dev-secrets/ ports/stm32/boards/Passport/bootloader/version_info.c - ports/stm32/boards/Passport/bootloader/secrets* - -*.pem -.vscode - +ports/stm32/ditto/ditto-component-library.json +ports/stm32/ditto/index.js +ports/stm32/ditto/Envoy \+ PP Clean Start.json +ports/stm32/secrets* ports/unix/passport-mpy +simulator/ENV/ +simulator/work/ simulator/work/microsd/backups/ - simulator/snapshots/ *.gif - -simulator/ENV/ -simulator/work/ -ports/stm32/ditto/ditto-component-library.json - -ports/stm32/ditto/index.js - -ports/stm32/ditto/Envoy \+ PP Clean Start.json - -ports/stm32/boards/Passport/bootloader/dev-secrets/ +*.pem +.vscode diff --git a/ports/stm32/boards/Passport/bootloader/.gitignore b/ports/stm32/boards/Passport/bootloader/.gitignore deleted file mode 100644 index b7a88c414..000000000 --- a/ports/stm32/boards/Passport/bootloader/.gitignore +++ /dev/null @@ -1 +0,0 @@ -version_info.c diff --git a/ports/stm32/boards/Passport/tools/cosign/.gitignore b/ports/stm32/boards/Passport/tools/cosign/.gitignore deleted file mode 100644 index b33be14ad..000000000 --- a/ports/stm32/boards/Passport/tools/cosign/.gitignore +++ /dev/null @@ -1 +0,0 @@ -x86/release/cosign diff --git a/ports/stm32/boards/Passport/tools/word_list_gen/word_list_gen b/ports/stm32/boards/Passport/tools/word_list_gen/word_list_gen deleted file mode 100755 index 152367e1bb9ecd493db28d327c3d56e57a1d1256..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101384 zcmb5$37A`D-9G+Ppb*xEMHm(#ip3Fa2^4VH!%_&y5{1gJl+Ko!q?1WPmQJP!L=c@) zkqC$bZiC|MAOiD>$RH>w2#hGaK?Mhpmxw4SWeKtv5$ON^KIblW?w?-Q`yZ}6PtGT2 zea^F=Q!ZY7^6{I@nd5Ev+tfSKv!%$hzC`%L^cViMPQ>f*w)7(22faPK&GGwY_-t5D z;}$pD5C^cX{cVbmZP&4hE&ado9zNp;{@;e9TRfNc@1nN7{WUklo)>bfncBIQ7x=%I z7ktS1hIsrWx9CkU-msmWo^4m*b`@^7A#VD+^ESjAuFtN`K4F)9am|&*TbNvA5K{tUsCVP9;~y-9Co0P}}XYe4!h= z80t=@y%SD8@t9+m9kB3#g$H@dPCVn3Wqt8nd?1-G#B*nya%?J-j-S!plZs=@fuT&A zTQ2ig{kJQ+YuN;OYvcd?yk_}rj{DE^Hstr>Zpkg}*96mGL;2rOZX+r^jA!{STn z9pZiTi1;8qDxRaq#7p!}@z2q_#4n*I#7F5_@vqQJ;#bkj;@8qg#lKCjh~G#b6aOK7 zTzrx~AwET)6#oT%O8l4fs`xa0TKrLZP5k%t8S$s-b@4yZ8{#j}o8qt1TjFofy#r?F z|F`J@@i{O07(L#dPRICeN6lk`ndSz^a=5+=#%2t(x=3~Nw13ENS_wJ znO+nBZ~Bb*UG%#6z4V6oFX>J3U(;LSHM+NGcK&~Y9uWT{Jt$tMw~7Ci9uj|v-Y)(c zJuKd$cZhrI{PGwP-+~?$-;N#=--+HS-bU{d{}4SP-cHYohv_Bp1Lp$I>g} zC(_5nWAt(HGwBoJ=g}v{`{`5SgY>F+jy^3uLa&KmLZ1=8oL(2dirx?(qc_FBLvM-S zNcRq$o&Rs92gE1oLGe53ZQ}RRL*ft7+r=NDhsA$K?+|~I9ufavdQ|+c^qBZd^iJ_N z=w0IfpeMxNqi4mpc*!rPCGlmEB*w%B>ptLEdCsQ zRD3PHBK{hEOuR)O7x!NF%j1OjX7ow%E$LI@+tI7yJJYAdcc<6HKSZAqZ>QJA7t$Nz z2hyA3htgZ($I!ilXXpPYJs^H6Jt%$#y-oaVdPuyB-Y%Y?hs87W4)Fp#B0fToieF5R ziC;$V6u+F_C4MD6A$|=#D}EilB>ruBS^P%&sQ69viui5xG4Y?$$Hjk6pAi2geNy~a z^eOQgy(<0(`n34d^qTmy^cnFN=ymaz=?(GM=}qx}&|Bi`>E0)2=l{8{`1M0Td>eXD zd z;>+n}@hp8*e3)JlznDHIei?mS{Brt)_?7fY@oVW*;@_fI#c!lfi{DJIiT{{BBR)m1 zi{C?Uh(ADYia$(mi9bg7I%enpKhOi>f20S+pQpEpzeo>>H|g!-f2W7V-=TMi&v}*O zU-8Z9QSq(mG4UPfo#MODyTo^=C&WKQ&x*IxOX3UZW$}aPqvD6rE8@q{$HY&hkBfhr zJ|TVpFyvSpG|LwchQ^T1N4@7itZgcJOAhD0r3%fQ2g`sHt{dfL*iG^+r_^|4~u`3 z-XZ=ydPMwYdQ|*&dQAK-dZ+lk^e*uS=n3&h=~?l|=_T=J=wPUG%VcoZcZmNRNo;=~3~O^q6>=-YNb?dYAZD z=n3(w=~?mX=_T>+(97aC(nrOAM6Zbdm_89uVJ$9u)sLy-hq!4~c)0 z-Y$MPJuH3M+~3GwgIC&ee|Q{uPMtKvVQPmAA8uZgdr&xk)nuZurIZ;1b%-V}d| z-V%S7?j12Z|Gz*Fh`&q^ioZ^86Mvf?5?@bm7oYpOUw*^l+t542cc4eaccVweL-d&V zN9mp7`_a3^52h!?52t6vBlMDZlwKA;g+402gkBLpi#{gaLmwAkPM;9Z(I>@M(x=4B z^s4wMeOmlVdQJQq`i%JX^t$-B=?(Gk)0^Tyq_@N;>E4mE^Z%XnfcP)yLGk=>_^I?M@g?-C___3H@jiM@JV~Ds&(iDS!}Nyu z#q_55W%QQ#m+9V7v-AJe^nmy`=|S=D(c8p-NDqnMMsF9tlO7hom);@%AUz`f2t6wP zI6Wr*M|!9DpXpuV>*xvbCOs?OqL;+qqnE`uebX;rqvBi9E8_F$W8yp0$Hn)gPl)eB zpA=t6pAtWaUKKx*J}thOUK2lwJ|liQy)J$(y&>L5Z;B`BE%Ec|USxLuUr7&$UqTOx zuco(&UqugzUq^2jzkwbW{{g*2{8oBI{7!mQ{BC+oyh`sBpQd+-{|`MO{scWM{tUe& z{%3kwyg?rof0#`n330={51|=`-Rt(Cgwi(Hr8E^rrX}y(PYe z?j1Kf|Nn{}5Pysw6#oOgP5c>pNc=f^yZBmqSiDK^5dS+pBK{sdD!%zY{Bjo)-_5 z(c8tR=wb0Hy+iz0^oaOl^r-mb^qBZl^iJ_->0RP~r6uZbT{pAkQrUKfwj8{((Y zo8o8CTjFQYz2j%+|7G-mct1TTK1gp9&(K5S!}NCX3+Q3-GQC6mi}Z;2m+4XQuhL`U zWAsk(Z_&HNZ=@&0Z=z?#Z=;vQ@1U2(@1~E6-$$>APt(W5AEl3r|CT->{s;P`_%rk= z@jub4;(w)2i?5^C#Q#R05&t{AF8&U^A->5!{d%J*z9qdS9;ACG%+CKGpa;Z1NDqqd zO>YzbI6WkO0KHxO5PDerD0+wZvGj=er|41fPt#-KXVW{yyXalw1N4M=nw}NU(@Wwb z^s@NH^ilE4=oRrV)5pZGqK}JzojxJ{4f>?`4fHATo9I>XTj|r{chGC%_t0m=*U;P}=(3|2RdP{sh-TTz+ z{Qn7hKzx6CQ2bzeoA_b$koZybcJbrrVeymc9pay%N5s#fN5#*h$HaT-o#KP^F7X^a zAwEpcieE@CiC;o5i+_neD*k19Mf_^|nD}+{aq;icC&Yh1pA^4^J|+HRdR2UiJ}rI^ zy(YefJ|q4Ry)OPJy&?X4dQ<$5^p^Oa>E6k+^M8XL5Py{(6n~T6CjK@(B)-XdzaD58 z-;y2{-eMbD-^t$*D=ne5(=}qxF=`HbJ z(7jV;=l=)k0r5xZLGj%j4~zee-XZ=EdPICZJt`jX=D30v6W@;B zDZVqkOZ@W%0x4qvFTVE8?G`kBP_V~yF#3#mgkBdvj@}SI zncfutG`%I>N%u~ho&T581L8gOpm>7bCZ48;#Pjra@nL#c{6cz%_@(rS_~rDd_?7gS z_%-xS@$2Ya;@_nw#BZW!#c!jR#P6V&#qXw%im#zp#D7H}6MvLGF8*8kg!mumlj6_P zr^Nq4uZq7&pB8_OUK4+dJ|q4Py)M4VCVoB85Z{X46rV?LiSJ1FVzcxAuJnL-h#nMg zr?-hOq=&>8(c8rjrH93jqIZa&K#z!@N{@;!p~u9}p?8XR(YwSG^n`epo)s_AOX3&O z%i@>NN5x0!74a+RW8zoQ$Hm9!6XM^ZPl|t+J|%t=y()eyeOmkudQJRi^cnFr^t$+i z^oIDa=}qz9(OcqA(!Ed5&j0^Q4~Rcc4~nm&w~06DA@Miq?c(p!!{VE4>X-Kp@h#~Q z@$KkQ@tx=~@!ja1;vc4WiGPfq5Z{lU6+ehx5YMf^1SnD`R!B6+fRoExv+Y6Tgr?BmQ}MU3`?@5U7e~=y)e}vv4{scWD{xm%*UZ=;zU!Zr2zfA8Ee~X?F|0g{w zzR6~O`7McWNiU0UPahTEnO+h9Abm{y!}M|Sed!b8`_U)GJLps5N7Ad}$I++7KSi&J z$LKTSXVUB9=g}MD{q&~zAiX7iKHWQgcK#ox2gEO=2gNU?w~3F^L*f;ByZE*Au=uy= z9pX3ABjUHvqvAiN$Had|?-Z}nyTl)$C&VA2XT^UzC6>@h#|6;`8WL@tx_@;(O3*;(OC)#6L=}i!Y=%#1E!7#gCx3#23@O zGiK-iPtgP7F?vw^v-CFcbLb)QUV6KDiXIlv(>ugh(j($!dQ^NBJtlr7y;J-edYAb1 z^o00#=vndqqL;*PrkBNkLLU{sn_dyWk3J^;Yx=nOWAq8}C+L&n&(NpDpQl&FU!qTo zzecZ#|D8S~{tmq^zUk(EIcL?+;yHR&e3)Jm{~Wz6{(1VS_?PGv z@hj+K;#bqh#lJzH5dSWHQv4?Rl=yA*s`yXn)8hBgYvOC@GvdFZ*Trk}hWHcorub9z zmiTjY@3XV>|5|!L{8f5T{B?Sp_}}Rv@ptI$;+t;am+P?jR`d?>9q1A9-RM#A57A@d zAES4Q??>+vKZu?XKZ2eWKZafsKb~F|Kbbx%emcD(einU9d?|fgyoWv^-cO$tPtm8u z3-qe^2z^@oB6>~y68enzD7`LzCA}ej4ZSIT9la&~9lCes?EL=&dO-YEdQkihdYkw? z^pN;{^mg%w>0$92y+iy-dPMwLdQ|+c^qBao^iJ`&=w0IP(G%jE1^n`x72k$l65oMd z7T=XVD*hpQMSLInnE1!(`m}f(y(YdFeMWpAdR=@0y&--Oy(xY;y(NAu-8*Y`{y%{p5I=<; z6hEEbCVnf{5pD8{04eS z{J-dB@muJl;UJ@_T%i{B!hi@k{6v;-mCQ@vqXS#K-7W@p1aJ_9X%$#6TMS>H+q-&Ui5_cN9bAced#6fFug2(5PekqFnUG& z82Xrals+zgDt$uybo!)tCw)qM8NDhVr%#I~={4~TeMY=UuZypwH^e_rZ;F43-V(o( z?k%02|F5M7#J^1sihrNpCjKLONc<=CcJaIEVe$Lv9pVquBjS(IqvA94nE12wPVpD$ zUE;6M6XI{sv*Pd2OX8bu>zCiMcz`}CK961zZ=;Wi??oRM--kXSzJNX{zKA|0-a)U5 zA4Q)QKb~F_KZQOczJy*EKbPJR@1r-x2k9;G0^K`rcK*MB9uWTmJt%$!y-oZYdPw{m z^mg&@(Zk|Dq<4t_m>vh0{*TfF;xT$qdk7oSfLi|uIO_+ome_{sDx@iXWN@ul>vct5=)o}!n< zbM#U15qd?uOdk{fB7I!^a{7e$SLu`DWArKUZ_%sbH`1rYZ>HD8Z>P_Q-$Sp9uc0@@ zAEYz$qdhv)(EJUuABlHMkMF+C*yMS8pVYI<0_Lhlg2mL3uR zCOsg5D{9E4@qn4thfTZhBUH4ZS4(AiXU98~UjDWAuvn6ZA3hXXxYN&(kNw z*U~4&U!hNlzfP};|ARg)K4%BN9;k_LL7x#1((B?o(;MP@(wpLY(_7;0bgyrA{$EHB zh%cfC#XIP2;z!a$;>Xh4#ZRJ##bfji@z2sD;^)$%;(hd(_;Pxuc$VHJUZN+&FQR9~ zzd$dEUrsNJf0aHe{&jjq{M+;~@f+#m;y2MJ#3$*K;yy@G#XnD<68{ptDt-lhTKsByP5e6gjQDryb@7|%4e?2OQ~XYPOT0?=`e*0= zX?j5XQF>7P33{9OAL$|S=jrX@>*!(eztKCy-=;^z*VCiooA2b8)0p_S^iJ^|>0RQx z(-Yz$dRF|S^pg0;>1FZ#>7(Ku^osbA^fB?p^l|Z1=o8|fp-+mRO`j6)qF2R}^l9-N zy(T_FpAr8&y)M3r-VpyPy(#{6dQ1G9bZ=mG{{JpLAU;74ir-3a6aNW4Bz_mYUHo2p zSo}eHhxl*k5%J&AqvB7~W8#0JcZxUYUE;6M6XI{uv*Q1tm&D(rm&NCPz%Qqx;#<)x z;`8WZ;ycmD#doJqh==Ht;``92#23)3;s?;D#XIOV@gwLn;>XbI;>Xh);-}D?;%CrX z;%Cvl#O(Zk9z7u5OAm@C=xyR@dPqD^ZxuIi_;K`-_=)tg_-XV}@iXZa@ul=J@m~74_yB!EJVl=rFVLsN zFQ8Y&%k*jSFVSn_U!l*4Urn!zUr%p{-#~AQPtaT9x6-}A+4=u=dO-XxdQkl5^fvMP z=ppfk>FwhGLl2A3&^yGRrANeHphv}DrpLtJq<4z{linrnwfW^bA-)AYE504QB)&7f zEWRgwRD3?YBEBzuOnec2T>LQlg!nP^N%1IsN<2odil0fJ7C(<(6YrmPSJ2zVFQSLVzew*8zk(hS{~A3i{tbFee4O4X{$KPi@muH#@!RQH@w@0H z@q6iI@dxOm;t$g+;=iSji9bmn7yn=Sg!o_Rlj1MZr^K7|s`#7qY4Nw|HSzWI8S%|` z^UH5td~13`d`Egyyp7%x57E8!?EF8U9uVJ`9uyDL+r$s1hr|z~w~HS|4~rj9?+`zQ z9ufZxJt}?{Jtp2w?-Y;IyTpg+3GpI5D}DjJBz`HqEIvvf75_55B7PNpO#JKgaq(}_ zC&a%;pA?^-(+{c9_SF?k{%J?jvf`?kscG@o!%)PqIZe!Lr;h= zpl8JopqIoyNiT~ZP9GINnqCnY zeMbC3dR_bydP95_y(xYLy(NA%-OJ9-|JTt2;@_bM#c!myiQhyIiQhtR7ymImEPf}w zL;N0kM0^cBD*hlnCjM)Br+AItCH^=)A^sFSEB-9KB>p_TEWVaLD*g(+BK|skOuR)O z7k`&NA->5TemyfOz6E_sd>eXIe0%z|_|Ej2`0n%>@esW(KA+wY-)LJx=^Ne_x2OK%g8(nI2>(A&j7Ll29eN$(IpmmU%Crbos5=`ry^dZ&1n-X&h7 zC&X9Mv*H)iOX6Rkm&I4nN5#KFuZUkw9}^#=kBfhcJ|X^H`lR>|=u_f9qF2TLn?5c6 zQ+iGOZu*RPm0lNrfZh;)nBElsA9_pt_jE5eJO4jP4~YLSJt+QXdYgEI9uj|<-Y)(( zdRYAL^bYZN=n?TbAN1?7sQBjenE2N8PVpeUOZ)@$g!pdstoUB^lK4mHW$};EN5vP? zE8>gjW8xk3aq%PQ6XM6vC&f>oPl=yQuZn+~J}v%PdQJQs`iyuNy)GW7H^i6Io8lRI zOT0k$^0V{*2t6Qv5j`k=DZNd6lpYelg5EBE6+JBeb$W;RH|Y`a8|YE-|DwmlZ>D#O zPtv=@@1Q5de@4%W-%Brv|B_x7{}p{y{84&E{CD&*@frHK_%rkg@#pB1;xEvr#9yLU z#b2XOi@!y$iT{&6Bkt|#*JE|@x%7tkR`jO$JbFufC%RXdo&R^G2gLWJ2gUcMw~4pY zL*fhQ?cxW}!{VQ$cZeTOkBA>lkBT2pkBNVZ-YFiVcZn~dC&bUDXT_J%OX7X>vUrj{ zDxRiS#Pjqq@e+Mp{6hMK_$Bm7@h{P*#J^0hihq?pEq*P%CjJfjjQBXcF8+ObL;Q#I zruc32miSNTUU7E*zl$Ca{{=lLem}iUe3~8-e}vvH{#$xj{15aF@jucd;(ww?#s5l= ziLaw~iZ|(9;&0Lu;&0Ql;_K-p@y+(~>$kG_mh@5a?dTQp9qD7@ZS-;R57H;ZKTMw# z|0sP*{1f!5`2O^1@q_6#@x$md;t_gXd@;QteiFSYej2?ceg@rJF+2aCMGuIdM-Phk z(%Zxn^pN-vyeO&zK^a=6%=#%0P(Wk_JL$8WIMxPdcf?gAUnm!|5r`N^* zLT`w_NN+$--X^Gz6U)b z{vmo)d>?vD{Nwaa@i4th{2+Ql{7`yU{3v=!{5X19{6zYw_^I@Y`04a9@lN`<_)_|W zcn^J2e1JYBo}yR9&!GU-`CdH<8S^`wrokhw&s?9 zYs;1tYpZVgVOzE&SUc&K@3UpQ^tIz|`DeClm%O&(mVa!^cByO2Zuy6{Y?rt;`~LR* z6)d~I{a-$D)nn&HS3MWK^!aA&jFYdJdlJ@-Ua{@(u#4ywM|g-NI!IS%XpY;Pg1Omx*ljo-Ype*LP&t%nxBVY;qk^^!N- zPjhPXe(H@beibMFDps5Ko~`!I>LtxpwKerk=G5j?SKYUI@jG*Bs}?seUHrzJ)r;Ra zY;h}BUA?&ZesYFzyhi^+i~r^h*RaDab%%Qg_{MhLLyKGPpvSCU(!xO-Q6BU)9P~A; z+>e9yuUh=pygQfRv-piwYkv3Ks@kgi@cnOF*6_>U`Y#=NW0Ol4w{ZB@VT<3%{nUQq z@p0_vs$$*k7$=Fi9>tX+Zmtd@Y_0Y_cHgSnQg`!DM^0|Hcd+j%|NHLtz03a|vhQd3-xu2VsQ>+7`+m56U%j{%UG*S#ZDd)? zUw`%7ORfodtE$m8_024?vbOH3#f^s+*KM7(KSE$vF&4dIrw2^1qZuSxbhWp7Nj=*8 z+vuvtqHF%NS#!xM7_E_?$5d{@MTMUS-s?WNr*WQ z&%5(8o6WoPx2sRVPrr(;dNjJ`uSla)kl$Wgz5j`;P$RFwy?6xGmVYm%|6%9kTB4)RJo>XI zuKL5#OO8fcH~+{JTvN8d;?s{__3nwQ-a7eX)(QloYu??ou~!ReblJ;=(Ed+vXn#&# z_4diD-a2m8t4FWj>5tJ%@1GMrmQe!rbM_Qzhq zoLRjb&l}F<`j(}V`NFb+czR*4XLX+a?YCd(^w@Eo3yx2w;>TvPBe~>2qHspMR5&zr zK=^?DL&s-|>AvnlGLsG+7hjR=jpsiRIx*e5Fm!k#o=RmR{qO(Y=l{I0H#2nPzxI1F zHc98>3r_5drwhscWIT6h=!DqG3l=R5FUaH;q`C|798O{@Z|`KfH&yJ5hYrsd`jY9w z!o-nVd4-W|yf5A#$`^9Q-a_aCFBB@`w?zjmD})B)BiZi0WqrwkWFdbTf7$&+% z7l(Rq&GPrJ-~F@qx_i3QeVH`kWGY!0L7a*s$P^0}uCVWUB&kK2T#rSCTz9WqF6R2M zT+CygUfi&}MM+D4`-1!BV*lqvGH$!V&j>Qbd?DG3FXtDNIn!LmZEWjX4zMVbvoPoH zwNUI%dEI^8S*+2AJ@oY@?F{<*{NMYQV~1EAN?KSHlm!J zzQu97vRp1{877yr^s{5<3h{oI?{WpyF1Cy!Fz9vX?URjLe#qy$-ObOVRN9hTFP|?C zVMqBwVhHC^NT2{*36bjwF*ct`KPM}ao7EmwP7e9leCUBXt*k}2wIN&mwy9>pF zOZH*`_pVqd4&j!si051uT9N7P?gOvLSk@Zu9>flZkq8#zVu$1TjGfMKe-Vi_JcysL zS}B?Ldb)c?5cHzDL(*3&)IlgS`T<3EeixQ#uy zGx)?)wo=aJZNyl{B1$R(6a<8WNTVKHD{f&=9EY_KM~vfwuw}fr+X^mXJKdgmydMEd zjeQ?Lap{RCaLE=Wk#;?C2IF0d)Jfd#vMawCy5kt7nQ=z#!|f7 zezyvwC*}5)%4D#U6zUq>e8lboQ^=P+DU>$^dF(x7Hv}Q}kU{zE$skkrWQKYWpztCn zVt<(ocAc>@-Ghq6E+&(+vWm#^YmZfDJ(+@KGE}5i2g6XX*a>On-BAh+KG|CC0jBS}-(QUg*BS#_1@&MUn!EKi3^q)leMC|t#(lBKj+?OaL|cX=OvI6!5XPM&GvT|t+=P|R-UKom z?kZyUljQ?^A4;PcLn~v=D58wp7C8)+NN=LpYwZf+wC%WGS!>1wiO{x49#h>A3vnJhb^#gRu>^e1&`V08XUx^su5ZXfQk~i+EzndgaDPLtubT?l^Jr0 zkr~QbV~SndUA4FmZH&eJNi>a!(e*%8fG=r(|LHvXQ+9}SA%{)|;uYw=+Wt`kAuvK? zY-?m~$2rR}R!bwWQ$oG(4&W{c^^sZ8T_xHv%Ve3Nwc&_zmRhJ1-Q~Fi&x~ZyQubPf zWucXSMEyA5TsKY@RhI)RAUW5&Ml_7W=ek#7$H=_4Qry~3L~+|k9Jkl1G%IMiq$Lw7 zFx-b6vIkNrm$C0wcOrCWiAoFi4PEl2U01GXebG`Dz;v`q8vI# zwsx@xYoR+(wA3hK&&8}?x%U=xNn9uZsbl4?$P!k}S=q#nT+u?_K>gWUv@~!nQy(hk zKJ>~^wh(0z*quOVm0%yTFiLcv)fauP;5$Ty>qCC-vy$8wM{|n};#O@VLO;QlQ2MQ# zjxV^?79l^o7&p_cZb^wN?u)y%`fZehg?@i66q~-d>#+94t>hp?zsYttWK9bqOD)va zmV$0*gsgzr)^vS3MArL3l*!{(Ax42gXuSYrJ?n(^#q+pDNKSmQe2XYKfD4PG@j;Na ziU~1tsBMDU%8pd9jEA8bdNW8WH)ONOvQ%FZU2NnI#8@+F6$MTp*^Rr0e!cyUISk;e&x0s~zMp+@86J^siXoJB^=I?PrC%GszX1oIAUf$lrY#H$*{%-X$_oAF7-_ zR0|el(I-MYWYsoCR_-ol&~VyTX;c_}85h`n$rLRU_gVkB&y_8N11P14?CQ`lu#$mz z7=e{2f5g*=`Vz-PhZ_e(#>0Kcq54DMc4R4z@__({L>-L)6=h%1@)a__7h%IGsVSK5ktW zSNP*N151Lq4Z5(&z=vLs#F)>{AQd0LIK*O?yofPs@?ix! z@3v~vcA7#eq5yTHp+ICkHbkhhOykxJ#)mSl;f)VvQ^=o)GB(&jjLXK*#L^!TGOHB> zd|ZzaamH#ybYJaakjF6WiDP(gIUt@Muu1@tmBDx#C+2jy?LTdUbwn97{)lifF0!m) z?K>(XWEVRDjI#U%+@yHgl@t7yMQ%hj5I^7g7zlA!tq+8colVaDhAPr(D74*{4!I&m z#VDcOS*(B&5cY=gk2@peV@o3(&N@!<0$TXIhoXq`ZzpWcFiIr)TnJOhIq{N9hZ1Tx zOO=uv(}TuP#7l8kMUjGz`pw(0LiW!j4f*Mk7n z{RmUmK#;N_N$t{)p(SO1R z>4(rp%ZQRTnC*9C&3+8@(0pMr-tC&2ewiwu+odj zYB_W)Y<0V!q;=E#Q5U+^-EX#Ba6R_^WXbDKVW5e?k_clcY>Zhm3vh{u>^f4eR&hnEKUKsS4x!rv5+Z|os~;65(i*j7zjdSfGj>HN6m}17ScU*QbHxjx z^+yrezyuNYkD9}3FT|+U5V~P=Ke`HTU#=JDCJ6Bxt^;+bOC?mI*d~W!WK}f2*co9M zWl3e#p#5lPgzl{UY~wkEXtNPoceNjV4Uly^`iodBrqOQpqnqopn|0FrG5SXW57;=p zfCyQ403-F%h()e*KVauDfL<>8#a3$|a$_LGD2BF(j;%$mo*TgU1s_`*c?yB$xB>Jh zYypEhOi;N@g*b`yL}W+D)gegKAeBK^03muu2$2W~-PX9512&u&gLL+aRA=e?m;02*+2EA-s2Yp-%adtVIy%|99#F|BScF3yODF(gf=wcvU zaHj`GhP(s@sRe}S++fhvk6;KbibXEFp-$|>LKfX_jJGiGx5y-iOoniU zBLdWJ=y6~jBxJ(MdjfT>-IzqC2XjgZlu-0NFiDBSW{?38B&}D9*venR1}q88ZkXUc zB{E27%x_`;Hl2YBb4?*~lRuDl*(!mK91e?d0|M(?B`~Z?SUyb@(et#>T2@511I!*^ zBw(>kN+QC^Vh+KrU?Wg0nB;9L+DnX}PVe)qCzwQU!owZvw!o(KNALw(q5Elr9J_LS z&{c4;tH?0liIYfTD%eU;68Fsd%ZRQ1Kn}JR4v}R=L~iC1anTwFjI0tC*wX=vEnN`# z-EY*d@e&r%Lv=ew2LV@xWwdp;0!;l|CPjqe?BWdS+$8!2cDiZYHDo4K$p!24CezEU zcZ|sDkYw6sd=Xhs79p~&+Y`FrShOi}TPJVBEkyo?HY~Iy*JvU}`((Ste5P%K2H$cY zzGM)%oQTL;DMYTNPom26FqduVjUI8D_Jc!{GW`r}|pp|I^Sp;YtQG_iM585QaAaVyjw(mh}_7Du9yNwuC!ywWbA53jv zbGu{&=sX}API`lBG-8A4B&xkZq%(GvMgd5nzQG3;Xe81n63z>O`EgZVIxiD5bVkw08C!1epdAE-qtfiMdj%tKB>e z0&ALGqk=BGZHh4rek=~Sem7=Ytap?urtNav@IO^7SxHLasUmu~Lzu_0hHwZcg4zHF zM3_b;iV>L!`V4MtHq^ZwcYDb0@DM6@9LQ=eeC#gU@YzZQVoVPrbbW5b)-fOIwhrU}>#y@3Ur7f0kDI%l&SSju6rYpY_cjKEILr3s3>+X$C!H3AlG7a04LEV4W`gr@>S z=$cnUeGVC5A zE+WXG*Xs|H5aK2ybSt3=8$t$hXO02A?H5lxkalQy?21wNTt^W7Xj~SmV7E`?6P$;Y zNCf`5V_c3aNn$F^wnCfkwsx(GO-$Iqtk5DTxZ7ZtpDdxNKKeEHao5 zz$Pf`_*gB8GLW>n>#=!DFKJJ-WI$p#;Durchxzq9CJc1H_x9Zuyv+0aw z?R3UQbQsVhPg|U^yN_FHWd)I)y)~qGj_AhGh}{B8-+-ap9TL!1#>o_sNOt;u`Axei zN1J5L;6V-glp_dSyNE+4QD#tkU~10A?lLkx?!IJtR=DXqJoG^41C1q$giXd+oshw( z-NS6HeQXi;3Rjfrw+6t59hpINd#oRX9uN{HlN!N1dasA;!&z9j*PihpOCjH6Fpzf( zxWDKS0Wi(ljSyMee$KisL?-L*4)T~)S$IBfJHjJStAhPmC4?BDA){kBV`pl^4_gNl zS~hOWk!6!;ku&)!|{0*h)k z4cd1+Rk8^AGi#Mv*41VR6ZX|zA!3`cMuclfBev3%we~IBJ>tqPo*~;w;Qrz2+yi9< z=;qi0S|y~4B|ARoDdRX8G2;$q(Z1QW#NDhnPO#syJz~3sh^*1G2RT{m&{~LMo=v#f zlWbxHk3NxjSqzDw$zFH0=&o5V%O)`si*Ud`aodaaE)m$3TH9w2Tx<$9n?&~*(=-LU zI_qd4T)7fS=%*>V33hmU25D*OdR7Q=0m%H81SvN)mbEqw3q>3cZJ6De3_4y2uraz& z7NUn?q5Wj7G$K^32(T}k`Ojw1ZFQ^QiMXAxP2loNK54}lV*5c)7?;Z?Hfy=Y(i2nb zb~SFuo<+^x~E^??p>`ak$?MLgAB1EHSzqxC` zOgq{Yx9IK+CMc~@#jj}8(EG+&;-YP&X1NH{TSd30j6E~PBF1^{XICv?8CA5~EYokl z;&!`T+ep$*5*`gI=OAE}H+F^=#1H@l+A(}`lmD%FTm6p;YI8$^kY}(G&MvSL;Ll)z`g&bnk z!FF%Z@Zi2%^JBqE1a?Un@mkG+yMSjpX^YLUBFY}_Fv4U8Ax_Q>i2a*{8XR>Kj+;eb zLl=bB4fg9IjFxde=;GO)+#y_{wuj7ifMI-AqO!!`20aCY*fsK}9XxJ5VTA5UFs9RO zXn`nhH6~)q{)kYoS>&FKAh+0kLuPS}5MmqrAhI%_!}|hmw-~1565|6d)8^vtp5nEH z?h?>18;EWAj>t~Q_0bUd9T+1aD0Js8(3!8DhBbHig4 z6^vLATFP2$gU~wMIlLiYhp>Tg4pmgnx;vOWv5&pRk}F#GA&(Ql$J!P|ZuFh+#wa3h z88weK#(u`DPic$%uwY;9IC<;uAh60Db-t~M*Lu*oL!80PD`Lx12wg8UZw-gdZQJZ6 zzFF&l0QVB1>n`UpjIpHzGK@u5L+0(ZDBBArrty#`k1uF%?VjNa3NIdOVPX!UjWz8V z7iQ8CVI~95iR@!9Gua~}+rsWVM&DKkBeJ|~V{x}L%z(Q(B5!>%1cL|$TpNe(p4CZ+ za5k2MQJPVO+L#v+ZiLmR{yCxp9>*D?t7Elk9u=a$Z#Tfg3r!dS=dHf=@(DK zLN|$n*b)PCNEX=9Y{~&WA*7|v9wTyVTb~Bsv9AQmGtRL4*61XR5Y%JHJb;Yi%*3Bm|SVd@$dEB!?%+p#SMPzGOy@k*n zAA<&K#PZm+?GE!TF0{R&TqATHdbDgstHtsdAmpv>$Pc`!AssV)l3nTbqX^-KKb!d7ool}l zy7?!>=ry9%M914+owE@rV#_<|db#hmFAO0pPobmaLaT7GV3&vvkp;-~h|u66wC=U5 zH7#qSe_|`RlS9V?U+u*&gf{hw$mJF^vKWWCY>Vd6-gmNLnR`B<*@4#=k4`mFF%4uvbY5pW!bwF`4K#;MCfjb ze~0Y_Oe75MEI!CVm}{`aLo|p0z3zfd`s4oE;}txdGr;Bu@iI#WQ7P%+W+UMc4k1A9 zwZR@fHjqGsr(hP@cbt2{(y?G;-2#SP*qhDJqho}$LWu1WahoQwu96e`YL|r&yFqFLkH~)s(Pd)<_N)?- ztBYNxMu2+3rZDkA-x#4)y~yg8jF=;__g4{P@5m--jdA7ZE+ApiJF+C@h}=1# zDk)%!7sUg$8bZ5hd$eS`wkL5eLWO~abl!3`zTnsxli_gIAH|-ndhk0}R=Dgd$~6j@ z9o4;hV#8zGJ04-VJs`tj!FH3uxXvQ?CWXDeZ>!lgqtjwPpoed1gcpQdXqRqx*j^7R zpg>t8i=MhwH+aO@ZGjDi(ZjO|CD+kI;BE`1xb21yBRAofVXGDqV)J2_D#J)M{4)Xz z+%U5^fa7D&=+5GK7xrz(K!n7z*k+6n+Hef9Rjvp#2;3{`h-{vshzAHZ8bMFf^{Elt ztJ#PO7GPW4B21p6p-CflbF7%ZLP;v(MOEuE7BT;Ci&;0DS+czm#G9^HBD$9go#5!^YBWW${m-RO`NEGnY9UV#S&afH^6 zA+-145h3aDPQHEYx%3LWOP)jMzlw#|Hf?L`Yp=i?#g;V47AtT<=^xE+%1Rj24 z<7(F2MR@e(dp1t^u@9srO_wqNMv>;V*0DC_W zyS9Pe3Use=m|+Gu?_s>6fB^NK)wdSdbjYxsFER>VMXGgY%4Z*z?fq)xZ}-d#@2KP8Nc>^< z^a`PUwf-+c+mqFl2<+6XD~SM22TsE3I|O!odzvt8uaF|Z7D!8cYziBZ{en6b0WR8q z?1ji(h7Ge&nrs-0$bGk+`R^zUXE1j(GmE~bqks-7cbPf23P1%iD%Qk}YiW42l6zzi(MTotu#ETu>2=VyUO|7j& z`{S~g|BqVSzvIZ_5n(s_H2BvEs7p~D;~yE=!%qL*fB!9ioCRLq$2->c#D}lS7x4Ce z5|94z4!XT6juAPIW$$+*Yw}%e_xiMZDH``5V;+0o*WS~$;^)6O>%Xdss)jFz;wEA& zQ?mCP?R7|d(Q*VyhY1C|5QaBe?9D`b4-s#UZ+Pv_-eW@^!+mnEpxH}jXeRu3$*ec+ z-W7ArE%FpzG;(i#**F&OE#ZwG8=c@Cq9Fvx)Obh7-mby$$JJ=4`SA)xascMPy@KoL z$IKbt6v6GmSORZ?;5m-H!GZTGtQEjp7_&%hcJyaIsN6Ny#Gab_kMVIw-TbWoOy07!|8V_Z57RL(jHlYD%KfL{ zn0U3P(RfnoKZ!>E!7#-h72~NCGAJ76Q0{@#5T1|tPl=GQ z81lHMI(U-dp4Z@U3!Y4%T}j)U3w##w{$m8|{rk@XtXIUTeRNzn&puM(jJi!`AX#kw z7!|0^Cu8mwXT|waRJoiKb+etQ4zkv##+)5yTk-NPCeJXOaMNgs8>sm_zo+20{?@Sj z%`a+Hzg_fOHe@rjXV%)F=fXzI+9UgSMk_K%d$u1|o%;=jYa?8{fD(mjAFHq`x9S^{ zkE~EpAE08e0L9*FKh$_gjS+h(V`X#h|3SGUmw7~scj;TA-2Dr{K%WL@-yC?QgF`h+iVf2%-JGnz6U-n zoXf|#jz#}|eb4&{ezW!4vA&(Fw_Wh~?b=S7xAkzK>>ah+Vf!xn$cK$>`{VGbU_JZ) z7;N~nZO_H$DqQPt43FL}_{B|*-FEX$9>N*<`~DpGNTk8DvwnZ-{olU{e;2=JXZ=3- z{_pp||G)O`JY1`Be;D{vyV0!-VLm7({lKS1xvpy?(Z@GT&^ z6Pg@q)8_Xv8ixIA!v2?X?=QGCY7k2EB6dV6Rl0oXnDw3g%>%zc-_4X4b?) zIhob(DcmBn<{d>^WY!&9v~^~~A(?d>W!7wzSv@B+E3^ykb25u1N`|g~597=Ts4rmkc!AYFLI}Mbk^{QMN~a9IeE2|IPa% z+O81quW>?pt&;8douQ)b@%A5=Z~vYH2M4A?GyL)!=0Hm?#R^4+dBoC7dJ?y=7SC0< zR6L%`ue|MJ855>pN-v|&jLt9q9ebsC{GODWzAd$si%6{89IeFhgcFOeYvq5V{qY=w z@$oC`AGZrrW~Hw$Gm1%fsFtEiplOv{_&o7 zzgKf3zu;aLNx$SJ5@lJ9`N#X;wu{w_?oa-9gLg!c5xk9e@E%U#Og_r_T*T-3FRtb~ zZs2Ba{s`6KtSz*kZJinA2Uu`;W&25a+t=CB3Zup_TzPxj+b zj^r3l;1o{hL!8G2{0EnE1z+V`e1{wP5x4RSe#7tiGZSA&`6|jx9>elHfz?@)wRs*J zvnAW{a&}>F_Tvza;22Ke6wcryoW})R#22`NuX8Q`!w>i|zu-6gk-zW&i+&U3?P!)^ zIac8*JcG4ZpN-g*t=NHAvMYOY0EclTZ{;1lm-llP=kN(G<}W+n40 zuq7{HCw5~m_UB;Uz)`%Ncky0Mvmv=d)bO zRb0(=e2<&>DZl1!{>nl>_?+XhJf78fI&1P=p3fXMXDfDKCw66TUdQ3QnPYhuCv!R< z=3G9>g?x_7xQefHE#KpZ+`{ermbY8!MvU~^L9?)WKQRUoWm#iG@s=QT*24* zHrMk5ZslkEir@1m{>CCdMS0C+Syo|nX0sOSvk_ae9j{=LeK>%_IFh4y2k+%HKFGOz zivQqJuHb5}<$K)3ZQQ|~+`|Jb^0ViTrCFB8@kE}+nmmUWurV*@rR>aZyp{twoHug} zC-6Sb;vCNBBEHB~e1q%xJ~wk4zvM3d!~-nyOO&Uhc`T3PiLAzK)?t0-usK_^J+ELF z_TaS~%;CI=V>zCaIgPV8hx7RiU*t-@!S&q054nY3@Eh*ouPm@H%3EO`$ug|KELP=d zJd5Y@d^TbWwq*x)Vv@btj{|uFZ{ld)!FzZgXYgUp<9t5DC0xdrxrXcbF5l;7e!?&K zHGkkw+|Po)MtLsIl025j^CX_mvssT9vN12_CG5zbn>_MpmSF`}VO7>(E!JZL zHepL%!pnITyR$E^<1mioZ5+qDIEm9ZlaKOAKF!7aCs*(_uH|}egspffJFyFUupfu;2HwIkyp#8EDrfRBKEbE?EMMeu zuHx%l$M^UVKjjYY8!=`n8S z5A!k3=Rz*wKe>vl`4<1f5BM=Zp2*X9 zChM{RoA6?`{9{R$V`ZMi>a4+Y*nrL0n(cW7uVPR3=Mdh&n|T}W!||NNX`IPN_yiYn377L_zR7p^0k`lA?&Mw`V4-4B{*Gd4R^SP&#?x7owOOBy z*n(}?o}HOwPxj*=UeB93h7&lM4{$c;@+mIj5-#IPuHnD=J~wk4zv3?b#QiK(Tpn4H ziTCcnm8si&c3V&t`o#W-DI8E7+BNIgrCSisLwu)A$hQaRC=|DOd1y zuH{B<=I8vHyZI|Kj`TUl(yYi6S)FIG9viVa+wwAYVGs7@b-bQ8a}3AxKF;8y{2LeW z89vXKxSH#@kz4pVzv52r;eHl6%5%g_9>a>P!jpL#YqAc{V-8!e4cqeyCfSSEa3F_s zByZ!LoW$vz&Byt7KF4Kzg>P~_|I01h&hPjm_cP<@D1XIRg5_C-)mVeISeF;F8C$a> zuVPR3<1pUD+c}Zb_#o%jVe#}p~gWvH-?qeb|%2Qz;!BQ;C<9QNK zWj1TGJ{z$G+p#0BVmJ2Y01o8{-pX;jhxhS*&f;u7&INpi&+{d|!ZlpS4cx@7+|F;f zn?EyA!t=*WmSrVYVO5^SnykwPY|2*bz^mDt{W*jqIGT5G0`KDtKFoPsz{On7Rb0(= z+`tdHjbCynf963JEg9vl1k3U`p2$;qCeP&s%wY?*9Ih_yjF+RzKT*75s#npV9>$#De`5C|DcihciSfF&2*P<-RvaHOL zSe@Cd#ky?3#=MB_cp0x^PhQJGypf}LJ16iyKET$GbV1)A=Chay}RFc`oOxe2edJBR6pyxAPnB;$Hs7jIvRFi?bBV zu?kP(8LY*6Y{-^u!;ZX~-PxD@IfNs4EAQlF-p>a)mrrpKmvAXp@HMXGd;E}}atFWT z9`0kJT$H!MJd&kYj>oeqPve<9hYi?-E!mcr^J?~BANJ=k-o(+ollO8eXK@an5&tnc-upKXF7xv}=4&jX)#oKuo zCvhrg@DV=2r@4g7`3m3QzqyegaVxj;TkhdLCMraEE5;Hm%gQ{Nr?MvN@&YztE4JsA z?7@B<%e; zDo_!+z;&vO}9@-@E6fAc+lz>oPU zcko;Oz@NCE1&)vIOA#K)l023bS%oL_RA#dl>+%BTusK`t5?;nD*_FL`EeCQKM{pF! zay%z;3LoG@oWs9y0T*!z|H&16m2Yqz|HJ=sGq-U&zv1`X%U_wO9Nm|~Jc1>73@flQ zPhxe};MqKv=d%%;@nW`PM|NhCJ$VhU<51qnTR4Vy@*dvD>3oon@^L=JXZReK@+H2) zHC)Sg`9445C;Wn6a~Jn;9}lun6+cIq$uca@<9Q-a;Tb%O=kPo>WK&+mw(P)8?7|-G z%K;q18+bEs;~l)4lX*X9@e$7Bd@kf-zQ}*^Wxme0xt<%jiCg(Ozv52*$X|GX8ClVN zDaNB&n&o&LPhd5k&YG;l`n-@$*phA7o>%Z{c4r^<=U`sXn>d=|IDwNmjWao$bNM8j zH*Q=%t9r-oVOsIwS?6Zg$*x(W*6{S!S)DMLWkz7$~8vTdHwbMue{di9hCZMu;Eo{GUv> zFPUg)eydVpJGHC|Uj@Sb?V2zCVTd1YoK&;J#s4gCssCN7K%#Wwn3Liw4FSvH#)G&V7_hRk$d=l*&q)GP>Po01Mybb)5amI#t z)*pvYObPK)1?dhYMA@7;7k!Y1n&kOspAbJWPbAuS zJAJ)>{5dr?v`<}E*-xT&hdwTQ3>lWLHJ05Y)bdCb+f3CtOAZ^5?2#(7J~WX`_8gcD z)iFZRkz~(M_hx9aTdF9?z*N1xVZC~0pL#^wL?XeLAB~7Q{xN`{kxAC)+@b!D3VMzyR=d3rpcylnk189m^`P@Gm&i4 zsZFESEgR?E6V-}KCY!hEm~7g@2rZginn*Tp)i$S5t7O||&DuBZknGSXr&ZI`sQs_$ z-Xqy#=UYj*2&A;UfQI6A{mOf4-0iDh7Ad2(DF7)7u4;YH;>)23ZZZ^D>7RF3 zs;Yf5RN79a%Atl^p1O(g)ueNfOjZ5J+b4a?h7C-H>La0KbgFkK0-An+!bv5g%!O0y zF1v_j!A^e<40H|oAD-Ng zRv0MU#rPpg-QM_nD9_DJCVSl2E%gk9s#YU=5-k<3I&M!CbD~uxGszrIc!L@CoX%H zZe}AH_Jv|&-BKN_4GNWKveQ}34y)OHLM_JZbosmN)c1C16pG7*2QIr;U*FArdxk;c zt*EPqC*31n4@U^~j(dc2N_P*pB9R^LQM%^oVLsIUFG7_v%*U5{_%TH?8$LM=I`Gm#P^1|YUAV2uo4@e zziD)%$#8Rx*(R(X8NTBFFItIh=YorbHmOxVp2APWXt^v9eqFZ55%?Hg}zm7v%x2hM-~!ikY#CDkSFf9O3=!s7Xc^XD(V z{@eA>Fl#CeMY zZ-kZb_L=@3O2y*$?$I@(j``ci+p!x$pAxzH$M5Ik{}20r68ff|z0~(`YKh Date: Tue, 7 Feb 2023 16:28:20 +0100 Subject: [PATCH 044/156] =?UTF-8?q?PASS1-483:=20Use=20=C2=A9=20for=20copyr?= =?UTF-8?q?ight=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-Pierre De Jesus DIAZ --- CHANGELOG.md | 2 +- DEVELOPMENT.md | 2 +- Dockerfile | 2 +- Justfile | 2 +- README.md | 2 +- SECURITY/SECURITY.md | 2 +- extmod/foundation/bip39_utils.c | 2 +- extmod/foundation/bip39_utils.h | 2 +- extmod/foundation/bip39_word_info.c | 2 +- extmod/foundation/bytewords_word_info.c | 2 +- extmod/foundation/image_conversion.c | 2 +- extmod/foundation/image_conversion.h | 2 +- extmod/foundation/modfoundation-bip39.h | 2 +- extmod/foundation/modfoundation-qr.h | 2 +- extmod/foundation/modfoundation.c | 2 +- extmod/foundation/modtcc-codecs.c | 2 +- ports/stm32/Justfile | 4 ++-- ports/stm32/boards/Passport/adc.c | 2 +- ports/stm32/boards/Passport/adc.h | 2 +- ports/stm32/boards/Passport/board_init.c | 2 +- ports/stm32/boards/Passport/board_init.h | 2 +- ports/stm32/boards/Passport/bootloader/Justfile | 2 +- ports/stm32/boards/Passport/bootloader/Makefile | 2 +- ports/stm32/boards/Passport/bootloader/constants.mk | 2 +- ports/stm32/boards/Passport/bootloader/factory-test.c | 2 +- ports/stm32/boards/Passport/bootloader/factory-test.h | 2 +- ports/stm32/boards/Passport/bootloader/flash.c | 2 +- ports/stm32/boards/Passport/bootloader/flash.h | 2 +- .../boards/Passport/bootloader/images/color/BACKGROUND.c | 2 +- .../boards/Passport/bootloader/images/color/ICON_ABOUT.c | 2 +- .../stm32/boards/Passport/bootloader/images/color/ICON_BACK.c | 2 +- .../boards/Passport/bootloader/images/color/ICON_CANCEL.c | 2 +- .../boards/Passport/bootloader/images/color/ICON_CHECKMARK.c | 2 +- .../boards/Passport/bootloader/images/color/ICON_EMAIL.c | 2 +- .../stm32/boards/Passport/bootloader/images/color/ICON_EXIT.c | 2 +- .../boards/Passport/bootloader/images/color/ICON_FORWARD.c | 2 +- .../boards/Passport/bootloader/images/color/ICON_PAGE_DOT.c | 2 +- .../Passport/bootloader/images/color/ICON_PAGE_DOT_SELECTED.c | 2 +- .../boards/Passport/bootloader/images/color/ICON_RETRY.c | 2 +- .../boards/Passport/bootloader/images/color/ICON_SHUTDOWN.c | 2 +- .../Passport/bootloader/images/color/LARGE_ICON_ERROR.c | 2 +- .../boards/Passport/bootloader/images/color/LARGE_ICON_INFO.c | 2 +- .../Passport/bootloader/images/color/LARGE_ICON_MICROSD.c | 2 +- .../Passport/bootloader/images/color/LARGE_ICON_QUESTION.c | 2 +- .../boards/Passport/bootloader/images/color/PROGRESS_BAR_BG.c | 2 +- .../boards/Passport/bootloader/images/color/PROGRESS_BAR_FG.c | 2 +- .../Passport/bootloader/images/color/PROGRESS_CAP_LEFT.c | 2 +- .../Passport/bootloader/images/color/PROGRESS_CAP_RIGHT.c | 2 +- .../Passport/bootloader/images/color/PROGRESS_CAP_RIGHT_BG.c | 2 +- ports/stm32/boards/Passport/bootloader/images/color/SPLASH.c | 2 +- .../boards/Passport/bootloader/images/copyright_template.c | 2 +- ports/stm32/boards/Passport/bootloader/images/images.h | 2 +- ports/stm32/boards/Passport/bootloader/images/lvgl.h | 2 +- ports/stm32/boards/Passport/bootloader/link-script.ld | 2 +- ports/stm32/boards/Passport/bootloader/main.c | 2 +- ports/stm32/boards/Passport/bootloader/printf.c | 2 +- ports/stm32/boards/Passport/bootloader/printf.h | 2 +- ports/stm32/boards/Passport/bootloader/se-atecc608a.c | 2 +- ports/stm32/boards/Passport/bootloader/se-atecc608a.h | 2 +- ports/stm32/boards/Passport/bootloader/startup.s | 2 +- ports/stm32/boards/Passport/bootloader/version_info.h | 2 +- ports/stm32/boards/Passport/camera-ovm7690.c | 2 +- ports/stm32/boards/Passport/camera-ovm7690.h | 2 +- ports/stm32/boards/Passport/common/backlight.c | 2 +- ports/stm32/boards/Passport/common/delay.c | 2 +- ports/stm32/boards/Passport/common/eeprom.c | 2 +- ports/stm32/boards/Passport/common/gpio.c | 2 +- ports/stm32/boards/Passport/common/hash.c | 2 +- ports/stm32/boards/Passport/common/i2c-init.c | 2 +- ports/stm32/boards/Passport/common/keypad-adp-5587.c | 2 +- ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c | 2 +- ports/stm32/boards/Passport/common/lcd-st7789.c | 2 +- ports/stm32/boards/Passport/common/pprng.c | 2 +- ports/stm32/boards/Passport/common/ring_buffer.c | 2 +- ports/stm32/boards/Passport/common/se.c | 2 +- ports/stm32/boards/Passport/common/spiflash.c | 2 +- ports/stm32/boards/Passport/common/utils.c | 2 +- ports/stm32/boards/Passport/contrib/openocd.cfg | 2 +- ports/stm32/boards/Passport/debug-utils.c | 2 +- ports/stm32/boards/Passport/debug-utils.h | 2 +- ports/stm32/boards/Passport/dispatch.c | 2 +- ports/stm32/boards/Passport/dispatch.h | 2 +- ports/stm32/boards/Passport/framebuffer.c | 2 +- ports/stm32/boards/Passport/framebuffer.h | 2 +- ports/stm32/boards/Passport/frequency.c | 2 +- ports/stm32/boards/Passport/frequency.h | 2 +- ports/stm32/boards/Passport/images/color/ICON_ADD_ACCOUNT.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_ADVANCED.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_BACK.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_BACKUP.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_BATTERY.c | 2 +- .../boards/Passport/images/color/ICON_BATTERY_CHARGING.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_BITCOIN.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_BRIGHTNESS.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_CANCEL.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_CASA.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_CHECKMARK.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_CIRCLE_CHECK.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_CLOCK.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_CONNECT.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_COUNTDOWN.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_DEVICE.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_EDIT1.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_EDIT2.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_ERASE.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_EXTENSIONS.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_FILE.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_FIRMWARE.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_FOLDER.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_FORWARD.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_HAMBURGER.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_HEALTH_CHECK.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_HOME.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_INFO.c | 2 +- .../Passport/images/color/ICON_INPUT_MODE_LOWER_ALPHA.c | 2 +- .../boards/Passport/images/color/ICON_INPUT_MODE_NUMERIC.c | 2 +- .../Passport/images/color/ICON_INPUT_MODE_PUNCTUATION.c | 2 +- .../Passport/images/color/ICON_INPUT_MODE_UPPER_ALPHA.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_MICROSD.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_MULTISIG.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_NETWORK.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_ONE_KEY.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PAGE_DOT.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PAGE_HOME.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PAGE_PLUS.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_LG.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_MD.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_SM.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PASSPHRASE.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PIN.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_PLUS.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_RETRY.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_SCAN_QR.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_SEED.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_SETTINGS.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_SETUP.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_SHIELD.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_SHUTDOWN.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_SIGN.c | 2 +- .../stm32/boards/Passport/images/color/ICON_SMALL_CHECKMARK.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_SPIRAL.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_TWO_KEYS.c | 2 +- .../stm32/boards/Passport/images/color/ICON_VERIFY_ADDRESS.c | 2 +- ports/stm32/boards/Passport/images/color/ICON_WARNING.c | 2 +- ports/stm32/boards/Passport/images/color/IMAGE_CARD_BOTTOM.c | 2 +- .../stm32/boards/Passport/images/color/IMAGE_DIAGONAL_LINES.c | 2 +- ports/stm32/boards/Passport/images/color/IMAGE_REGULATORY.c | 2 +- .../stm32/boards/Passport/images/color/IMAGE_SCREEN_OVERLAY.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_BACKUP.c | 2 +- .../stm32/boards/Passport/images/color/LARGE_ICON_BRANDMARK.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_CLOCK.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_CONNECT.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_ERROR.c | 2 +- .../stm32/boards/Passport/images/color/LARGE_ICON_FIRMWARE.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_INFO.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_MICROSD.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_PIN.c | 2 +- .../stm32/boards/Passport/images/color/LARGE_ICON_QUESTION.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_SEED.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP.c | 2 +- .../stm32/boards/Passport/images/color/LARGE_ICON_SETUP_QR.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_SHIELD.c | 2 +- .../Passport/images/color/LARGE_ICON_STATIC_PIN_SPINNER.c | 2 +- ports/stm32/boards/Passport/images/color/LARGE_ICON_SUCCESS.c | 2 +- ports/stm32/boards/Passport/images/copyright_template.c | 2 +- ports/stm32/boards/Passport/images/images.h | 2 +- ports/stm32/boards/Passport/images/mono/ICON_ADD_ACCOUNT.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_ADVANCED.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_BACK.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_BACKUP.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_BATTERY.c | 2 +- .../stm32/boards/Passport/images/mono/ICON_BATTERY_CHARGING.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_BITCOIN.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_BRIGHTNESS.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_CANCEL.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_CASA.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_CHECKMARK.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_CIRCLE_CHECK.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_CLOCK.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_CONNECT.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_COUNTDOWN.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_DEVICE.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_EDIT1.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_EDIT2.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_ERASE.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_EXTENSIONS.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_FILE.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_FIRMWARE.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_FOLDER.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_FORWARD.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_HAMBURGER.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_HEALTH_CHECK.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_HOME.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_INFO.c | 2 +- .../boards/Passport/images/mono/ICON_INPUT_MODE_LOWER_ALPHA.c | 2 +- .../boards/Passport/images/mono/ICON_INPUT_MODE_NUMERIC.c | 2 +- .../boards/Passport/images/mono/ICON_INPUT_MODE_PUNCTUATION.c | 2 +- .../boards/Passport/images/mono/ICON_INPUT_MODE_UPPER_ALPHA.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_MICROSD.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_MULTISIG.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_NETWORK.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_ONE_KEY.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PAGE_DOT.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PAGE_HOME.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PAGE_INDICATOR.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PAGE_PLUS.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_LG.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_MD.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_SM.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PASSPHRASE.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PIN.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_PLUS.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_RETRY.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_SCAN_QR.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_SEED.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_SETTINGS.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_SETUP.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_SHIELD.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_SHUTDOWN.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_SIGN.c | 2 +- .../stm32/boards/Passport/images/mono/ICON_SMALL_CHECKMARK.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_SPIRAL.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_TWO_KEYS.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_VERIFY_ADDRESS.c | 2 +- ports/stm32/boards/Passport/images/mono/ICON_WARNING.c | 2 +- ports/stm32/boards/Passport/images/mono/IMAGE_CARD_BOTTOM.c | 2 +- .../stm32/boards/Passport/images/mono/IMAGE_DIAGONAL_LINES.c | 2 +- ports/stm32/boards/Passport/images/mono/IMAGE_REGULATORY.c | 2 +- .../stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY.c | 2 +- .../boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_0.c | 2 +- .../boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_1.c | 2 +- .../boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_2.c | 2 +- .../boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_3.c | 2 +- .../boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_4.c | 2 +- .../boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_5.c | 2 +- .../boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_6.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_BACKUP.c | 2 +- .../stm32/boards/Passport/images/mono/LARGE_ICON_BRANDMARK.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_CLOCK.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_CONNECT.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_ERROR.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_FIRMWARE.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_INFO.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_MICROSD.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_PIN.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_QUESTION.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_SEED.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP_QR.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_SHIELD.c | 2 +- .../Passport/images/mono/LARGE_ICON_STATIC_PIN_SPINNER.c | 2 +- ports/stm32/boards/Passport/images/mono/LARGE_ICON_SUCCESS.c | 2 +- ports/stm32/boards/Passport/include/backlight.h | 2 +- ports/stm32/boards/Passport/include/bq27520.h | 2 +- ports/stm32/boards/Passport/include/delay.h | 2 +- ports/stm32/boards/Passport/include/display.h | 2 +- ports/stm32/boards/Passport/include/eeprom.h | 2 +- ports/stm32/boards/Passport/include/firmware-keys.h | 2 +- ports/stm32/boards/Passport/include/fwheader.h | 2 +- ports/stm32/boards/Passport/include/gpio.h | 2 +- ports/stm32/boards/Passport/include/hash.h | 2 +- ports/stm32/boards/Passport/include/i2c-init.h | 2 +- ports/stm32/boards/Passport/include/keypad-adp-5587.h | 2 +- ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h | 2 +- ports/stm32/boards/Passport/include/lcd-st7789.h | 2 +- ports/stm32/boards/Passport/include/pprng.h | 2 +- ports/stm32/boards/Passport/include/ring_buffer.h | 2 +- ports/stm32/boards/Passport/include/se.h | 2 +- ports/stm32/boards/Passport/include/secresult.h | 2 +- ports/stm32/boards/Passport/include/secrets.h | 2 +- ports/stm32/boards/Passport/include/spiflash.h | 2 +- ports/stm32/boards/Passport/include/utils.h | 2 +- ports/stm32/boards/Passport/manifest.py | 2 +- ports/stm32/boards/Passport/modpassport-backlight.h | 2 +- ports/stm32/boards/Passport/modpassport-boardrev.h | 2 +- ports/stm32/boards/Passport/modpassport-camera.h | 2 +- ports/stm32/boards/Passport/modpassport-fuelgauge.h | 2 +- ports/stm32/boards/Passport/modpassport-noise.h | 2 +- ports/stm32/boards/Passport/modpassport-powermon.h | 2 +- ports/stm32/boards/Passport/modpassport-settingsflash.h | 2 +- ports/stm32/boards/Passport/modpassport-sram4.h | 2 +- ports/stm32/boards/Passport/modpassport-system.h | 2 +- ports/stm32/boards/Passport/modpassport.c | 2 +- ports/stm32/boards/Passport/modpassport_lv-keypad.h | 2 +- ports/stm32/boards/Passport/modpassport_lv-lcd.h | 2 +- ports/stm32/boards/Passport/modpassport_lv.c | 2 +- ports/stm32/boards/Passport/modules/Enum.py | 2 +- ports/stm32/boards/Passport/modules/animations/__init__.py | 2 +- ports/stm32/boards/Passport/modules/animations/card_anim.py | 2 +- ports/stm32/boards/Passport/modules/animations/constants.py | 2 +- ports/stm32/boards/Passport/modules/animations/page_anim.py | 2 +- ports/stm32/boards/Passport/modules/animations/prop_cb.py | 2 +- ports/stm32/boards/Passport/modules/callgate.py | 2 +- ports/stm32/boards/Passport/modules/chains.py | 2 +- ports/stm32/boards/Passport/modules/common.py | 2 +- ports/stm32/boards/Passport/modules/constants.py | 2 +- ports/stm32/boards/Passport/modules/data_codecs/__init__.py | 2 +- .../boards/Passport/modules/data_codecs/address_sampler.py | 2 +- .../stm32/boards/Passport/modules/data_codecs/data_decoder.py | 2 +- .../stm32/boards/Passport/modules/data_codecs/data_encoder.py | 2 +- .../stm32/boards/Passport/modules/data_codecs/data_format.py | 2 +- .../stm32/boards/Passport/modules/data_codecs/data_sampler.py | 2 +- .../stm32/boards/Passport/modules/data_codecs/http_sampler.py | 2 +- .../Passport/modules/data_codecs/multisig_config_sampler.py | 2 +- .../boards/Passport/modules/data_codecs/psbt_txn_sampler.py | 2 +- ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py | 2 +- ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py | 2 +- ports/stm32/boards/Passport/modules/data_codecs/qr_type.py | 2 +- .../stm32/boards/Passport/modules/data_codecs/seed_sampler.py | 2 +- ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py | 2 +- ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py | 2 +- ports/stm32/boards/Passport/modules/descriptor.py | 2 +- ports/stm32/boards/Passport/modules/display.py | 2 +- ports/stm32/boards/Passport/modules/errors.py | 2 +- ports/stm32/boards/Passport/modules/export.py | 2 +- ports/stm32/boards/Passport/modules/ext_settings.py | 2 +- ports/stm32/boards/Passport/modules/flows/__init__.py | 2 +- ports/stm32/boards/Passport/modules/flows/about_flow.py | 2 +- .../boards/Passport/modules/flows/apply_passphrase_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/auto_backup_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/backup_flow.py | 2 +- .../Passport/modules/flows/casa_health_check_common_flow.py | 2 +- .../Passport/modules/flows/casa_health_check_microsd_flow.py | 2 +- .../Passport/modules/flows/casa_health_check_qr_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/change_pin_flow.py | 2 +- .../boards/Passport/modules/flows/connect_wallet_flow.py | 2 +- .../boards/Passport/modules/flows/delete_account_flow.py | 2 +- .../boards/Passport/modules/flows/delete_multisig_flow.py | 2 +- .../boards/Passport/modules/flows/developer_functions_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/envoy_setup_flow.py | 2 +- .../boards/Passport/modules/flows/erase_passport_flow.py | 2 +- .../Passport/modules/flows/export_multisig_microsd_flow.py | 2 +- .../boards/Passport/modules/flows/export_multisig_qr_flow.py | 2 +- .../boards/Passport/modules/flows/export_summary_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/file_picker_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/flow.py | 2 +- .../boards/Passport/modules/flows/format_microsd_flow.py | 2 +- .../Passport/modules/flows/import_multisig_wallet_flow.py | 2 +- .../modules/flows/import_multisig_wallet_from_microsd_flow.py | 2 +- .../modules/flows/import_multisig_wallet_from_qr_flow.py | 2 +- .../boards/Passport/modules/flows/initial_seed_setup_flow.py | 2 +- .../boards/Passport/modules/flows/install_dev_pubkey_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/list_files_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/login_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/magic_scan_flow.py | 2 +- .../Passport/modules/flows/magic_scan_import_multisig_flow.py | 2 +- .../Passport/modules/flows/magic_scan_import_seed_flow.py | 2 +- .../Passport/modules/flows/magic_scan_sign_psbt_flow.py | 2 +- .../modules/flows/magic_scan_validate_address_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/main_flow.py | 2 +- .../stm32/boards/Passport/modules/flows/manual_setup_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/menu_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/new_account_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/new_seed_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/page_flow.py | 2 +- .../boards/Passport/modules/flows/remove_dev_pubkey_flow.py | 2 +- .../boards/Passport/modules/flows/rename_account_flow.py | 2 +- .../boards/Passport/modules/flows/rename_multisig_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py | 2 +- .../boards/Passport/modules/flows/restore_backup_flow.py | 2 +- .../stm32/boards/Passport/modules/flows/restore_seed_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/scv_flow.py | 2 +- .../boards/Passport/modules/flows/select_setup_mode_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/set_chain_flow.py | 2 +- .../boards/Passport/modules/flows/set_initial_pin_flow.py | 2 +- .../modules/flows/show_security_words_setting_flow.py | 2 +- .../boards/Passport/modules/flows/sign_psbt_common_flow.py | 2 +- .../boards/Passport/modules/flows/sign_psbt_microsd_flow.py | 2 +- .../stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py | 2 +- .../boards/Passport/modules/flows/sign_text_file_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/spin_delay_flow.py | 2 +- .../boards/Passport/modules/flows/system_test_camera_flow.py | 2 +- ports/stm32/boards/Passport/modules/flows/system_test_flow.py | 2 +- .../boards/Passport/modules/flows/system_test_microsd_flow.py | 2 +- .../stm32/boards/Passport/modules/flows/terms_of_use_flow.py | 2 +- .../boards/Passport/modules/flows/update_firmware_flow.py | 2 +- .../boards/Passport/modules/flows/verify_address_flow.py | 2 +- .../stm32/boards/Passport/modules/flows/verify_backup_flow.py | 2 +- .../boards/Passport/modules/flows/view_backup_code_flow.py | 2 +- .../Passport/modules/flows/view_current_firmware_flow.py | 2 +- .../boards/Passport/modules/flows/view_dev_pubkey_flow.py | 2 +- .../Passport/modules/flows/view_multisig_details_flow.py | 2 +- .../boards/Passport/modules/flows/view_seed_words_flow.py | 2 +- ports/stm32/boards/Passport/modules/history.py | 2 +- ports/stm32/boards/Passport/modules/keypad.py | 2 +- ports/stm32/boards/Passport/modules/keypad_manager.py | 2 +- ports/stm32/boards/Passport/modules/keys.py | 2 +- ports/stm32/boards/Passport/modules/main.py | 2 +- ports/stm32/boards/Passport/modules/menus.py | 2 +- ports/stm32/boards/Passport/modules/microns/__init__.py | 2 +- ports/stm32/boards/Passport/modules/multisig_wallet.py | 2 +- ports/stm32/boards/Passport/modules/opcodes.py | 2 +- ports/stm32/boards/Passport/modules/pages/__init__.py | 2 +- .../Passport/modules/pages/accept_terms_chooser_page.py | 2 +- .../boards/Passport/modules/pages/account_details_page.py | 2 +- .../Passport/modules/pages/address_type_chooser_page.py | 2 +- .../Passport/modules/pages/auto_shutdown_setting_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/backup_code_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/battery_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/brandmark_page.py | 2 +- .../boards/Passport/modules/pages/brightness_setting_page.py | 2 +- .../stm32/boards/Passport/modules/pages/chain_setting_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/chooser_page.py | 2 +- .../stm32/boards/Passport/modules/pages/color_picker_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/error_page.py | 2 +- .../boards/Passport/modules/pages/export_mode_chooser_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/file_picker_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/info_page.py | 2 +- .../boards/Passport/modules/pages/insert_microsd_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/long_text_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/menu_page.py | 2 +- .../Passport/modules/pages/multisig_policy_setting_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/page.py | 2 +- ports/stm32/boards/Passport/modules/pages/pin_entry_page.py | 2 +- .../Passport/modules/pages/predictive_text_input_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/progress_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/question_page.py | 2 +- .../Passport/modules/pages/recovery_mode_chooser_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/scan_qr_page.py | 2 +- .../boards/Passport/modules/pages/seed_length_chooser_page.py | 2 +- .../boards/Passport/modules/pages/seed_words_list_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/setting_page.py | 2 +- .../boards/Passport/modules/pages/setup_mode_chooser_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/shield_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/show_qr_page.py | 2 +- .../modules/pages/show_security_words_setting_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/shutdown_page.py | 2 +- .../boards/Passport/modules/pages/sig_type_chooser_page.py | 2 +- .../Passport/modules/pages/singlesig_multisig_chooser_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/spinner_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/status_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/success_page.py | 2 +- .../boards/Passport/modules/pages/sw_wallet_chooser_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/test_keypad_page.py | 2 +- ports/stm32/boards/Passport/modules/pages/text_input_page.py | 2 +- .../stm32/boards/Passport/modules/pages/units_setting_page.py | 2 +- .../boards/Passport/modules/pages/yes_no_chooser_page.py | 2 +- ports/stm32/boards/Passport/modules/pincodes.py | 2 +- ports/stm32/boards/Passport/modules/predictive_utils.py | 2 +- ports/stm32/boards/Passport/modules/psbt.py | 2 +- ports/stm32/boards/Passport/modules/public_constants.py | 2 +- ports/stm32/boards/Passport/modules/schema_evolution.py | 2 +- ports/stm32/boards/Passport/modules/screens/__init__.py | 2 +- ports/stm32/boards/Passport/modules/screens/main_screen.py | 2 +- ports/stm32/boards/Passport/modules/se_commands.py | 2 +- ports/stm32/boards/Passport/modules/settings.py | 2 +- ports/stm32/boards/Passport/modules/sffile.py | 2 +- ports/stm32/boards/Passport/modules/sflash.py | 2 +- ports/stm32/boards/Passport/modules/stash.py | 2 +- ports/stm32/boards/Passport/modules/styles/__init__.py | 2 +- ports/stm32/boards/Passport/modules/styles/colors.py | 2 +- ports/stm32/boards/Passport/modules/styles/font_sizes.py | 2 +- ports/stm32/boards/Passport/modules/styles/local_style.py | 2 +- ports/stm32/boards/Passport/modules/styles/style.py | 2 +- ports/stm32/boards/Passport/modules/system_test_ux.py | 2 +- ports/stm32/boards/Passport/modules/t9.py | 2 +- ports/stm32/boards/Passport/modules/tasks/__init__.py | 2 +- .../boards/Passport/modules/tasks/apply_passphrase_task.py | 2 +- .../stm32/boards/Passport/modules/tasks/auto_shutdown_task.py | 2 +- .../Passport/modules/tasks/calculate_file_sha256_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/card_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/change_pin_task.py | 2 +- .../boards/Passport/modules/tasks/charge_monitor_task.py | 2 +- .../modules/tasks/clear_psbt_from_external_flash_task.py | 2 +- .../Passport/modules/tasks/copy_firmware_to_spi_flash_task.py | 2 +- .../modules/tasks/copy_psbt_file_to_external_flash_task.py | 2 +- .../modules/tasks/copy_psbt_to_external_flash_task.py | 2 +- .../Passport/modules/tasks/create_wallet_export_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/delay_task.py | 2 +- .../boards/Passport/modules/tasks/delete_account_task.py | 2 +- .../boards/Passport/modules/tasks/delete_multisig_task.py | 2 +- .../Passport/modules/tasks/double_check_psbt_change_task.py | 2 +- .../boards/Passport/modules/tasks/erase_passport_task.py | 2 +- .../boards/Passport/modules/tasks/export_summary_task.py | 2 +- .../boards/Passport/modules/tasks/fcc_copy_files_task.py | 2 +- .../boards/Passport/modules/tasks/format_microsd_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/fuelgauge_task.py | 2 +- .../boards/Passport/modules/tasks/generate_addresses_task.py | 2 +- .../boards/Passport/modules/tasks/get_backup_code_task.py | 2 +- .../boards/Passport/modules/tasks/get_security_words_task.py | 2 +- .../boards/Passport/modules/tasks/get_seed_words_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/login_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/lvgl_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/main_task.py | 2 +- .../Passport/modules/tasks/make_microsd_file_system_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/new_seed_task.py | 2 +- .../stm32/boards/Passport/modules/tasks/power_button_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/read_file_task.py | 2 +- .../boards/Passport/modules/tasks/rename_account_task.py | 2 +- .../boards/Passport/modules/tasks/rename_multisig_task.py | 2 +- .../boards/Passport/modules/tasks/restore_backup_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/save_backup_task.py | 2 +- .../Passport/modules/tasks/save_multisig_wallet_task.py | 2 +- .../boards/Passport/modules/tasks/save_new_account_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/save_seed_task.py | 2 +- .../modules/tasks/save_wallet_export_to_microsd_task.py | 2 +- .../boards/Passport/modules/tasks/search_for_address_task.py | 2 +- .../boards/Passport/modules/tasks/set_initial_pin_task.py | 2 +- ports/stm32/boards/Passport/modules/tasks/sign_psbt_task.py | 2 +- .../boards/Passport/modules/tasks/sign_text_file_task.py | 2 +- .../stm32/boards/Passport/modules/tasks/validate_psbt_task.py | 2 +- .../stm32/boards/Passport/modules/tasks/verify_backup_task.py | 2 +- .../boards/Passport/modules/tasks/write_data_to_file_task.py | 2 +- ports/stm32/boards/Passport/modules/tests/conftest.py | 2 +- .../stm32/boards/Passport/modules/tests/fixtures/simulator.py | 2 +- ports/stm32/boards/Passport/modules/tests/micropython.py | 2 +- ports/stm32/boards/Passport/modules/tests/test_enum.py | 2 +- ports/stm32/boards/Passport/modules/tests/test_sflash.py | 2 +- .../stm32/boards/Passport/modules/tests/test_translations.py | 2 +- ports/stm32/boards/Passport/modules/tests/test_unit.py | 2 +- ports/stm32/boards/Passport/modules/tests/test_version.py | 2 +- .../stm32/boards/Passport/modules/tests/unit/ext_settings.py | 2 +- ports/stm32/boards/Passport/modules/tests/unit/foundation.py | 2 +- ports/stm32/boards/Passport/modules/tests/unit/ui.py | 2 +- ports/stm32/boards/Passport/modules/translations/__init__.py | 2 +- ports/stm32/boards/Passport/modules/translations/en.py | 2 +- ports/stm32/boards/Passport/modules/translations/tags.py | 2 +- ports/stm32/boards/Passport/modules/ui/__init__.py | 2 +- ports/stm32/boards/Passport/modules/ui/ui.py | 2 +- ports/stm32/boards/Passport/modules/ur1/bc32.py | 2 +- ports/stm32/boards/Passport/modules/ur1/bech32.py | 2 +- ports/stm32/boards/Passport/modules/ur1/bech32_version.py | 2 +- ports/stm32/boards/Passport/modules/ur1/decode_ur.py | 2 +- ports/stm32/boards/Passport/modules/ur1/encode_ur.py | 2 +- ports/stm32/boards/Passport/modules/ur1/mini_cbor.py | 2 +- ports/stm32/boards/Passport/modules/ur1/utils.py | 2 +- ports/stm32/boards/Passport/modules/ur2/__init__.py | 2 +- ports/stm32/boards/Passport/modules/ur2/bytewords.py | 2 +- ports/stm32/boards/Passport/modules/ur2/cbor_lite.py | 2 +- ports/stm32/boards/Passport/modules/ur2/constants.py | 2 +- ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py | 2 +- ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py | 2 +- ports/stm32/boards/Passport/modules/ur2/fountain_utils.py | 2 +- ports/stm32/boards/Passport/modules/ur2/random_sampler.py | 2 +- ports/stm32/boards/Passport/modules/ur2/ur.py | 2 +- ports/stm32/boards/Passport/modules/ur2/ur_decoder.py | 2 +- ports/stm32/boards/Passport/modules/ur2/ur_encoder.py | 2 +- ports/stm32/boards/Passport/modules/ur2/utils.py | 2 +- ports/stm32/boards/Passport/modules/ur2/xoshiro256.py | 2 +- ports/stm32/boards/Passport/modules/utils.py | 2 +- ports/stm32/boards/Passport/modules/version.py | 2 +- ports/stm32/boards/Passport/modules/views/__init__.py | 2 +- ports/stm32/boards/Passport/modules/views/arc.py | 2 +- .../boards/Passport/modules/views/backup_code_section.py | 2 +- .../stm32/boards/Passport/modules/views/battery_indicator.py | 2 +- ports/stm32/boards/Passport/modules/views/bold_label.py | 2 +- ports/stm32/boards/Passport/modules/views/button.py | 2 +- ports/stm32/boards/Passport/modules/views/camera.py | 2 +- ports/stm32/boards/Passport/modules/views/card.py | 2 +- ports/stm32/boards/Passport/modules/views/card_nav.py | 2 +- ports/stm32/boards/Passport/modules/views/color_picker.py | 2 +- ports/stm32/boards/Passport/modules/views/container.py | 2 +- ports/stm32/boards/Passport/modules/views/file_item.py | 2 +- ports/stm32/boards/Passport/modules/views/filler.py | 2 +- ports/stm32/boards/Passport/modules/views/icon.py | 2 +- ports/stm32/boards/Passport/modules/views/icon_button.py | 2 +- ports/stm32/boards/Passport/modules/views/image.py | 2 +- ports/stm32/boards/Passport/modules/views/keyboard.py | 2 +- ports/stm32/boards/Passport/modules/views/keypad.py | 2 +- ports/stm32/boards/Passport/modules/views/label.py | 2 +- ports/stm32/boards/Passport/modules/views/line.py | 2 +- ports/stm32/boards/Passport/modules/views/list_item.py | 2 +- ports/stm32/boards/Passport/modules/views/menu_item.py | 2 +- ports/stm32/boards/Passport/modules/views/micron_bar.py | 2 +- ports/stm32/boards/Passport/modules/views/pin_input.py | 2 +- ports/stm32/boards/Passport/modules/views/qrcode.py | 2 +- ports/stm32/boards/Passport/modules/views/slider.py | 2 +- ports/stm32/boards/Passport/modules/views/spinner.py | 2 +- ports/stm32/boards/Passport/modules/views/statusbar.py | 2 +- ports/stm32/boards/Passport/modules/views/switch.py | 2 +- ports/stm32/boards/Passport/modules/views/symbol_picker.py | 2 +- ports/stm32/boards/Passport/modules/views/text_area.py | 2 +- ports/stm32/boards/Passport/modules/views/text_input.py | 2 +- ports/stm32/boards/Passport/modules/views/view.py | 2 +- ports/stm32/boards/Passport/modules/wallets/__init__.py | 2 +- ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py | 2 +- ports/stm32/boards/Passport/modules/wallets/bluewallet.py | 2 +- ports/stm32/boards/Passport/modules/wallets/btcpay.py | 2 +- ports/stm32/boards/Passport/modules/wallets/caravan.py | 2 +- ports/stm32/boards/Passport/modules/wallets/casa.py | 2 +- ports/stm32/boards/Passport/modules/wallets/constants.py | 2 +- ports/stm32/boards/Passport/modules/wallets/dux_reserve.py | 2 +- ports/stm32/boards/Passport/modules/wallets/electrum.py | 2 +- ports/stm32/boards/Passport/modules/wallets/envoy.py | 2 +- ports/stm32/boards/Passport/modules/wallets/fullynoded.py | 2 +- .../boards/Passport/modules/wallets/generic_json_wallet.py | 2 +- ports/stm32/boards/Passport/modules/wallets/gordian.py | 2 +- ports/stm32/boards/Passport/modules/wallets/keeper.py | 2 +- ports/stm32/boards/Passport/modules/wallets/lily.py | 2 +- .../stm32/boards/Passport/modules/wallets/multisig_import.py | 2 +- ports/stm32/boards/Passport/modules/wallets/multisig_json.py | 2 +- ports/stm32/boards/Passport/modules/wallets/nunchuk.py | 2 +- .../boards/Passport/modules/wallets/simple_bitcoin_wallet.py | 2 +- ports/stm32/boards/Passport/modules/wallets/sparrow.py | 2 +- ports/stm32/boards/Passport/modules/wallets/specter.py | 2 +- ports/stm32/boards/Passport/modules/wallets/sw_wallets.py | 2 +- ports/stm32/boards/Passport/modules/wallets/utils.py | 2 +- ports/stm32/boards/Passport/modules/wallets/vault.py | 2 +- ports/stm32/boards/Passport/modules/wallets/wasabi.py | 2 +- ports/stm32/boards/Passport/mpconfigboard.h | 2 +- ports/stm32/boards/Passport/mpconfigboard.mk | 2 +- ports/stm32/boards/Passport/noise.c | 2 +- ports/stm32/boards/Passport/noise.h | 2 +- ports/stm32/boards/Passport/passport.ld | 2 +- ports/stm32/boards/Passport/pins.c | 2 +- ports/stm32/boards/Passport/pins.h | 2 +- ports/stm32/boards/Passport/se-atecc608a.c | 4 ++-- ports/stm32/boards/Passport/se-atecc608a.h | 2 +- ports/stm32/boards/Passport/stm32h7xx_hal_conf.h | 2 +- ports/stm32/boards/Passport/tools/add-secrets/Makefile | 2 +- ports/stm32/boards/Passport/tools/add-secrets/add-secrets.c | 2 +- ports/stm32/boards/Passport/tools/cosign/Makefile | 2 +- ports/stm32/boards/Passport/tools/cosign/cosign.c | 2 +- ports/stm32/boards/Passport/tools/provisioning/provision.py | 2 +- .../boards/Passport/tools/se_config_gen/se_config_gen.py | 2 +- ports/stm32/boards/Passport/tools/version_info/version_info | 2 +- ports/stm32/boards/Passport/tools/word_list_gen/bip39_test.c | 2 +- ports/stm32/boards/Passport/tools/word_list_gen/bip39_words.c | 2 +- .../boards/Passport/tools/word_list_gen/bytewords_words.c | 2 +- .../stm32/boards/Passport/tools/word_list_gen/word_list_gen.c | 4 ++-- ports/stm32/boards/Passport/version.c | 2 +- ports/stm32/boards/Passport/version.h | 2 +- ports/unix/modpassport_lv-keypad.h | 2 +- ports/unix/modpassport_lv-lcd.h | 2 +- ports/unix/modpassport_lv.c | 2 +- ports/unix/ring_buffer.c | 2 +- ports/unix/ring_buffer.h | 2 +- simulator/Justfile | 2 +- simulator/Makefile | 2 +- simulator/README.md | 2 +- simulator/SIMULATOR.md | 2 +- simulator/requirements.txt | 2 +- simulator/sim_boot.py | 2 +- simulator/sim_modules/ffilib.py | 2 +- simulator/sim_modules/keypad_worker.py | 2 +- simulator/sim_modules/passport/__init__.py | 2 +- simulator/sim_modules/passport/camera.py | 2 +- simulator/sim_modules/passport/sram4.py | 2 +- simulator/sim_modules/pincodes.py | 2 +- simulator/sim_modules/settings.py | 2 +- simulator/unix_random.c | 2 +- simulator/variant/simulator/mpconfigvariant.h | 2 +- simulator/variant/simulator/mpconfigvariant.mk | 2 +- 644 files changed, 647 insertions(+), 647 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 420663b72..616c4261d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 7c9166d12..735f2f1cd 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,5 +1,5 @@ diff --git a/Dockerfile b/Dockerfile index e769a425b..704fe9cc5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/Justfile b/Justfile index 30ce55700..b5ac61960 100644 --- a/Justfile +++ b/Justfile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # Justfile - Root-level justfile for Passport diff --git a/README.md b/README.md index b0d665f89..2ca52a533 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ diff --git a/SECURITY/SECURITY.md b/SECURITY/SECURITY.md index 87bf78a42..adc6d991e 100644 --- a/SECURITY/SECURITY.md +++ b/SECURITY/SECURITY.md @@ -1,5 +1,5 @@ diff --git a/extmod/foundation/bip39_utils.c b/extmod/foundation/bip39_utils.c index 0d3bb5ca0..ace2fac70 100644 --- a/extmod/foundation/bip39_utils.c +++ b/extmod/foundation/bip39_utils.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/extmod/foundation/bip39_utils.h b/extmod/foundation/bip39_utils.h index 9ede1f347..6523070a5 100644 --- a/extmod/foundation/bip39_utils.h +++ b/extmod/foundation/bip39_utils.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/extmod/foundation/bip39_word_info.c b/extmod/foundation/bip39_word_info.c index 62933622e..e81743257 100644 --- a/extmod/foundation/bip39_word_info.c +++ b/extmod/foundation/bip39_word_info.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/extmod/foundation/bytewords_word_info.c b/extmod/foundation/bytewords_word_info.c index 711d7798b..3cc99de1e 100644 --- a/extmod/foundation/bytewords_word_info.c +++ b/extmod/foundation/bytewords_word_info.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/extmod/foundation/image_conversion.c b/extmod/foundation/image_conversion.c index d8f386549..2b5381969 100644 --- a/extmod/foundation/image_conversion.c +++ b/extmod/foundation/image_conversion.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/extmod/foundation/image_conversion.h b/extmod/foundation/image_conversion.h index c86cd0738..ea8ef134f 100644 --- a/extmod/foundation/image_conversion.h +++ b/extmod/foundation/image_conversion.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/extmod/foundation/modfoundation-bip39.h b/extmod/foundation/modfoundation-bip39.h index de72a3fdf..3e69ead99 100644 --- a/extmod/foundation/modfoundation-bip39.h +++ b/extmod/foundation/modfoundation-bip39.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/extmod/foundation/modfoundation-qr.h b/extmod/foundation/modfoundation-qr.h index 570c19f73..56227f817 100644 --- a/extmod/foundation/modfoundation-qr.h +++ b/extmod/foundation/modfoundation-qr.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later #include diff --git a/extmod/foundation/modfoundation.c b/extmod/foundation/modfoundation.c index 95941f7eb..cdb1a15cc 100644 --- a/extmod/foundation/modfoundation.c +++ b/extmod/foundation/modfoundation.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // MP C foundation module, supports LCD, backlight, keypad and other devices as they are added diff --git a/extmod/foundation/modtcc-codecs.c b/extmod/foundation/modtcc-codecs.c index d68564d86..5a3f1b092 100644 --- a/extmod/foundation/modtcc-codecs.c +++ b/extmod/foundation/modtcc-codecs.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/Justfile b/ports/stm32/Justfile index b74c9936e..f2c0e30a2 100644 --- a/ports/stm32/Justfile +++ b/ports/stm32/Justfile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later @@ -183,7 +183,7 @@ convert-images image_path: f = open(image_path + '/images.h', 'w') # NOTE: We split the string up below so that REUSE doesn't think this is a direct copyright string - f.write('// SP' + 'DX-FileCopyrightText: 2022 Foundation Devices, Inc. \n') + f.write('// SP' + 'DX-FileCopyrightText: © 2022 Foundation Devices, Inc. \n') f.write('// SP' + 'DX-License-Identifier: GPL-3.0-or-later\n') f.write('//\n') f.write('// Autogenerated by ports/stm32/Justfile images command -- DO NOT EDIT MANUALLY!\n') diff --git a/ports/stm32/boards/Passport/adc.c b/ports/stm32/boards/Passport/adc.c index b97bfcd09..7f3d4ab92 100644 --- a/ports/stm32/boards/Passport/adc.c +++ b/ports/stm32/boards/Passport/adc.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Copyright 2020 - Foundation Devices Inc. diff --git a/ports/stm32/boards/Passport/adc.h b/ports/stm32/boards/Passport/adc.h index e7cb0b2cd..2f47a42c3 100644 --- a/ports/stm32/boards/Passport/adc.h +++ b/ports/stm32/boards/Passport/adc.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Copyright 2020 - Foundation Devices Inc. diff --git a/ports/stm32/boards/Passport/board_init.c b/ports/stm32/boards/Passport/board_init.c index d99233ba4..9b551abcf 100644 --- a/ports/stm32/boards/Passport/board_init.c +++ b/ports/stm32/boards/Passport/board_init.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/board_init.h b/ports/stm32/boards/Passport/board_init.h index 24d5563c2..444092a57 100644 --- a/ports/stm32/boards/Passport/board_init.h +++ b/ports/stm32/boards/Passport/board_init.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/bootloader/Justfile b/ports/stm32/boards/Passport/bootloader/Justfile index 6e947509a..9c6477aeb 100644 --- a/ports/stm32/boards/Passport/bootloader/Justfile +++ b/ports/stm32/boards/Passport/bootloader/Justfile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/bootloader/Makefile b/ports/stm32/boards/Passport/bootloader/Makefile index 9e10cf227..db9cd619d 100644 --- a/ports/stm32/boards/Passport/bootloader/Makefile +++ b/ports/stm32/boards/Passport/bootloader/Makefile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020-2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020-2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/constants.mk b/ports/stm32/boards/Passport/bootloader/constants.mk index ddd8d21a9..9f5479b9e 100644 --- a/ports/stm32/boards/Passport/bootloader/constants.mk +++ b/ports/stm32/boards/Passport/bootloader/constants.mk @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # Common bootloader file between the bootloader itself and the firmware. diff --git a/ports/stm32/boards/Passport/bootloader/factory-test.c b/ports/stm32/boards/Passport/bootloader/factory-test.c index b2cbb7c1f..9a206db08 100644 --- a/ports/stm32/boards/Passport/bootloader/factory-test.c +++ b/ports/stm32/boards/Passport/bootloader/factory-test.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // factory-test.c - Code for testing Passport boards before final provisioning and lockdown. diff --git a/ports/stm32/boards/Passport/bootloader/factory-test.h b/ports/stm32/boards/Passport/bootloader/factory-test.h index 3bd04bfc5..494811532 100644 --- a/ports/stm32/boards/Passport/bootloader/factory-test.h +++ b/ports/stm32/boards/Passport/bootloader/factory-test.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // factory-test.h - Code for testing Passport boards before final provisioning and lockdown. diff --git a/ports/stm32/boards/Passport/bootloader/flash.c b/ports/stm32/boards/Passport/bootloader/flash.c index 8e41ef79a..a53400f83 100644 --- a/ports/stm32/boards/Passport/bootloader/flash.c +++ b/ports/stm32/boards/Passport/bootloader/flash.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/flash.h b/ports/stm32/boards/Passport/bootloader/flash.h index 36ed2b808..8f516c0b6 100644 --- a/ports/stm32/boards/Passport/bootloader/flash.h +++ b/ports/stm32/boards/Passport/bootloader/flash.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/images/color/BACKGROUND.c b/ports/stm32/boards/Passport/bootloader/images/color/BACKGROUND.c index 4a2b91101..072fb5e43 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/BACKGROUND.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/BACKGROUND.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_ABOUT.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_ABOUT.c index 8040f608e..c7ef7454a 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_ABOUT.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_ABOUT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_BACK.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_BACK.c index 5c2dc55d7..3263b26e4 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_BACK.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_BACK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_CANCEL.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_CANCEL.c index 55804af78..f8b1b0901 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_CANCEL.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_CANCEL.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_CHECKMARK.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_CHECKMARK.c index 2f673b4b8..0457bbc21 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_CHECKMARK.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_CHECKMARK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_EMAIL.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_EMAIL.c index ca8034fa8..d6e6cc214 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_EMAIL.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_EMAIL.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_EXIT.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_EXIT.c index 3452919c5..f646d7e63 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_EXIT.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_EXIT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_FORWARD.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_FORWARD.c index 7e1ed101c..012ab1ee0 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_FORWARD.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_FORWARD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_PAGE_DOT.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_PAGE_DOT.c index 5c2bfc489..963f8f9ea 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_PAGE_DOT.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_PAGE_DOT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_PAGE_DOT_SELECTED.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_PAGE_DOT_SELECTED.c index 6320a5884..402f9a4e8 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_PAGE_DOT_SELECTED.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_PAGE_DOT_SELECTED.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_RETRY.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_RETRY.c index 51f855991..62f845cf5 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_RETRY.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_RETRY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/ICON_SHUTDOWN.c b/ports/stm32/boards/Passport/bootloader/images/color/ICON_SHUTDOWN.c index 1929722af..03adb0a4d 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/ICON_SHUTDOWN.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/ICON_SHUTDOWN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_ERROR.c b/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_ERROR.c index ef0727e72..a7773fa5a 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_ERROR.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_ERROR.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_INFO.c b/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_INFO.c index ec1d5b382..35329a263 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_INFO.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_INFO.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_MICROSD.c b/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_MICROSD.c index 333b3c903..cf6702ff8 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_MICROSD.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_MICROSD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_QUESTION.c b/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_QUESTION.c index d8c7111e6..3377f08b0 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_QUESTION.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/LARGE_ICON_QUESTION.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_BAR_BG.c b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_BAR_BG.c index 4ab703d61..6d42032d1 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_BAR_BG.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_BAR_BG.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_BAR_FG.c b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_BAR_FG.c index 060e2036e..8e73b2b57 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_BAR_FG.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_BAR_FG.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_LEFT.c b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_LEFT.c index e3cb1a201..12f2c87e4 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_LEFT.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_LEFT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_RIGHT.c b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_RIGHT.c index b52749125..8a29ed9f5 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_RIGHT.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_RIGHT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_RIGHT_BG.c b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_RIGHT_BG.c index fc12e1211..a2e00c5b5 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_RIGHT_BG.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/PROGRESS_CAP_RIGHT_BG.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/color/SPLASH.c b/ports/stm32/boards/Passport/bootloader/images/color/SPLASH.c index 9c3782add..ebb5831aa 100644 --- a/ports/stm32/boards/Passport/bootloader/images/color/SPLASH.c +++ b/ports/stm32/boards/Passport/bootloader/images/color/SPLASH.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #ifdef LV_LVGL_H_INCLUDE_SIMPLE diff --git a/ports/stm32/boards/Passport/bootloader/images/copyright_template.c b/ports/stm32/boards/Passport/bootloader/images/copyright_template.c index 11dc66ca0..c93c65f77 100644 --- a/ports/stm32/boards/Passport/bootloader/images/copyright_template.c +++ b/ports/stm32/boards/Passport/bootloader/images/copyright_template.c @@ -1,3 +1,3 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/bootloader/images/images.h b/ports/stm32/boards/Passport/bootloader/images/images.h index 76bec870e..1b3d24cab 100644 --- a/ports/stm32/boards/Passport/bootloader/images/images.h +++ b/ports/stm32/boards/Passport/bootloader/images/images.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Autogenerated by ports/stm32/Justfile images command -- DO NOT EDIT MANUALLY! diff --git a/ports/stm32/boards/Passport/bootloader/images/lvgl.h b/ports/stm32/boards/Passport/bootloader/images/lvgl.h index c47352a1e..6ce233920 100644 --- a/ports/stm32/boards/Passport/bootloader/images/lvgl.h +++ b/ports/stm32/boards/Passport/bootloader/images/lvgl.h @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2021 Lvgl Kft // SPDX-License-Identifier: MIT // -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // Stub file to use LVGL images on the bootloader. diff --git a/ports/stm32/boards/Passport/bootloader/link-script.ld b/ports/stm32/boards/Passport/bootloader/link-script.ld index d6c9cb2aa..7b2349b94 100644 --- a/ports/stm32/boards/Passport/bootloader/link-script.ld +++ b/ports/stm32/boards/Passport/bootloader/link-script.ld @@ -1,5 +1,5 @@ /* - SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. + SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. SPDX-License-Identifier: GPL-3.0-or-later SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/main.c b/ports/stm32/boards/Passport/bootloader/main.c index 52ea384f2..09180be0c 100644 --- a/ports/stm32/boards/Passport/bootloader/main.c +++ b/ports/stm32/boards/Passport/bootloader/main.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/printf.c b/ports/stm32/boards/Passport/bootloader/printf.c index 18b6d2da0..103df3267 100644 --- a/ports/stm32/boards/Passport/bootloader/printf.c +++ b/ports/stm32/boards/Passport/bootloader/printf.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/printf.h b/ports/stm32/boards/Passport/bootloader/printf.h index a3216f4ba..282139373 100644 --- a/ports/stm32/boards/Passport/bootloader/printf.h +++ b/ports/stm32/boards/Passport/bootloader/printf.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/se-atecc608a.c b/ports/stm32/boards/Passport/bootloader/se-atecc608a.c index 5a39662af..fd7097144 100644 --- a/ports/stm32/boards/Passport/bootloader/se-atecc608a.c +++ b/ports/stm32/boards/Passport/bootloader/se-atecc608a.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/se-atecc608a.h b/ports/stm32/boards/Passport/bootloader/se-atecc608a.h index c1a820f14..5266c5080 100644 --- a/ports/stm32/boards/Passport/bootloader/se-atecc608a.h +++ b/ports/stm32/boards/Passport/bootloader/se-atecc608a.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/startup.s b/ports/stm32/boards/Passport/bootloader/startup.s index 2810d4138..73822e003 100644 --- a/ports/stm32/boards/Passport/bootloader/startup.s +++ b/ports/stm32/boards/Passport/bootloader/startup.s @@ -1,5 +1,5 @@ /* - SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. + SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. SPDX-License-Identifier: GPL-3.0-or-later SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/bootloader/version_info.h b/ports/stm32/boards/Passport/bootloader/version_info.h index 1a6914246..7d36b9f6f 100644 --- a/ports/stm32/boards/Passport/bootloader/version_info.h +++ b/ports/stm32/boards/Passport/bootloader/version_info.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/camera-ovm7690.c b/ports/stm32/boards/Passport/camera-ovm7690.c index 9ac34ad49..7ac1d054c 100644 --- a/ports/stm32/boards/Passport/camera-ovm7690.c +++ b/ports/stm32/boards/Passport/camera-ovm7690.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // // SPDX-License-Identifier: BSD-3-Clause diff --git a/ports/stm32/boards/Passport/camera-ovm7690.h b/ports/stm32/boards/Passport/camera-ovm7690.h index d3a2e5ab5..e2a8fac60 100644 --- a/ports/stm32/boards/Passport/camera-ovm7690.h +++ b/ports/stm32/boards/Passport/camera-ovm7690.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: BSD-3-Clause // diff --git a/ports/stm32/boards/Passport/common/backlight.c b/ports/stm32/boards/Passport/common/backlight.c index c9cee6a77..85e7dd4a5 100644 --- a/ports/stm32/boards/Passport/common/backlight.c +++ b/ports/stm32/boards/Passport/common/backlight.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Backlight driver for LED diff --git a/ports/stm32/boards/Passport/common/delay.c b/ports/stm32/boards/Passport/common/delay.c index b0d3b013f..e57ce4a98 100644 --- a/ports/stm32/boards/Passport/common/delay.c +++ b/ports/stm32/boards/Passport/common/delay.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/common/eeprom.c b/ports/stm32/boards/Passport/common/eeprom.c index 59e1a7125..05a348a5b 100644 --- a/ports/stm32/boards/Passport/common/eeprom.c +++ b/ports/stm32/boards/Passport/common/eeprom.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // EEPROM driver and accessor functions for Passport Gen 1.2 diff --git a/ports/stm32/boards/Passport/common/gpio.c b/ports/stm32/boards/Passport/common/gpio.c index b6ec07eb6..596cc51dc 100644 --- a/ports/stm32/boards/Passport/common/gpio.c +++ b/ports/stm32/boards/Passport/common/gpio.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/common/hash.c b/ports/stm32/boards/Passport/common/hash.c index ae6415bd4..09b50498f 100644 --- a/ports/stm32/boards/Passport/common/hash.c +++ b/ports/stm32/boards/Passport/common/hash.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/common/i2c-init.c b/ports/stm32/boards/Passport/common/i2c-init.c index 81ab8b08c..e5b4d1b1a 100644 --- a/ports/stm32/boards/Passport/common/i2c-init.c +++ b/ports/stm32/boards/Passport/common/i2c-init.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/common/keypad-adp-5587.c b/ports/stm32/boards/Passport/common/keypad-adp-5587.c index dcaece892..51ae9d18c 100644 --- a/ports/stm32/boards/Passport/common/keypad-adp-5587.c +++ b/ports/stm32/boards/Passport/common/keypad-adp-5587.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c b/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c index ce1caadca..5f7899a8f 100644 --- a/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c +++ b/ports/stm32/boards/Passport/common/lcd-sharp-ls018b7dh02.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Screen driver for Sharp LS018B7DH02 monochrome display diff --git a/ports/stm32/boards/Passport/common/lcd-st7789.c b/ports/stm32/boards/Passport/common/lcd-st7789.c index 53c862a41..d36676377 100644 --- a/ports/stm32/boards/Passport/common/lcd-st7789.c +++ b/ports/stm32/boards/Passport/common/lcd-st7789.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Driver for ST7789 display with 240x320 RGB565 display diff --git a/ports/stm32/boards/Passport/common/pprng.c b/ports/stm32/boards/Passport/common/pprng.c index e73e5940f..d8578e542 100644 --- a/ports/stm32/boards/Passport/common/pprng.c +++ b/ports/stm32/boards/Passport/common/pprng.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/common/ring_buffer.c b/ports/stm32/boards/Passport/common/ring_buffer.c index 6d43c0157..4d3060636 100644 --- a/ports/stm32/boards/Passport/common/ring_buffer.c +++ b/ports/stm32/boards/Passport/common/ring_buffer.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #include diff --git a/ports/stm32/boards/Passport/common/se.c b/ports/stm32/boards/Passport/common/se.c index ba33c56fb..3db1de3a8 100644 --- a/ports/stm32/boards/Passport/common/se.c +++ b/ports/stm32/boards/Passport/common/se.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/common/spiflash.c b/ports/stm32/boards/Passport/common/spiflash.c index 13684b210..5bc9c4358 100644 --- a/ports/stm32/boards/Passport/common/spiflash.c +++ b/ports/stm32/boards/Passport/common/spiflash.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/common/utils.c b/ports/stm32/boards/Passport/common/utils.c index 0e7144e04..fb11e132c 100644 --- a/ports/stm32/boards/Passport/common/utils.c +++ b/ports/stm32/boards/Passport/common/utils.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/contrib/openocd.cfg b/ports/stm32/boards/Passport/contrib/openocd.cfg index af65cf81b..7684e0b17 100644 --- a/ports/stm32/boards/Passport/contrib/openocd.cfg +++ b/ports/stm32/boards/Passport/contrib/openocd.cfg @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/debug-utils.c b/ports/stm32/boards/Passport/debug-utils.c index 76f5917ef..c8716271b 100644 --- a/ports/stm32/boards/Passport/debug-utils.c +++ b/ports/stm32/boards/Passport/debug-utils.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Utility functions diff --git a/ports/stm32/boards/Passport/debug-utils.h b/ports/stm32/boards/Passport/debug-utils.h index 5ee117232..6b32fa4aa 100644 --- a/ports/stm32/boards/Passport/debug-utils.h +++ b/ports/stm32/boards/Passport/debug-utils.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Utility functions diff --git a/ports/stm32/boards/Passport/dispatch.c b/ports/stm32/boards/Passport/dispatch.c index c63903caa..182647610 100644 --- a/ports/stm32/boards/Passport/dispatch.c +++ b/ports/stm32/boards/Passport/dispatch.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/dispatch.h b/ports/stm32/boards/Passport/dispatch.h index d18603a0b..9e471b619 100644 --- a/ports/stm32/boards/Passport/dispatch.h +++ b/ports/stm32/boards/Passport/dispatch.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/framebuffer.c b/ports/stm32/boards/Passport/framebuffer.c index fabf8bfd9..cb2b935f5 100644 --- a/ports/stm32/boards/Passport/framebuffer.c +++ b/ports/stm32/boards/Passport/framebuffer.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/framebuffer.h b/ports/stm32/boards/Passport/framebuffer.h index 78da2c824..7519b296f 100644 --- a/ports/stm32/boards/Passport/framebuffer.h +++ b/ports/stm32/boards/Passport/framebuffer.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/frequency.c b/ports/stm32/boards/Passport/frequency.c index 86d47bb9d..b0839d451 100644 --- a/ports/stm32/boards/Passport/frequency.c +++ b/ports/stm32/boards/Passport/frequency.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/frequency.h b/ports/stm32/boards/Passport/frequency.h index 0decfd203..8940e450e 100644 --- a/ports/stm32/boards/Passport/frequency.h +++ b/ports/stm32/boards/Passport/frequency.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_ADD_ACCOUNT.c b/ports/stm32/boards/Passport/images/color/ICON_ADD_ACCOUNT.c index 9742b65df..e94a751cb 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_ADD_ACCOUNT.c +++ b/ports/stm32/boards/Passport/images/color/ICON_ADD_ACCOUNT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_ADVANCED.c b/ports/stm32/boards/Passport/images/color/ICON_ADVANCED.c index 89d6a9d58..839106ccf 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_ADVANCED.c +++ b/ports/stm32/boards/Passport/images/color/ICON_ADVANCED.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_BACK.c b/ports/stm32/boards/Passport/images/color/ICON_BACK.c index f5640b4b7..3e1fdfc3b 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_BACK.c +++ b/ports/stm32/boards/Passport/images/color/ICON_BACK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_BACKUP.c b/ports/stm32/boards/Passport/images/color/ICON_BACKUP.c index 8e8e8d677..0774299df 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_BACKUP.c +++ b/ports/stm32/boards/Passport/images/color/ICON_BACKUP.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_BATTERY.c b/ports/stm32/boards/Passport/images/color/ICON_BATTERY.c index 4b65b02ad..922dca2d2 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_BATTERY.c +++ b/ports/stm32/boards/Passport/images/color/ICON_BATTERY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_BATTERY_CHARGING.c b/ports/stm32/boards/Passport/images/color/ICON_BATTERY_CHARGING.c index bb7560a0a..029100794 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_BATTERY_CHARGING.c +++ b/ports/stm32/boards/Passport/images/color/ICON_BATTERY_CHARGING.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_BITCOIN.c b/ports/stm32/boards/Passport/images/color/ICON_BITCOIN.c index 465c6b0d9..c1bc0ddd8 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_BITCOIN.c +++ b/ports/stm32/boards/Passport/images/color/ICON_BITCOIN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_BRIGHTNESS.c b/ports/stm32/boards/Passport/images/color/ICON_BRIGHTNESS.c index fb5c9cb9e..00dcadf75 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_BRIGHTNESS.c +++ b/ports/stm32/boards/Passport/images/color/ICON_BRIGHTNESS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_CANCEL.c b/ports/stm32/boards/Passport/images/color/ICON_CANCEL.c index 6c1b3c71a..2d068f3c1 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_CANCEL.c +++ b/ports/stm32/boards/Passport/images/color/ICON_CANCEL.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_CASA.c b/ports/stm32/boards/Passport/images/color/ICON_CASA.c index 71b026990..c7c46dcd3 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_CASA.c +++ b/ports/stm32/boards/Passport/images/color/ICON_CASA.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_CHECKMARK.c b/ports/stm32/boards/Passport/images/color/ICON_CHECKMARK.c index 8a9340f44..0191622d6 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_CHECKMARK.c +++ b/ports/stm32/boards/Passport/images/color/ICON_CHECKMARK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_CIRCLE_CHECK.c b/ports/stm32/boards/Passport/images/color/ICON_CIRCLE_CHECK.c index 3a79cbf1e..67c4b1835 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_CIRCLE_CHECK.c +++ b/ports/stm32/boards/Passport/images/color/ICON_CIRCLE_CHECK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_CLOCK.c b/ports/stm32/boards/Passport/images/color/ICON_CLOCK.c index f483c65a9..4a24fb525 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_CLOCK.c +++ b/ports/stm32/boards/Passport/images/color/ICON_CLOCK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_CONNECT.c b/ports/stm32/boards/Passport/images/color/ICON_CONNECT.c index 74476d44f..b6f90856e 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_CONNECT.c +++ b/ports/stm32/boards/Passport/images/color/ICON_CONNECT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_COUNTDOWN.c b/ports/stm32/boards/Passport/images/color/ICON_COUNTDOWN.c index 0d813f6f5..3650ee882 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_COUNTDOWN.c +++ b/ports/stm32/boards/Passport/images/color/ICON_COUNTDOWN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_DEVICE.c b/ports/stm32/boards/Passport/images/color/ICON_DEVICE.c index c444db8de..bd4a2f3b5 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_DEVICE.c +++ b/ports/stm32/boards/Passport/images/color/ICON_DEVICE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_EDIT1.c b/ports/stm32/boards/Passport/images/color/ICON_EDIT1.c index c52f15bfd..992a8c485 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_EDIT1.c +++ b/ports/stm32/boards/Passport/images/color/ICON_EDIT1.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_EDIT2.c b/ports/stm32/boards/Passport/images/color/ICON_EDIT2.c index fc4b53233..94bf05b8e 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_EDIT2.c +++ b/ports/stm32/boards/Passport/images/color/ICON_EDIT2.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_ERASE.c b/ports/stm32/boards/Passport/images/color/ICON_ERASE.c index cdda32549..de5e008cd 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_ERASE.c +++ b/ports/stm32/boards/Passport/images/color/ICON_ERASE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_EXTENSIONS.c b/ports/stm32/boards/Passport/images/color/ICON_EXTENSIONS.c index c7564fa79..3cdf4bbc6 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_EXTENSIONS.c +++ b/ports/stm32/boards/Passport/images/color/ICON_EXTENSIONS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_FILE.c b/ports/stm32/boards/Passport/images/color/ICON_FILE.c index 293b6245b..4edf4cc85 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_FILE.c +++ b/ports/stm32/boards/Passport/images/color/ICON_FILE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_FIRMWARE.c b/ports/stm32/boards/Passport/images/color/ICON_FIRMWARE.c index 678d3ea68..2b5da11f9 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_FIRMWARE.c +++ b/ports/stm32/boards/Passport/images/color/ICON_FIRMWARE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_FOLDER.c b/ports/stm32/boards/Passport/images/color/ICON_FOLDER.c index b7815bd8e..6042d258b 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_FOLDER.c +++ b/ports/stm32/boards/Passport/images/color/ICON_FOLDER.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_FORWARD.c b/ports/stm32/boards/Passport/images/color/ICON_FORWARD.c index 6611f55e9..d940b769c 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_FORWARD.c +++ b/ports/stm32/boards/Passport/images/color/ICON_FORWARD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_HAMBURGER.c b/ports/stm32/boards/Passport/images/color/ICON_HAMBURGER.c index 52a51dbb4..0604cc2a3 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_HAMBURGER.c +++ b/ports/stm32/boards/Passport/images/color/ICON_HAMBURGER.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_HEALTH_CHECK.c b/ports/stm32/boards/Passport/images/color/ICON_HEALTH_CHECK.c index 685a3c4d3..aac186bd0 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_HEALTH_CHECK.c +++ b/ports/stm32/boards/Passport/images/color/ICON_HEALTH_CHECK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_HOME.c b/ports/stm32/boards/Passport/images/color/ICON_HOME.c index 0b5028c0b..529409a84 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_HOME.c +++ b/ports/stm32/boards/Passport/images/color/ICON_HOME.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_INFO.c b/ports/stm32/boards/Passport/images/color/ICON_INFO.c index 4bdfa453e..e871b46e4 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_INFO.c +++ b/ports/stm32/boards/Passport/images/color/ICON_INFO.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_LOWER_ALPHA.c b/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_LOWER_ALPHA.c index 45d70d7fa..b5e9f2a61 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_LOWER_ALPHA.c +++ b/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_LOWER_ALPHA.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_NUMERIC.c b/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_NUMERIC.c index 789235ba8..716a82e33 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_NUMERIC.c +++ b/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_NUMERIC.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_PUNCTUATION.c b/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_PUNCTUATION.c index 28c25f0e3..3be5fab56 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_PUNCTUATION.c +++ b/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_PUNCTUATION.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_UPPER_ALPHA.c b/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_UPPER_ALPHA.c index d15078769..ef8264b09 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_UPPER_ALPHA.c +++ b/ports/stm32/boards/Passport/images/color/ICON_INPUT_MODE_UPPER_ALPHA.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_MICROSD.c b/ports/stm32/boards/Passport/images/color/ICON_MICROSD.c index 936164886..b4ab20f57 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_MICROSD.c +++ b/ports/stm32/boards/Passport/images/color/ICON_MICROSD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_MULTISIG.c b/ports/stm32/boards/Passport/images/color/ICON_MULTISIG.c index 7c0e98425..0a06ba3ec 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_MULTISIG.c +++ b/ports/stm32/boards/Passport/images/color/ICON_MULTISIG.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_NETWORK.c b/ports/stm32/boards/Passport/images/color/ICON_NETWORK.c index f5f42940f..efc62aeea 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_NETWORK.c +++ b/ports/stm32/boards/Passport/images/color/ICON_NETWORK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_ONE_KEY.c b/ports/stm32/boards/Passport/images/color/ICON_ONE_KEY.c index 732c9042e..e0f5c71c5 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_ONE_KEY.c +++ b/ports/stm32/boards/Passport/images/color/ICON_ONE_KEY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PAGE_DOT.c b/ports/stm32/boards/Passport/images/color/ICON_PAGE_DOT.c index d0ba34f45..9892be40a 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PAGE_DOT.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PAGE_DOT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PAGE_HOME.c b/ports/stm32/boards/Passport/images/color/ICON_PAGE_HOME.c index 88e55ccb9..a1ed9999e 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PAGE_HOME.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PAGE_HOME.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PAGE_PLUS.c b/ports/stm32/boards/Passport/images/color/ICON_PAGE_PLUS.c index 1c8142383..c824af5e6 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PAGE_PLUS.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PAGE_PLUS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_LG.c b/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_LG.c index 618680b9b..9182fb996 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_LG.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_LG.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_MD.c b/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_MD.c index 087f5a115..4b8c9f955 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_MD.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_MD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_SM.c b/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_SM.c index eeee54990..131538df8 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_SM.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PAGE_QR_SM.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PASSPHRASE.c b/ports/stm32/boards/Passport/images/color/ICON_PASSPHRASE.c index 50bcd7317..c9b3a4f26 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PASSPHRASE.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PASSPHRASE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PIN.c b/ports/stm32/boards/Passport/images/color/ICON_PIN.c index 971a8cb5a..6bb3f15a2 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PIN.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PIN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_PLUS.c b/ports/stm32/boards/Passport/images/color/ICON_PLUS.c index d34b7c6a1..91982e182 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_PLUS.c +++ b/ports/stm32/boards/Passport/images/color/ICON_PLUS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_RETRY.c b/ports/stm32/boards/Passport/images/color/ICON_RETRY.c index 53f773541..9ec7bf212 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_RETRY.c +++ b/ports/stm32/boards/Passport/images/color/ICON_RETRY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SCAN_QR.c b/ports/stm32/boards/Passport/images/color/ICON_SCAN_QR.c index ef7534e81..44fbad285 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SCAN_QR.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SCAN_QR.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SEED.c b/ports/stm32/boards/Passport/images/color/ICON_SEED.c index 803aab189..de3e3accf 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SEED.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SEED.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SETTINGS.c b/ports/stm32/boards/Passport/images/color/ICON_SETTINGS.c index ec8435433..8e4cf5098 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SETTINGS.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SETTINGS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SETUP.c b/ports/stm32/boards/Passport/images/color/ICON_SETUP.c index 4e01e2544..48ccf74a6 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SETUP.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SETUP.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SHIELD.c b/ports/stm32/boards/Passport/images/color/ICON_SHIELD.c index ccf6e7217..337df9054 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SHIELD.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SHIELD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SHUTDOWN.c b/ports/stm32/boards/Passport/images/color/ICON_SHUTDOWN.c index 69daaa437..3dbefc31d 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SHUTDOWN.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SHUTDOWN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SIGN.c b/ports/stm32/boards/Passport/images/color/ICON_SIGN.c index e6bfac11b..890194c68 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SIGN.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SIGN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SMALL_CHECKMARK.c b/ports/stm32/boards/Passport/images/color/ICON_SMALL_CHECKMARK.c index 46bb2e724..ce0431f0d 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SMALL_CHECKMARK.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SMALL_CHECKMARK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_SPIRAL.c b/ports/stm32/boards/Passport/images/color/ICON_SPIRAL.c index 770a1f49a..5e816850c 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_SPIRAL.c +++ b/ports/stm32/boards/Passport/images/color/ICON_SPIRAL.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_TWO_KEYS.c b/ports/stm32/boards/Passport/images/color/ICON_TWO_KEYS.c index 6990ae846..3b6bc980b 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_TWO_KEYS.c +++ b/ports/stm32/boards/Passport/images/color/ICON_TWO_KEYS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_VERIFY_ADDRESS.c b/ports/stm32/boards/Passport/images/color/ICON_VERIFY_ADDRESS.c index 667527bda..7129b402d 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_VERIFY_ADDRESS.c +++ b/ports/stm32/boards/Passport/images/color/ICON_VERIFY_ADDRESS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/ICON_WARNING.c b/ports/stm32/boards/Passport/images/color/ICON_WARNING.c index 97cba5706..ab5dceaa2 100644 --- a/ports/stm32/boards/Passport/images/color/ICON_WARNING.c +++ b/ports/stm32/boards/Passport/images/color/ICON_WARNING.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/IMAGE_CARD_BOTTOM.c b/ports/stm32/boards/Passport/images/color/IMAGE_CARD_BOTTOM.c index d866ef419..88a5e5012 100644 --- a/ports/stm32/boards/Passport/images/color/IMAGE_CARD_BOTTOM.c +++ b/ports/stm32/boards/Passport/images/color/IMAGE_CARD_BOTTOM.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/IMAGE_DIAGONAL_LINES.c b/ports/stm32/boards/Passport/images/color/IMAGE_DIAGONAL_LINES.c index 158a1c02e..15384773a 100644 --- a/ports/stm32/boards/Passport/images/color/IMAGE_DIAGONAL_LINES.c +++ b/ports/stm32/boards/Passport/images/color/IMAGE_DIAGONAL_LINES.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/IMAGE_REGULATORY.c b/ports/stm32/boards/Passport/images/color/IMAGE_REGULATORY.c index 6a76285cc..db4fbd085 100644 --- a/ports/stm32/boards/Passport/images/color/IMAGE_REGULATORY.c +++ b/ports/stm32/boards/Passport/images/color/IMAGE_REGULATORY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/IMAGE_SCREEN_OVERLAY.c b/ports/stm32/boards/Passport/images/color/IMAGE_SCREEN_OVERLAY.c index c7663d368..4a5b0cedf 100644 --- a/ports/stm32/boards/Passport/images/color/IMAGE_SCREEN_OVERLAY.c +++ b/ports/stm32/boards/Passport/images/color/IMAGE_SCREEN_OVERLAY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_BACKUP.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_BACKUP.c index 7eb96015b..7a48a4f6c 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_BACKUP.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_BACKUP.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_BRANDMARK.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_BRANDMARK.c index 61aa6941c..e5b8440cf 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_BRANDMARK.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_BRANDMARK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_CLOCK.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_CLOCK.c index 51b285444..e9838f7ec 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_CLOCK.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_CLOCK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_CONNECT.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_CONNECT.c index 961306cf6..8c0633025 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_CONNECT.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_CONNECT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_ERROR.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_ERROR.c index fe1619e70..eb304db70 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_ERROR.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_ERROR.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_FIRMWARE.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_FIRMWARE.c index ed422b356..5548cc7ba 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_FIRMWARE.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_FIRMWARE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_INFO.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_INFO.c index 6c5797e8f..af3926d69 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_INFO.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_INFO.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_MICROSD.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_MICROSD.c index 0965e41d8..dcc6bc5fd 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_MICROSD.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_MICROSD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_PIN.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_PIN.c index ec8a87527..9f5a24790 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_PIN.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_PIN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_QUESTION.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_QUESTION.c index a9d2498aa..f34eae93c 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_QUESTION.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_QUESTION.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SEED.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SEED.c index 7d3a1236c..6b082ce1a 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SEED.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SEED.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP.c index 5eaa66d79..723d6adc0 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP_QR.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP_QR.c index 388001829..a73e88f42 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP_QR.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SETUP_QR.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SHIELD.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SHIELD.c index ff161f22d..4bd24d237 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SHIELD.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SHIELD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_STATIC_PIN_SPINNER.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_STATIC_PIN_SPINNER.c index ad0a2ea0a..bb2a27c83 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_STATIC_PIN_SPINNER.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_STATIC_PIN_SPINNER.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SUCCESS.c b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SUCCESS.c index 69b635f49..9fa2d4ad1 100644 --- a/ports/stm32/boards/Passport/images/color/LARGE_ICON_SUCCESS.c +++ b/ports/stm32/boards/Passport/images/color/LARGE_ICON_SUCCESS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/copyright_template.c b/ports/stm32/boards/Passport/images/copyright_template.c index eb69fd6b4..dd9341443 100644 --- a/ports/stm32/boards/Passport/images/copyright_template.c +++ b/ports/stm32/boards/Passport/images/copyright_template.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/images.h b/ports/stm32/boards/Passport/images/images.h index 2cd60b24b..927687de7 100644 --- a/ports/stm32/boards/Passport/images/images.h +++ b/ports/stm32/boards/Passport/images/images.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Autogenerated by ports/stm32/Justfile images command -- DO NOT EDIT MANUALLY! diff --git a/ports/stm32/boards/Passport/images/mono/ICON_ADD_ACCOUNT.c b/ports/stm32/boards/Passport/images/mono/ICON_ADD_ACCOUNT.c index c524ac7ab..131ffb486 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_ADD_ACCOUNT.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_ADD_ACCOUNT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_ADVANCED.c b/ports/stm32/boards/Passport/images/mono/ICON_ADVANCED.c index a10b25905..36d681409 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_ADVANCED.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_ADVANCED.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_BACK.c b/ports/stm32/boards/Passport/images/mono/ICON_BACK.c index d92001128..7f206ac4f 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_BACK.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_BACK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_BACKUP.c b/ports/stm32/boards/Passport/images/mono/ICON_BACKUP.c index 8f650506f..eb404d7c3 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_BACKUP.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_BACKUP.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_BATTERY.c b/ports/stm32/boards/Passport/images/mono/ICON_BATTERY.c index dd2dc7925..494269227 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_BATTERY.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_BATTERY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_BATTERY_CHARGING.c b/ports/stm32/boards/Passport/images/mono/ICON_BATTERY_CHARGING.c index 47026bdb2..742f89113 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_BATTERY_CHARGING.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_BATTERY_CHARGING.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_BITCOIN.c b/ports/stm32/boards/Passport/images/mono/ICON_BITCOIN.c index 3ab558b3a..df34fde7d 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_BITCOIN.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_BITCOIN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_BRIGHTNESS.c b/ports/stm32/boards/Passport/images/mono/ICON_BRIGHTNESS.c index 6aff28eed..9362f740c 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_BRIGHTNESS.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_BRIGHTNESS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_CANCEL.c b/ports/stm32/boards/Passport/images/mono/ICON_CANCEL.c index 0e3dec728..c29bdce9d 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_CANCEL.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_CANCEL.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_CASA.c b/ports/stm32/boards/Passport/images/mono/ICON_CASA.c index a91a0c8b3..cad5cfc9c 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_CASA.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_CASA.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_CHECKMARK.c b/ports/stm32/boards/Passport/images/mono/ICON_CHECKMARK.c index a2330a6f6..86e1747e5 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_CHECKMARK.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_CHECKMARK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_CIRCLE_CHECK.c b/ports/stm32/boards/Passport/images/mono/ICON_CIRCLE_CHECK.c index 86ee8dca4..e6e508fa7 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_CIRCLE_CHECK.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_CIRCLE_CHECK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_CLOCK.c b/ports/stm32/boards/Passport/images/mono/ICON_CLOCK.c index a1a585177..7357c93b9 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_CLOCK.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_CLOCK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_CONNECT.c b/ports/stm32/boards/Passport/images/mono/ICON_CONNECT.c index 10e649b7a..45268ebfa 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_CONNECT.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_CONNECT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_COUNTDOWN.c b/ports/stm32/boards/Passport/images/mono/ICON_COUNTDOWN.c index ecf2633f7..a93336748 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_COUNTDOWN.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_COUNTDOWN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_DEVICE.c b/ports/stm32/boards/Passport/images/mono/ICON_DEVICE.c index 4c5bd330e..9bf298d32 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_DEVICE.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_DEVICE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_EDIT1.c b/ports/stm32/boards/Passport/images/mono/ICON_EDIT1.c index 9fc2d84e1..13a861703 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_EDIT1.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_EDIT1.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_EDIT2.c b/ports/stm32/boards/Passport/images/mono/ICON_EDIT2.c index 423f391fe..6677684da 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_EDIT2.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_EDIT2.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_ERASE.c b/ports/stm32/boards/Passport/images/mono/ICON_ERASE.c index e34408984..fb20c2c45 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_ERASE.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_ERASE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_EXTENSIONS.c b/ports/stm32/boards/Passport/images/mono/ICON_EXTENSIONS.c index 0f5c33eb6..71995cb15 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_EXTENSIONS.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_EXTENSIONS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_FILE.c b/ports/stm32/boards/Passport/images/mono/ICON_FILE.c index c9a0d798a..15b92e370 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_FILE.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_FILE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_FIRMWARE.c b/ports/stm32/boards/Passport/images/mono/ICON_FIRMWARE.c index 0d238eab0..ee2bc39c1 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_FIRMWARE.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_FIRMWARE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_FOLDER.c b/ports/stm32/boards/Passport/images/mono/ICON_FOLDER.c index fa6b3a5cb..32b3760d9 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_FOLDER.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_FOLDER.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_FORWARD.c b/ports/stm32/boards/Passport/images/mono/ICON_FORWARD.c index 203003d70..ffa6538dd 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_FORWARD.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_FORWARD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_HAMBURGER.c b/ports/stm32/boards/Passport/images/mono/ICON_HAMBURGER.c index 00f09dae4..83fda169a 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_HAMBURGER.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_HAMBURGER.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_HEALTH_CHECK.c b/ports/stm32/boards/Passport/images/mono/ICON_HEALTH_CHECK.c index 4eb5896c3..1076df770 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_HEALTH_CHECK.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_HEALTH_CHECK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_HOME.c b/ports/stm32/boards/Passport/images/mono/ICON_HOME.c index 48ead68e1..4e524118d 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_HOME.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_HOME.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_INFO.c b/ports/stm32/boards/Passport/images/mono/ICON_INFO.c index 8ff25537a..b12919c24 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_INFO.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_INFO.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_LOWER_ALPHA.c b/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_LOWER_ALPHA.c index 670db0f7e..88de06aa0 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_LOWER_ALPHA.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_LOWER_ALPHA.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_NUMERIC.c b/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_NUMERIC.c index 03dc82213..2c0d49a23 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_NUMERIC.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_NUMERIC.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_PUNCTUATION.c b/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_PUNCTUATION.c index 82b60dbf5..816297c2b 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_PUNCTUATION.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_PUNCTUATION.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_UPPER_ALPHA.c b/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_UPPER_ALPHA.c index 8eb07bb17..52816da14 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_UPPER_ALPHA.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_INPUT_MODE_UPPER_ALPHA.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_MICROSD.c b/ports/stm32/boards/Passport/images/mono/ICON_MICROSD.c index a14c92671..f45c655d0 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_MICROSD.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_MICROSD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_MULTISIG.c b/ports/stm32/boards/Passport/images/mono/ICON_MULTISIG.c index 094d5208a..85425667d 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_MULTISIG.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_MULTISIG.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_NETWORK.c b/ports/stm32/boards/Passport/images/mono/ICON_NETWORK.c index f7eed1bf5..367833abd 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_NETWORK.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_NETWORK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_ONE_KEY.c b/ports/stm32/boards/Passport/images/mono/ICON_ONE_KEY.c index 034048fcf..3a24e26bb 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_ONE_KEY.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_ONE_KEY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_DOT.c b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_DOT.c index f4806dd96..619f4e374 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_DOT.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_DOT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_HOME.c b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_HOME.c index 392d603c8..82475914a 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_HOME.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_HOME.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_INDICATOR.c b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_INDICATOR.c index d66e3eb6a..99f1879b4 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_INDICATOR.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_INDICATOR.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_PLUS.c b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_PLUS.c index 16a0ebb86..22393d844 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_PLUS.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_PLUS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_LG.c b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_LG.c index 0132d624a..2cb7ae958 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_LG.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_LG.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_MD.c b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_MD.c index 2ea24c3a9..78804ae2b 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_MD.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_MD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_SM.c b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_SM.c index db0b70108..f5ab60a47 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_SM.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PAGE_QR_SM.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PASSPHRASE.c b/ports/stm32/boards/Passport/images/mono/ICON_PASSPHRASE.c index e1ad6a09e..62b428d1d 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PASSPHRASE.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PASSPHRASE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PIN.c b/ports/stm32/boards/Passport/images/mono/ICON_PIN.c index d5dd31322..e2cca0d85 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PIN.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PIN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_PLUS.c b/ports/stm32/boards/Passport/images/mono/ICON_PLUS.c index 763ba4854..063370289 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_PLUS.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_PLUS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_RETRY.c b/ports/stm32/boards/Passport/images/mono/ICON_RETRY.c index c49dfc1ae..a5b40a1e8 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_RETRY.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_RETRY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SCAN_QR.c b/ports/stm32/boards/Passport/images/mono/ICON_SCAN_QR.c index 1b96cc02d..818d9bc1a 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SCAN_QR.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SCAN_QR.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SEED.c b/ports/stm32/boards/Passport/images/mono/ICON_SEED.c index 0889a65d7..74b771500 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SEED.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SEED.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SETTINGS.c b/ports/stm32/boards/Passport/images/mono/ICON_SETTINGS.c index d81ec38b1..5af7616c3 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SETTINGS.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SETTINGS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SETUP.c b/ports/stm32/boards/Passport/images/mono/ICON_SETUP.c index 8e79c7d28..cf4e7442a 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SETUP.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SETUP.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SHIELD.c b/ports/stm32/boards/Passport/images/mono/ICON_SHIELD.c index cd1a752e0..9f1b17f2d 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SHIELD.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SHIELD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SHUTDOWN.c b/ports/stm32/boards/Passport/images/mono/ICON_SHUTDOWN.c index a08fec5cd..08f4edfb8 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SHUTDOWN.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SHUTDOWN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SIGN.c b/ports/stm32/boards/Passport/images/mono/ICON_SIGN.c index bd3658e7e..351197802 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SIGN.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SIGN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SMALL_CHECKMARK.c b/ports/stm32/boards/Passport/images/mono/ICON_SMALL_CHECKMARK.c index 488ec5de7..a63f3a188 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SMALL_CHECKMARK.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SMALL_CHECKMARK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_SPIRAL.c b/ports/stm32/boards/Passport/images/mono/ICON_SPIRAL.c index 05b1c8337..f78ed667f 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_SPIRAL.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_SPIRAL.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_TWO_KEYS.c b/ports/stm32/boards/Passport/images/mono/ICON_TWO_KEYS.c index d369c8c64..28f4c994b 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_TWO_KEYS.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_TWO_KEYS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_VERIFY_ADDRESS.c b/ports/stm32/boards/Passport/images/mono/ICON_VERIFY_ADDRESS.c index 603a50425..848f775f4 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_VERIFY_ADDRESS.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_VERIFY_ADDRESS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/ICON_WARNING.c b/ports/stm32/boards/Passport/images/mono/ICON_WARNING.c index 11a5c8345..21daa12b4 100644 --- a/ports/stm32/boards/Passport/images/mono/ICON_WARNING.c +++ b/ports/stm32/boards/Passport/images/mono/ICON_WARNING.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_CARD_BOTTOM.c b/ports/stm32/boards/Passport/images/mono/IMAGE_CARD_BOTTOM.c index 9b527dcc9..1d5f0fb64 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_CARD_BOTTOM.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_CARD_BOTTOM.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_DIAGONAL_LINES.c b/ports/stm32/boards/Passport/images/mono/IMAGE_DIAGONAL_LINES.c index 0f1a78e81..1bd8f7145 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_DIAGONAL_LINES.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_DIAGONAL_LINES.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_REGULATORY.c b/ports/stm32/boards/Passport/images/mono/IMAGE_REGULATORY.c index abc8556a0..8391e0522 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_REGULATORY.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_REGULATORY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY.c b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY.c index bc7ac166c..e25c1bab8 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_0.c b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_0.c index e5d5ed981..4706dac6f 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_0.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_0.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_1.c b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_1.c index 1958d93d6..26ada4f12 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_1.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_1.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_2.c b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_2.c index ade0735d1..47d38e013 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_2.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_2.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_3.c b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_3.c index 6ca9da86d..4b314e206 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_3.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_3.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_4.c b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_4.c index 1fbdabd1b..0fb607f48 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_4.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_4.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_5.c b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_5.c index 1562d7ce9..d1e778917 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_5.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_5.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_6.c b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_6.c index 3a3b12250..817d6d0ca 100644 --- a/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_6.c +++ b/ports/stm32/boards/Passport/images/mono/IMAGE_SCREEN_OVERLAY_6.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_BACKUP.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_BACKUP.c index 119354d20..fb176bed9 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_BACKUP.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_BACKUP.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_BRANDMARK.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_BRANDMARK.c index 54a27199c..28061f41f 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_BRANDMARK.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_BRANDMARK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_CLOCK.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_CLOCK.c index 482a28593..4a05db391 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_CLOCK.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_CLOCK.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_CONNECT.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_CONNECT.c index 12abc9e2e..cb4fec9e5 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_CONNECT.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_CONNECT.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_ERROR.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_ERROR.c index 338368991..9c92a1678 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_ERROR.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_ERROR.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_FIRMWARE.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_FIRMWARE.c index 32f1f0e58..f7694686a 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_FIRMWARE.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_FIRMWARE.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_INFO.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_INFO.c index dd32c4f64..a6c6edf83 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_INFO.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_INFO.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_MICROSD.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_MICROSD.c index 023de4428..178c414e8 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_MICROSD.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_MICROSD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_PIN.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_PIN.c index 594eb3151..a349d7ab8 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_PIN.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_PIN.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_QUESTION.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_QUESTION.c index baa188c77..8ea6b8085 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_QUESTION.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_QUESTION.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SEED.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SEED.c index 5170a0edc..d3e3fb8a9 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SEED.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SEED.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP.c index f1482ba75..f8a17c228 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP_QR.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP_QR.c index b1e07587e..5d5f5cf30 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP_QR.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SETUP_QR.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SHIELD.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SHIELD.c index 94a4fded3..76d09caa0 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SHIELD.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SHIELD.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_STATIC_PIN_SPINNER.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_STATIC_PIN_SPINNER.c index 6422142a2..6961f52c6 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_STATIC_PIN_SPINNER.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_STATIC_PIN_SPINNER.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SUCCESS.c b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SUCCESS.c index b64fb3f77..12e86edd4 100644 --- a/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SUCCESS.c +++ b/ports/stm32/boards/Passport/images/mono/LARGE_ICON_SUCCESS.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/include/backlight.h b/ports/stm32/boards/Passport/include/backlight.h index 7e8286df5..298fc6638 100644 --- a/ports/stm32/boards/Passport/include/backlight.h +++ b/ports/stm32/boards/Passport/include/backlight.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/include/bq27520.h b/ports/stm32/boards/Passport/include/bq27520.h index 890d1b762..0a30fc9fa 100644 --- a/ports/stm32/boards/Passport/include/bq27520.h +++ b/ports/stm32/boards/Passport/include/bq27520.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // This code is specific to the Passport hardware build only. It is not shared with the unix diff --git a/ports/stm32/boards/Passport/include/delay.h b/ports/stm32/boards/Passport/include/delay.h index 59f8490f1..56020b076 100644 --- a/ports/stm32/boards/Passport/include/delay.h +++ b/ports/stm32/boards/Passport/include/delay.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/include/display.h b/ports/stm32/boards/Passport/include/display.h index 011b3bc9f..9e8f1073c 100644 --- a/ports/stm32/boards/Passport/include/display.h +++ b/ports/stm32/boards/Passport/include/display.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // display.h - Display rendering functions for the Passport bootloader diff --git a/ports/stm32/boards/Passport/include/eeprom.h b/ports/stm32/boards/Passport/include/eeprom.h index a0427b495..00963cd68 100644 --- a/ports/stm32/boards/Passport/include/eeprom.h +++ b/ports/stm32/boards/Passport/include/eeprom.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // EEPROM driver for Passport Gen 1.2 diff --git a/ports/stm32/boards/Passport/include/firmware-keys.h b/ports/stm32/boards/Passport/include/firmware-keys.h index 85207ecf2..5154a9052 100644 --- a/ports/stm32/boards/Passport/include/firmware-keys.h +++ b/ports/stm32/boards/Passport/include/firmware-keys.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/include/fwheader.h b/ports/stm32/boards/Passport/include/fwheader.h index 094f65874..a62964b15 100644 --- a/ports/stm32/boards/Passport/include/fwheader.h +++ b/ports/stm32/boards/Passport/include/fwheader.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/include/gpio.h b/ports/stm32/boards/Passport/include/gpio.h index 0e8c3b38b..4870c0969 100644 --- a/ports/stm32/boards/Passport/include/gpio.h +++ b/ports/stm32/boards/Passport/include/gpio.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/include/hash.h b/ports/stm32/boards/Passport/include/hash.h index 7df9e3363..1109bed84 100644 --- a/ports/stm32/boards/Passport/include/hash.h +++ b/ports/stm32/boards/Passport/include/hash.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/include/i2c-init.h b/ports/stm32/boards/Passport/include/i2c-init.h index bb5730afb..38fd60a44 100644 --- a/ports/stm32/boards/Passport/include/i2c-init.h +++ b/ports/stm32/boards/Passport/include/i2c-init.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/include/keypad-adp-5587.h b/ports/stm32/boards/Passport/include/keypad-adp-5587.h index 0509986e0..86d9509c1 100644 --- a/ports/stm32/boards/Passport/include/keypad-adp-5587.h +++ b/ports/stm32/boards/Passport/include/keypad-adp-5587.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h b/ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h index b22550423..a907732f4 100644 --- a/ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h +++ b/ports/stm32/boards/Passport/include/lcd-sharp-ls018b7dh02.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // LCD driver for Sharp LS018B7DH02 monochrome display diff --git a/ports/stm32/boards/Passport/include/lcd-st7789.h b/ports/stm32/boards/Passport/include/lcd-st7789.h index 42bfd52c1..5565e9b9c 100644 --- a/ports/stm32/boards/Passport/include/lcd-st7789.h +++ b/ports/stm32/boards/Passport/include/lcd-st7789.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // Driver for ST7789 display with 240x320 RGB565 display diff --git a/ports/stm32/boards/Passport/include/pprng.h b/ports/stm32/boards/Passport/include/pprng.h index e126109d4..4af76569b 100644 --- a/ports/stm32/boards/Passport/include/pprng.h +++ b/ports/stm32/boards/Passport/include/pprng.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/include/ring_buffer.h b/ports/stm32/boards/Passport/include/ring_buffer.h index 196cf050f..c30913237 100644 --- a/ports/stm32/boards/Passport/include/ring_buffer.h +++ b/ports/stm32/boards/Passport/include/ring_buffer.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/include/se.h b/ports/stm32/boards/Passport/include/se.h index 088e2d6b5..6eafc59cd 100644 --- a/ports/stm32/boards/Passport/include/se.h +++ b/ports/stm32/boards/Passport/include/se.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. + * SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. * SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef _SECURE_ELEMENT_H_ diff --git a/ports/stm32/boards/Passport/include/secresult.h b/ports/stm32/boards/Passport/include/secresult.h index 556a3c1fe..417a3b66b 100644 --- a/ports/stm32/boards/Passport/include/secresult.h +++ b/ports/stm32/boards/Passport/include/secresult.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // secresult.h - Secure return values from security-critical functions -- ensures that single bit glitches cannot diff --git a/ports/stm32/boards/Passport/include/secrets.h b/ports/stm32/boards/Passport/include/secrets.h index 4f3e406db..cf77897b0 100644 --- a/ports/stm32/boards/Passport/include/secrets.h +++ b/ports/stm32/boards/Passport/include/secrets.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. + * SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. * SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef _SECRETS_H_ diff --git a/ports/stm32/boards/Passport/include/spiflash.h b/ports/stm32/boards/Passport/include/spiflash.h index 18f23007f..e36a552f8 100644 --- a/ports/stm32/boards/Passport/include/spiflash.h +++ b/ports/stm32/boards/Passport/include/spiflash.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. + * SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. * SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef _SPIFLASH_H_ diff --git a/ports/stm32/boards/Passport/include/utils.h b/ports/stm32/boards/Passport/include/utils.h index bd0c7c472..b5a6c1bf7 100644 --- a/ports/stm32/boards/Passport/include/utils.h +++ b/ports/stm32/boards/Passport/include/utils.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. + * SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. * SPDX-License-Identifier: GPL-3.0-or-later */ #ifndef _UTILS_H_ diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index 216d252da..aa157d6e4 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modpassport-backlight.h b/ports/stm32/boards/Passport/modpassport-backlight.h index 39224585a..6efb0639b 100644 --- a/ports/stm32/boards/Passport/modpassport-backlight.h +++ b/ports/stm32/boards/Passport/modpassport-backlight.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport-boardrev.h b/ports/stm32/boards/Passport/modpassport-boardrev.h index b90dd8b2d..83163b65b 100644 --- a/ports/stm32/boards/Passport/modpassport-boardrev.h +++ b/ports/stm32/boards/Passport/modpassport-boardrev.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport-camera.h b/ports/stm32/boards/Passport/modpassport-camera.h index 37ebc09ed..516cbb49c 100644 --- a/ports/stm32/boards/Passport/modpassport-camera.h +++ b/ports/stm32/boards/Passport/modpassport-camera.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport-fuelgauge.h b/ports/stm32/boards/Passport/modpassport-fuelgauge.h index a20fb365b..8db742ef3 100644 --- a/ports/stm32/boards/Passport/modpassport-fuelgauge.h +++ b/ports/stm32/boards/Passport/modpassport-fuelgauge.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport-noise.h b/ports/stm32/boards/Passport/modpassport-noise.h index 749201b9e..75e9d2661 100644 --- a/ports/stm32/boards/Passport/modpassport-noise.h +++ b/ports/stm32/boards/Passport/modpassport-noise.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport-powermon.h b/ports/stm32/boards/Passport/modpassport-powermon.h index fca74e1c9..f9878a6fe 100644 --- a/ports/stm32/boards/Passport/modpassport-powermon.h +++ b/ports/stm32/boards/Passport/modpassport-powermon.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport-settingsflash.h b/ports/stm32/boards/Passport/modpassport-settingsflash.h index 3fb2d1bae..578d86df6 100644 --- a/ports/stm32/boards/Passport/modpassport-settingsflash.h +++ b/ports/stm32/boards/Passport/modpassport-settingsflash.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport-sram4.h b/ports/stm32/boards/Passport/modpassport-sram4.h index 424abb84a..fb07f6f84 100644 --- a/ports/stm32/boards/Passport/modpassport-sram4.h +++ b/ports/stm32/boards/Passport/modpassport-sram4.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport-system.h b/ports/stm32/boards/Passport/modpassport-system.h index b50dff4e8..a8995433d 100644 --- a/ports/stm32/boards/Passport/modpassport-system.h +++ b/ports/stm32/boards/Passport/modpassport-system.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport.c b/ports/stm32/boards/Passport/modpassport.c index a702344a1..a8876cea2 100644 --- a/ports/stm32/boards/Passport/modpassport.c +++ b/ports/stm32/boards/Passport/modpassport.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/modpassport_lv-keypad.h b/ports/stm32/boards/Passport/modpassport_lv-keypad.h index a473ea89f..563c70910 100644 --- a/ports/stm32/boards/Passport/modpassport_lv-keypad.h +++ b/ports/stm32/boards/Passport/modpassport_lv-keypad.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport_lv-lcd.h b/ports/stm32/boards/Passport/modpassport_lv-lcd.h index 2510467d8..faf62b677 100644 --- a/ports/stm32/boards/Passport/modpassport_lv-lcd.h +++ b/ports/stm32/boards/Passport/modpassport_lv-lcd.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modpassport_lv.c b/ports/stm32/boards/Passport/modpassport_lv.c index e08bc0e31..88f71c93e 100644 --- a/ports/stm32/boards/Passport/modpassport_lv.c +++ b/ports/stm32/boards/Passport/modpassport_lv.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/modules/Enum.py b/ports/stm32/boards/Passport/modules/Enum.py index e66c2e264..d10722918 100644 --- a/ports/stm32/boards/Passport/modules/Enum.py +++ b/ports/stm32/boards/Passport/modules/Enum.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # enum.py diff --git a/ports/stm32/boards/Passport/modules/animations/__init__.py b/ports/stm32/boards/Passport/modules/animations/__init__.py index 387c691e2..6d122edb6 100644 --- a/ports/stm32/boards/Passport/modules/animations/__init__.py +++ b/ports/stm32/boards/Passport/modules/animations/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/animations/card_anim.py b/ports/stm32/boards/Passport/modules/animations/card_anim.py index c023db924..45aa6d64d 100644 --- a/ports/stm32/boards/Passport/modules/animations/card_anim.py +++ b/ports/stm32/boards/Passport/modules/animations/card_anim.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # card_anim.py diff --git a/ports/stm32/boards/Passport/modules/animations/constants.py b/ports/stm32/boards/Passport/modules/animations/constants.py index bafddf50e..3048cb45e 100644 --- a/ports/stm32/boards/Passport/modules/animations/constants.py +++ b/ports/stm32/boards/Passport/modules/animations/constants.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # constants.py diff --git a/ports/stm32/boards/Passport/modules/animations/page_anim.py b/ports/stm32/boards/Passport/modules/animations/page_anim.py index b989453c8..b38323a01 100644 --- a/ports/stm32/boards/Passport/modules/animations/page_anim.py +++ b/ports/stm32/boards/Passport/modules/animations/page_anim.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # page_anim.py diff --git a/ports/stm32/boards/Passport/modules/animations/prop_cb.py b/ports/stm32/boards/Passport/modules/animations/prop_cb.py index 48cc2ce31..5596d870b 100644 --- a/ports/stm32/boards/Passport/modules/animations/prop_cb.py +++ b/ports/stm32/boards/Passport/modules/animations/prop_cb.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # prop_cb.py diff --git a/ports/stm32/boards/Passport/modules/callgate.py b/ports/stm32/boards/Passport/modules/callgate.py index c01aa6145..8426cd2a8 100644 --- a/ports/stm32/boards/Passport/modules/callgate.py +++ b/ports/stm32/boards/Passport/modules/callgate.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/chains.py b/ports/stm32/boards/Passport/modules/chains.py index cb6b6257b..06db4a732 100644 --- a/ports/stm32/boards/Passport/modules/chains.py +++ b/ports/stm32/boards/Passport/modules/chains.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/common.py b/ports/stm32/boards/Passport/modules/common.py index eb352bb4d..d9df9e41f 100644 --- a/ports/stm32/boards/Passport/modules/common.py +++ b/ports/stm32/boards/Passport/modules/common.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # common.py - Shared global values diff --git a/ports/stm32/boards/Passport/modules/constants.py b/ports/stm32/boards/Passport/modules/constants.py index 2ea12aa59..c9710b32e 100644 --- a/ports/stm32/boards/Passport/modules/constants.py +++ b/ports/stm32/boards/Passport/modules/constants.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # constants.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/__init__.py b/ports/stm32/boards/Passport/modules/data_codecs/__init__.py index 3574f74bf..073546ac4 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/__init__.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/__init__.py @@ -1,3 +1,3 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # diff --git a/ports/stm32/boards/Passport/modules/data_codecs/address_sampler.py b/ports/stm32/boards/Passport/modules/data_codecs/address_sampler.py index fe8b0b53e..8e5071f64 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/address_sampler.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/address_sampler.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # address_sampler.py - Indicate if the given data is a Bitcoin address diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py b/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py index 182e7a48d..ef101b909 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # data_decoder.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py b/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py index 59a9e0c23..4af29bd87 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # data_decoder.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_format.py b/ports/stm32/boards/Passport/modules/data_codecs/data_format.py index 38c186aba..5a3444c9a 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_format.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_format.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # data_format.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_sampler.py b/ports/stm32/boards/Passport/modules/data_codecs/data_sampler.py index 7d2d4042c..96c36fc4a 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_sampler.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_sampler.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # data_sampler.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/http_sampler.py b/ports/stm32/boards/Passport/modules/data_codecs/http_sampler.py index a7d71025b..55fba6b24 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/http_sampler.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/http_sampler.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # http_sampler.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/multisig_config_sampler.py b/ports/stm32/boards/Passport/modules/data_codecs/multisig_config_sampler.py index 12c0eea97..6ff98d065 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/multisig_config_sampler.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/multisig_config_sampler.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # multisig_config_sampler.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/psbt_txn_sampler.py b/ports/stm32/boards/Passport/modules/data_codecs/psbt_txn_sampler.py index 0b85ff506..2a2528f6e 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/psbt_txn_sampler.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/psbt_txn_sampler.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # psbt_txn_sampler.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index 70e2f7800..c3a28f137 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # qr_decoder.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py index f6489b7c0..0958f888c 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # qr_factory.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_type.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_type.py index 26e56403b..d2b36d870 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_type.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_type.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # qr_type.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/seed_sampler.py b/ports/stm32/boards/Passport/modules/data_codecs/seed_sampler.py index 1e7cae305..e293c79a2 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/seed_sampler.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/seed_sampler.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # seed_sampler.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index ac508d851..1c837bf65 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # ur1_codec.py diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index ff7fc4d0b..aec13bd39 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # ur2_codec.py diff --git a/ports/stm32/boards/Passport/modules/descriptor.py b/ports/stm32/boards/Passport/modules/descriptor.py index 4db60ec5b..da2982eb6 100644 --- a/ports/stm32/boards/Passport/modules/descriptor.py +++ b/ports/stm32/boards/Passport/modules/descriptor.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2019 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/display.py b/ports/stm32/boards/Passport/modules/display.py index ef99c1d2e..4acacb601 100644 --- a/ports/stm32/boards/Passport/modules/display.py +++ b/ports/stm32/boards/Passport/modules/display.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/errors.py b/ports/stm32/boards/Passport/modules/errors.py index 416241af6..059f1c88b 100644 --- a/ports/stm32/boards/Passport/modules/errors.py +++ b/ports/stm32/boards/Passport/modules/errors.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # errors.py - Error codes that functions can return -- mostly used for tasks to return diff --git a/ports/stm32/boards/Passport/modules/export.py b/ports/stm32/boards/Passport/modules/export.py index 4087c727a..8f7e866ed 100644 --- a/ports/stm32/boards/Passport/modules/export.py +++ b/ports/stm32/boards/Passport/modules/export.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/ext_settings.py b/ports/stm32/boards/Passport/modules/ext_settings.py index 73f2b88e4..6c085129e 100644 --- a/ports/stm32/boards/Passport/modules/ext_settings.py +++ b/ports/stm32/boards/Passport/modules/ext_settings.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/flows/__init__.py b/ports/stm32/boards/Passport/modules/flows/__init__.py index ca47aa300..b10555221 100644 --- a/ports/stm32/boards/Passport/modules/flows/__init__.py +++ b/ports/stm32/boards/Passport/modules/flows/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/flows/about_flow.py b/ports/stm32/boards/Passport/modules/flows/about_flow.py index 85195b3f7..71a78aa9e 100644 --- a/ports/stm32/boards/Passport/modules/flows/about_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/about_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # about_flow.py - About Passport, and regulatory info diff --git a/ports/stm32/boards/Passport/modules/flows/apply_passphrase_flow.py b/ports/stm32/boards/Passport/modules/flows/apply_passphrase_flow.py index 1ce745d14..fc57a9af7 100644 --- a/ports/stm32/boards/Passport/modules/flows/apply_passphrase_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/apply_passphrase_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # apply_passphrase_flow.py - Ask user to enter a passphrase, then apply it. diff --git a/ports/stm32/boards/Passport/modules/flows/auto_backup_flow.py b/ports/stm32/boards/Passport/modules/flows/auto_backup_flow.py index 297c7ccab..cf99c85ad 100644 --- a/ports/stm32/boards/Passport/modules/flows/auto_backup_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/auto_backup_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # auto_backup_flow.py - Check to see if microSD is inserted and, if so, backup automatically diff --git a/ports/stm32/boards/Passport/modules/flows/backup_flow.py b/ports/stm32/boards/Passport/modules/flows/backup_flow.py index d5d6ad6cd..99e1f5aec 100644 --- a/ports/stm32/boards/Passport/modules/flows/backup_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/backup_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # backup_flow.py - Backup Passport to microSD diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py index 7a064e466..194de1fc1 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_common_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py index a306d305c..495735428 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index 7f74a0b64..ff19878fb 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format diff --git a/ports/stm32/boards/Passport/modules/flows/change_pin_flow.py b/ports/stm32/boards/Passport/modules/flows/change_pin_flow.py index 9cd002c88..d24060a0d 100644 --- a/ports/stm32/boards/Passport/modules/flows/change_pin_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/change_pin_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # change_pin_flow.py - Change the user's PIN diff --git a/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py b/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py index 2effa3703..b25bcfeea 100644 --- a/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # connect_wallet_flow.py - Connect a new software wallet with Passport. diff --git a/ports/stm32/boards/Passport/modules/flows/delete_account_flow.py b/ports/stm32/boards/Passport/modules/flows/delete_account_flow.py index 64e4a7dca..cb20d0c1c 100644 --- a/ports/stm32/boards/Passport/modules/flows/delete_account_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/delete_account_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # delete_account_flow.py - Delete the current account diff --git a/ports/stm32/boards/Passport/modules/flows/delete_multisig_flow.py b/ports/stm32/boards/Passport/modules/flows/delete_multisig_flow.py index 58006b3f4..d3fcaee3c 100644 --- a/ports/stm32/boards/Passport/modules/flows/delete_multisig_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/delete_multisig_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # delete_multisig_flow.py - Delete the specified multisig config diff --git a/ports/stm32/boards/Passport/modules/flows/developer_functions_flow.py b/ports/stm32/boards/Passport/modules/flows/developer_functions_flow.py index b6635caa8..2041c4a8f 100644 --- a/ports/stm32/boards/Passport/modules/flows/developer_functions_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/developer_functions_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # developer_functions_flow.py - Run a named developer function diff --git a/ports/stm32/boards/Passport/modules/flows/envoy_setup_flow.py b/ports/stm32/boards/Passport/modules/flows/envoy_setup_flow.py index a979d6597..a013bc9e7 100644 --- a/ports/stm32/boards/Passport/modules/flows/envoy_setup_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/envoy_setup_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # envoy_setup_flow.py - The main overall flow for Envoy setup - controls the process diff --git a/ports/stm32/boards/Passport/modules/flows/erase_passport_flow.py b/ports/stm32/boards/Passport/modules/flows/erase_passport_flow.py index 4b0316b14..64231de49 100644 --- a/ports/stm32/boards/Passport/modules/flows/erase_passport_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/erase_passport_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # erase_passport_flow.py - Confirm the user wants to erase Passport, then erase Passport's wallet diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py index 76cf5f070..2d2faef15 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # export_multisig_microsd_flow.py - Export a multisig wallet via microSD diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py index ae16b58b0..859932925 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # export_multisig_qr_flow.py - Export a multisig wallet via QR code diff --git a/ports/stm32/boards/Passport/modules/flows/export_summary_flow.py b/ports/stm32/boards/Passport/modules/flows/export_summary_flow.py index 3d50bfdf8..056e7fd8a 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_summary_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_summary_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # export_summary_flow.py - Flow to let export a summary of the current wallet diff --git a/ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py b/ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py index 144785b3d..98fa3194c 100644 --- a/ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/fcc_test_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # fcc_test_flow.py - Flow to iterate through a test loop indefinitely diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index 13a828e9a..c294ee211 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # file_picker_flow.py - Allow the user to pick a file and (optionally) navigate up/down folder hierarchy diff --git a/ports/stm32/boards/Passport/modules/flows/flow.py b/ports/stm32/boards/Passport/modules/flows/flow.py index 8cdba62d5..7c3b92611 100644 --- a/ports/stm32/boards/Passport/modules/flows/flow.py +++ b/ports/stm32/boards/Passport/modules/flows/flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # flow.py - Base class for all UI flows diff --git a/ports/stm32/boards/Passport/modules/flows/format_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/format_microsd_flow.py index e58471e32..cb72f6088 100644 --- a/ports/stm32/boards/Passport/modules/flows/format_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/format_microsd_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # format_microsd_flow.py - Ask the user to confirm, then format the microsd card diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_flow.py index 0f3db5122..08c9ff991 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # import_multisig_wallet_flow.py - Show user details of a wallet to be imported, then save if accepted diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_microsd_flow.py index 4548806c6..172022abf 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_microsd_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # import_multisig_wallet_from_microsd_flow.py - Import a multisig wallet from microSD diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py index 15cce73b0..08fc7c484 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # import_multisig_wallet_from_qr_flow.py - Import a multisig wallet from a QR code diff --git a/ports/stm32/boards/Passport/modules/flows/initial_seed_setup_flow.py b/ports/stm32/boards/Passport/modules/flows/initial_seed_setup_flow.py index d4ad3fbc9..c0f896d0f 100644 --- a/ports/stm32/boards/Passport/modules/flows/initial_seed_setup_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/initial_seed_setup_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # initial_seed_setup_flow.py - Menu to let user choose seed setup method diff --git a/ports/stm32/boards/Passport/modules/flows/install_dev_pubkey_flow.py b/ports/stm32/boards/Passport/modules/flows/install_dev_pubkey_flow.py index 99be2ecf6..befb68cf0 100644 --- a/ports/stm32/boards/Passport/modules/flows/install_dev_pubkey_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/install_dev_pubkey_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # install_dev_pubkey_flow.py - Flow to let the user choose a dev pubkey file and install it diff --git a/ports/stm32/boards/Passport/modules/flows/list_files_flow.py b/ports/stm32/boards/Passport/modules/flows/list_files_flow.py index 9aaa665c6..9bb4f80b4 100644 --- a/ports/stm32/boards/Passport/modules/flows/list_files_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/list_files_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # list_files_flow.py - Flow to let user view microSD card files and view the SHA256 of the chosen file diff --git a/ports/stm32/boards/Passport/modules/flows/login_flow.py b/ports/stm32/boards/Passport/modules/flows/login_flow.py index 0bfc2079d..2c68cf882 100644 --- a/ports/stm32/boards/Passport/modules/flows/login_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/login_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # login_flow.py - Login to Passport diff --git a/ports/stm32/boards/Passport/modules/flows/magic_scan_flow.py b/ports/stm32/boards/Passport/modules/flows/magic_scan_flow.py index ade662c41..9f8e171a1 100644 --- a/ports/stm32/boards/Passport/modules/flows/magic_scan_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/magic_scan_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # magic_scan_flow.py - Scan a QR code and "magically" figure out which handler flow to run. diff --git a/ports/stm32/boards/Passport/modules/flows/magic_scan_import_multisig_flow.py b/ports/stm32/boards/Passport/modules/flows/magic_scan_import_multisig_flow.py index 6994190d3..f6e45dcbe 100644 --- a/ports/stm32/boards/Passport/modules/flows/magic_scan_import_multisig_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/magic_scan_import_multisig_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # magic_scan_import_multisig_flow.py - Import a multisig file diff --git a/ports/stm32/boards/Passport/modules/flows/magic_scan_import_seed_flow.py b/ports/stm32/boards/Passport/modules/flows/magic_scan_import_seed_flow.py index d9cd9e302..56da6942e 100644 --- a/ports/stm32/boards/Passport/modules/flows/magic_scan_import_seed_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/magic_scan_import_seed_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # magic_scan_import_seed_flow.py - Import a multisig file diff --git a/ports/stm32/boards/Passport/modules/flows/magic_scan_sign_psbt_flow.py b/ports/stm32/boards/Passport/modules/flows/magic_scan_sign_psbt_flow.py index 61d96dfe7..2e86c10fc 100644 --- a/ports/stm32/boards/Passport/modules/flows/magic_scan_sign_psbt_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/magic_scan_sign_psbt_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # magic_scan_sign_psbt_flow.py - Import a multisig file diff --git a/ports/stm32/boards/Passport/modules/flows/magic_scan_validate_address_flow.py b/ports/stm32/boards/Passport/modules/flows/magic_scan_validate_address_flow.py index 82d21f392..e6b464636 100644 --- a/ports/stm32/boards/Passport/modules/flows/magic_scan_validate_address_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/magic_scan_validate_address_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # magic_scan_validate_address_flow.py - Validate the given address diff --git a/ports/stm32/boards/Passport/modules/flows/main_flow.py b/ports/stm32/boards/Passport/modules/flows/main_flow.py index 1e30680e8..09742aae4 100644 --- a/ports/stm32/boards/Passport/modules/flows/main_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/main_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # main_flow.py - Flow class to track position in a menu diff --git a/ports/stm32/boards/Passport/modules/flows/manual_setup_flow.py b/ports/stm32/boards/Passport/modules/flows/manual_setup_flow.py index 675202ef8..0e0392f46 100644 --- a/ports/stm32/boards/Passport/modules/flows/manual_setup_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/manual_setup_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # manual_setup_flow.py - The main overall flow for manual setup - controls the process diff --git a/ports/stm32/boards/Passport/modules/flows/menu_flow.py b/ports/stm32/boards/Passport/modules/flows/menu_flow.py index 87bfa14f2..7fc077ac3 100644 --- a/ports/stm32/boards/Passport/modules/flows/menu_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/menu_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # menu_flow.py - Flow class to track position in a menu diff --git a/ports/stm32/boards/Passport/modules/flows/new_account_flow.py b/ports/stm32/boards/Passport/modules/flows/new_account_flow.py index 63509f284..61fe75ed0 100644 --- a/ports/stm32/boards/Passport/modules/flows/new_account_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/new_account_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # new_account_flow.py - Create a new random seed diff --git a/ports/stm32/boards/Passport/modules/flows/new_seed_flow.py b/ports/stm32/boards/Passport/modules/flows/new_seed_flow.py index 17d654177..1ddb78fc4 100644 --- a/ports/stm32/boards/Passport/modules/flows/new_seed_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/new_seed_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # new_seed_flow.py - Create a new random seed diff --git a/ports/stm32/boards/Passport/modules/flows/page_flow.py b/ports/stm32/boards/Passport/modules/flows/page_flow.py index d2886f49f..8490282fe 100644 --- a/ports/stm32/boards/Passport/modules/flows/page_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/page_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # page_flow.py - Flow class to present a single Page that doesn't forward to other pages (e.g., a settings Page) diff --git a/ports/stm32/boards/Passport/modules/flows/remove_dev_pubkey_flow.py b/ports/stm32/boards/Passport/modules/flows/remove_dev_pubkey_flow.py index a66c0bd21..d03862480 100644 --- a/ports/stm32/boards/Passport/modules/flows/remove_dev_pubkey_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/remove_dev_pubkey_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # remove_dev_pubkey_flow.py - Flow to remove the currently installed dev pubkey (after confirming removal) diff --git a/ports/stm32/boards/Passport/modules/flows/rename_account_flow.py b/ports/stm32/boards/Passport/modules/flows/rename_account_flow.py index 5f7b9bdcf..8d168aef1 100644 --- a/ports/stm32/boards/Passport/modules/flows/rename_account_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/rename_account_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # rename_account_flow.py - Rename an account diff --git a/ports/stm32/boards/Passport/modules/flows/rename_multisig_flow.py b/ports/stm32/boards/Passport/modules/flows/rename_multisig_flow.py index c27f284d9..4f92aec37 100644 --- a/ports/stm32/boards/Passport/modules/flows/rename_multisig_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/rename_multisig_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # rename_multisig_flow.py - Rename a multisig entry diff --git a/ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py b/ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py index 15e0a3093..613ca2869 100644 --- a/ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # reset_pin_flow.py - Change the user's PIN to uninitialized - ONLY FOR DEV diff --git a/ports/stm32/boards/Passport/modules/flows/restore_backup_flow.py b/ports/stm32/boards/Passport/modules/flows/restore_backup_flow.py index 97b3268ac..f28b332d7 100644 --- a/ports/stm32/boards/Passport/modules/flows/restore_backup_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/restore_backup_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # restore_backup_flow.py -Restore a selected backup file to Passport. diff --git a/ports/stm32/boards/Passport/modules/flows/restore_seed_flow.py b/ports/stm32/boards/Passport/modules/flows/restore_seed_flow.py index a49909339..55aff404c 100644 --- a/ports/stm32/boards/Passport/modules/flows/restore_seed_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/restore_seed_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # restore_seed_flow.py -Restore a seed to Passport by entering the seed words. diff --git a/ports/stm32/boards/Passport/modules/flows/scv_flow.py b/ports/stm32/boards/Passport/modules/flows/scv_flow.py index a98a8f434..194c498c7 100644 --- a/ports/stm32/boards/Passport/modules/flows/scv_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/scv_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # scv_flow.py - Supply Chain Validation Flow diff --git a/ports/stm32/boards/Passport/modules/flows/select_setup_mode_flow.py b/ports/stm32/boards/Passport/modules/flows/select_setup_mode_flow.py index 21ae75838..f0306c495 100644 --- a/ports/stm32/boards/Passport/modules/flows/select_setup_mode_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/select_setup_mode_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # select_setup_mode_flow.py - The main overall flow for Envoy setup - controls the process diff --git a/ports/stm32/boards/Passport/modules/flows/set_chain_flow.py b/ports/stm32/boards/Passport/modules/flows/set_chain_flow.py index 6c9bcf282..7bb7d41b2 100644 --- a/ports/stm32/boards/Passport/modules/flows/set_chain_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/set_chain_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # set_chain_flow.py - Set the chain to testnet or mainnet, then if testnet was chosen, show a warning diff --git a/ports/stm32/boards/Passport/modules/flows/set_initial_pin_flow.py b/ports/stm32/boards/Passport/modules/flows/set_initial_pin_flow.py index 50e4205a3..cac873529 100644 --- a/ports/stm32/boards/Passport/modules/flows/set_initial_pin_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/set_initial_pin_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # set_initial_pin_flow.py - Change the user's PIN diff --git a/ports/stm32/boards/Passport/modules/flows/show_security_words_setting_flow.py b/ports/stm32/boards/Passport/modules/flows/show_security_words_setting_flow.py index 05af4d681..20bbf34f0 100644 --- a/ports/stm32/boards/Passport/modules/flows/show_security_words_setting_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/show_security_words_setting_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # show_security_words_setting_flow.py - Choose to decide to show security words at login or not. diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py index 443c5396e..24401a902 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py index a515f044f..94b62248c 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # sign_psbt_microsd_flow.py - Sign a PSBT from a microSD card diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index 492353631..db42bc4d2 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # sign_psbt_qr_flow.py - Sign a PSBT from a microSD card 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 index 2ec56c10b..218179e48 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_text_file_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_text_file_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # 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. diff --git a/ports/stm32/boards/Passport/modules/flows/spin_delay_flow.py b/ports/stm32/boards/Passport/modules/flows/spin_delay_flow.py index aa0f636c4..493394b46 100644 --- a/ports/stm32/boards/Passport/modules/flows/spin_delay_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/spin_delay_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # spin_delay_flow.py - Show a spinner that will display until the given delay has expired. diff --git a/ports/stm32/boards/Passport/modules/flows/system_test_camera_flow.py b/ports/stm32/boards/Passport/modules/flows/system_test_camera_flow.py index 0f8fb3953..2565c49d7 100644 --- a/ports/stm32/boards/Passport/modules/flows/system_test_camera_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/system_test_camera_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # system_test_camera_flow.py - Scans a QR code with the camera and shows the data in it diff --git a/ports/stm32/boards/Passport/modules/flows/system_test_flow.py b/ports/stm32/boards/Passport/modules/flows/system_test_flow.py index c861ad311..46dc67bf5 100644 --- a/ports/stm32/boards/Passport/modules/flows/system_test_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/system_test_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # system_test_flow.py - Runs a suite of system test flows diff --git a/ports/stm32/boards/Passport/modules/flows/system_test_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/system_test_microsd_flow.py index 215dba465..768ce2866 100644 --- a/ports/stm32/boards/Passport/modules/flows/system_test_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/system_test_microsd_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # test_microsd_flow.py - Tests SD card by writing and reading a test file diff --git a/ports/stm32/boards/Passport/modules/flows/terms_of_use_flow.py b/ports/stm32/boards/Passport/modules/flows/terms_of_use_flow.py index 994d3a768..f3781c7f2 100644 --- a/ports/stm32/boards/Passport/modules/flows/terms_of_use_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/terms_of_use_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # terms_of_use_flow.py - Show the terms of use and get acceptance from user diff --git a/ports/stm32/boards/Passport/modules/flows/update_firmware_flow.py b/ports/stm32/boards/Passport/modules/flows/update_firmware_flow.py index 6fa3ce871..3cafaf29d 100644 --- a/ports/stm32/boards/Passport/modules/flows/update_firmware_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/update_firmware_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # update_firmware_flow.py - Flow to update firmware on Passport diff --git a/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py b/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py index 305801e65..da8bc6f38 100644 --- a/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/flows/verify_backup_flow.py b/ports/stm32/boards/Passport/modules/flows/verify_backup_flow.py index 3873f31bc..38f6f332f 100644 --- a/ports/stm32/boards/Passport/modules/flows/verify_backup_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/verify_backup_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # verify_backup_flow.py - Verify a selected backup file. diff --git a/ports/stm32/boards/Passport/modules/flows/view_backup_code_flow.py b/ports/stm32/boards/Passport/modules/flows/view_backup_code_flow.py index 897cad5d3..91e364e5f 100644 --- a/ports/stm32/boards/Passport/modules/flows/view_backup_code_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/view_backup_code_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # view_backup_code_flow.py - Confirm the user wants to see this sensitive info, then show it. diff --git a/ports/stm32/boards/Passport/modules/flows/view_current_firmware_flow.py b/ports/stm32/boards/Passport/modules/flows/view_current_firmware_flow.py index 040634e1b..16d24f12e 100644 --- a/ports/stm32/boards/Passport/modules/flows/view_current_firmware_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/view_current_firmware_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # view_current_firmware_flow.py - View the current firmware information diff --git a/ports/stm32/boards/Passport/modules/flows/view_dev_pubkey_flow.py b/ports/stm32/boards/Passport/modules/flows/view_dev_pubkey_flow.py index c2e142918..1ad698d52 100644 --- a/ports/stm32/boards/Passport/modules/flows/view_dev_pubkey_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/view_dev_pubkey_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # view_dev_pubkey_flow.py - Flow to show the developer pubkey to the user diff --git a/ports/stm32/boards/Passport/modules/flows/view_multisig_details_flow.py b/ports/stm32/boards/Passport/modules/flows/view_multisig_details_flow.py index decd80899..95b100123 100644 --- a/ports/stm32/boards/Passport/modules/flows/view_multisig_details_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/view_multisig_details_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # view_multisig_details_flow.py - Show user details of an existing wallet diff --git a/ports/stm32/boards/Passport/modules/flows/view_seed_words_flow.py b/ports/stm32/boards/Passport/modules/flows/view_seed_words_flow.py index 4a0017d2e..75fd3342b 100644 --- a/ports/stm32/boards/Passport/modules/flows/view_seed_words_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/view_seed_words_flow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # view_seed_words_flow.py - Confirm the user wants to see this sensitive info, then show it. diff --git a/ports/stm32/boards/Passport/modules/history.py b/ports/stm32/boards/Passport/modules/history.py index 5668da25c..0032a46c5 100644 --- a/ports/stm32/boards/Passport/modules/history.py +++ b/ports/stm32/boards/Passport/modules/history.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2020 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/keypad.py b/ports/stm32/boards/Passport/modules/keypad.py index 534cdb2a5..2b9f4a8ef 100644 --- a/ports/stm32/boards/Passport/modules/keypad.py +++ b/ports/stm32/boards/Passport/modules/keypad.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # keypad.py diff --git a/ports/stm32/boards/Passport/modules/keypad_manager.py b/ports/stm32/boards/Passport/modules/keypad_manager.py index 1884057fc..bbff7be81 100644 --- a/ports/stm32/boards/Passport/modules/keypad_manager.py +++ b/ports/stm32/boards/Passport/modules/keypad_manager.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # keypad_manager.py diff --git a/ports/stm32/boards/Passport/modules/keys.py b/ports/stm32/boards/Passport/modules/keys.py index 06e09066b..71dba5080 100644 --- a/ports/stm32/boards/Passport/modules/keys.py +++ b/ports/stm32/boards/Passport/modules/keys.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/main.py b/ports/stm32/boards/Passport/modules/main.py index 2f1bca49f..20b78595b 100644 --- a/ports/stm32/boards/Passport/modules/main.py +++ b/ports/stm32/boards/Passport/modules/main.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index 64a97683e..de492bf9b 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # menus.py - Menu configuration diff --git a/ports/stm32/boards/Passport/modules/microns/__init__.py b/ports/stm32/boards/Passport/modules/microns/__init__.py index aaca96456..217d6e758 100644 --- a/ports/stm32/boards/Passport/modules/microns/__init__.py +++ b/ports/stm32/boards/Passport/modules/microns/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/multisig_wallet.py b/ports/stm32/boards/Passport/modules/multisig_wallet.py index b25026074..23a028bd5 100644 --- a/ports/stm32/boards/Passport/modules/multisig_wallet.py +++ b/ports/stm32/boards/Passport/modules/multisig_wallet.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/opcodes.py b/ports/stm32/boards/Passport/modules/opcodes.py index 4865ecbfc..186ec30fc 100644 --- a/ports/stm32/boards/Passport/modules/opcodes.py +++ b/ports/stm32/boards/Passport/modules/opcodes.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/pages/__init__.py b/ports/stm32/boards/Passport/modules/pages/__init__.py index 3c7d0b44f..98beea4cc 100644 --- a/ports/stm32/boards/Passport/modules/pages/__init__.py +++ b/ports/stm32/boards/Passport/modules/pages/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/pages/accept_terms_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/accept_terms_chooser_page.py index 1c1a3e674..f9e99e552 100644 --- a/ports/stm32/boards/Passport/modules/pages/accept_terms_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/accept_terms_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # accept_terms_chooser_page.py - Chooser to accept terms or not. diff --git a/ports/stm32/boards/Passport/modules/pages/account_details_page.py b/ports/stm32/boards/Passport/modules/pages/account_details_page.py index c8a24438b..170df0650 100644 --- a/ports/stm32/boards/Passport/modules/pages/account_details_page.py +++ b/ports/stm32/boards/Passport/modules/pages/account_details_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # account_details_page.py - Show a page with information for the current account. diff --git a/ports/stm32/boards/Passport/modules/pages/address_type_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/address_type_chooser_page.py index 551a0df17..3eb91695b 100644 --- a/ports/stm32/boards/Passport/modules/pages/address_type_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/address_type_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # address_type_chooser_page.py - Chooser to select address type. diff --git a/ports/stm32/boards/Passport/modules/pages/auto_shutdown_setting_page.py b/ports/stm32/boards/Passport/modules/pages/auto_shutdown_setting_page.py index a3d8aae3c..cc324dca9 100644 --- a/ports/stm32/boards/Passport/modules/pages/auto_shutdown_setting_page.py +++ b/ports/stm32/boards/Passport/modules/pages/auto_shutdown_setting_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # auto_shutdown_setting_page.py - Set the auto-shutdown timeout diff --git a/ports/stm32/boards/Passport/modules/pages/backup_code_page.py b/ports/stm32/boards/Passport/modules/pages/backup_code_page.py index a1d09965f..301240fcd 100644 --- a/ports/stm32/boards/Passport/modules/pages/backup_code_page.py +++ b/ports/stm32/boards/Passport/modules/pages/backup_code_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # backup_code_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/battery_page.py b/ports/stm32/boards/Passport/modules/pages/battery_page.py index 39aa072f6..3b4d4f8a6 100644 --- a/ports/stm32/boards/Passport/modules/pages/battery_page.py +++ b/ports/stm32/boards/Passport/modules/pages/battery_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # info_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/brandmark_page.py b/ports/stm32/boards/Passport/modules/pages/brandmark_page.py index fa271a3fd..35ed21c2e 100644 --- a/ports/stm32/boards/Passport/modules/pages/brandmark_page.py +++ b/ports/stm32/boards/Passport/modules/pages/brandmark_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # brandmark_page.py - Show a message along with the Passport brandmark. diff --git a/ports/stm32/boards/Passport/modules/pages/brightness_setting_page.py b/ports/stm32/boards/Passport/modules/pages/brightness_setting_page.py index d881633cb..6ff429b48 100644 --- a/ports/stm32/boards/Passport/modules/pages/brightness_setting_page.py +++ b/ports/stm32/boards/Passport/modules/pages/brightness_setting_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # brightness_setting_page.py - Set the screen brightness and save it diff --git a/ports/stm32/boards/Passport/modules/pages/chain_setting_page.py b/ports/stm32/boards/Passport/modules/pages/chain_setting_page.py index 1ef3ced8d..9e5b0d26f 100644 --- a/ports/stm32/boards/Passport/modules/pages/chain_setting_page.py +++ b/ports/stm32/boards/Passport/modules/pages/chain_setting_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # chain_setting_page.py - Set the current chain to Bitcoin mainnet or testnet diff --git a/ports/stm32/boards/Passport/modules/pages/chooser_page.py b/ports/stm32/boards/Passport/modules/pages/chooser_page.py index 2ff4108b4..2c605a668 100644 --- a/ports/stm32/boards/Passport/modules/pages/chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # chooser_page.py - A page to let the user choose from a list of options. diff --git a/ports/stm32/boards/Passport/modules/pages/color_picker_page.py b/ports/stm32/boards/Passport/modules/pages/color_picker_page.py index 0c7be2ea7..9fba28ba6 100644 --- a/ports/stm32/boards/Passport/modules/pages/color_picker_page.py +++ b/ports/stm32/boards/Passport/modules/pages/color_picker_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # color_picker_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/error_page.py b/ports/stm32/boards/Passport/modules/pages/error_page.py index 64459d247..96e9c9695 100644 --- a/ports/stm32/boards/Passport/modules/pages/error_page.py +++ b/ports/stm32/boards/Passport/modules/pages/error_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # error_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/export_mode_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/export_mode_chooser_page.py index 09746cfe1..dfbedf2aa 100644 --- a/ports/stm32/boards/Passport/modules/pages/export_mode_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/export_mode_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # export_mode_chooser_page.py - Chooser to select export mode (e.g., QR vs. microSD) diff --git a/ports/stm32/boards/Passport/modules/pages/file_picker_page.py b/ports/stm32/boards/Passport/modules/pages/file_picker_page.py index bfbe0fe99..39fc7a90d 100644 --- a/ports/stm32/boards/Passport/modules/pages/file_picker_page.py +++ b/ports/stm32/boards/Passport/modules/pages/file_picker_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # file_picker_page.py - View to render a title and a list of files/folders. diff --git a/ports/stm32/boards/Passport/modules/pages/info_page.py b/ports/stm32/boards/Passport/modules/pages/info_page.py index 5c90d41e1..bec18ee7b 100644 --- a/ports/stm32/boards/Passport/modules/pages/info_page.py +++ b/ports/stm32/boards/Passport/modules/pages/info_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # info_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/insert_microsd_page.py b/ports/stm32/boards/Passport/modules/pages/insert_microsd_page.py index 185d3a504..393a29828 100644 --- a/ports/stm32/boards/Passport/modules/pages/insert_microsd_page.py +++ b/ports/stm32/boards/Passport/modules/pages/insert_microsd_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # insert_microsd_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/long_text_page.py b/ports/stm32/boards/Passport/modules/pages/long_text_page.py index 86d9bbc4a..da663eefd 100644 --- a/ports/stm32/boards/Passport/modules/pages/long_text_page.py +++ b/ports/stm32/boards/Passport/modules/pages/long_text_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # long_text_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/menu_page.py b/ports/stm32/boards/Passport/modules/pages/menu_page.py index 55a2a7d43..f805fc741 100644 --- a/ports/stm32/boards/Passport/modules/pages/menu_page.py +++ b/ports/stm32/boards/Passport/modules/pages/menu_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # menu_page.py - View to render a list of menu items diff --git a/ports/stm32/boards/Passport/modules/pages/multisig_policy_setting_page.py b/ports/stm32/boards/Passport/modules/pages/multisig_policy_setting_page.py index aef3d0046..beaeecc4e 100644 --- a/ports/stm32/boards/Passport/modules/pages/multisig_policy_setting_page.py +++ b/ports/stm32/boards/Passport/modules/pages/multisig_policy_setting_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # multisig_policy_setting_page.py - Set the multisig policy diff --git a/ports/stm32/boards/Passport/modules/pages/page.py b/ports/stm32/boards/Passport/modules/pages/page.py index b1449ebf4..452276dfc 100644 --- a/ports/stm32/boards/Passport/modules/pages/page.py +++ b/ports/stm32/boards/Passport/modules/pages/page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # page.py diff --git a/ports/stm32/boards/Passport/modules/pages/pin_entry_page.py b/ports/stm32/boards/Passport/modules/pages/pin_entry_page.py index 77c9fa373..60d29a711 100644 --- a/ports/stm32/boards/Passport/modules/pages/pin_entry_page.py +++ b/ports/stm32/boards/Passport/modules/pages/pin_entry_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # pin_entry_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/predictive_text_input_page.py b/ports/stm32/boards/Passport/modules/pages/predictive_text_input_page.py index c78db329b..609cd8122 100644 --- a/ports/stm32/boards/Passport/modules/pages/predictive_text_input_page.py +++ b/ports/stm32/boards/Passport/modules/pages/predictive_text_input_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # predictive_text_input_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/progress_page.py b/ports/stm32/boards/Passport/modules/pages/progress_page.py index a8406e89c..5efc83ddc 100644 --- a/ports/stm32/boards/Passport/modules/pages/progress_page.py +++ b/ports/stm32/boards/Passport/modules/pages/progress_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # spinner_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/question_page.py b/ports/stm32/boards/Passport/modules/pages/question_page.py index 72d7b81aa..b55aea892 100644 --- a/ports/stm32/boards/Passport/modules/pages/question_page.py +++ b/ports/stm32/boards/Passport/modules/pages/question_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # question_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/recovery_mode_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/recovery_mode_chooser_page.py index bf2a96be4..57431d5d9 100644 --- a/ports/stm32/boards/Passport/modules/pages/recovery_mode_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/recovery_mode_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # recovery_mode_chooser_page.py - Chooser to select the type of password for recovering a backup. diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index d76b835fe..b9155cdf9 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/pages/seed_length_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/seed_length_chooser_page.py index 363c447a4..4c5263dd3 100644 --- a/ports/stm32/boards/Passport/modules/pages/seed_length_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/seed_length_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # seed_length_chooser_page.py - Chooser to select seed length to restore/create. diff --git a/ports/stm32/boards/Passport/modules/pages/seed_words_list_page.py b/ports/stm32/boards/Passport/modules/pages/seed_words_list_page.py index 2a7435282..1f9707938 100644 --- a/ports/stm32/boards/Passport/modules/pages/seed_words_list_page.py +++ b/ports/stm32/boards/Passport/modules/pages/seed_words_list_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # account_details_page.py - Show a page with information for the current account. diff --git a/ports/stm32/boards/Passport/modules/pages/setting_page.py b/ports/stm32/boards/Passport/modules/pages/setting_page.py index b83126fa1..0ef094e2b 100644 --- a/ports/stm32/boards/Passport/modules/pages/setting_page.py +++ b/ports/stm32/boards/Passport/modules/pages/setting_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # setting_page.py - A ChooserPage that can get the current value from settings and save it to settings. diff --git a/ports/stm32/boards/Passport/modules/pages/setup_mode_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/setup_mode_chooser_page.py index 2f51070ed..b8d9adf88 100644 --- a/ports/stm32/boards/Passport/modules/pages/setup_mode_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/setup_mode_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # setup_mode_chooser_page.py - Chooser to select address type. diff --git a/ports/stm32/boards/Passport/modules/pages/shield_page.py b/ports/stm32/boards/Passport/modules/pages/shield_page.py index 974c100ff..dda274925 100644 --- a/ports/stm32/boards/Passport/modules/pages/shield_page.py +++ b/ports/stm32/boards/Passport/modules/pages/shield_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # info_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/show_qr_page.py b/ports/stm32/boards/Passport/modules/pages/show_qr_page.py index 0bcbbc83e..3eb81c842 100644 --- a/ports/stm32/boards/Passport/modules/pages/show_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/show_qr_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # show_qr_page.py - Show a QR code diff --git a/ports/stm32/boards/Passport/modules/pages/show_security_words_setting_page.py b/ports/stm32/boards/Passport/modules/pages/show_security_words_setting_page.py index 3ee06ea40..944c82084 100644 --- a/ports/stm32/boards/Passport/modules/pages/show_security_words_setting_page.py +++ b/ports/stm32/boards/Passport/modules/pages/show_security_words_setting_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # show_security_words_setting_page.py - Chooser to decide to show security words at login or not. diff --git a/ports/stm32/boards/Passport/modules/pages/shutdown_page.py b/ports/stm32/boards/Passport/modules/pages/shutdown_page.py index af08d46bc..810f00ea1 100644 --- a/ports/stm32/boards/Passport/modules/pages/shutdown_page.py +++ b/ports/stm32/boards/Passport/modules/pages/shutdown_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # shutdown_page.py - Ask user if they want to shutdown diff --git a/ports/stm32/boards/Passport/modules/pages/sig_type_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/sig_type_chooser_page.py index 64c8cb619..942b3a92e 100644 --- a/ports/stm32/boards/Passport/modules/pages/sig_type_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/sig_type_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # sig_type_chooser_page.py - Chooser to select signature type. diff --git a/ports/stm32/boards/Passport/modules/pages/singlesig_multisig_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/singlesig_multisig_chooser_page.py index 1d24dfc7a..458d90d69 100644 --- a/ports/stm32/boards/Passport/modules/pages/singlesig_multisig_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/singlesig_multisig_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # singlesig_multisig_chooser_page.py - Chooser to select singlesig or a specific multisig config diff --git a/ports/stm32/boards/Passport/modules/pages/spinner_page.py b/ports/stm32/boards/Passport/modules/pages/spinner_page.py index 3521e8049..e3ba7ab9f 100644 --- a/ports/stm32/boards/Passport/modules/pages/spinner_page.py +++ b/ports/stm32/boards/Passport/modules/pages/spinner_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # spinner_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/status_page.py b/ports/stm32/boards/Passport/modules/pages/status_page.py index c9dff4077..56657553e 100644 --- a/ports/stm32/boards/Passport/modules/pages/status_page.py +++ b/ports/stm32/boards/Passport/modules/pages/status_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # status_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/success_page.py b/ports/stm32/boards/Passport/modules/pages/success_page.py index 4a960e766..8d29c7621 100644 --- a/ports/stm32/boards/Passport/modules/pages/success_page.py +++ b/ports/stm32/boards/Passport/modules/pages/success_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # success_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/sw_wallet_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/sw_wallet_chooser_page.py index 457a54e8e..833c01dd5 100644 --- a/ports/stm32/boards/Passport/modules/pages/sw_wallet_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/sw_wallet_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # sw_wallet_chooser_page.py - Chooser to select a specific softwre wallet to which to connect diff --git a/ports/stm32/boards/Passport/modules/pages/test_keypad_page.py b/ports/stm32/boards/Passport/modules/pages/test_keypad_page.py index 92718d63c..180ba52c4 100644 --- a/ports/stm32/boards/Passport/modules/pages/test_keypad_page.py +++ b/ports/stm32/boards/Passport/modules/pages/test_keypad_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # test_keypad_page.py - tests keypad by showing pressed keys on the display diff --git a/ports/stm32/boards/Passport/modules/pages/text_input_page.py b/ports/stm32/boards/Passport/modules/pages/text_input_page.py index 9af18dff5..062951e63 100644 --- a/ports/stm32/boards/Passport/modules/pages/text_input_page.py +++ b/ports/stm32/boards/Passport/modules/pages/text_input_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # text_input_page.py diff --git a/ports/stm32/boards/Passport/modules/pages/units_setting_page.py b/ports/stm32/boards/Passport/modules/pages/units_setting_page.py index 9158c1786..a1266ae67 100644 --- a/ports/stm32/boards/Passport/modules/pages/units_setting_page.py +++ b/ports/stm32/boards/Passport/modules/pages/units_setting_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # units_setting_page.py - Set the current units (e.g., Sats/Bitcoin) based on the active chain diff --git a/ports/stm32/boards/Passport/modules/pages/yes_no_chooser_page.py b/ports/stm32/boards/Passport/modules/pages/yes_no_chooser_page.py index f27cf5c5d..93b151757 100644 --- a/ports/stm32/boards/Passport/modules/pages/yes_no_chooser_page.py +++ b/ports/stm32/boards/Passport/modules/pages/yes_no_chooser_page.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # yes_no_chooser_page.py - Chooser to select a yes or not response. diff --git a/ports/stm32/boards/Passport/modules/pincodes.py b/ports/stm32/boards/Passport/modules/pincodes.py index 032a54fa1..672807fcc 100644 --- a/ports/stm32/boards/Passport/modules/pincodes.py +++ b/ports/stm32/boards/Passport/modules/pincodes.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/predictive_utils.py b/ports/stm32/boards/Passport/modules/predictive_utils.py index 8a49471ba..80e5a31e2 100644 --- a/ports/stm32/boards/Passport/modules/predictive_utils.py +++ b/ports/stm32/boards/Passport/modules/predictive_utils.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # predictive_utils.py - Utility functions for working with BIP39 seed phrases and bytewords. diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index 968923797..050298181 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/public_constants.py b/ports/stm32/boards/Passport/modules/public_constants.py index 662af48f7..41de79281 100644 --- a/ports/stm32/boards/Passport/modules/public_constants.py +++ b/ports/stm32/boards/Passport/modules/public_constants.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/schema_evolution.py b/ports/stm32/boards/Passport/modules/schema_evolution.py index 2234185d1..359fcc392 100644 --- a/ports/stm32/boards/Passport/modules/schema_evolution.py +++ b/ports/stm32/boards/Passport/modules/schema_evolution.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # schema_evolution.py diff --git a/ports/stm32/boards/Passport/modules/screens/__init__.py b/ports/stm32/boards/Passport/modules/screens/__init__.py index 631de8795..5b045a346 100644 --- a/ports/stm32/boards/Passport/modules/screens/__init__.py +++ b/ports/stm32/boards/Passport/modules/screens/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/screens/main_screen.py b/ports/stm32/boards/Passport/modules/screens/main_screen.py index d766a77df..8832eb864 100644 --- a/ports/stm32/boards/Passport/modules/screens/main_screen.py +++ b/ports/stm32/boards/Passport/modules/screens/main_screen.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # main_screen.py - Main screen that shows the recolorable background image, and contains diff --git a/ports/stm32/boards/Passport/modules/se_commands.py b/ports/stm32/boards/Passport/modules/se_commands.py index a0866be7d..ce7f43006 100644 --- a/ports/stm32/boards/Passport/modules/se_commands.py +++ b/ports/stm32/boards/Passport/modules/se_commands.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # se_commands.py - Constants used to identify commands for Foundation.System.dispatch() diff --git a/ports/stm32/boards/Passport/modules/settings.py b/ports/stm32/boards/Passport/modules/settings.py index f70c2f97e..169f5c963 100644 --- a/ports/stm32/boards/Passport/modules/settings.py +++ b/ports/stm32/boards/Passport/modules/settings.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/sffile.py b/ports/stm32/boards/Passport/modules/sffile.py index 7fd3c543c..248ce05f4 100644 --- a/ports/stm32/boards/Passport/modules/sffile.py +++ b/ports/stm32/boards/Passport/modules/sffile.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/sflash.py b/ports/stm32/boards/Passport/modules/sflash.py index c22809d94..040c53c01 100644 --- a/ports/stm32/boards/Passport/modules/sflash.py +++ b/ports/stm32/boards/Passport/modules/sflash.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/stash.py b/ports/stm32/boards/Passport/modules/stash.py index 382b072fb..0f18fb98f 100644 --- a/ports/stm32/boards/Passport/modules/stash.py +++ b/ports/stm32/boards/Passport/modules/stash.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/styles/__init__.py b/ports/stm32/boards/Passport/modules/styles/__init__.py index 84440c3df..bbd9613fa 100644 --- a/ports/stm32/boards/Passport/modules/styles/__init__.py +++ b/ports/stm32/boards/Passport/modules/styles/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/styles/colors.py b/ports/stm32/boards/Passport/modules/styles/colors.py index 7a5b655af..2c70c0fff 100644 --- a/ports/stm32/boards/Passport/modules/styles/colors.py +++ b/ports/stm32/boards/Passport/modules/styles/colors.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # colors.py diff --git a/ports/stm32/boards/Passport/modules/styles/font_sizes.py b/ports/stm32/boards/Passport/modules/styles/font_sizes.py index 729a0da2a..55ef9c2e6 100644 --- a/ports/stm32/boards/Passport/modules/styles/font_sizes.py +++ b/ports/stm32/boards/Passport/modules/styles/font_sizes.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/styles/local_style.py b/ports/stm32/boards/Passport/modules/styles/local_style.py index 30d865a3d..b1f0055e4 100644 --- a/ports/stm32/boards/Passport/modules/styles/local_style.py +++ b/ports/stm32/boards/Passport/modules/styles/local_style.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # local_style.py diff --git a/ports/stm32/boards/Passport/modules/styles/style.py b/ports/stm32/boards/Passport/modules/styles/style.py index 59f6a496b..11859767c 100644 --- a/ports/stm32/boards/Passport/modules/styles/style.py +++ b/ports/stm32/boards/Passport/modules/styles/style.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/system_test_ux.py b/ports/stm32/boards/Passport/modules/system_test_ux.py index c0619cadf..c726ccaa4 100644 --- a/ports/stm32/boards/Passport/modules/system_test_ux.py +++ b/ports/stm32/boards/Passport/modules/system_test_ux.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # system_test_ux.py - Self test UX diff --git a/ports/stm32/boards/Passport/modules/t9.py b/ports/stm32/boards/Passport/modules/t9.py index 5e6bc6db5..272da07e2 100644 --- a/ports/stm32/boards/Passport/modules/t9.py +++ b/ports/stm32/boards/Passport/modules/t9.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # t9.py - A T9-style text input mechanism, but with no word prediction. diff --git a/ports/stm32/boards/Passport/modules/tasks/__init__.py b/ports/stm32/boards/Passport/modules/tasks/__init__.py index 7c90c69c3..e1800803b 100644 --- a/ports/stm32/boards/Passport/modules/tasks/__init__.py +++ b/ports/stm32/boards/Passport/modules/tasks/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tasks/apply_passphrase_task.py b/ports/stm32/boards/Passport/modules/tasks/apply_passphrase_task.py index 0d54f9600..c9b67d382 100644 --- a/ports/stm32/boards/Passport/modules/tasks/apply_passphrase_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/apply_passphrase_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/auto_shutdown_task.py b/ports/stm32/boards/Passport/modules/tasks/auto_shutdown_task.py index e552ca549..557fc8769 100644 --- a/ports/stm32/boards/Passport/modules/tasks/auto_shutdown_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/auto_shutdown_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # auto_shutdown_task.py diff --git a/ports/stm32/boards/Passport/modules/tasks/calculate_file_sha256_task.py b/ports/stm32/boards/Passport/modules/tasks/calculate_file_sha256_task.py index 5ea6f3bae..5f7d840c9 100644 --- a/ports/stm32/boards/Passport/modules/tasks/calculate_file_sha256_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/calculate_file_sha256_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/card_task.py b/ports/stm32/boards/Passport/modules/tasks/card_task.py index dfa308489..c981fde1a 100644 --- a/ports/stm32/boards/Passport/modules/tasks/card_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/card_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # card_task.py - Task for handling card flows diff --git a/ports/stm32/boards/Passport/modules/tasks/change_pin_task.py b/ports/stm32/boards/Passport/modules/tasks/change_pin_task.py index 4eb0d6f17..07ef6ce1f 100644 --- a/ports/stm32/boards/Passport/modules/tasks/change_pin_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/change_pin_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/charge_monitor_task.py b/ports/stm32/boards/Passport/modules/tasks/charge_monitor_task.py index a5cee8fc5..299f1c28a 100644 --- a/ports/stm32/boards/Passport/modules/tasks/charge_monitor_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/charge_monitor_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # charge_monitor_task.py - Updates the UI when charging cable is plugged or unplugged. diff --git a/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py index 734f09b8d..e4f96f1e9 100644 --- a/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/clear_psbt_from_external_flash_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_firmware_to_spi_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_firmware_to_spi_flash_task.py index b3afa9abf..c9fcc8da9 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_firmware_to_spi_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_firmware_to_spi_flash_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py index a4add503b..819aec900 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py index 3c558c28c..06273b854 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/create_wallet_export_task.py b/ports/stm32/boards/Passport/modules/tasks/create_wallet_export_task.py index ef953f8a2..0346caec4 100644 --- a/ports/stm32/boards/Passport/modules/tasks/create_wallet_export_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/create_wallet_export_task.py @@ -1,5 +1,5 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # create_wallet_export_task.py - Run the function that will generate the wallet export data diff --git a/ports/stm32/boards/Passport/modules/tasks/delay_task.py b/ports/stm32/boards/Passport/modules/tasks/delay_task.py index 7266418aa..30270626b 100644 --- a/ports/stm32/boards/Passport/modules/tasks/delay_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/delay_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # delay_task.py - Task to wait a specific amount of time diff --git a/ports/stm32/boards/Passport/modules/tasks/delete_account_task.py b/ports/stm32/boards/Passport/modules/tasks/delete_account_task.py index d38a93172..8e7869598 100644 --- a/ports/stm32/boards/Passport/modules/tasks/delete_account_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/delete_account_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # delete_account_task.py - Task to delete an account diff --git a/ports/stm32/boards/Passport/modules/tasks/delete_multisig_task.py b/ports/stm32/boards/Passport/modules/tasks/delete_multisig_task.py index 1c33012c2..4c10f8967 100644 --- a/ports/stm32/boards/Passport/modules/tasks/delete_multisig_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/delete_multisig_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/double_check_psbt_change_task.py b/ports/stm32/boards/Passport/modules/tasks/double_check_psbt_change_task.py index 17d934789..343c71d23 100644 --- a/ports/stm32/boards/Passport/modules/tasks/double_check_psbt_change_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/double_check_psbt_change_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/erase_passport_task.py b/ports/stm32/boards/Passport/modules/tasks/erase_passport_task.py index f4423f597..4a5df1029 100644 --- a/ports/stm32/boards/Passport/modules/tasks/erase_passport_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/erase_passport_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/export_summary_task.py b/ports/stm32/boards/Passport/modules/tasks/export_summary_task.py index 88fbcaafc..2df90f298 100644 --- a/ports/stm32/boards/Passport/modules/tasks/export_summary_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/export_summary_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/fcc_copy_files_task.py b/ports/stm32/boards/Passport/modules/tasks/fcc_copy_files_task.py index a68f29f3a..13b99d000 100644 --- a/ports/stm32/boards/Passport/modules/tasks/fcc_copy_files_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/fcc_copy_files_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # fcc_copy_files_task.py - Task to perform the copy from microSD to flash and back. diff --git a/ports/stm32/boards/Passport/modules/tasks/format_microsd_task.py b/ports/stm32/boards/Passport/modules/tasks/format_microsd_task.py index 06816b3fb..752a9b6a8 100644 --- a/ports/stm32/boards/Passport/modules/tasks/format_microsd_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/format_microsd_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/fuelgauge_task.py b/ports/stm32/boards/Passport/modules/tasks/fuelgauge_task.py index 63be78bd0..45dae74e8 100644 --- a/ports/stm32/boards/Passport/modules/tasks/fuelgauge_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/fuelgauge_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # fuelgauge_task.py - Task for updating the battery level in the UI by reading the fuel gauge diff --git a/ports/stm32/boards/Passport/modules/tasks/generate_addresses_task.py b/ports/stm32/boards/Passport/modules/tasks/generate_addresses_task.py index 99669542e..93c0abb46 100644 --- a/ports/stm32/boards/Passport/modules/tasks/generate_addresses_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/generate_addresses_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/get_backup_code_task.py b/ports/stm32/boards/Passport/modules/tasks/get_backup_code_task.py index 5ba52c453..7c584787d 100644 --- a/ports/stm32/boards/Passport/modules/tasks/get_backup_code_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/get_backup_code_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # get_backup_code_task.py - Task to get the backup code for the current device/wallet. diff --git a/ports/stm32/boards/Passport/modules/tasks/get_security_words_task.py b/ports/stm32/boards/Passport/modules/tasks/get_security_words_task.py index 665fc3b0a..3474a3140 100644 --- a/ports/stm32/boards/Passport/modules/tasks/get_security_words_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/get_security_words_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # get_security_words_task.py - Task to get the security words associated with a given PIN attempt. diff --git a/ports/stm32/boards/Passport/modules/tasks/get_seed_words_task.py b/ports/stm32/boards/Passport/modules/tasks/get_seed_words_task.py index 09acbaae4..c6528bcfe 100644 --- a/ports/stm32/boards/Passport/modules/tasks/get_seed_words_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/get_seed_words_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # get_seed_words_task.py - Task to get the seed words of the current wallet. diff --git a/ports/stm32/boards/Passport/modules/tasks/login_task.py b/ports/stm32/boards/Passport/modules/tasks/login_task.py index f0072c714..486ce1cda 100644 --- a/ports/stm32/boards/Passport/modules/tasks/login_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/login_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/lvgl_task.py b/ports/stm32/boards/Passport/modules/tasks/lvgl_task.py index d76282ad7..f650407ee 100644 --- a/ports/stm32/boards/Passport/modules/tasks/lvgl_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/lvgl_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # lvgl_task.py - Main LVGL loop diff --git a/ports/stm32/boards/Passport/modules/tasks/main_task.py b/ports/stm32/boards/Passport/modules/tasks/main_task.py index 0e2ad6d16..4b1d9b4fd 100644 --- a/ports/stm32/boards/Passport/modules/tasks/main_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/main_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # main_task.py - Run the main UI from startup based on device state diff --git a/ports/stm32/boards/Passport/modules/tasks/make_microsd_file_system_task.py b/ports/stm32/boards/Passport/modules/tasks/make_microsd_file_system_task.py index dd4282030..784729a23 100644 --- a/ports/stm32/boards/Passport/modules/tasks/make_microsd_file_system_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/make_microsd_file_system_task.py @@ -1,5 +1,5 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/new_seed_task.py b/ports/stm32/boards/Passport/modules/tasks/new_seed_task.py index 8c86e56d9..9effd5e1e 100644 --- a/ports/stm32/boards/Passport/modules/tasks/new_seed_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/new_seed_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # new_seed_task.py - Task to create a new random seed diff --git a/ports/stm32/boards/Passport/modules/tasks/power_button_task.py b/ports/stm32/boards/Passport/modules/tasks/power_button_task.py index 3cf51d5ca..2b3d5b179 100644 --- a/ports/stm32/boards/Passport/modules/tasks/power_button_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/power_button_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # power_button_task.py - Monitors the power button and asks the user if they want to shutdown when pressed diff --git a/ports/stm32/boards/Passport/modules/tasks/read_file_task.py b/ports/stm32/boards/Passport/modules/tasks/read_file_task.py index cbcdb0238..b0b2c0f40 100644 --- a/ports/stm32/boards/Passport/modules/tasks/read_file_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/read_file_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # read_file_task.py - Write data to microSD card at the given path. diff --git a/ports/stm32/boards/Passport/modules/tasks/rename_account_task.py b/ports/stm32/boards/Passport/modules/tasks/rename_account_task.py index 844200ac0..f84d43181 100644 --- a/ports/stm32/boards/Passport/modules/tasks/rename_account_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/rename_account_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # rename_account_task.py - Task to rename and save an account diff --git a/ports/stm32/boards/Passport/modules/tasks/rename_multisig_task.py b/ports/stm32/boards/Passport/modules/tasks/rename_multisig_task.py index f6f6a5d26..9d1960321 100644 --- a/ports/stm32/boards/Passport/modules/tasks/rename_multisig_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/rename_multisig_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/restore_backup_task.py b/ports/stm32/boards/Passport/modules/tasks/restore_backup_task.py index 9dcb489d1..73ce63f29 100644 --- a/ports/stm32/boards/Passport/modules/tasks/restore_backup_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/restore_backup_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/save_backup_task.py b/ports/stm32/boards/Passport/modules/tasks/save_backup_task.py index 5f5c1b41c..eef2e497b 100644 --- a/ports/stm32/boards/Passport/modules/tasks/save_backup_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/save_backup_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/save_multisig_wallet_task.py b/ports/stm32/boards/Passport/modules/tasks/save_multisig_wallet_task.py index 290357920..2337bf2e7 100644 --- a/ports/stm32/boards/Passport/modules/tasks/save_multisig_wallet_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/save_multisig_wallet_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/save_new_account_task.py b/ports/stm32/boards/Passport/modules/tasks/save_new_account_task.py index 4dcf0adb6..2c21a45cd 100644 --- a/ports/stm32/boards/Passport/modules/tasks/save_new_account_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/save_new_account_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # save_new_account_task.py - Task to save a new account diff --git a/ports/stm32/boards/Passport/modules/tasks/save_seed_task.py b/ports/stm32/boards/Passport/modules/tasks/save_seed_task.py index c63e28806..52b55e5e4 100644 --- a/ports/stm32/boards/Passport/modules/tasks/save_seed_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/save_seed_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/save_wallet_export_to_microsd_task.py b/ports/stm32/boards/Passport/modules/tasks/save_wallet_export_to_microsd_task.py index 21dd7c719..c897a2fe0 100644 --- a/ports/stm32/boards/Passport/modules/tasks/save_wallet_export_to_microsd_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/save_wallet_export_to_microsd_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # save_wallet_export_to_microsd_task.py - Task to save the given wallet data to microsd diff --git a/ports/stm32/boards/Passport/modules/tasks/search_for_address_task.py b/ports/stm32/boards/Passport/modules/tasks/search_for_address_task.py index b273630dd..b8c813041 100644 --- a/ports/stm32/boards/Passport/modules/tasks/search_for_address_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/search_for_address_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/set_initial_pin_task.py b/ports/stm32/boards/Passport/modules/tasks/set_initial_pin_task.py index 5e67d424f..f3b9516a0 100644 --- a/ports/stm32/boards/Passport/modules/tasks/set_initial_pin_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/set_initial_pin_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/sign_psbt_task.py b/ports/stm32/boards/Passport/modules/tasks/sign_psbt_task.py index 560f7e0f6..bc2df0856 100644 --- a/ports/stm32/boards/Passport/modules/tasks/sign_psbt_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/sign_psbt_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/sign_text_file_task.py b/ports/stm32/boards/Passport/modules/tasks/sign_text_file_task.py index df1198901..d1f69e92c 100644 --- a/ports/stm32/boards/Passport/modules/tasks/sign_text_file_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/sign_text_file_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/validate_psbt_task.py b/ports/stm32/boards/Passport/modules/tasks/validate_psbt_task.py index 5d81976e3..24345180f 100644 --- a/ports/stm32/boards/Passport/modules/tasks/validate_psbt_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/validate_psbt_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/verify_backup_task.py b/ports/stm32/boards/Passport/modules/tasks/verify_backup_task.py index a5fe5a0c4..08a1070e5 100644 --- a/ports/stm32/boards/Passport/modules/tasks/verify_backup_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/verify_backup_task.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tasks/write_data_to_file_task.py b/ports/stm32/boards/Passport/modules/tasks/write_data_to_file_task.py index 635a045d5..7c92693a4 100644 --- a/ports/stm32/boards/Passport/modules/tasks/write_data_to_file_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/write_data_to_file_task.py @@ -1,5 +1,5 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/tests/conftest.py b/ports/stm32/boards/Passport/modules/tests/conftest.py index 6a76af5dd..f0f2426f0 100644 --- a/ports/stm32/boards/Passport/modules/tests/conftest.py +++ b/ports/stm32/boards/Passport/modules/tests/conftest.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/fixtures/simulator.py b/ports/stm32/boards/Passport/modules/tests/fixtures/simulator.py index d843ce664..f6c559e04 100644 --- a/ports/stm32/boards/Passport/modules/tests/fixtures/simulator.py +++ b/ports/stm32/boards/Passport/modules/tests/fixtures/simulator.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modules/tests/micropython.py b/ports/stm32/boards/Passport/modules/tests/micropython.py index d11dc31fc..a21d06d35 100644 --- a/ports/stm32/boards/Passport/modules/tests/micropython.py +++ b/ports/stm32/boards/Passport/modules/tests/micropython.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/test_enum.py b/ports/stm32/boards/Passport/modules/tests/test_enum.py index adf057139..a8a78773f 100644 --- a/ports/stm32/boards/Passport/modules/tests/test_enum.py +++ b/ports/stm32/boards/Passport/modules/tests/test_enum.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/test_sflash.py b/ports/stm32/boards/Passport/modules/tests/test_sflash.py index 991fbd646..98e1b48d8 100644 --- a/ports/stm32/boards/Passport/modules/tests/test_sflash.py +++ b/ports/stm32/boards/Passport/modules/tests/test_sflash.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/test_translations.py b/ports/stm32/boards/Passport/modules/tests/test_translations.py index 002d0f895..35320c80d 100644 --- a/ports/stm32/boards/Passport/modules/tests/test_translations.py +++ b/ports/stm32/boards/Passport/modules/tests/test_translations.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/test_unit.py b/ports/stm32/boards/Passport/modules/tests/test_unit.py index 7dd740f59..953b94ae5 100644 --- a/ports/stm32/boards/Passport/modules/tests/test_unit.py +++ b/ports/stm32/boards/Passport/modules/tests/test_unit.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/test_version.py b/ports/stm32/boards/Passport/modules/tests/test_version.py index 58228d8f0..5593452f9 100644 --- a/ports/stm32/boards/Passport/modules/tests/test_version.py +++ b/ports/stm32/boards/Passport/modules/tests/test_version.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/unit/ext_settings.py b/ports/stm32/boards/Passport/modules/tests/unit/ext_settings.py index eb823cdd1..fbbd9c62b 100644 --- a/ports/stm32/boards/Passport/modules/tests/unit/ext_settings.py +++ b/ports/stm32/boards/Passport/modules/tests/unit/ext_settings.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/unit/foundation.py b/ports/stm32/boards/Passport/modules/tests/unit/foundation.py index d6997bc1e..1a776109d 100644 --- a/ports/stm32/boards/Passport/modules/tests/unit/foundation.py +++ b/ports/stm32/boards/Passport/modules/tests/unit/foundation.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/tests/unit/ui.py b/ports/stm32/boards/Passport/modules/tests/unit/ui.py index 193731682..b635be7bf 100644 --- a/ports/stm32/boards/Passport/modules/tests/unit/ui.py +++ b/ports/stm32/boards/Passport/modules/tests/unit/ui.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/translations/__init__.py b/ports/stm32/boards/Passport/modules/translations/__init__.py index 12a8fdf60..6d365b57d 100644 --- a/ports/stm32/boards/Passport/modules/translations/__init__.py +++ b/ports/stm32/boards/Passport/modules/translations/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/translations/en.py b/ports/stm32/boards/Passport/modules/translations/en.py index 24b324a39..e51111605 100644 --- a/ports/stm32/boards/Passport/modules/translations/en.py +++ b/ports/stm32/boards/Passport/modules/translations/en.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # en.py - String translations for EN language code diff --git a/ports/stm32/boards/Passport/modules/translations/tags.py b/ports/stm32/boards/Passport/modules/translations/tags.py index 1d84a619f..b1caa8e0f 100644 --- a/ports/stm32/boards/Passport/modules/translations/tags.py +++ b/ports/stm32/boards/Passport/modules/translations/tags.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # tags.py diff --git a/ports/stm32/boards/Passport/modules/ui/__init__.py b/ports/stm32/boards/Passport/modules/ui/__init__.py index ea5de2059..23e417386 100644 --- a/ports/stm32/boards/Passport/modules/ui/__init__.py +++ b/ports/stm32/boards/Passport/modules/ui/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/ui/ui.py b/ports/stm32/boards/Passport/modules/ui/ui.py index a5f798a7d..b9a5979c2 100644 --- a/ports/stm32/boards/Passport/modules/ui/ui.py +++ b/ports/stm32/boards/Passport/modules/ui/ui.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # ui.py - High-level UI interface diff --git a/ports/stm32/boards/Passport/modules/ur1/bc32.py b/ports/stm32/boards/Passport/modules/ur1/bc32.py index db8f09ce6..0914d9842 100644 --- a/ports/stm32/boards/Passport/modules/ur1/bc32.py +++ b/ports/stm32/boards/Passport/modules/ur1/bc32.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # from .bech32 import encode, decode diff --git a/ports/stm32/boards/Passport/modules/ur1/bech32.py b/ports/stm32/boards/Passport/modules/ur1/bech32.py index 8b289ac72..cb55246f4 100644 --- a/ports/stm32/boards/Passport/modules/ur1/bech32.py +++ b/ports/stm32/boards/Passport/modules/ur1/bech32.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # from .bech32_version import Bech32_Version_Origin, Bech32_Version_Bis diff --git a/ports/stm32/boards/Passport/modules/ur1/bech32_version.py b/ports/stm32/boards/Passport/modules/ur1/bech32_version.py index 3cb97decd..98b0abe22 100644 --- a/ports/stm32/boards/Passport/modules/ur1/bech32_version.py +++ b/ports/stm32/boards/Passport/modules/ur1/bech32_version.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/ur1/decode_ur.py b/ports/stm32/boards/Passport/modules/ur1/decode_ur.py index 8daf6f0d1..16c727216 100644 --- a/ports/stm32/boards/Passport/modules/ur1/decode_ur.py +++ b/ports/stm32/boards/Passport/modules/ur1/decode_ur.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # from .mini_cbor import decode_simple_cbor diff --git a/ports/stm32/boards/Passport/modules/ur1/encode_ur.py b/ports/stm32/boards/Passport/modules/ur1/encode_ur.py index 1b821a367..2f707365b 100644 --- a/ports/stm32/boards/Passport/modules/ur1/encode_ur.py +++ b/ports/stm32/boards/Passport/modules/ur1/encode_ur.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # from .mini_cbor import encode_simple_cbor diff --git a/ports/stm32/boards/Passport/modules/ur1/mini_cbor.py b/ports/stm32/boards/Passport/modules/ur1/mini_cbor.py index ca3883567..095beccea 100644 --- a/ports/stm32/boards/Passport/modules/ur1/mini_cbor.py +++ b/ports/stm32/boards/Passport/modules/ur1/mini_cbor.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # from ubinascii import hexlify diff --git a/ports/stm32/boards/Passport/modules/ur1/utils.py b/ports/stm32/boards/Passport/modules/ur1/utils.py index ffe155346..ba1484e9c 100644 --- a/ports/stm32/boards/Passport/modules/ur1/utils.py +++ b/ports/stm32/boards/Passport/modules/ur1/utils.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/ur2/__init__.py b/ports/stm32/boards/Passport/modules/ur2/__init__.py index 3574f74bf..073546ac4 100644 --- a/ports/stm32/boards/Passport/modules/ur2/__init__.py +++ b/ports/stm32/boards/Passport/modules/ur2/__init__.py @@ -1,3 +1,3 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # diff --git a/ports/stm32/boards/Passport/modules/ur2/bytewords.py b/ports/stm32/boards/Passport/modules/ur2/bytewords.py index a4f3bf317..c3a3a42be 100644 --- a/ports/stm32/boards/Passport/modules/ur2/bytewords.py +++ b/ports/stm32/boards/Passport/modules/ur2/bytewords.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # bytewords.py diff --git a/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py b/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py index 901e386fa..7caf9c2b6 100644 --- a/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py +++ b/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # cbor_lite.py diff --git a/ports/stm32/boards/Passport/modules/ur2/constants.py b/ports/stm32/boards/Passport/modules/ur2/constants.py index 4cf07056c..b5c49eb4a 100644 --- a/ports/stm32/boards/Passport/modules/ur2/constants.py +++ b/ports/stm32/boards/Passport/modules/ur2/constants.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # constants.py diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py index 35849570a..bcb204a85 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # fountain_decoder.py diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py index a20fbbbd5..e782cf403 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # fountain_encoder.py diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_utils.py b/ports/stm32/boards/Passport/modules/ur2/fountain_utils.py index 7cd1b0ebf..3826ab796 100644 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_utils.py +++ b/ports/stm32/boards/Passport/modules/ur2/fountain_utils.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # fountain_utils.py diff --git a/ports/stm32/boards/Passport/modules/ur2/random_sampler.py b/ports/stm32/boards/Passport/modules/ur2/random_sampler.py index 3a6323ff7..0c3999b27 100644 --- a/ports/stm32/boards/Passport/modules/ur2/random_sampler.py +++ b/ports/stm32/boards/Passport/modules/ur2/random_sampler.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # random_sampler.py diff --git a/ports/stm32/boards/Passport/modules/ur2/ur.py b/ports/stm32/boards/Passport/modules/ur2/ur.py index b4d769e5d..43869ece7 100644 --- a/ports/stm32/boards/Passport/modules/ur2/ur.py +++ b/ports/stm32/boards/Passport/modules/ur2/ur.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # ur.py diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py index 47f2ca529..64ce50c25 100644 --- a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # ur_decoder.py diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py index abb6d3433..5cb1a8caa 100644 --- a/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py +++ b/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # ur_encoder.py diff --git a/ports/stm32/boards/Passport/modules/ur2/utils.py b/ports/stm32/boards/Passport/modules/ur2/utils.py index 6969e4a82..0c9672c03 100644 --- a/ports/stm32/boards/Passport/modules/ur2/utils.py +++ b/ports/stm32/boards/Passport/modules/ur2/utils.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # utils.py diff --git a/ports/stm32/boards/Passport/modules/ur2/xoshiro256.py b/ports/stm32/boards/Passport/modules/ur2/xoshiro256.py index 64f2ebd7d..10ffce6ca 100644 --- a/ports/stm32/boards/Passport/modules/ur2/xoshiro256.py +++ b/ports/stm32/boards/Passport/modules/ur2/xoshiro256.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: BSD-2-Clause-Patent # # xoshiro256.py diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 6ad6ef21e..5904e15dc 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/version.py b/ports/stm32/boards/Passport/modules/version.py index b52c6e873..13e36c306 100644 --- a/ports/stm32/boards/Passport/modules/version.py +++ b/ports/stm32/boards/Passport/modules/version.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # version.py - Compare simple version numbers diff --git a/ports/stm32/boards/Passport/modules/views/__init__.py b/ports/stm32/boards/Passport/modules/views/__init__.py index 9b18938f3..f9932094d 100644 --- a/ports/stm32/boards/Passport/modules/views/__init__.py +++ b/ports/stm32/boards/Passport/modules/views/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py diff --git a/ports/stm32/boards/Passport/modules/views/arc.py b/ports/stm32/boards/Passport/modules/views/arc.py index 4c40e95eb..481067b83 100644 --- a/ports/stm32/boards/Passport/modules/views/arc.py +++ b/ports/stm32/boards/Passport/modules/views/arc.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # arc.py - Wrapper around lv.arc diff --git a/ports/stm32/boards/Passport/modules/views/backup_code_section.py b/ports/stm32/boards/Passport/modules/views/backup_code_section.py index e97976d76..2bdb33503 100644 --- a/ports/stm32/boards/Passport/modules/views/backup_code_section.py +++ b/ports/stm32/boards/Passport/modules/views/backup_code_section.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # backup_code_section.py diff --git a/ports/stm32/boards/Passport/modules/views/battery_indicator.py b/ports/stm32/boards/Passport/modules/views/battery_indicator.py index 98fa4db35..561a2d4e9 100644 --- a/ports/stm32/boards/Passport/modules/views/battery_indicator.py +++ b/ports/stm32/boards/Passport/modules/views/battery_indicator.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # battery_indicator.py - Render the battery icon with a fill corresponding to the current state of charge diff --git a/ports/stm32/boards/Passport/modules/views/bold_label.py b/ports/stm32/boards/Passport/modules/views/bold_label.py index 36f910acb..db8fa1fab 100644 --- a/ports/stm32/boards/Passport/modules/views/bold_label.py +++ b/ports/stm32/boards/Passport/modules/views/bold_label.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # bold_label.py - Bold label (drawn twice with offsets)) diff --git a/ports/stm32/boards/Passport/modules/views/button.py b/ports/stm32/boards/Passport/modules/views/button.py index a73bbe90a..df83da2a9 100644 --- a/ports/stm32/boards/Passport/modules/views/button.py +++ b/ports/stm32/boards/Passport/modules/views/button.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # button.py - Basic button diff --git a/ports/stm32/boards/Passport/modules/views/camera.py b/ports/stm32/boards/Passport/modules/views/camera.py index 9606f7b04..4c0b4e892 100644 --- a/ports/stm32/boards/Passport/modules/views/camera.py +++ b/ports/stm32/boards/Passport/modules/views/camera.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # camera.py diff --git a/ports/stm32/boards/Passport/modules/views/card.py b/ports/stm32/boards/Passport/modules/views/card.py index 7ab1488c0..c6a7bf3f4 100644 --- a/ports/stm32/boards/Passport/modules/views/card.py +++ b/ports/stm32/boards/Passport/modules/views/card.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # card.py - Card header and card content - Custom content and header title and icon can be passed in diff --git a/ports/stm32/boards/Passport/modules/views/card_nav.py b/ports/stm32/boards/Passport/modules/views/card_nav.py index c812b3ef0..3a65bc0bb 100644 --- a/ports/stm32/boards/Passport/modules/views/card_nav.py +++ b/ports/stm32/boards/Passport/modules/views/card_nav.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # card_nav.py - Top-level, card-based navigation. Cards animate left/right as they are shown/hidden. diff --git a/ports/stm32/boards/Passport/modules/views/color_picker.py b/ports/stm32/boards/Passport/modules/views/color_picker.py index 4c1055d98..30c927ad8 100644 --- a/ports/stm32/boards/Passport/modules/views/color_picker.py +++ b/ports/stm32/boards/Passport/modules/views/color_picker.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # color_picker.py -RGB color picker for RGB565 colors diff --git a/ports/stm32/boards/Passport/modules/views/container.py b/ports/stm32/boards/Passport/modules/views/container.py index fc2e2660e..051586fc2 100644 --- a/ports/stm32/boards/Passport/modules/views/container.py +++ b/ports/stm32/boards/Passport/modules/views/container.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # container.py - Default widget with some LVGL styles applied. Used mainly as the root container for View subclasses. diff --git a/ports/stm32/boards/Passport/modules/views/file_item.py b/ports/stm32/boards/Passport/modules/views/file_item.py index 61c804910..0e0fe4fc9 100644 --- a/ports/stm32/boards/Passport/modules/views/file_item.py +++ b/ports/stm32/boards/Passport/modules/views/file_item.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # file_item.py - Render a file item string, and an icon to indicate if that item is selected diff --git a/ports/stm32/boards/Passport/modules/views/filler.py b/ports/stm32/boards/Passport/modules/views/filler.py index b319912af..0fed14d77 100644 --- a/ports/stm32/boards/Passport/modules/views/filler.py +++ b/ports/stm32/boards/Passport/modules/views/filler.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # filler.py - A transparent container that fills in space in a flex layout diff --git a/ports/stm32/boards/Passport/modules/views/icon.py b/ports/stm32/boards/Passport/modules/views/icon.py index 802316c72..685b5a785 100644 --- a/ports/stm32/boards/Passport/modules/views/icon.py +++ b/ports/stm32/boards/Passport/modules/views/icon.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # icon.py - A recolorable icon view diff --git a/ports/stm32/boards/Passport/modules/views/icon_button.py b/ports/stm32/boards/Passport/modules/views/icon_button.py index 27c8f5159..4c7127476 100644 --- a/ports/stm32/boards/Passport/modules/views/icon_button.py +++ b/ports/stm32/boards/Passport/modules/views/icon_button.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # icon_button.py - A recolorable icon view diff --git a/ports/stm32/boards/Passport/modules/views/image.py b/ports/stm32/boards/Passport/modules/views/image.py index ae2096eb2..d2c2c6e86 100644 --- a/ports/stm32/boards/Passport/modules/views/image.py +++ b/ports/stm32/boards/Passport/modules/views/image.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # image.py - A simple, recolorable image component diff --git a/ports/stm32/boards/Passport/modules/views/keyboard.py b/ports/stm32/boards/Passport/modules/views/keyboard.py index e22399075..7d0b2f76f 100644 --- a/ports/stm32/boards/Passport/modules/views/keyboard.py +++ b/ports/stm32/boards/Passport/modules/views/keyboard.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # keyboard.py - Wrapper for the lvgl keyboard widget diff --git a/ports/stm32/boards/Passport/modules/views/keypad.py b/ports/stm32/boards/Passport/modules/views/keypad.py index a5fda3c0a..a00b5f9fa 100644 --- a/ports/stm32/boards/Passport/modules/views/keypad.py +++ b/ports/stm32/boards/Passport/modules/views/keypad.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/modules/views/label.py b/ports/stm32/boards/Passport/modules/views/label.py index cdbd97414..c6ff8028d 100644 --- a/ports/stm32/boards/Passport/modules/views/label.py +++ b/ports/stm32/boards/Passport/modules/views/label.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # label.py - Basic label with multiple wrapping behaviors diff --git a/ports/stm32/boards/Passport/modules/views/line.py b/ports/stm32/boards/Passport/modules/views/line.py index b3e5eb929..17117af9b 100644 --- a/ports/stm32/boards/Passport/modules/views/line.py +++ b/ports/stm32/boards/Passport/modules/views/line.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # line.py - Simple wrapper around a line widget diff --git a/ports/stm32/boards/Passport/modules/views/list_item.py b/ports/stm32/boards/Passport/modules/views/list_item.py index c991011b2..f73e8db09 100644 --- a/ports/stm32/boards/Passport/modules/views/list_item.py +++ b/ports/stm32/boards/Passport/modules/views/list_item.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # list_item.py - Render a list item string, and an icon to indicate if that item is selected diff --git a/ports/stm32/boards/Passport/modules/views/menu_item.py b/ports/stm32/boards/Passport/modules/views/menu_item.py index 3eae988ea..d2d3d1227 100644 --- a/ports/stm32/boards/Passport/modules/views/menu_item.py +++ b/ports/stm32/boards/Passport/modules/views/menu_item.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # menu_item.py - Component to render a single menu item (icon and label) diff --git a/ports/stm32/boards/Passport/modules/views/micron_bar.py b/ports/stm32/boards/Passport/modules/views/micron_bar.py index 9663c6bd1..d9eb5bcbb 100644 --- a/ports/stm32/boards/Passport/modules/views/micron_bar.py +++ b/ports/stm32/boards/Passport/modules/views/micron_bar.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # micron_bar.py - "Footer" component that shows the contextual button icons and either the card diff --git a/ports/stm32/boards/Passport/modules/views/pin_input.py b/ports/stm32/boards/Passport/modules/views/pin_input.py index 1711a99c4..c66991604 100644 --- a/ports/stm32/boards/Passport/modules/views/pin_input.py +++ b/ports/stm32/boards/Passport/modules/views/pin_input.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # pin_input.py - Single PIN input diff --git a/ports/stm32/boards/Passport/modules/views/qrcode.py b/ports/stm32/boards/Passport/modules/views/qrcode.py index 2eeaf853c..dec3181ce 100644 --- a/ports/stm32/boards/Passport/modules/views/qrcode.py +++ b/ports/stm32/boards/Passport/modules/views/qrcode.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # qrcode.py - Wrapper for LVGL QR code widget diff --git a/ports/stm32/boards/Passport/modules/views/slider.py b/ports/stm32/boards/Passport/modules/views/slider.py index 7e1d7bf03..518411050 100644 --- a/ports/stm32/boards/Passport/modules/views/slider.py +++ b/ports/stm32/boards/Passport/modules/views/slider.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # slider.py - Wrapper over the lvgl slider widget diff --git a/ports/stm32/boards/Passport/modules/views/spinner.py b/ports/stm32/boards/Passport/modules/views/spinner.py index a824c3766..56d60cfc0 100644 --- a/ports/stm32/boards/Passport/modules/views/spinner.py +++ b/ports/stm32/boards/Passport/modules/views/spinner.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # spinner.py - Wrapper around LVLG spinner component diff --git a/ports/stm32/boards/Passport/modules/views/statusbar.py b/ports/stm32/boards/Passport/modules/views/statusbar.py index ad0e47db1..7cfd6aa2e 100644 --- a/ports/stm32/boards/Passport/modules/views/statusbar.py +++ b/ports/stm32/boards/Passport/modules/views/statusbar.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # statusbar.py - Top status bar that shows a title and some icons diff --git a/ports/stm32/boards/Passport/modules/views/switch.py b/ports/stm32/boards/Passport/modules/views/switch.py index c71df8acd..16a580595 100644 --- a/ports/stm32/boards/Passport/modules/views/switch.py +++ b/ports/stm32/boards/Passport/modules/views/switch.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # switch.py - An lvgl switch widget wrapper diff --git a/ports/stm32/boards/Passport/modules/views/symbol_picker.py b/ports/stm32/boards/Passport/modules/views/symbol_picker.py index 256980597..65331d2af 100644 --- a/ports/stm32/boards/Passport/modules/views/symbol_picker.py +++ b/ports/stm32/boards/Passport/modules/views/symbol_picker.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # symbol_picker.py - View to display a grid of symbols to the user and let them select one diff --git a/ports/stm32/boards/Passport/modules/views/text_area.py b/ports/stm32/boards/Passport/modules/views/text_area.py index c098fb408..46a0f422f 100644 --- a/ports/stm32/boards/Passport/modules/views/text_area.py +++ b/ports/stm32/boards/Passport/modules/views/text_area.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # text_area.py - Wrapper around lvgl textarea diff --git a/ports/stm32/boards/Passport/modules/views/text_input.py b/ports/stm32/boards/Passport/modules/views/text_input.py index 97fd91737..2afa4be09 100644 --- a/ports/stm32/boards/Passport/modules/views/text_input.py +++ b/ports/stm32/boards/Passport/modules/views/text_input.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # text_input.py - Single line text input component diff --git a/ports/stm32/boards/Passport/modules/views/view.py b/ports/stm32/boards/Passport/modules/views/view.py index 8d2ef1f7c..cde338aa3 100644 --- a/ports/stm32/boards/Passport/modules/views/view.py +++ b/ports/stm32/boards/Passport/modules/views/view.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # view.py - Base class for all Views diff --git a/ports/stm32/boards/Passport/modules/wallets/__init__.py b/ports/stm32/boards/Passport/modules/wallets/__init__.py index b7106a319..2c67d657e 100644 --- a/ports/stm32/boards/Passport/modules/wallets/__init__.py +++ b/ports/stm32/boards/Passport/modules/wallets/__init__.py @@ -1,2 +1,2 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py b/ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py index 6302deb7d..85c4a80a2 100644 --- a/ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py +++ b/ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/wallets/bluewallet.py b/ports/stm32/boards/Passport/modules/wallets/bluewallet.py index a776f90f7..fc5e76bd1 100644 --- a/ports/stm32/boards/Passport/modules/wallets/bluewallet.py +++ b/ports/stm32/boards/Passport/modules/wallets/bluewallet.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # bluewallet.py - BlueWallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/btcpay.py b/ports/stm32/boards/Passport/modules/wallets/btcpay.py index 140cfc458..a349751d3 100644 --- a/ports/stm32/boards/Passport/modules/wallets/btcpay.py +++ b/ports/stm32/boards/Passport/modules/wallets/btcpay.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # btcpay.py - BTCPay wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/caravan.py b/ports/stm32/boards/Passport/modules/wallets/caravan.py index 0f6d3f47a..908004cf5 100644 --- a/ports/stm32/boards/Passport/modules/wallets/caravan.py +++ b/ports/stm32/boards/Passport/modules/wallets/caravan.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # caravan.py - Caravan wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/casa.py b/ports/stm32/boards/Passport/modules/wallets/casa.py index fece2e566..13c1bb732 100644 --- a/ports/stm32/boards/Passport/modules/wallets/casa.py +++ b/ports/stm32/boards/Passport/modules/wallets/casa.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # casa.py - Casa support diff --git a/ports/stm32/boards/Passport/modules/wallets/constants.py b/ports/stm32/boards/Passport/modules/wallets/constants.py index 861d14b35..1e2b93205 100644 --- a/ports/stm32/boards/Passport/modules/wallets/constants.py +++ b/ports/stm32/boards/Passport/modules/wallets/constants.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # constants.py - Software wallet constants diff --git a/ports/stm32/boards/Passport/modules/wallets/dux_reserve.py b/ports/stm32/boards/Passport/modules/wallets/dux_reserve.py index cc77f37e0..a66e6ac4e 100644 --- a/ports/stm32/boards/Passport/modules/wallets/dux_reserve.py +++ b/ports/stm32/boards/Passport/modules/wallets/dux_reserve.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # dux_reserve.py - Dux Reserve wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/electrum.py b/ports/stm32/boards/Passport/modules/wallets/electrum.py index 42da33901..42ee01f9d 100644 --- a/ports/stm32/boards/Passport/modules/wallets/electrum.py +++ b/ports/stm32/boards/Passport/modules/wallets/electrum.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/wallets/envoy.py b/ports/stm32/boards/Passport/modules/wallets/envoy.py index 47454bcee..078f8c47b 100644 --- a/ports/stm32/boards/Passport/modules/wallets/envoy.py +++ b/ports/stm32/boards/Passport/modules/wallets/envoy.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # envoy.py - Envoy support diff --git a/ports/stm32/boards/Passport/modules/wallets/fullynoded.py b/ports/stm32/boards/Passport/modules/wallets/fullynoded.py index 0a50b62b4..25a8c3647 100644 --- a/ports/stm32/boards/Passport/modules/wallets/fullynoded.py +++ b/ports/stm32/boards/Passport/modules/wallets/fullynoded.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # fullynoded.py - FullyNoded wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/generic_json_wallet.py b/ports/stm32/boards/Passport/modules/wallets/generic_json_wallet.py index 8e5f5dd8b..ec7fe4c76 100644 --- a/ports/stm32/boards/Passport/modules/wallets/generic_json_wallet.py +++ b/ports/stm32/boards/Passport/modules/wallets/generic_json_wallet.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/wallets/gordian.py b/ports/stm32/boards/Passport/modules/wallets/gordian.py index 3aadeddbf..518724967 100644 --- a/ports/stm32/boards/Passport/modules/wallets/gordian.py +++ b/ports/stm32/boards/Passport/modules/wallets/gordian.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # gordian.py - Gordian wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/keeper.py b/ports/stm32/boards/Passport/modules/wallets/keeper.py index 599d55ae6..7f879fb90 100644 --- a/ports/stm32/boards/Passport/modules/wallets/keeper.py +++ b/ports/stm32/boards/Passport/modules/wallets/keeper.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # keeper.py - Keeper wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/lily.py b/ports/stm32/boards/Passport/modules/wallets/lily.py index 4ae64427f..91e39a838 100644 --- a/ports/stm32/boards/Passport/modules/wallets/lily.py +++ b/ports/stm32/boards/Passport/modules/wallets/lily.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # lily.py - Lily wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/multisig_import.py b/ports/stm32/boards/Passport/modules/wallets/multisig_import.py index 935dc5524..da2c5fa13 100644 --- a/ports/stm32/boards/Passport/modules/wallets/multisig_import.py +++ b/ports/stm32/boards/Passport/modules/wallets/multisig_import.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/wallets/multisig_json.py b/ports/stm32/boards/Passport/modules/wallets/multisig_json.py index c79e8b2af..f842d116f 100644 --- a/ports/stm32/boards/Passport/modules/wallets/multisig_json.py +++ b/ports/stm32/boards/Passport/modules/wallets/multisig_json.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/modules/wallets/nunchuk.py b/ports/stm32/boards/Passport/modules/wallets/nunchuk.py index f57fc892c..f934c4834 100644 --- a/ports/stm32/boards/Passport/modules/wallets/nunchuk.py +++ b/ports/stm32/boards/Passport/modules/wallets/nunchuk.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # nunchuk.py - Nunchuk wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/simple_bitcoin_wallet.py b/ports/stm32/boards/Passport/modules/wallets/simple_bitcoin_wallet.py index 035ba3913..fef3a3caf 100644 --- a/ports/stm32/boards/Passport/modules/wallets/simple_bitcoin_wallet.py +++ b/ports/stm32/boards/Passport/modules/wallets/simple_bitcoin_wallet.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # simple_bitcoin_wallet.py - Simple Bitcoin Wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/sparrow.py b/ports/stm32/boards/Passport/modules/wallets/sparrow.py index 0cfaf0a38..1910b5f2e 100644 --- a/ports/stm32/boards/Passport/modules/wallets/sparrow.py +++ b/ports/stm32/boards/Passport/modules/wallets/sparrow.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # sparrow.py - Sparrow wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/specter.py b/ports/stm32/boards/Passport/modules/wallets/specter.py index 69eb6965d..078e9df29 100644 --- a/ports/stm32/boards/Passport/modules/wallets/specter.py +++ b/ports/stm32/boards/Passport/modules/wallets/specter.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # specter.py - Specter wallet support diff --git a/ports/stm32/boards/Passport/modules/wallets/sw_wallets.py b/ports/stm32/boards/Passport/modules/wallets/sw_wallets.py index 863c70230..8ee12ef0d 100644 --- a/ports/stm32/boards/Passport/modules/wallets/sw_wallets.py +++ b/ports/stm32/boards/Passport/modules/wallets/sw_wallets.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # sw_wallets.py - Software wallet config data for all supported wallets diff --git a/ports/stm32/boards/Passport/modules/wallets/utils.py b/ports/stm32/boards/Passport/modules/wallets/utils.py index 724645d9c..148b01411 100644 --- a/ports/stm32/boards/Passport/modules/wallets/utils.py +++ b/ports/stm32/boards/Passport/modules/wallets/utils.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # utils.py - Wallet utils diff --git a/ports/stm32/boards/Passport/modules/wallets/vault.py b/ports/stm32/boards/Passport/modules/wallets/vault.py index 371214e7c..e218fe5ba 100644 --- a/ports/stm32/boards/Passport/modules/wallets/vault.py +++ b/ports/stm32/boards/Passport/modules/wallets/vault.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # vault.py - Export format used by some wallets diff --git a/ports/stm32/boards/Passport/modules/wallets/wasabi.py b/ports/stm32/boards/Passport/modules/wallets/wasabi.py index 0985ef0fa..b363f4e5c 100644 --- a/ports/stm32/boards/Passport/modules/wallets/wasabi.py +++ b/ports/stm32/boards/Passport/modules/wallets/wasabi.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/mpconfigboard.h b/ports/stm32/boards/Passport/mpconfigboard.h index 5359265f0..944814a08 100644 --- a/ports/stm32/boards/Passport/mpconfigboard.h +++ b/ports/stm32/boards/Passport/mpconfigboard.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/mpconfigboard.mk b/ports/stm32/boards/Passport/mpconfigboard.mk index 763c234c7..d527308c9 100644 --- a/ports/stm32/boards/Passport/mpconfigboard.mk +++ b/ports/stm32/boards/Passport/mpconfigboard.mk @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ports/stm32/boards/Passport/noise.c b/ports/stm32/boards/Passport/noise.c index c8d59259a..4b0ecb0f9 100644 --- a/ports/stm32/boards/Passport/noise.c +++ b/ports/stm32/boards/Passport/noise.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/noise.h b/ports/stm32/boards/Passport/noise.h index 012b58527..47fe96581 100644 --- a/ports/stm32/boards/Passport/noise.h +++ b/ports/stm32/boards/Passport/noise.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/passport.ld b/ports/stm32/boards/Passport/passport.ld index a42770bb5..01a9944aa 100644 --- a/ports/stm32/boards/Passport/passport.ld +++ b/ports/stm32/boards/Passport/passport.ld @@ -1,5 +1,5 @@ /* - SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. + SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. SPDX-License-Identifier: GPL-3.0-or-later GNU linker script for STM32H753 diff --git a/ports/stm32/boards/Passport/pins.c b/ports/stm32/boards/Passport/pins.c index 8af919718..2ac7a7508 100644 --- a/ports/stm32/boards/Passport/pins.c +++ b/ports/stm32/boards/Passport/pins.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/pins.h b/ports/stm32/boards/Passport/pins.h index 80665e5c4..966bf115b 100644 --- a/ports/stm32/boards/Passport/pins.h +++ b/ports/stm32/boards/Passport/pins.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/se-atecc608a.c b/ports/stm32/boards/Passport/se-atecc608a.c index f14212b3f..f99eb2257 100644 --- a/ports/stm32/boards/Passport/se-atecc608a.c +++ b/ports/stm32/boards/Passport/se-atecc608a.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. @@ -8,7 +8,7 @@ * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard * and is covered by GPLv3 license found in COPYING. * - * SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. + * SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. * SPDX-License-Identifier: GPL-3.0-or-later */ #include diff --git a/ports/stm32/boards/Passport/se-atecc608a.h b/ports/stm32/boards/Passport/se-atecc608a.h index 277c4b102..ed4af1d82 100644 --- a/ports/stm32/boards/Passport/se-atecc608a.h +++ b/ports/stm32/boards/Passport/se-atecc608a.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/stm32h7xx_hal_conf.h b/ports/stm32/boards/Passport/stm32h7xx_hal_conf.h index 7664f122e..0f51fcb80 100644 --- a/ports/stm32/boards/Passport/stm32h7xx_hal_conf.h +++ b/ports/stm32/boards/Passport/stm32h7xx_hal_conf.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: Copyright (c) 2019 Damien P. George diff --git a/ports/stm32/boards/Passport/tools/add-secrets/Makefile b/ports/stm32/boards/Passport/tools/add-secrets/Makefile index 43b88bf41..561de890e 100644 --- a/ports/stm32/boards/Passport/tools/add-secrets/Makefile +++ b/ports/stm32/boards/Passport/tools/add-secrets/Makefile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later TOP = ../.. diff --git a/ports/stm32/boards/Passport/tools/add-secrets/add-secrets.c b/ports/stm32/boards/Passport/tools/add-secrets/add-secrets.c index 44bebcb57..bc6c52dda 100644 --- a/ports/stm32/boards/Passport/tools/add-secrets/add-secrets.c +++ b/ports/stm32/boards/Passport/tools/add-secrets/add-secrets.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #include diff --git a/ports/stm32/boards/Passport/tools/cosign/Makefile b/ports/stm32/boards/Passport/tools/cosign/Makefile index 98c27640b..46cce4bfc 100644 --- a/ports/stm32/boards/Passport/tools/cosign/Makefile +++ b/ports/stm32/boards/Passport/tools/cosign/Makefile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later TOP = ../.. diff --git a/ports/stm32/boards/Passport/tools/cosign/cosign.c b/ports/stm32/boards/Passport/tools/cosign/cosign.c index 5839879a1..2807f3f9a 100644 --- a/ports/stm32/boards/Passport/tools/cosign/cosign.c +++ b/ports/stm32/boards/Passport/tools/cosign/cosign.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #include diff --git a/ports/stm32/boards/Passport/tools/provisioning/provision.py b/ports/stm32/boards/Passport/tools/provisioning/provision.py index 5a05411b8..fe70c8eb1 100755 --- a/ports/stm32/boards/Passport/tools/provisioning/provision.py +++ b/ports/stm32/boards/Passport/tools/provisioning/provision.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # import telnetlib diff --git a/ports/stm32/boards/Passport/tools/se_config_gen/se_config_gen.py b/ports/stm32/boards/Passport/tools/se_config_gen/se_config_gen.py index 5b0564450..0cf3b398f 100644 --- a/ports/stm32/boards/Passport/tools/se_config_gen/se_config_gen.py +++ b/ports/stm32/boards/Passport/tools/se_config_gen/se_config_gen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/tools/version_info/version_info b/ports/stm32/boards/Passport/tools/version_info/version_info index 252b723a6..d32301dd7 100755 --- a/ports/stm32/boards/Passport/tools/version_info/version_info +++ b/ports/stm32/boards/Passport/tools/version_info/version_info @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later usage() diff --git a/ports/stm32/boards/Passport/tools/word_list_gen/bip39_test.c b/ports/stm32/boards/Passport/tools/word_list_gen/bip39_test.c index 6ebe7ae67..89014fee3 100644 --- a/ports/stm32/boards/Passport/tools/word_list_gen/bip39_test.c +++ b/ports/stm32/boards/Passport/tools/word_list_gen/bip39_test.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/tools/word_list_gen/bip39_words.c b/ports/stm32/boards/Passport/tools/word_list_gen/bip39_words.c index 8e7da42af..953b3aa64 100644 --- a/ports/stm32/boards/Passport/tools/word_list_gen/bip39_words.c +++ b/ports/stm32/boards/Passport/tools/word_list_gen/bip39_words.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/tools/word_list_gen/bytewords_words.c b/ports/stm32/boards/Passport/tools/word_list_gen/bytewords_words.c index f258f1583..e82b92e87 100644 --- a/ports/stm32/boards/Passport/tools/word_list_gen/bytewords_words.c +++ b/ports/stm32/boards/Passport/tools/word_list_gen/bytewords_words.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/stm32/boards/Passport/tools/word_list_gen/word_list_gen.c b/ports/stm32/boards/Passport/tools/word_list_gen/word_list_gen.c index a4ee7c554..db3a41acd 100644 --- a/ports/stm32/boards/Passport/tools/word_list_gen/word_list_gen.c +++ b/ports/stm32/boards/Passport/tools/word_list_gen/word_list_gen.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // @@ -87,7 +87,7 @@ int compare_word_info(const void* a, const void* b) { void make_num_pairs_array(const char** words, char* prefix) { // Insert the hyphen all weird like this so that `reuse lint` doesn't complain about parsing this - printf("// SPDX%cFileCopyrightText: 2021 Foundation Devices, Inc. \n", '-'); + printf("// SPDX%cFileCopyrightText: © 2021 Foundation Devices, Inc. \n", '-'); printf("// SPDX%cLicense-Identifier: GPL-3.0-or-later\n", '-'); printf("//\n\n"); printf("#include \n\n"); diff --git a/ports/stm32/boards/Passport/version.c b/ports/stm32/boards/Passport/version.c index fddc316dd..a6c7c6aa2 100644 --- a/ports/stm32/boards/Passport/version.c +++ b/ports/stm32/boards/Passport/version.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/stm32/boards/Passport/version.h b/ports/stm32/boards/Passport/version.h index a91ab670b..a2f90fa69 100644 --- a/ports/stm32/boards/Passport/version.h +++ b/ports/stm32/boards/Passport/version.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // // SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/ports/unix/modpassport_lv-keypad.h b/ports/unix/modpassport_lv-keypad.h index 6352692fb..abf2e5751 100644 --- a/ports/unix/modpassport_lv-keypad.h +++ b/ports/unix/modpassport_lv-keypad.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/unix/modpassport_lv-lcd.h b/ports/unix/modpassport_lv-lcd.h index 04ac29242..84e0f084f 100644 --- a/ports/unix/modpassport_lv-lcd.h +++ b/ports/unix/modpassport_lv-lcd.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/unix/modpassport_lv.c b/ports/unix/modpassport_lv.c index 171fc8be8..c678b00fc 100644 --- a/ports/unix/modpassport_lv.c +++ b/ports/unix/modpassport_lv.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/ports/unix/ring_buffer.c b/ports/unix/ring_buffer.c index 6d43c0157..4d3060636 100644 --- a/ports/unix/ring_buffer.c +++ b/ports/unix/ring_buffer.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // #include diff --git a/ports/unix/ring_buffer.h b/ports/unix/ring_buffer.h index f13375163..01760cf03 100644 --- a/ports/unix/ring_buffer.h +++ b/ports/unix/ring_buffer.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later // diff --git a/simulator/Justfile b/simulator/Justfile index 4e5148d6e..7403c3ed9 100644 --- a/simulator/Justfile +++ b/simulator/Justfile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/simulator/Makefile b/simulator/Makefile index c20b8917b..d530d7862 100644 --- a/simulator/Makefile +++ b/simulator/Makefile @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/simulator/README.md b/simulator/README.md index 5ecf2add9..689ccb0f5 100644 --- a/simulator/README.md +++ b/simulator/README.md @@ -3,7 +3,7 @@ SPDX-FileCopyrightText: 2018 Coinkite, Inc. SPDX-License-Identifier: GPL-3.0-only -SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. SPDX-License-Identifier: GPL-3.0-or-later --> diff --git a/simulator/SIMULATOR.md b/simulator/SIMULATOR.md index 114ea34e9..ce0ebf9a8 100644 --- a/simulator/SIMULATOR.md +++ b/simulator/SIMULATOR.md @@ -1,5 +1,5 @@ diff --git a/simulator/requirements.txt b/simulator/requirements.txt index b05920d3f..2aabdfda9 100644 --- a/simulator/requirements.txt +++ b/simulator/requirements.txt @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: MIT # -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/simulator/sim_boot.py b/simulator/sim_boot.py index 656738bf3..a842f4226 100644 --- a/simulator/sim_boot.py +++ b/simulator/sim_boot.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/simulator/sim_modules/ffilib.py b/simulator/sim_modules/ffilib.py index 423a4e48b..06cb19896 100644 --- a/simulator/sim_modules/ffilib.py +++ b/simulator/sim_modules/ffilib.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: MIT # -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/simulator/sim_modules/keypad_worker.py b/simulator/sim_modules/keypad_worker.py index 3a656781d..71a9782c1 100644 --- a/simulator/sim_modules/keypad_worker.py +++ b/simulator/sim_modules/keypad_worker.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # keypad.py diff --git a/simulator/sim_modules/passport/__init__.py b/simulator/sim_modules/passport/__init__.py index 223114667..3fde52fd7 100644 --- a/simulator/sim_modules/passport/__init__.py +++ b/simulator/sim_modules/passport/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # __init__.py - Simulated replacements for some Foundation code diff --git a/simulator/sim_modules/passport/camera.py b/simulator/sim_modules/passport/camera.py index 2e7a1b457..7e14bb392 100644 --- a/simulator/sim_modules/passport/camera.py +++ b/simulator/sim_modules/passport/camera.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/simulator/sim_modules/passport/sram4.py b/simulator/sim_modules/passport/sram4.py index 2bc58243f..2ab8e0437 100644 --- a/simulator/sim_modules/passport/sram4.py +++ b/simulator/sim_modules/passport/sram4.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later MAX_QR_VERSION = 13 diff --git a/simulator/sim_modules/pincodes.py b/simulator/sim_modules/pincodes.py index 2f4ca111b..478181593 100644 --- a/simulator/sim_modules/pincodes.py +++ b/simulator/sim_modules/pincodes.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/simulator/sim_modules/settings.py b/simulator/sim_modules/settings.py index 8f83a54b2..7589e14e3 100644 --- a/simulator/sim_modules/settings.py +++ b/simulator/sim_modules/settings.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # SPDX-FileCopyrightText: 2018 Coinkite, Inc. diff --git a/simulator/unix_random.c b/simulator/unix_random.c index f14e698cd..f87db0fa4 100644 --- a/simulator/unix_random.c +++ b/simulator/unix_random.c @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT // -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/simulator/variant/simulator/mpconfigvariant.h b/simulator/variant/simulator/mpconfigvariant.h index dd3c5b1f5..80c116bf2 100644 --- a/simulator/variant/simulator/mpconfigvariant.h +++ b/simulator/variant/simulator/mpconfigvariant.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +// SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. // SPDX-License-Identifier: GPL-3.0-or-later #define MICROPY_PY_UASYNCIO (1) diff --git a/simulator/variant/simulator/mpconfigvariant.mk b/simulator/variant/simulator/mpconfigvariant.mk index beec57d00..60ac1362a 100644 --- a/simulator/variant/simulator/mpconfigvariant.mk +++ b/simulator/variant/simulator/mpconfigvariant.mk @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later PROG ?= passport-mpy From 5c320026df3c290f876694f3b6e63f6a19d54c11 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 6 Feb 2023 13:09:44 +0100 Subject: [PATCH 045/156] PASS1-650: Remove duplicated license files. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/LICENSES/Apache-2.0.txt | 183 ------ .../Passport/LICENSES/BSD-2-Clause-Patent.txt | 47 -- .../boards/Passport/LICENSES/BSD-2-Clause.txt | 22 - .../boards/Passport/LICENSES/BSD-3-Clause.txt | 26 - .../boards/Passport/LICENSES/GPL-3.0-only.txt | 604 ------------------ .../Passport/LICENSES/GPL-3.0-or-later.txt | 604 ------------------ ports/stm32/boards/Passport/LICENSES/ISC.txt | 15 - ports/stm32/boards/Passport/LICENSES/MIT.txt | 20 - .../boards/Passport/LICENSES/Unlicense.txt | 22 - 9 files changed, 1543 deletions(-) delete mode 100644 ports/stm32/boards/Passport/LICENSES/Apache-2.0.txt delete mode 100644 ports/stm32/boards/Passport/LICENSES/BSD-2-Clause-Patent.txt delete mode 100644 ports/stm32/boards/Passport/LICENSES/BSD-2-Clause.txt delete mode 100644 ports/stm32/boards/Passport/LICENSES/BSD-3-Clause.txt delete mode 100644 ports/stm32/boards/Passport/LICENSES/GPL-3.0-only.txt delete mode 100644 ports/stm32/boards/Passport/LICENSES/GPL-3.0-or-later.txt delete mode 100644 ports/stm32/boards/Passport/LICENSES/ISC.txt delete mode 100644 ports/stm32/boards/Passport/LICENSES/MIT.txt delete mode 100644 ports/stm32/boards/Passport/LICENSES/Unlicense.txt diff --git a/ports/stm32/boards/Passport/LICENSES/Apache-2.0.txt b/ports/stm32/boards/Passport/LICENSES/Apache-2.0.txt deleted file mode 100644 index 9a4104bbf..000000000 --- a/ports/stm32/boards/Passport/LICENSES/Apache-2.0.txt +++ /dev/null @@ -1,183 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution -as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct -or indirect, to cause the direction or management of such entity, whether -by contract or otherwise, or (ii) ownership of fifty percent (50%) or more -of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions -granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation -or translation of a Source form, including but not limited to compiled object -code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, -made available under the License, as indicated by a copyright notice that -is included in or attached to the work (an example is provided in the Appendix -below). - -"Derivative Works" shall mean any work, whether in Source or Object form, -that is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative -Works shall not include works that remain separable from, or merely link (or -bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative -Works thereof, that is intentionally submitted to Licensor for inclusion in -the Work by the copyright owner or by an individual or Legal Entity authorized -to submit on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication -sent to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor -for the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently incorporated -within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this -License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable copyright license to reproduce, prepare -Derivative Works of, publicly display, publicly perform, sublicense, and distribute -the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, -each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) patent -license to make, have made, use, offer to sell, sell, import, and otherwise -transfer the Work, where such license applies only to those patent claims -licensable by such Contributor that are necessarily infringed by their Contribution(s) -alone or by combination of their Contribution(s) with the Work to which such -Contribution(s) was submitted. If You institute patent litigation against -any entity (including a cross-claim or counterclaim in a lawsuit) alleging -that the Work or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses granted to You -under this License for that Work shall terminate as of the date such litigation -is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or -Derivative Works thereof in any medium, with or without modifications, and -in Source or Object form, provided that You meet the following conditions: - -(a) You must give any other recipients of the Work or Derivative Works a copy -of this License; and - -(b) You must cause any modified files to carry prominent notices stating that -You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source -form of the Work, excluding those notices that do not pertain to any part -of the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its distribution, -then any Derivative Works that You distribute must include a readable copy -of the attribution notices contained within such NOTICE file, excluding those -notices that do not pertain to any part of the Derivative Works, in at least -one of the following places: within a NOTICE text file distributed as part -of the Derivative Works; within the Source form or documentation, if provided -along with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works -that You distribute, alongside or as an addendum to the NOTICE text from the -Work, provided that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, -or distribution of Your modifications, or for any such Derivative Works as -a whole, provided Your use, reproduction, and distribution of the Work otherwise -complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any -Contribution intentionally submitted for inclusion in the Work by You to the -Licensor shall be under the terms and conditions of this License, without -any additional terms or conditions. Notwithstanding the above, nothing herein -shall supersede or modify the terms of any separate license agreement you -may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, -trademarks, service marks, or product names of the Licensor, except as required -for reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to -in writing, Licensor provides the Work (and each Contributor provides its -Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied, including, without limitation, any warranties -or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR -A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness -of using or redistributing the Work and assume any risks associated with Your -exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether -in tort (including negligence), contract, or otherwise, unless required by -applicable law (such as deliberate and grossly negligent acts) or agreed to -in writing, shall any Contributor be liable to You for damages, including -any direct, indirect, special, incidental, or consequential damages of any -character arising as a result of this License or out of the use or inability -to use the Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all other commercial -damages or losses), even if such Contributor has been advised of the possibility -of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work -or Derivative Works thereof, You may choose to offer, and charge a fee for, -acceptance of support, warranty, indemnity, or other liability obligations -and/or rights consistent with this License. However, in accepting such obligations, -You may act only on Your own behalf and on Your sole responsibility, not on -behalf of any other Contributor, and only if You agree to indemnify, defend, -and hold each Contributor harmless for any liability incurred by, or claims -asserted against, such Contributor by reason of your accepting any such warranty -or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own identifying -information. (Don't include the brackets!) The text should be enclosed in -the appropriate comment syntax for the file format. We also recommend that -a file or class name and description of purpose be included on the same "printed -page" as the copyright notice for easier identification within third-party -archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/ports/stm32/boards/Passport/LICENSES/BSD-2-Clause-Patent.txt b/ports/stm32/boards/Passport/LICENSES/BSD-2-Clause-Patent.txt deleted file mode 100644 index 1184c0295..000000000 --- a/ports/stm32/boards/Passport/LICENSES/BSD-2-Clause-Patent.txt +++ /dev/null @@ -1,47 +0,0 @@ -Copyright (c) - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -Subject to the terms and conditions of this license, each copyright holder -and contributor hereby grants to those receiving rights under this license -a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except for failure to satisfy the conditions of this license) patent license -to make, have made, use, offer to sell, sell, import, and otherwise transfer -this software, where such license applies only to those patent claims, already -acquired or hereafter acquired, licensable by such copyright holder or contributor -that are necessarily infringed by: - -(a) their Contribution(s) (the licensed copyrights of copyright holders and -non-copyrightable additions of contributors, in source or binary form) alone; -or - -(b) combination of their Contribution(s) with the work of authorship to which -such Contribution(s) was added by such copyright holder or contributor, if, -at the time the Contribution is added, such addition causes such combination -to be necessarily infringed. The patent license shall not apply to any other -combinations which include the Contribution. - -Except as expressly stated above, no rights or licenses from any copyright -holder or contributor is granted under this license, whether expressly, by -implication, estoppel or otherwise. - -DISCLAIMER - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ports/stm32/boards/Passport/LICENSES/BSD-2-Clause.txt b/ports/stm32/boards/Passport/LICENSES/BSD-2-Clause.txt deleted file mode 100644 index baa80b56a..000000000 --- a/ports/stm32/boards/Passport/LICENSES/BSD-2-Clause.txt +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ports/stm32/boards/Passport/LICENSES/BSD-3-Clause.txt b/ports/stm32/boards/Passport/LICENSES/BSD-3-Clause.txt deleted file mode 100644 index 0741db789..000000000 --- a/ports/stm32/boards/Passport/LICENSES/BSD-3-Clause.txt +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) . All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors -may be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ports/stm32/boards/Passport/LICENSES/GPL-3.0-only.txt b/ports/stm32/boards/Passport/LICENSES/GPL-3.0-only.txt deleted file mode 100644 index 0adc84e82..000000000 --- a/ports/stm32/boards/Passport/LICENSES/GPL-3.0-only.txt +++ /dev/null @@ -1,604 +0,0 @@ -GNU GENERAL PUBLIC LICENSE -Version 3, 29 June 2007 - -Copyright © 2007 Free Software Foundation, Inc. - -Everyone is permitted to copy and distribute verbatim copies of this license -document, but changing it is not allowed. - -Preamble - -The GNU General Public License is a free, copyleft license for software and -other kinds of works. - -The licenses for most software and other practical works are designed to take -away your freedom to share and change the works. By contrast, the GNU General -Public License is intended to guarantee your freedom to share and change all -versions of a program--to make sure it remains free software for all its users. -We, the Free Software Foundation, use the GNU General Public License for most -of our software; it applies also to any other work released this way by its -authors. You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom -to distribute copies of free software (and charge for them if you wish), that -you receive source code or can get it if you want it, that you can change -the software or use pieces of it in new free programs, and that you know you -can do these things. - -To protect your rights, we need to prevent others from denying you these rights -or asking you to surrender the rights. Therefore, you have certain responsibilities -if you distribute copies of the software, or if you modify it: responsibilities -to respect the freedom of others. - -For example, if you distribute copies of such a program, whether gratis or -for a fee, you must pass on to the recipients the same freedoms that you received. -You must make sure that they, too, receive or can get the source code. And -you must show them these terms so they know their rights. - -Developers that use the GNU GPL protect your rights with two steps: (1) assert -copyright on the software, and (2) offer you this License giving you legal -permission to copy, distribute and/or modify it. - -For the developers' and authors' protection, the GPL clearly explains that -there is no warranty for this free software. For both users' and authors' -sake, the GPL requires that modified versions be marked as changed, so that -their problems will not be attributed erroneously to authors of previous versions. - -Some devices are designed to deny users access to install or run modified -versions of the software inside them, although the manufacturer can do so. -This is fundamentally incompatible with the aim of protecting users' freedom -to change the software. The systematic pattern of such abuse occurs in the -area of products for individuals to use, which is precisely where it is most -unacceptable. Therefore, we have designed this version of the GPL to prohibit -the practice for those products. If such problems arise substantially in other -domains, we stand ready to extend this provision to those domains in future -versions of the GPL, as needed to protect the freedom of users. - -Finally, every program is threatened constantly by software patents. States -should not allow patents to restrict development and use of software on general-purpose -computers, but in those that do, we wish to avoid the special danger that -patents applied to a free program could make it effectively proprietary. To -prevent this, the GPL assures that patents cannot be used to render the program -non-free. - -The precise terms and conditions for copying, distribution and modification -follow. - -TERMS AND CONDITIONS - -0. Definitions. - -“This License” refers to version 3 of the GNU General Public License. - -“Copyright” also means copyright-like laws that apply to other kinds of works, -such as semiconductor masks. - -“The Program” refers to any copyrightable work licensed under this License. -Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals -or organizations. - -To “modify” a work means to copy from or adapt all or part of the work in -a fashion requiring copyright permission, other than the making of an exact -copy. The resulting work is called a “modified version” of the earlier work -or a work “based on” the earlier work. - -A “covered work” means either the unmodified Program or a work based on the -Program. - -To “propagate” a work means to do anything with it that, without permission, -would make you directly or secondarily liable for infringement under applicable -copyright law, except executing it on a computer or modifying a private copy. -Propagation includes copying, distribution (with or without modification), -making available to the public, and in some countries other activities as -well. - -To “convey” a work means any kind of propagation that enables other parties -to make or receive copies. Mere interaction with a user through a computer -network, with no transfer of a copy, is not conveying. - -An interactive user interface displays “Appropriate Legal Notices” to the -extent that it includes a convenient and prominently visible feature that -(1) displays an appropriate copyright notice, and (2) tells the user that -there is no warranty for the work (except to the extent that warranties are -provided), that licensees may convey the work under this License, and how -to view a copy of this License. If the interface presents a list of user commands -or options, such as a menu, a prominent item in the list meets this criterion. - -1. Source Code. -The “source code” for a work means the preferred form of the work for making -modifications to it. “Object code” means any non-source form of a work. - -A “Standard Interface” means an interface that either is an official standard -defined by a recognized standards body, or, in the case of interfaces specified -for a particular programming language, one that is widely used among developers -working in that language. - -The “System Libraries” of an executable work include anything, other than -the work as a whole, that (a) is included in the normal form of packaging -a Major Component, but which is not part of that Major Component, and (b) -serves only to enable use of the work with that Major Component, or to implement -a Standard Interface for which an implementation is available to the public -in source code form. A “Major Component”, in this context, means a major essential -component (kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to produce -the work, or an object code interpreter used to run it. - -The “Corresponding Source” for a work in object code form means all the source -code needed to generate, install, and (for an executable work) run the object -code and to modify the work, including scripts to control those activities. -However, it does not include the work's System Libraries, or general-purpose -tools or generally available free programs which are used unmodified in performing -those activities but which are not part of the work. For example, Corresponding -Source includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically linked -subprograms that the work is specifically designed to require, such as by -intimate data communication or control flow between those subprograms and -other parts of the work. - -The Corresponding Source need not include anything that users can regenerate -automatically from other parts of the Corresponding Source. - -The Corresponding Source for a work in source code form is that same work. - -2. Basic Permissions. -All rights granted under this License are granted for the term of copyright -on the Program, and are irrevocable provided the stated conditions are met. -This License explicitly affirms your unlimited permission to run the unmodified -Program. The output from running a covered work is covered by this License -only if the output, given its content, constitutes a covered work. This License -acknowledges your rights of fair use or other equivalent, as provided by copyright -law. - -You may make, run and propagate covered works that you do not convey, without -conditions so long as your license otherwise remains in force. You may convey -covered works to others for the sole purpose of having them make modifications -exclusively for you, or provide you with facilities for running those works, -provided that you comply with the terms of this License in conveying all material -for which you do not control copyright. Those thus making or running the covered -works for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of your copyrighted -material outside their relationship with you. - -Conveying under any other circumstances is permitted solely under the conditions -stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - -3. Protecting Users' Legal Rights From Anti-Circumvention Law. -No covered work shall be deemed part of an effective technological measure -under any applicable law fulfilling obligations under article 11 of the WIPO -copyright treaty adopted on 20 December 1996, or similar laws prohibiting -or restricting circumvention of such measures. - -When you convey a covered work, you waive any legal power to forbid circumvention -of technological measures to the extent such circumvention is effected by -exercising rights under this License with respect to the covered work, and -you disclaim any intention to limit operation or modification of the work -as a means of enforcing, against the work's users, your or third parties' -legal rights to forbid circumvention of technological measures. - -4. Conveying Verbatim Copies. -You may convey verbatim copies of the Program's source code as you receive -it, in any medium, provided that you conspicuously and appropriately publish -on each copy an appropriate copyright notice; keep intact all notices stating -that this License and any non-permissive terms added in accord with section -7 apply to the code; keep intact all notices of the absence of any warranty; -and give all recipients a copy of this License along with the Program. - -You may charge any price or no price for each copy that you convey, and you -may offer support or warranty protection for a fee. - -5. Conveying Modified Source Versions. -You may convey a work based on the Program, or the modifications to produce -it from the Program, in the form of source code under the terms of section -4, provided that you also meet all of these conditions: - -a) The work must carry prominent notices stating that you modified it, and -giving a relevant date. - -b) The work must carry prominent notices stating that it is released under -this License and any conditions added under section 7. This requirement modifies -the requirement in section 4 to “keep intact all notices”. - -c) You must license the entire work, as a whole, under this License to anyone -who comes into possession of a copy. This License will therefore apply, along -with any applicable section 7 additional terms, to the whole of the work, -and all its parts, regardless of how they are packaged. This License gives -no permission to license the work in any other way, but it does not invalidate -such permission if you have separately received it. - -d) If the work has interactive user interfaces, each must display Appropriate -Legal Notices; however, if the Program has interactive interfaces that do -not display Appropriate Legal Notices, your work need not make them do so. - -A compilation of a covered work with other separate and independent works, -which are not by their nature extensions of the covered work, and which are -not combined with it such as to form a larger program, in or on a volume of -a storage or distribution medium, is called an “aggregate” if the compilation -and its resulting copyright are not used to limit the access or legal rights -of the compilation's users beyond what the individual works permit. Inclusion -of a covered work in an aggregate does not cause this License to apply to -the other parts of the aggregate. - -6. Conveying Non-Source Forms. -You may convey a covered work in object code form under the terms of sections -4 and 5, provided that you also convey the machine-readable Corresponding -Source under the terms of this License, in one of these ways: - -a) Convey the object code in, or embodied in, a physical product (including -a physical distribution medium), accompanied by the Corresponding Source fixed -on a durable physical medium customarily used for software interchange. - -b) Convey the object code in, or embodied in, a physical product (including -a physical distribution medium), accompanied by a written offer, valid for -at least three years and valid for as long as you offer spare parts or customer -support for that product model, to give anyone who possesses the object code -either (1) a copy of the Corresponding Source for all the software in the -product that is covered by this License, on a durable physical medium customarily -used for software interchange, for a price no more than your reasonable cost -of physically performing this conveying of source, or (2) access to copy the -Corresponding Source from a network server at no charge. - -c) Convey individual copies of the object code with a copy of the written -offer to provide the Corresponding Source. This alternative is allowed only -occasionally and noncommercially, and only if you received the object code -with such an offer, in accord with subsection 6b. - -d) Convey the object code by offering access from a designated place (gratis -or for a charge), and offer equivalent access to the Corresponding Source -in the same way through the same place at no further charge. You need not -require recipients to copy the Corresponding Source along with the object -code. If the place to copy the object code is a network server, the Corresponding -Source may be on a different server (operated by you or a third party) that -supports equivalent copying facilities, provided you maintain clear directions -next to the object code saying where to find the Corresponding Source. Regardless -of what server hosts the Corresponding Source, you remain obligated to ensure -that it is available for as long as needed to satisfy these requirements. - -e) Convey the object code using peer-to-peer transmission, provided you inform -other peers where the object code and Corresponding Source of the work are -being offered to the general public at no charge under subsection 6d. - -A separable portion of the object code, whose source code is excluded from -the Corresponding Source as a System Library, need not be included in conveying -the object code work. - -A “User Product” is either (1) a “consumer product”, which means any tangible -personal property which is normally used for personal, family, or household -purposes, or (2) anything designed or sold for incorporation into a dwelling. -In determining whether a product is a consumer product, doubtful cases shall -be resolved in favor of coverage. For a particular product received by a particular -user, “normally used” refers to a typical or common use of that class of product, -regardless of the status of the particular user or of the way in which the -particular user actually uses, or expects or is expected to use, the product. -A product is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent the -only significant mode of use of the product. - -“Installation Information” for a User Product means any methods, procedures, -authorization keys, or other information required to install and execute modified -versions of a covered work in that User Product from a modified version of -its Corresponding Source. The information must suffice to ensure that the -continued functioning of the modified object code is in no case prevented -or interfered with solely because modification has been made. - -If you convey an object code work under this section in, or with, or specifically -for use in, a User Product, and the conveying occurs as part of a transaction -in which the right of possession and use of the User Product is transferred -to the recipient in perpetuity or for a fixed term (regardless of how the -transaction is characterized), the Corresponding Source conveyed under this -section must be accompanied by the Installation Information. But this requirement -does not apply if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has been installed -in ROM). - -The requirement to provide Installation Information does not include a requirement -to continue to provide support service, warranty, or updates for a work that -has been modified or installed by the recipient, or for the User Product in -which it has been modified or installed. Access to a network may be denied -when the modification itself materially and adversely affects the operation -of the network or violates the rules and protocols for communication across -the network. - -Corresponding Source conveyed, and Installation Information provided, in accord -with this section must be in a format that is publicly documented (and with -an implementation available to the public in source code form), and must require -no special password or key for unpacking, reading or copying. - -7. Additional Terms. -“Additional permissions” are terms that supplement the terms of this License -by making exceptions from one or more of its conditions. Additional permissions -that are applicable to the entire Program shall be treated as though they -were included in this License, to the extent that they are valid under applicable -law. If additional permissions apply only to part of the Program, that part -may be used separately under those permissions, but the entire Program remains -governed by this License without regard to the additional permissions. - -When you convey a copy of a covered work, you may at your option remove any -additional permissions from that copy, or from any part of it. (Additional -permissions may be written to require their own removal in certain cases when -you modify the work.) You may place additional permissions on material, added -by you to a covered work, for which you have or can give appropriate copyright -permission. - -Notwithstanding any other provision of this License, for material you add -to a covered work, you may (if authorized by the copyright holders of that -material) supplement the terms of this License with terms: - -a) Disclaiming warranty or limiting liability differently from the terms of -sections 15 and 16 of this License; or - -b) Requiring preservation of specified reasonable legal notices or author -attributions in that material or in the Appropriate Legal Notices displayed -by works containing it; or - -c) Prohibiting misrepresentation of the origin of that material, or requiring -that modified versions of such material be marked in reasonable ways as different -from the original version; or - -d) Limiting the use for publicity purposes of names of licensors or authors -of the material; or - -e) Declining to grant rights under trademark law for use of some trade names, -trademarks, or service marks; or - -f) Requiring indemnification of licensors and authors of that material by -anyone who conveys the material (or modified versions of it) with contractual -assumptions of liability to the recipient, for any liability that these contractual -assumptions directly impose on those licensors and authors. - -All other non-permissive additional terms are considered “further restrictions” -within the meaning of section 10. If the Program as you received it, or any -part of it, contains a notice stating that it is governed by this License -along with a term that is a further restriction, you may remove that term. -If a license document contains a further restriction but permits relicensing -or conveying under this License, you may add to a covered work material governed -by the terms of that license document, provided that the further restriction -does not survive such relicensing or conveying. - -If you add terms to a covered work in accord with this section, you must place, -in the relevant source files, a statement of the additional terms that apply -to those files, or a notice indicating where to find the applicable terms. - -Additional terms, permissive or non-permissive, may be stated in the form -of a separately written license, or stated as exceptions; the above requirements -apply either way. - -8. Termination. -You may not propagate or modify a covered work except as expressly provided -under this License. Any attempt otherwise to propagate or modify it is void, -and will automatically terminate your rights under this License (including -any patent licenses granted under the third paragraph of section 11). - -However, if you cease all violation of this License, then your license from -a particular copyright holder is reinstated (a) provisionally, unless and -until the copyright holder explicitly and finally terminates your license, -and (b) permanently, if the copyright holder fails to notify you of the violation -by some reasonable means prior to 60 days after the cessation. - -Moreover, your license from a particular copyright holder is reinstated permanently -if the copyright holder notifies you of the violation by some reasonable means, -this is the first time you have received notice of violation of this License -(for any work) from that copyright holder, and you cure the violation prior -to 30 days after your receipt of the notice. - -Termination of your rights under this section does not terminate the licenses -of parties who have received copies or rights from you under this License. -If your rights have been terminated and not permanently reinstated, you do -not qualify to receive new licenses for the same material under section 10. - -9. Acceptance Not Required for Having Copies. -You are not required to accept this License in order to receive or run a copy -of the Program. Ancillary propagation of a covered work occurring solely as -a consequence of using peer-to-peer transmission to receive a copy likewise -does not require acceptance. However, nothing other than this License grants -you permission to propagate or modify any covered work. These actions infringe -copyright if you do not accept this License. Therefore, by modifying or propagating -a covered work, you indicate your acceptance of this License to do so. - -10. Automatic Licensing of Downstream Recipients. -Each time you convey a covered work, the recipient automatically receives -a license from the original licensors, to run, modify and propagate that work, -subject to this License. You are not responsible for enforcing compliance -by third parties with this License. - -An “entity transaction” is a transaction transferring control of an organization, -or substantially all assets of one, or subdividing an organization, or merging -organizations. If propagation of a covered work results from an entity transaction, -each party to that transaction who receives a copy of the work also receives -whatever licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the Corresponding -Source of the work from the predecessor in interest, if the predecessor has -it or can get it with reasonable efforts. - -You may not impose any further restrictions on the exercise of the rights -granted or affirmed under this License. For example, you may not impose a -license fee, royalty, or other charge for exercise of rights granted under -this License, and you may not initiate litigation (including a cross-claim -or counterclaim in a lawsuit) alleging that any patent claim is infringed -by making, using, selling, offering for sale, or importing the Program or -any portion of it. - -11. Patents. -A “contributor” is a copyright holder who authorizes use under this License -of the Program or a work on which the Program is based. The work thus licensed -is called the contributor's “contributor version”. - -A contributor's “essential patent claims” are all patent claims owned or controlled -by the contributor, whether already acquired or hereafter acquired, that would -be infringed by some manner, permitted by this License, of making, using, -or selling its contributor version, but do not include claims that would be -infringed only as a consequence of further modification of the contributor -version. For purposes of this definition, “control” includes the right to -grant patent sublicenses in a manner consistent with the requirements of this -License. - -Each contributor grants you a non-exclusive, worldwide, royalty-free patent -license under the contributor's essential patent claims, to make, use, sell, -offer for sale, import and otherwise run, modify and propagate the contents -of its contributor version. - -In the following three paragraphs, a “patent license” is any express agreement -or commitment, however denominated, not to enforce a patent (such as an express -permission to practice a patent or covenant not to sue for patent infringement). -To “grant” such a patent license to a party means to make such an agreement -or commitment not to enforce a patent against the party. - -If you convey a covered work, knowingly relying on a patent license, and the -Corresponding Source of the work is not available for anyone to copy, free -of charge and under the terms of this License, through a publicly available -network server or other readily accessible means, then you must either (1) -cause the Corresponding Source to be so available, or (2) arrange to deprive -yourself of the benefit of the patent license for this particular work, or -(3) arrange, in a manner consistent with the requirements of this License, -to extend the patent license to downstream recipients. “Knowingly relying” -means you have actual knowledge that, but for the patent license, your conveying -the covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that country -that you have reason to believe are valid. - -If, pursuant to or in connection with a single transaction or arrangement, -you convey, or propagate by procuring conveyance of, a covered work, and grant -a patent license to some of the parties receiving the covered work authorizing -them to use, propagate, modify or convey a specific copy of the covered work, -then the patent license you grant is automatically extended to all recipients -of the covered work and works based on it. - -A patent license is “discriminatory” if it does not include within the scope -of its coverage, prohibits the exercise of, or is conditioned on the non-exercise -of one or more of the rights that are specifically granted under this License. -You may not convey a covered work if you are a party to an arrangement with -a third party that is in the business of distributing software, under which -you make payment to the third party based on the extent of your activity of -conveying the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory patent -license (a) in connection with copies of the covered work conveyed by you -(or copies made from those copies), or (b) primarily for and in connection -with specific products or compilations that contain the covered work, unless -you entered into that arrangement, or that patent license was granted, prior -to 28 March 2007. - -Nothing in this License shall be construed as excluding or limiting any implied -license or other defenses to infringement that may otherwise be available -to you under applicable patent law. - -12. No Surrender of Others' Freedom. -If conditions are imposed on you (whether by court order, agreement or otherwise) -that contradict the conditions of this License, they do not excuse you from -the conditions of this License. If you cannot convey a covered work so as -to satisfy simultaneously your obligations under this License and any other -pertinent obligations, then as a consequence you may not convey it at all. -For example, if you agree to terms that obligate you to collect a royalty -for further conveying from those to whom you convey the Program, the only -way you could satisfy both those terms and this License would be to refrain -entirely from conveying the Program. - -13. Use with the GNU Affero General Public License. -Notwithstanding any other provision of this License, you have permission to -link or combine any covered work with a work licensed under version 3 of the -GNU Affero General Public License into a single combined work, and to convey -the resulting work. The terms of this License will continue to apply to the -part which is the covered work, but the special requirements of the GNU Affero -General Public License, section 13, concerning interaction through a network -will apply to the combination as such. - -14. Revised Versions of this License. -The Free Software Foundation may publish revised and/or new versions of the -GNU General Public License from time to time. Such new versions will be similar -in spirit to the present version, but may differ in detail to address new -problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies -that a certain numbered version of the GNU General Public License “or any -later version” applies to it, you have the option of following the terms and -conditions either of that numbered version or of any later version published -by the Free Software Foundation. If the Program does not specify a version -number of the GNU General Public License, you may choose any version ever -published by the Free Software Foundation. - -If the Program specifies that a proxy can decide which future versions of -the GNU General Public License can be used, that proxy's public statement -of acceptance of a version permanently authorizes you to choose that version -for the Program. - -Later license versions may give you additional or different permissions. However, -no additional obligations are imposed on any author or copyright holder as -a result of your choosing to follow a later version. - -15. Disclaimer of Warranty. -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE -LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM -PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR -CORRECTION. - -16. Limitation of Liability. -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL -ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM -AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, -INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO -USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED -INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE -PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER -PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -17. Interpretation of Sections 15 and 16. -If the disclaimer of warranty and limitation of liability provided above cannot -be given local legal effect according to their terms, reviewing courts shall -apply local law that most closely approximates an absolute waiver of all civil -liability in connection with the Program, unless a warranty or assumption -of liability accompanies a copy of the Program in return for a fee. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible -use to the public, the best way to achieve this is to make it free software -which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach -them to the start of each source file to most effectively state the exclusion -of warranty; and each file should have at least the “copyright” line and a -pointer to where the full notice is found. - - - Copyright (C) - -This program is free software: you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - -If the program does terminal interaction, make it output a short notice like -this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -This is free software, and you are welcome to redistribute it under certain -conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands might -be different; for a GUI interface, you would use an “about box”. - -You should also get your employer (if you work as a programmer) or school, -if any, to sign a “copyright disclaimer” for the program, if necessary. For -more information on this, and how to apply and follow the GNU GPL, see . - -The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General Public -License instead of this License. But first, please read . diff --git a/ports/stm32/boards/Passport/LICENSES/GPL-3.0-or-later.txt b/ports/stm32/boards/Passport/LICENSES/GPL-3.0-or-later.txt deleted file mode 100644 index 0adc84e82..000000000 --- a/ports/stm32/boards/Passport/LICENSES/GPL-3.0-or-later.txt +++ /dev/null @@ -1,604 +0,0 @@ -GNU GENERAL PUBLIC LICENSE -Version 3, 29 June 2007 - -Copyright © 2007 Free Software Foundation, Inc. - -Everyone is permitted to copy and distribute verbatim copies of this license -document, but changing it is not allowed. - -Preamble - -The GNU General Public License is a free, copyleft license for software and -other kinds of works. - -The licenses for most software and other practical works are designed to take -away your freedom to share and change the works. By contrast, the GNU General -Public License is intended to guarantee your freedom to share and change all -versions of a program--to make sure it remains free software for all its users. -We, the Free Software Foundation, use the GNU General Public License for most -of our software; it applies also to any other work released this way by its -authors. You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our -General Public Licenses are designed to make sure that you have the freedom -to distribute copies of free software (and charge for them if you wish), that -you receive source code or can get it if you want it, that you can change -the software or use pieces of it in new free programs, and that you know you -can do these things. - -To protect your rights, we need to prevent others from denying you these rights -or asking you to surrender the rights. Therefore, you have certain responsibilities -if you distribute copies of the software, or if you modify it: responsibilities -to respect the freedom of others. - -For example, if you distribute copies of such a program, whether gratis or -for a fee, you must pass on to the recipients the same freedoms that you received. -You must make sure that they, too, receive or can get the source code. And -you must show them these terms so they know their rights. - -Developers that use the GNU GPL protect your rights with two steps: (1) assert -copyright on the software, and (2) offer you this License giving you legal -permission to copy, distribute and/or modify it. - -For the developers' and authors' protection, the GPL clearly explains that -there is no warranty for this free software. For both users' and authors' -sake, the GPL requires that modified versions be marked as changed, so that -their problems will not be attributed erroneously to authors of previous versions. - -Some devices are designed to deny users access to install or run modified -versions of the software inside them, although the manufacturer can do so. -This is fundamentally incompatible with the aim of protecting users' freedom -to change the software. The systematic pattern of such abuse occurs in the -area of products for individuals to use, which is precisely where it is most -unacceptable. Therefore, we have designed this version of the GPL to prohibit -the practice for those products. If such problems arise substantially in other -domains, we stand ready to extend this provision to those domains in future -versions of the GPL, as needed to protect the freedom of users. - -Finally, every program is threatened constantly by software patents. States -should not allow patents to restrict development and use of software on general-purpose -computers, but in those that do, we wish to avoid the special danger that -patents applied to a free program could make it effectively proprietary. To -prevent this, the GPL assures that patents cannot be used to render the program -non-free. - -The precise terms and conditions for copying, distribution and modification -follow. - -TERMS AND CONDITIONS - -0. Definitions. - -“This License” refers to version 3 of the GNU General Public License. - -“Copyright” also means copyright-like laws that apply to other kinds of works, -such as semiconductor masks. - -“The Program” refers to any copyrightable work licensed under this License. -Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals -or organizations. - -To “modify” a work means to copy from or adapt all or part of the work in -a fashion requiring copyright permission, other than the making of an exact -copy. The resulting work is called a “modified version” of the earlier work -or a work “based on” the earlier work. - -A “covered work” means either the unmodified Program or a work based on the -Program. - -To “propagate” a work means to do anything with it that, without permission, -would make you directly or secondarily liable for infringement under applicable -copyright law, except executing it on a computer or modifying a private copy. -Propagation includes copying, distribution (with or without modification), -making available to the public, and in some countries other activities as -well. - -To “convey” a work means any kind of propagation that enables other parties -to make or receive copies. Mere interaction with a user through a computer -network, with no transfer of a copy, is not conveying. - -An interactive user interface displays “Appropriate Legal Notices” to the -extent that it includes a convenient and prominently visible feature that -(1) displays an appropriate copyright notice, and (2) tells the user that -there is no warranty for the work (except to the extent that warranties are -provided), that licensees may convey the work under this License, and how -to view a copy of this License. If the interface presents a list of user commands -or options, such as a menu, a prominent item in the list meets this criterion. - -1. Source Code. -The “source code” for a work means the preferred form of the work for making -modifications to it. “Object code” means any non-source form of a work. - -A “Standard Interface” means an interface that either is an official standard -defined by a recognized standards body, or, in the case of interfaces specified -for a particular programming language, one that is widely used among developers -working in that language. - -The “System Libraries” of an executable work include anything, other than -the work as a whole, that (a) is included in the normal form of packaging -a Major Component, but which is not part of that Major Component, and (b) -serves only to enable use of the work with that Major Component, or to implement -a Standard Interface for which an implementation is available to the public -in source code form. A “Major Component”, in this context, means a major essential -component (kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to produce -the work, or an object code interpreter used to run it. - -The “Corresponding Source” for a work in object code form means all the source -code needed to generate, install, and (for an executable work) run the object -code and to modify the work, including scripts to control those activities. -However, it does not include the work's System Libraries, or general-purpose -tools or generally available free programs which are used unmodified in performing -those activities but which are not part of the work. For example, Corresponding -Source includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically linked -subprograms that the work is specifically designed to require, such as by -intimate data communication or control flow between those subprograms and -other parts of the work. - -The Corresponding Source need not include anything that users can regenerate -automatically from other parts of the Corresponding Source. - -The Corresponding Source for a work in source code form is that same work. - -2. Basic Permissions. -All rights granted under this License are granted for the term of copyright -on the Program, and are irrevocable provided the stated conditions are met. -This License explicitly affirms your unlimited permission to run the unmodified -Program. The output from running a covered work is covered by this License -only if the output, given its content, constitutes a covered work. This License -acknowledges your rights of fair use or other equivalent, as provided by copyright -law. - -You may make, run and propagate covered works that you do not convey, without -conditions so long as your license otherwise remains in force. You may convey -covered works to others for the sole purpose of having them make modifications -exclusively for you, or provide you with facilities for running those works, -provided that you comply with the terms of this License in conveying all material -for which you do not control copyright. Those thus making or running the covered -works for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of your copyrighted -material outside their relationship with you. - -Conveying under any other circumstances is permitted solely under the conditions -stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - -3. Protecting Users' Legal Rights From Anti-Circumvention Law. -No covered work shall be deemed part of an effective technological measure -under any applicable law fulfilling obligations under article 11 of the WIPO -copyright treaty adopted on 20 December 1996, or similar laws prohibiting -or restricting circumvention of such measures. - -When you convey a covered work, you waive any legal power to forbid circumvention -of technological measures to the extent such circumvention is effected by -exercising rights under this License with respect to the covered work, and -you disclaim any intention to limit operation or modification of the work -as a means of enforcing, against the work's users, your or third parties' -legal rights to forbid circumvention of technological measures. - -4. Conveying Verbatim Copies. -You may convey verbatim copies of the Program's source code as you receive -it, in any medium, provided that you conspicuously and appropriately publish -on each copy an appropriate copyright notice; keep intact all notices stating -that this License and any non-permissive terms added in accord with section -7 apply to the code; keep intact all notices of the absence of any warranty; -and give all recipients a copy of this License along with the Program. - -You may charge any price or no price for each copy that you convey, and you -may offer support or warranty protection for a fee. - -5. Conveying Modified Source Versions. -You may convey a work based on the Program, or the modifications to produce -it from the Program, in the form of source code under the terms of section -4, provided that you also meet all of these conditions: - -a) The work must carry prominent notices stating that you modified it, and -giving a relevant date. - -b) The work must carry prominent notices stating that it is released under -this License and any conditions added under section 7. This requirement modifies -the requirement in section 4 to “keep intact all notices”. - -c) You must license the entire work, as a whole, under this License to anyone -who comes into possession of a copy. This License will therefore apply, along -with any applicable section 7 additional terms, to the whole of the work, -and all its parts, regardless of how they are packaged. This License gives -no permission to license the work in any other way, but it does not invalidate -such permission if you have separately received it. - -d) If the work has interactive user interfaces, each must display Appropriate -Legal Notices; however, if the Program has interactive interfaces that do -not display Appropriate Legal Notices, your work need not make them do so. - -A compilation of a covered work with other separate and independent works, -which are not by their nature extensions of the covered work, and which are -not combined with it such as to form a larger program, in or on a volume of -a storage or distribution medium, is called an “aggregate” if the compilation -and its resulting copyright are not used to limit the access or legal rights -of the compilation's users beyond what the individual works permit. Inclusion -of a covered work in an aggregate does not cause this License to apply to -the other parts of the aggregate. - -6. Conveying Non-Source Forms. -You may convey a covered work in object code form under the terms of sections -4 and 5, provided that you also convey the machine-readable Corresponding -Source under the terms of this License, in one of these ways: - -a) Convey the object code in, or embodied in, a physical product (including -a physical distribution medium), accompanied by the Corresponding Source fixed -on a durable physical medium customarily used for software interchange. - -b) Convey the object code in, or embodied in, a physical product (including -a physical distribution medium), accompanied by a written offer, valid for -at least three years and valid for as long as you offer spare parts or customer -support for that product model, to give anyone who possesses the object code -either (1) a copy of the Corresponding Source for all the software in the -product that is covered by this License, on a durable physical medium customarily -used for software interchange, for a price no more than your reasonable cost -of physically performing this conveying of source, or (2) access to copy the -Corresponding Source from a network server at no charge. - -c) Convey individual copies of the object code with a copy of the written -offer to provide the Corresponding Source. This alternative is allowed only -occasionally and noncommercially, and only if you received the object code -with such an offer, in accord with subsection 6b. - -d) Convey the object code by offering access from a designated place (gratis -or for a charge), and offer equivalent access to the Corresponding Source -in the same way through the same place at no further charge. You need not -require recipients to copy the Corresponding Source along with the object -code. If the place to copy the object code is a network server, the Corresponding -Source may be on a different server (operated by you or a third party) that -supports equivalent copying facilities, provided you maintain clear directions -next to the object code saying where to find the Corresponding Source. Regardless -of what server hosts the Corresponding Source, you remain obligated to ensure -that it is available for as long as needed to satisfy these requirements. - -e) Convey the object code using peer-to-peer transmission, provided you inform -other peers where the object code and Corresponding Source of the work are -being offered to the general public at no charge under subsection 6d. - -A separable portion of the object code, whose source code is excluded from -the Corresponding Source as a System Library, need not be included in conveying -the object code work. - -A “User Product” is either (1) a “consumer product”, which means any tangible -personal property which is normally used for personal, family, or household -purposes, or (2) anything designed or sold for incorporation into a dwelling. -In determining whether a product is a consumer product, doubtful cases shall -be resolved in favor of coverage. For a particular product received by a particular -user, “normally used” refers to a typical or common use of that class of product, -regardless of the status of the particular user or of the way in which the -particular user actually uses, or expects or is expected to use, the product. -A product is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent the -only significant mode of use of the product. - -“Installation Information” for a User Product means any methods, procedures, -authorization keys, or other information required to install and execute modified -versions of a covered work in that User Product from a modified version of -its Corresponding Source. The information must suffice to ensure that the -continued functioning of the modified object code is in no case prevented -or interfered with solely because modification has been made. - -If you convey an object code work under this section in, or with, or specifically -for use in, a User Product, and the conveying occurs as part of a transaction -in which the right of possession and use of the User Product is transferred -to the recipient in perpetuity or for a fixed term (regardless of how the -transaction is characterized), the Corresponding Source conveyed under this -section must be accompanied by the Installation Information. But this requirement -does not apply if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has been installed -in ROM). - -The requirement to provide Installation Information does not include a requirement -to continue to provide support service, warranty, or updates for a work that -has been modified or installed by the recipient, or for the User Product in -which it has been modified or installed. Access to a network may be denied -when the modification itself materially and adversely affects the operation -of the network or violates the rules and protocols for communication across -the network. - -Corresponding Source conveyed, and Installation Information provided, in accord -with this section must be in a format that is publicly documented (and with -an implementation available to the public in source code form), and must require -no special password or key for unpacking, reading or copying. - -7. Additional Terms. -“Additional permissions” are terms that supplement the terms of this License -by making exceptions from one or more of its conditions. Additional permissions -that are applicable to the entire Program shall be treated as though they -were included in this License, to the extent that they are valid under applicable -law. If additional permissions apply only to part of the Program, that part -may be used separately under those permissions, but the entire Program remains -governed by this License without regard to the additional permissions. - -When you convey a copy of a covered work, you may at your option remove any -additional permissions from that copy, or from any part of it. (Additional -permissions may be written to require their own removal in certain cases when -you modify the work.) You may place additional permissions on material, added -by you to a covered work, for which you have or can give appropriate copyright -permission. - -Notwithstanding any other provision of this License, for material you add -to a covered work, you may (if authorized by the copyright holders of that -material) supplement the terms of this License with terms: - -a) Disclaiming warranty or limiting liability differently from the terms of -sections 15 and 16 of this License; or - -b) Requiring preservation of specified reasonable legal notices or author -attributions in that material or in the Appropriate Legal Notices displayed -by works containing it; or - -c) Prohibiting misrepresentation of the origin of that material, or requiring -that modified versions of such material be marked in reasonable ways as different -from the original version; or - -d) Limiting the use for publicity purposes of names of licensors or authors -of the material; or - -e) Declining to grant rights under trademark law for use of some trade names, -trademarks, or service marks; or - -f) Requiring indemnification of licensors and authors of that material by -anyone who conveys the material (or modified versions of it) with contractual -assumptions of liability to the recipient, for any liability that these contractual -assumptions directly impose on those licensors and authors. - -All other non-permissive additional terms are considered “further restrictions” -within the meaning of section 10. If the Program as you received it, or any -part of it, contains a notice stating that it is governed by this License -along with a term that is a further restriction, you may remove that term. -If a license document contains a further restriction but permits relicensing -or conveying under this License, you may add to a covered work material governed -by the terms of that license document, provided that the further restriction -does not survive such relicensing or conveying. - -If you add terms to a covered work in accord with this section, you must place, -in the relevant source files, a statement of the additional terms that apply -to those files, or a notice indicating where to find the applicable terms. - -Additional terms, permissive or non-permissive, may be stated in the form -of a separately written license, or stated as exceptions; the above requirements -apply either way. - -8. Termination. -You may not propagate or modify a covered work except as expressly provided -under this License. Any attempt otherwise to propagate or modify it is void, -and will automatically terminate your rights under this License (including -any patent licenses granted under the third paragraph of section 11). - -However, if you cease all violation of this License, then your license from -a particular copyright holder is reinstated (a) provisionally, unless and -until the copyright holder explicitly and finally terminates your license, -and (b) permanently, if the copyright holder fails to notify you of the violation -by some reasonable means prior to 60 days after the cessation. - -Moreover, your license from a particular copyright holder is reinstated permanently -if the copyright holder notifies you of the violation by some reasonable means, -this is the first time you have received notice of violation of this License -(for any work) from that copyright holder, and you cure the violation prior -to 30 days after your receipt of the notice. - -Termination of your rights under this section does not terminate the licenses -of parties who have received copies or rights from you under this License. -If your rights have been terminated and not permanently reinstated, you do -not qualify to receive new licenses for the same material under section 10. - -9. Acceptance Not Required for Having Copies. -You are not required to accept this License in order to receive or run a copy -of the Program. Ancillary propagation of a covered work occurring solely as -a consequence of using peer-to-peer transmission to receive a copy likewise -does not require acceptance. However, nothing other than this License grants -you permission to propagate or modify any covered work. These actions infringe -copyright if you do not accept this License. Therefore, by modifying or propagating -a covered work, you indicate your acceptance of this License to do so. - -10. Automatic Licensing of Downstream Recipients. -Each time you convey a covered work, the recipient automatically receives -a license from the original licensors, to run, modify and propagate that work, -subject to this License. You are not responsible for enforcing compliance -by third parties with this License. - -An “entity transaction” is a transaction transferring control of an organization, -or substantially all assets of one, or subdividing an organization, or merging -organizations. If propagation of a covered work results from an entity transaction, -each party to that transaction who receives a copy of the work also receives -whatever licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the Corresponding -Source of the work from the predecessor in interest, if the predecessor has -it or can get it with reasonable efforts. - -You may not impose any further restrictions on the exercise of the rights -granted or affirmed under this License. For example, you may not impose a -license fee, royalty, or other charge for exercise of rights granted under -this License, and you may not initiate litigation (including a cross-claim -or counterclaim in a lawsuit) alleging that any patent claim is infringed -by making, using, selling, offering for sale, or importing the Program or -any portion of it. - -11. Patents. -A “contributor” is a copyright holder who authorizes use under this License -of the Program or a work on which the Program is based. The work thus licensed -is called the contributor's “contributor version”. - -A contributor's “essential patent claims” are all patent claims owned or controlled -by the contributor, whether already acquired or hereafter acquired, that would -be infringed by some manner, permitted by this License, of making, using, -or selling its contributor version, but do not include claims that would be -infringed only as a consequence of further modification of the contributor -version. For purposes of this definition, “control” includes the right to -grant patent sublicenses in a manner consistent with the requirements of this -License. - -Each contributor grants you a non-exclusive, worldwide, royalty-free patent -license under the contributor's essential patent claims, to make, use, sell, -offer for sale, import and otherwise run, modify and propagate the contents -of its contributor version. - -In the following three paragraphs, a “patent license” is any express agreement -or commitment, however denominated, not to enforce a patent (such as an express -permission to practice a patent or covenant not to sue for patent infringement). -To “grant” such a patent license to a party means to make such an agreement -or commitment not to enforce a patent against the party. - -If you convey a covered work, knowingly relying on a patent license, and the -Corresponding Source of the work is not available for anyone to copy, free -of charge and under the terms of this License, through a publicly available -network server or other readily accessible means, then you must either (1) -cause the Corresponding Source to be so available, or (2) arrange to deprive -yourself of the benefit of the patent license for this particular work, or -(3) arrange, in a manner consistent with the requirements of this License, -to extend the patent license to downstream recipients. “Knowingly relying” -means you have actual knowledge that, but for the patent license, your conveying -the covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that country -that you have reason to believe are valid. - -If, pursuant to or in connection with a single transaction or arrangement, -you convey, or propagate by procuring conveyance of, a covered work, and grant -a patent license to some of the parties receiving the covered work authorizing -them to use, propagate, modify or convey a specific copy of the covered work, -then the patent license you grant is automatically extended to all recipients -of the covered work and works based on it. - -A patent license is “discriminatory” if it does not include within the scope -of its coverage, prohibits the exercise of, or is conditioned on the non-exercise -of one or more of the rights that are specifically granted under this License. -You may not convey a covered work if you are a party to an arrangement with -a third party that is in the business of distributing software, under which -you make payment to the third party based on the extent of your activity of -conveying the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory patent -license (a) in connection with copies of the covered work conveyed by you -(or copies made from those copies), or (b) primarily for and in connection -with specific products or compilations that contain the covered work, unless -you entered into that arrangement, or that patent license was granted, prior -to 28 March 2007. - -Nothing in this License shall be construed as excluding or limiting any implied -license or other defenses to infringement that may otherwise be available -to you under applicable patent law. - -12. No Surrender of Others' Freedom. -If conditions are imposed on you (whether by court order, agreement or otherwise) -that contradict the conditions of this License, they do not excuse you from -the conditions of this License. If you cannot convey a covered work so as -to satisfy simultaneously your obligations under this License and any other -pertinent obligations, then as a consequence you may not convey it at all. -For example, if you agree to terms that obligate you to collect a royalty -for further conveying from those to whom you convey the Program, the only -way you could satisfy both those terms and this License would be to refrain -entirely from conveying the Program. - -13. Use with the GNU Affero General Public License. -Notwithstanding any other provision of this License, you have permission to -link or combine any covered work with a work licensed under version 3 of the -GNU Affero General Public License into a single combined work, and to convey -the resulting work. The terms of this License will continue to apply to the -part which is the covered work, but the special requirements of the GNU Affero -General Public License, section 13, concerning interaction through a network -will apply to the combination as such. - -14. Revised Versions of this License. -The Free Software Foundation may publish revised and/or new versions of the -GNU General Public License from time to time. Such new versions will be similar -in spirit to the present version, but may differ in detail to address new -problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies -that a certain numbered version of the GNU General Public License “or any -later version” applies to it, you have the option of following the terms and -conditions either of that numbered version or of any later version published -by the Free Software Foundation. If the Program does not specify a version -number of the GNU General Public License, you may choose any version ever -published by the Free Software Foundation. - -If the Program specifies that a proxy can decide which future versions of -the GNU General Public License can be used, that proxy's public statement -of acceptance of a version permanently authorizes you to choose that version -for the Program. - -Later license versions may give you additional or different permissions. However, -no additional obligations are imposed on any author or copyright holder as -a result of your choosing to follow a later version. - -15. Disclaimer of Warranty. -THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE -LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM -PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR -CORRECTION. - -16. Limitation of Liability. -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL -ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM -AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, -INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO -USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED -INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE -PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER -PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -17. Interpretation of Sections 15 and 16. -If the disclaimer of warranty and limitation of liability provided above cannot -be given local legal effect according to their terms, reviewing courts shall -apply local law that most closely approximates an absolute waiver of all civil -liability in connection with the Program, unless a warranty or assumption -of liability accompanies a copy of the Program in return for a fee. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible -use to the public, the best way to achieve this is to make it free software -which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach -them to the start of each source file to most effectively state the exclusion -of warranty; and each file should have at least the “copyright” line and a -pointer to where the full notice is found. - - - Copyright (C) - -This program is free software: you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - -If the program does terminal interaction, make it output a short notice like -this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -This is free software, and you are welcome to redistribute it under certain -conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands might -be different; for a GUI interface, you would use an “about box”. - -You should also get your employer (if you work as a programmer) or school, -if any, to sign a “copyright disclaimer” for the program, if necessary. For -more information on this, and how to apply and follow the GNU GPL, see . - -The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General Public -License instead of this License. But first, please read . diff --git a/ports/stm32/boards/Passport/LICENSES/ISC.txt b/ports/stm32/boards/Passport/LICENSES/ISC.txt deleted file mode 100644 index a6d1964fe..000000000 --- a/ports/stm32/boards/Passport/LICENSES/ISC.txt +++ /dev/null @@ -1,15 +0,0 @@ -ISC License: - -Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") -Copyright (c) 1995-2003 by Internet Software Consortium - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD -TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING -OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/ports/stm32/boards/Passport/LICENSES/MIT.txt b/ports/stm32/boards/Passport/LICENSES/MIT.txt deleted file mode 100644 index f0fd20ab6..000000000 --- a/ports/stm32/boards/Passport/LICENSES/MIT.txt +++ /dev/null @@ -1,20 +0,0 @@ -MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF -OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/ports/stm32/boards/Passport/LICENSES/Unlicense.txt b/ports/stm32/boards/Passport/LICENSES/Unlicense.txt deleted file mode 100644 index 5227a51bd..000000000 --- a/ports/stm32/boards/Passport/LICENSES/Unlicense.txt +++ /dev/null @@ -1,22 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or distribute -this software, either in source code form or as a compiled binary, for any -purpose, commercial or non-commercial, and by any means. - -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and -to the detriment of our heirs and -successors. We intend this dedication to be an overt act of relinquishment -in perpetuity of all present and future rights to this software under copyright -law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to From 55e0427532a2e71c6093a88bf7e14e5eb2ab90cf Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 6 Feb 2023 14:49:24 +0100 Subject: [PATCH 046/156] PASS1-650: Reuse finer grained control. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .gitignore | 4 + .reuse/dep5 | 112 +++++++++++++++--- LICENSES/Zlib.txt | 11 ++ .../Passport/docs/generic-wallet-export.md | 6 + .../Passport/tools/pubkey-to-c/pubkey-to-c | 3 + .../Passport/tools/word_list_gen/README.md | 6 + ports/stm32/ditto/config.yml | 3 + simulator/sim_modules/pyb.py | 3 +- simulator/sim_modules/sflash.py | 6 +- simulator/simulator.py | 3 + version.txt | 2 +- 11 files changed, 136 insertions(+), 23 deletions(-) create mode 100644 LICENSES/Zlib.txt diff --git a/.gitignore b/.gitignore index 86f93757d..de533f3d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2021 Damien P. George (http://micropython.org/) +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later + # Compiled Sources ################### *.o diff --git a/.reuse/dep5 b/.reuse/dep5 index fd828c579..992dbfcf3 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -1,30 +1,106 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream - Name: Passport Upstream - Contact: hello@foundationdevices.com -Source: https://git.example.com/FoundationDevices/passport +Source: https://git.example.com/FoundationDevices/passport2 -Files: MP-*.md TODO.md MP-ACKNOWLEDGEMENTS docs/* drivers/* examples/* extmod/* lib/* py/* tests/* tools/* .gitattributes .gitignore .gitmodules .travis.yml logo/* mpy-cross/* -Copyright: Copyright (c) 2016-2021 Damien P. George (http://micropython.org/) -License: MIT +Files: + extmod/crypto-algorithms/* +Copyright: Brad Conte (brad AT bradconte.com) +License: Unlicense + +Files: + extmod/re1.5/* +Copyright: Copyright (c) 2007-2009 Russ Cox, Google Inc. +License: BSD-3-Clause + +Files: extmod/trezor-firmware/* +Copyright: Copyright (c) SatoshiLabs +License: GPL-3.0-only -Files: ports/unix/* -Copyright: Copyright(c) 2016 - 2021 Damien P.George(http://micropython.org/) +Files: extmod/uzlib/* +Copyright: Copyright (c) 2003 by Joergen Ibsen / Jibz +License: Zlib + +Files: ports/stm32/boards/Passport/common/micro-ecc/* +Copyright: Copyright (c) 2014, Kenneth MacKay +License: BSD-2-Clause + +Files: ports/stm32/pybcdc.inf_template +Copyright: + Copyright (c) 2000 Microsoft Corporation + Copyright (C) 2007 Microchip Technology Inc. + Copyright (c) 2016-2021 Damien P. George (http://micropython.org/) License: MIT -Files: ports/stm32/* -Copyright: Copyright (c) 2016-2021 Damien P. George (http://micropython.org/) +Files: + extmod/virtpin.c + extmod/virtpin.h +Copyright: Copyright (c) 2016 Paul Sokolovsky License: MIT -Copyright: 2020 Foundation Devices, Inc. -License: GPL-3.0-or-later -Files: SECURITY/*.png -Copyright: 2020 Foundation Devices, Inc. -License: GPL-3.0-or-later +Files: + extmod/misc.h + extmod/uos_dupterm.c + extmod/utime_mphal.c + extmod/utime_mphal.h +Copyright: + Copyright (c) 2013-2016 Damien P. George + Copyright (c) 2016 Paul Sokolovsky +License: MIT -Files: simulator/*.png simulator/*.jpg -Copyright: 2021 Foundation Devices, Inc. -License: GPL-3.0-or-later +Files: + MP-*.md + MP-ACKNOWLEDGEMENTS + docs/* + drivers/* + examples/* + extmod/axtls-include/* + extmod/bufhelper.c + extmod/bufhelper.h + extmod/btstack/* + extmod/extmod.cmake + extmod/extmod.mk + extmod/lwip-include/* + extmod/machine_*.c + extmod/machine_*.h + extmod/mod*.c + extmod/mod*.h + extmod/mpbthci.c + extmod/mpbthci.h + extmod/network_cyw43.c + extmod/network_cyw43.h + extmod/nimble/* + extmod/uasyncio/* + extmod/vfs*.c + extmod/vfs*.h + extmod/webrepl/* + lib/* + ports/stm32/*.c + ports/stm32/*.h + ports/stm32/*.mk + ports/stm32/*.py + ports/stm32/*.s + ports/stm32/autoflash + ports/stm32/boards/*.cfg + ports/stm32/boards/*.ld + ports/stm32/Makefile + ports/stm32/README.md + ports/unix/* + py/* + tests/* + tools/* + .gitattributes + logo/* + mpy-cross/* +Copyright: Copyright (c) 2016-2021 Damien P. George (http://micropython.org/) +License: MIT -Files: simulator/*.py simulator/sim_modules/* simulator/work/* version.txt -Copyright: 2021 Foundation Devices, Inc. +Files: + ports/stm32/boards/Passport/images/*/*.png + ports/stm32/boards/Passport/bootloader/images/*/*.png + SECURITY/*.png + simulator/*.png + simulator/*.jpg + version.txt +Copyright: © 2021 Foundation Devices, Inc. License: GPL-3.0-or-later diff --git a/LICENSES/Zlib.txt b/LICENSES/Zlib.txt new file mode 100644 index 000000000..e0e3605ba --- /dev/null +++ b/LICENSES/Zlib.txt @@ -0,0 +1,11 @@ +zlib License + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. diff --git a/ports/stm32/boards/Passport/docs/generic-wallet-export.md b/ports/stm32/boards/Passport/docs/generic-wallet-export.md index c803636bc..ec435d488 100644 --- a/ports/stm32/boards/Passport/docs/generic-wallet-export.md +++ b/ports/stm32/boards/Passport/docs/generic-wallet-export.md @@ -1,3 +1,9 @@ + + # Export wallet file format (Generic JSON) Passport can export data intended for various desktop and mobile diff --git a/ports/stm32/boards/Passport/tools/pubkey-to-c/pubkey-to-c b/ports/stm32/boards/Passport/tools/pubkey-to-c/pubkey-to-c index 8cd19170d..4c0166b76 100755 --- a/ports/stm32/boards/Passport/tools/pubkey-to-c/pubkey-to-c +++ b/ports/stm32/boards/Passport/tools/pubkey-to-c/pubkey-to-c @@ -1,4 +1,7 @@ #! /usr/bin/python +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# # Dump binary pubkey as C text to insert into firmware-keys.h import os diff --git a/ports/stm32/boards/Passport/tools/word_list_gen/README.md b/ports/stm32/boards/Passport/tools/word_list_gen/README.md index d42c216b5..b6b2ca01f 100644 --- a/ports/stm32/boards/Passport/tools/word_list_gen/README.md +++ b/ports/stm32/boards/Passport/tools/word_list_gen/README.md @@ -1,3 +1,9 @@ + + # Building the generator You should only need to regenerate the ../bip39_word_info.c file if BIP39 changes, which is extremely unlikely, or if you want to generate the same structure for words diff --git a/ports/stm32/ditto/config.yml b/ports/stm32/ditto/config.yml index ebddb9c3e..bfe017eff 100644 --- a/ports/stm32/ditto/config.yml +++ b/ports/stm32/ditto/config.yml @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later + projects: - name: Envoy + PP Clean Start id: 61d85527a3996201477cbeec diff --git a/simulator/sim_modules/pyb.py b/simulator/sim_modules/pyb.py index f0d282ca5..5f52d3a3d 100644 --- a/simulator/sim_modules/pyb.py +++ b/simulator/sim_modules/pyb.py @@ -1,4 +1,5 @@ - +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later class SDCard: ejected = False diff --git a/simulator/sim_modules/sflash.py b/simulator/sim_modules/sflash.py index 178a666d8..8a15e9cb8 100644 --- a/simulator/sim_modules/sflash.py +++ b/simulator/sim_modules/sflash.py @@ -1,6 +1,6 @@ -# replacement for serial flash stuff, just enough to pass selftest -# -# see real deal at ../shared/sflash.py +# SPDX-FileCopyrightText: 2018 Coinkite, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-only from utils import file_exists diff --git a/simulator/simulator.py b/simulator/simulator.py index 28c81aa3a..cbebc8cc5 100755 --- a/simulator/simulator.py +++ b/simulator/simulator.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +# SPDX-FileCopyrightText: (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later # # (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard # and is covered by GPLv3 license found in COPYING. diff --git a/version.txt b/version.txt index b0f3d96f8..703cec9e2 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.8 +2.0.6 \ No newline at end of file From 33026b593031ef551b8159f88cf93abd85721aa1 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 7 Feb 2023 20:50:28 +0100 Subject: [PATCH 047/156] PASS1-651: Ignore cosign binaries. Signed-off-by: Jean-Pierre De Jesus DIAZ --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index de533f3d5..22437a3a0 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,7 @@ genrst/ # Passport ###################### +ports/stm32/boards/Passport/tools/cosign/x86 ports/stm32/boards/Passport/tools/add-secrets/x86 ports/stm32/boards/Passport/bootloader/dev-secrets/ ports/stm32/boards/Passport/bootloader/version_info.c From eb658f53df514084584202a85763d35d3e38b1dc Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 17 Jan 2023 10:53:04 -0600 Subject: [PATCH 048/156] PASS1-618: first pass at file deletion --- .../modules/flows/file_picker_flow.py | 20 +++++++++++++---- ports/stm32/boards/Passport/modules/utils.py | 22 +++++++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index c294ee211..8afd536d9 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -7,11 +7,11 @@ from animations.constants import TRANSITION_DIR_POP, TRANSITION_DIR_PUSH from files import CardMissingError, CardSlot from flows import Flow -from pages import FilePickerPage, StatusPage, InsertMicroSDPage +from pages import FilePickerPage, StatusPage, InsertMicroSDPage, ChooserPage from styles.colors import COPPER import microns import common -from utils import get_file_list +from utils import get_file_list, delete_file from uasyncio import sleep_ms @@ -131,14 +131,26 @@ def on_result(res): else: # Go back up a level self.paths.pop(-1) - return True _filename, full_path, is_folder = res + + options = [{'label': 'Navigate' if is_folder else 'Select', 'value': 0}, + {'label': 'Delete', 'value': 1}] + + selection = await ChooserPage(text=None, + options=options, + initial_value=options[0].get('value'), + left_micron=microns.Back).show() + + if selection == 1: + delete_file(full_path) + print("deleting {}".format(full_path)) + return True + if is_folder: common.page_transition_dir = TRANSITION_DIR_PUSH self.paths.append(full_path) - return True # User chose this file diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 5904e15dc..46f84f511 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -279,6 +279,23 @@ def get_file_list(path=None, include_folders=False, include_parent=False, suffix return file_list +def delete_file(path): + with CardSlot() as card: + if path is None: + return + + # Ensure path is build properly + if not path.startswith(card.get_sd_root()): + # print('ERROR: The path for get_file_list() must start with "{}"'.format(card.get_sd_root())) + return + + if folder_exists(path): + uos.rmdir(path) + + if file_exists(path): + uos.remove(path) + + class InputMode(): UPPER_ALPHA = 0 LOWER_ALPHA = 1 @@ -1126,7 +1143,7 @@ def restore_sd_cb(): except Exception as e: page.unmount() restore_sd_cb() - on_result(None) + await on_result(None) await ErrorPage(text='Unable to display page.').show() return @@ -1154,7 +1171,8 @@ def restore_sd_cb(): except StopIteration as result: result = result.value - if on_result(result): + success = await on_result(result) + if success: page.restore_statusbar_and_card_header() restore_sd_cb() return From cff135ec92351f76d84e985625fa53a7fc3a3f7b Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 17 Jan 2023 13:16:08 -0600 Subject: [PATCH 049/156] PASS1-618: adding error handling for recursive delete --- .../modules/flows/file_picker_flow.py | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index 8afd536d9..acebcaab7 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -7,7 +7,7 @@ from animations.constants import TRANSITION_DIR_POP, TRANSITION_DIR_PUSH from files import CardMissingError, CardSlot from flows import Flow -from pages import FilePickerPage, StatusPage, InsertMicroSDPage, ChooserPage +from pages import FilePickerPage, StatusPage, InsertMicroSDPage, ChooserPage, QuestionPage from styles.colors import COPPER import microns import common @@ -84,7 +84,7 @@ def on_sd_card_change(sd_card_present): result = None - def on_result(res): + async def on_result(res): nonlocal result result = res return True @@ -119,7 +119,7 @@ def on_sd_card_change(sd_card_present): finished = False - def on_result(res): + async def on_result(res): nonlocal finished # No file selected - go back to previous page @@ -138,14 +138,38 @@ def on_result(res): options = [{'label': 'Navigate' if is_folder else 'Select', 'value': 0}, {'label': 'Delete', 'value': 1}] - selection = await ChooserPage(text=None, - options=options, - initial_value=options[0].get('value'), - left_micron=microns.Back).show() + selection = await ChooserPage(options=options).show() + + if selection is None: + return True + + if selection == 1: # delete + if not is_folder: + delete_file(full_path) + return True + + subfiles = get_file_list(path=full_path, include_folders=True) + if len(subfiles) == 0: + delete_file(full_path) + return True + + confirm = await QuestionPage(text="Delete folder and all its files?").show() + if not confirm: + return True + + while len(subfiles) != 0: + for f in subfiles: + (name, path, folder) = f + if folder: + subsubfiles = get_file_list(path=path, include_folders=True) + if len(subsubfiles) == 0: + delete_file(path) + else: + subfiles.append(subsubfiles) + else: + delete_file(path) + subfiles.remove(f) - if selection == 1: - delete_file(full_path) - print("deleting {}".format(full_path)) return True if is_folder: From 3af06c63fe09e1453854b3966b09dd090cd6ad9d Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 17 Jan 2023 14:21:47 -0600 Subject: [PATCH 050/156] PASS1-618: refined recursive delete --- .../boards/Passport/modules/flows/file_picker_flow.py | 7 ++++--- ports/stm32/boards/Passport/modules/utils.py | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index acebcaab7..91fcefabf 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -164,12 +164,13 @@ async def on_result(res): subsubfiles = get_file_list(path=path, include_folders=True) if len(subsubfiles) == 0: delete_file(path) + subfiles.remove(f) else: - subfiles.append(subsubfiles) + subfiles.extend(subsubfiles) else: delete_file(path) - subfiles.remove(f) - + subfiles.remove(f) + delete_file(full_path) return True if is_folder: diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 46f84f511..6689c468b 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -235,7 +235,8 @@ def handle_fatal_error(exc): sys.print_exception(exc2) -def get_file_list(path=None, include_folders=False, include_parent=False, suffix=None, filter_fn=None): +def get_file_list(path=None, include_folders=False, include_parent=False, + suffix=None, filter_fn=None, show_hidden=True): file_list = [] with CardSlot() as card: @@ -265,7 +266,7 @@ def get_file_list(path=None, include_folders=False, include_parent=False, suffix continue # Skip "hidden" files that start with "." - if filename[0] == '.': + if filename[0] == '.' and not show_hidden: continue # Apply file filter, if given (only to files -- folder are included by default) From 6108bda58cecd8a5c99c22409e1c5cbcf1148100 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 17 Jan 2023 15:33:06 -0600 Subject: [PATCH 051/156] PASS1-618: split delete functionality into logical parts --- ports/stm32/boards/Passport/manifest.py | 2 + .../boards/Passport/modules/flows/__init__.py | 1 + .../modules/flows/file_picker_flow.py | 61 ++++--------------- .../modules/flows/select_file_flow.py | 50 +++++++++++++++ .../boards/Passport/modules/tasks/__init__.py | 1 + .../modules/tasks/delete_directory_task.py | 25 ++++++++ 6 files changed, 90 insertions(+), 50 deletions(-) create mode 100644 ports/stm32/boards/Passport/modules/flows/select_file_flow.py create mode 100644 ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index aa157d6e4..559ba8d1c 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -127,6 +127,7 @@ 'flows/restore_seed_flow.py', 'flows/scv_flow.py', 'flows/select_setup_mode_flow.py', + 'flows/select_file_flow.py', 'flows/set_chain_flow.py', 'flows/set_initial_pin_flow.py', 'flows/show_security_words_setting_flow.py', @@ -233,6 +234,7 @@ 'tasks/copy_firmware_to_spi_flash_task.py', 'tasks/charge_monitor_task.py', 'tasks/delete_account_task.py', + 'tasks/delete_directory_task.py', 'tasks/delete_multisig_task.py', 'tasks/delay_task.py', 'tasks/erase_passport_task.py', diff --git a/ports/stm32/boards/Passport/modules/flows/__init__.py b/ports/stm32/boards/Passport/modules/flows/__init__.py index b10555221..0f8591f37 100644 --- a/ports/stm32/boards/Passport/modules/flows/__init__.py +++ b/ports/stm32/boards/Passport/modules/flows/__init__.py @@ -34,6 +34,7 @@ from .export_multisig_qr_flow import * from .export_summary_flow import * # from .fcc_test_flow import * +from .select_file_flow import * from .file_picker_flow import * from .format_microsd_flow import * from .import_multisig_wallet_flow import * diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index 91fcefabf..f697a2b72 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -6,12 +6,12 @@ import lvgl as lv from animations.constants import TRANSITION_DIR_POP, TRANSITION_DIR_PUSH from files import CardMissingError, CardSlot -from flows import Flow +from flows import Flow, SelectFileFlow from pages import FilePickerPage, StatusPage, InsertMicroSDPage, ChooserPage, QuestionPage from styles.colors import COPPER import microns import common -from utils import get_file_list, delete_file +from utils import get_file_list from uasyncio import sleep_ms @@ -134,54 +134,15 @@ async def on_result(res): return True _filename, full_path, is_folder = res - - options = [{'label': 'Navigate' if is_folder else 'Select', 'value': 0}, - {'label': 'Delete', 'value': 1}] - - selection = await ChooserPage(options=options).show() - - if selection is None: - return True - - if selection == 1: # delete - if not is_folder: - delete_file(full_path) - return True - - subfiles = get_file_list(path=full_path, include_folders=True) - if len(subfiles) == 0: - delete_file(full_path) - return True - - confirm = await QuestionPage(text="Delete folder and all its files?").show() - if not confirm: - return True - - while len(subfiles) != 0: - for f in subfiles: - (name, path, folder) = f - if folder: - subsubfiles = get_file_list(path=path, include_folders=True) - if len(subsubfiles) == 0: - delete_file(path) - subfiles.remove(f) - else: - subfiles.extend(subsubfiles) - else: - delete_file(path) - subfiles.remove(f) - delete_file(full_path) - return True - - if is_folder: - common.page_transition_dir = TRANSITION_DIR_PUSH - self.paths.append(full_path) - return True - - # User chose this file - common.page_transition_dir = TRANSITION_DIR_POP - self.set_result(res) - finished = True + result = await SelectFileFlow(_filename, full_path, is_folder).run() + if result is not None: + if is_folder: + common.page_transition_dir = TRANSITION_DIR_PUSH + self.paths.append(full_path) + else: + common.page_transition_dir = TRANSITION_DIR_POP + self.set_result(result) + finished = True return True diff --git a/ports/stm32/boards/Passport/modules/flows/select_file_flow.py b/ports/stm32/boards/Passport/modules/flows/select_file_flow.py new file mode 100644 index 000000000..6ec733d16 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/flows/select_file_flow.py @@ -0,0 +1,50 @@ +# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# select_file_flow.py - Decide what to do with a selected file + +from flows import Flow +from pages import ChooserPage, QuestionPage + + +class SelectFileFlow(Flow): + def __init__(self, file_name, full_path, is_folder): + self.file_name = file_name + self.full_path = full_path + self.is_folder = is_folder + super().__init__(initial_state=self.choose_action, name='SelectFileFlow') + + async def choose_action(self): + options = [{'label': 'Navigate' if self.is_folder else 'Select', 'value': 0}, + {'label': 'Delete', 'value': 1}] + + selection = await ChooserPage(options=options).show() + + if selection is None: + self.set_result(None) + return + + if selection == 1: + self.goto(self.delete_selected_file) + else: + self.set_result((self.file_name, self.full_path, self.is_folder)) + + async def delete_selected_file(self): + from tasks import delete_directory_task + from utils import get_file_list, delete_file + if not self.is_folder: + delete_file(self.full_path) + self.set_result(None) + return + + subfiles = get_file_list(path=self.full_path, include_folders=True) + if len(subfiles) == 0: + delete_file(self.full_path) + self.set_result(None) + return + + confirm = await QuestionPage(text="Delete folder and all its files?").show() + if confirm: + await spinner_task(text="Deleting folder and all its files.", + task=delete_directory_task, args=[self.full_path]) + self.set_result(None) diff --git a/ports/stm32/boards/Passport/modules/tasks/__init__.py b/ports/stm32/boards/Passport/modules/tasks/__init__.py index e1800803b..94f2550d5 100644 --- a/ports/stm32/boards/Passport/modules/tasks/__init__.py +++ b/ports/stm32/boards/Passport/modules/tasks/__init__.py @@ -19,6 +19,7 @@ from .clear_psbt_from_external_flash_task import clear_psbt_from_external_flash_task from .create_wallet_export_task import create_wallet_export_task from .delete_account_task import delete_account_task +from .delete_directory_task import delete_directory_task from .delay_task import delay_task from .delete_multisig_task import delete_multisig_task from .double_check_psbt_change_task import double_check_psbt_change_task diff --git a/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py b/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py new file mode 100644 index 000000000..fbb226da7 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# delete_directory_task.py - Task to delete a directory recursively + +from utils import get_file_list, delete_file + + +async def delete_directory_task(on_done, full_path): + subfiles = get_file_list(path=full_path, include_folders=True) + while len(subfiles) != 0: + for f in subfiles: + (name, path, folder) = f + if folder: + subsubfiles = get_file_list(path=path, include_folders=True) + if len(subsubfiles) == 0: + delete_file(path) + subfiles.remove(f) + else: + subfiles.extend(subsubfiles) + else: + delete_file(path) + subfiles.remove(f) + delete_file(full_path) + await on_done(None) From 4019d7a38184f4509750a68ebe85cd3f6eeeb911 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 17 Jan 2023 16:20:18 -0600 Subject: [PATCH 052/156] PASS1-618: fixed compiler error, added delay to directory delete for spinner updates --- .../boards/Passport/modules/flows/select_file_flow.py | 2 +- .../Passport/modules/tasks/delete_directory_task.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/select_file_flow.py b/ports/stm32/boards/Passport/modules/flows/select_file_flow.py index 6ec733d16..2d0d8b6b4 100644 --- a/ports/stm32/boards/Passport/modules/flows/select_file_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/select_file_flow.py @@ -31,7 +31,7 @@ async def choose_action(self): async def delete_selected_file(self): from tasks import delete_directory_task - from utils import get_file_list, delete_file + from utils import get_file_list, delete_file, spinner_task if not self.is_folder: delete_file(self.full_path) self.set_result(None) diff --git a/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py b/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py index fbb226da7..02dcaf3c9 100644 --- a/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py @@ -3,11 +3,13 @@ # # delete_directory_task.py - Task to delete a directory recursively -from utils import get_file_list, delete_file - async def delete_directory_task(on_done, full_path): + from utils import get_file_list, delete_file + from uasyncio import sleep_ms + subfiles = get_file_list(path=full_path, include_folders=True) + while len(subfiles) != 0: for f in subfiles: (name, path, folder) = f @@ -21,5 +23,8 @@ async def delete_directory_task(on_done, full_path): else: delete_file(path) subfiles.remove(f) + + await sleep_ms(1) + delete_file(full_path) await on_done(None) From 761cdf2c1771d5c52743b169fc9e2692609b81e4 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 17 Jan 2023 18:03:27 -0600 Subject: [PATCH 053/156] PASS1-618: cleaned up select file flow --- ports/stm32/boards/Passport/modules/flows/file_picker_flow.py | 3 +-- ports/stm32/boards/Passport/modules/flows/select_file_flow.py | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index f697a2b72..84493d525 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -7,12 +7,11 @@ from animations.constants import TRANSITION_DIR_POP, TRANSITION_DIR_PUSH from files import CardMissingError, CardSlot from flows import Flow, SelectFileFlow -from pages import FilePickerPage, StatusPage, InsertMicroSDPage, ChooserPage, QuestionPage +from pages import FilePickerPage, StatusPage, InsertMicroSDPage from styles.colors import COPPER import microns import common from utils import get_file_list -from uasyncio import sleep_ms class FilePickerFlow(Flow): diff --git a/ports/stm32/boards/Passport/modules/flows/select_file_flow.py b/ports/stm32/boards/Passport/modules/flows/select_file_flow.py index 2d0d8b6b4..fa3605f34 100644 --- a/ports/stm32/boards/Passport/modules/flows/select_file_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/select_file_flow.py @@ -4,7 +4,6 @@ # select_file_flow.py - Decide what to do with a selected file from flows import Flow -from pages import ChooserPage, QuestionPage class SelectFileFlow(Flow): @@ -12,9 +11,11 @@ def __init__(self, file_name, full_path, is_folder): self.file_name = file_name self.full_path = full_path self.is_folder = is_folder + self.error = None super().__init__(initial_state=self.choose_action, name='SelectFileFlow') async def choose_action(self): + from pages import ChooserPage options = [{'label': 'Navigate' if self.is_folder else 'Select', 'value': 0}, {'label': 'Delete', 'value': 1}] @@ -30,6 +31,7 @@ async def choose_action(self): self.set_result((self.file_name, self.full_path, self.is_folder)) async def delete_selected_file(self): + from pages import QuestionPage from tasks import delete_directory_task from utils import get_file_list, delete_file, spinner_task if not self.is_folder: From ebec012c8921d63f48cdc032b754a05eea67d999 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 23 Jan 2023 13:29:58 -0600 Subject: [PATCH 054/156] PASS1-618: renamed selected_file_flow, reverted file picker to not show hidden by default --- ports/stm32/boards/Passport/manifest.py | 2 +- ports/stm32/boards/Passport/modules/flows/__init__.py | 2 +- ports/stm32/boards/Passport/modules/flows/file_picker_flow.py | 4 ++-- .../flows/{select_file_flow.py => selected_file_flow.py} | 2 +- .../boards/Passport/modules/tasks/delete_directory_task.py | 4 ++-- ports/stm32/boards/Passport/modules/utils.py | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename ports/stm32/boards/Passport/modules/flows/{select_file_flow.py => selected_file_flow.py} (98%) diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index 559ba8d1c..bff245af3 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -127,7 +127,7 @@ 'flows/restore_seed_flow.py', 'flows/scv_flow.py', 'flows/select_setup_mode_flow.py', - 'flows/select_file_flow.py', + 'flows/selected_file_flow.py', 'flows/set_chain_flow.py', 'flows/set_initial_pin_flow.py', 'flows/show_security_words_setting_flow.py', diff --git a/ports/stm32/boards/Passport/modules/flows/__init__.py b/ports/stm32/boards/Passport/modules/flows/__init__.py index 0f8591f37..2e3ad4e10 100644 --- a/ports/stm32/boards/Passport/modules/flows/__init__.py +++ b/ports/stm32/boards/Passport/modules/flows/__init__.py @@ -34,7 +34,7 @@ from .export_multisig_qr_flow import * from .export_summary_flow import * # from .fcc_test_flow import * -from .select_file_flow import * +from .selected_file_flow import * from .file_picker_flow import * from .format_microsd_flow import * from .import_multisig_wallet_flow import * diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index 84493d525..a21d18415 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -6,7 +6,7 @@ import lvgl as lv from animations.constants import TRANSITION_DIR_POP, TRANSITION_DIR_PUSH from files import CardMissingError, CardSlot -from flows import Flow, SelectFileFlow +from flows import Flow, SelectedFileFlow from pages import FilePickerPage, StatusPage, InsertMicroSDPage from styles.colors import COPPER import microns @@ -133,7 +133,7 @@ async def on_result(res): return True _filename, full_path, is_folder = res - result = await SelectFileFlow(_filename, full_path, is_folder).run() + result = await SelectedFileFlow(_filename, full_path, is_folder).run() if result is not None: if is_folder: common.page_transition_dir = TRANSITION_DIR_PUSH diff --git a/ports/stm32/boards/Passport/modules/flows/select_file_flow.py b/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py similarity index 98% rename from ports/stm32/boards/Passport/modules/flows/select_file_flow.py rename to ports/stm32/boards/Passport/modules/flows/selected_file_flow.py index fa3605f34..aeb22a2e1 100644 --- a/ports/stm32/boards/Passport/modules/flows/select_file_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py @@ -6,7 +6,7 @@ from flows import Flow -class SelectFileFlow(Flow): +class SelectedFileFlow(Flow): def __init__(self, file_name, full_path, is_folder): self.file_name = file_name self.full_path = full_path diff --git a/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py b/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py index 02dcaf3c9..2a8b8ee46 100644 --- a/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py @@ -8,13 +8,13 @@ async def delete_directory_task(on_done, full_path): from utils import get_file_list, delete_file from uasyncio import sleep_ms - subfiles = get_file_list(path=full_path, include_folders=True) + subfiles = get_file_list(path=full_path, include_folders=True, show_hidden=True) while len(subfiles) != 0: for f in subfiles: (name, path, folder) = f if folder: - subsubfiles = get_file_list(path=path, include_folders=True) + subsubfiles = get_file_list(path=path, include_folders=True, show_hidden=True) if len(subsubfiles) == 0: delete_file(path) subfiles.remove(f) diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index 6689c468b..e601f635c 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -236,7 +236,7 @@ def handle_fatal_error(exc): def get_file_list(path=None, include_folders=False, include_parent=False, - suffix=None, filter_fn=None, show_hidden=True): + suffix=None, filter_fn=None, show_hidden=False): file_list = [] with CardSlot() as card: From a48ae8b2870b33e2fcf7ae6148d5731dbc8d7cb6 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 26 Jan 2023 11:36:52 -0600 Subject: [PATCH 055/156] PASS1-618: removed delete directory functionality --- ports/stm32/boards/Passport/manifest.py | 1 - .../modules/flows/file_picker_flow.py | 14 ++++----- .../modules/flows/selected_file_flow.py | 20 ++----------- .../boards/Passport/modules/tasks/__init__.py | 1 - .../modules/tasks/delete_directory_task.py | 30 ------------------- 5 files changed, 9 insertions(+), 57 deletions(-) delete mode 100644 ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index bff245af3..034b6111f 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -234,7 +234,6 @@ 'tasks/copy_firmware_to_spi_flash_task.py', 'tasks/charge_monitor_task.py', 'tasks/delete_account_task.py', - 'tasks/delete_directory_task.py', 'tasks/delete_multisig_task.py', 'tasks/delay_task.py', 'tasks/erase_passport_task.py', diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index a21d18415..b2427b81a 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -133,15 +133,15 @@ async def on_result(res): return True _filename, full_path, is_folder = res + if is_folder: + common.page_transition_dir = TRANSITION_DIR_PUSH + self.paths.append(full_path) + return True result = await SelectedFileFlow(_filename, full_path, is_folder).run() if result is not None: - if is_folder: - common.page_transition_dir = TRANSITION_DIR_PUSH - self.paths.append(full_path) - else: - common.page_transition_dir = TRANSITION_DIR_POP - self.set_result(result) - finished = True + common.page_transition_dir = TRANSITION_DIR_POP + self.set_result(result) + finished = True return True diff --git a/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py b/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py index aeb22a2e1..1bb660564 100644 --- a/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py @@ -8,11 +8,10 @@ class SelectedFileFlow(Flow): def __init__(self, file_name, full_path, is_folder): + super().__init__(initial_state=self.choose_action, name='SelectFileFlow') self.file_name = file_name self.full_path = full_path self.is_folder = is_folder - self.error = None - super().__init__(initial_state=self.choose_action, name='SelectFileFlow') async def choose_action(self): from pages import ChooserPage @@ -31,22 +30,7 @@ async def choose_action(self): self.set_result((self.file_name, self.full_path, self.is_folder)) async def delete_selected_file(self): - from pages import QuestionPage - from tasks import delete_directory_task - from utils import get_file_list, delete_file, spinner_task + from utils import delete_file if not self.is_folder: delete_file(self.full_path) - self.set_result(None) - return - - subfiles = get_file_list(path=self.full_path, include_folders=True) - if len(subfiles) == 0: - delete_file(self.full_path) - self.set_result(None) - return - - confirm = await QuestionPage(text="Delete folder and all its files?").show() - if confirm: - await spinner_task(text="Deleting folder and all its files.", - task=delete_directory_task, args=[self.full_path]) self.set_result(None) diff --git a/ports/stm32/boards/Passport/modules/tasks/__init__.py b/ports/stm32/boards/Passport/modules/tasks/__init__.py index 94f2550d5..e1800803b 100644 --- a/ports/stm32/boards/Passport/modules/tasks/__init__.py +++ b/ports/stm32/boards/Passport/modules/tasks/__init__.py @@ -19,7 +19,6 @@ from .clear_psbt_from_external_flash_task import clear_psbt_from_external_flash_task from .create_wallet_export_task import create_wallet_export_task from .delete_account_task import delete_account_task -from .delete_directory_task import delete_directory_task from .delay_task import delay_task from .delete_multisig_task import delete_multisig_task from .double_check_psbt_change_task import double_check_psbt_change_task diff --git a/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py b/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py deleted file mode 100644 index 2a8b8ee46..000000000 --- a/ports/stm32/boards/Passport/modules/tasks/delete_directory_task.py +++ /dev/null @@ -1,30 +0,0 @@ -# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. -# SPDX-License-Identifier: GPL-3.0-or-later -# -# delete_directory_task.py - Task to delete a directory recursively - - -async def delete_directory_task(on_done, full_path): - from utils import get_file_list, delete_file - from uasyncio import sleep_ms - - subfiles = get_file_list(path=full_path, include_folders=True, show_hidden=True) - - while len(subfiles) != 0: - for f in subfiles: - (name, path, folder) = f - if folder: - subsubfiles = get_file_list(path=path, include_folders=True, show_hidden=True) - if len(subsubfiles) == 0: - delete_file(path) - subfiles.remove(f) - else: - subfiles.extend(subsubfiles) - else: - delete_file(path) - subfiles.remove(f) - - await sleep_ms(1) - - delete_file(full_path) - await on_done(None) From 13a5c775024f2c8cf69b6c20c339d3728141e5b5 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 30 Jan 2023 10:13:08 -0600 Subject: [PATCH 056/156] PASS1-618: added confirmation page for deleting files --- .../boards/Passport/modules/flows/selected_file_flow.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py b/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py index 1bb660564..3c30e99a8 100644 --- a/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py @@ -31,6 +31,15 @@ async def choose_action(self): async def delete_selected_file(self): from utils import delete_file + from pages import QuestionPage + + confirmation_text = 'Are you sure you want to delete {}?'.format(self.file_name) + confirmation = await QuestionPage(text=confirmation_text).show() + + if not confirmation: + self.set_result(None) + return + if not self.is_folder: delete_file(self.full_path) self.set_result(None) From 246173122f4c175461abef2e78e6a05542fd768d Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 30 Jan 2023 16:37:46 -0600 Subject: [PATCH 057/156] PASS1-618: changed the file explorer select text to "Info" --- .../stm32/boards/Passport/modules/flows/file_picker_flow.py | 5 +++-- ports/stm32/boards/Passport/modules/flows/list_files_flow.py | 2 +- .../boards/Passport/modules/flows/selected_file_flow.py | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index b2427b81a..d3012a382 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -17,7 +17,7 @@ class FilePickerFlow(Flow): def __init__( self, initial_path=None, show_folders=False, enable_parent_nav=False, suffix=None, - filter_fn=None): + filter_fn=None, select_text="Select"): super().__init__(initial_state=self.show_file_picker, name='FilePickerFlow: {}'.format( initial_path)) self.initial_path = initial_path @@ -26,6 +26,7 @@ def __init__( self.enable_parent_nav = enable_parent_nav self.suffix = suffix self.filter_fn = filter_fn + self.select_text = select_text async def show_file_picker(self): from utils import show_page_with_sd_card @@ -137,7 +138,7 @@ async def on_result(res): common.page_transition_dir = TRANSITION_DIR_PUSH self.paths.append(full_path) return True - result = await SelectedFileFlow(_filename, full_path, is_folder).run() + result = await SelectedFileFlow(_filename, full_path, is_folder, self.select_text).run() if result is not None: common.page_transition_dir = TRANSITION_DIR_POP self.set_result(result) diff --git a/ports/stm32/boards/Passport/modules/flows/list_files_flow.py b/ports/stm32/boards/Passport/modules/flows/list_files_flow.py index 9bb4f80b4..4e670eaa2 100644 --- a/ports/stm32/boards/Passport/modules/flows/list_files_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/list_files_flow.py @@ -26,7 +26,7 @@ async def on_done(self, digest, error=None): async def choose_file(self): root_path = CardSlot.get_sd_root() - result = await FilePickerFlow(initial_path=root_path, show_folders=True).run() + result = await FilePickerFlow(initial_path=root_path, show_folders=True, select_text='Info').run() if result is None: self.set_result(False) return diff --git a/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py b/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py index 3c30e99a8..b839b993a 100644 --- a/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/selected_file_flow.py @@ -7,15 +7,16 @@ class SelectedFileFlow(Flow): - def __init__(self, file_name, full_path, is_folder): + def __init__(self, file_name, full_path, is_folder, select_text): super().__init__(initial_state=self.choose_action, name='SelectFileFlow') self.file_name = file_name self.full_path = full_path self.is_folder = is_folder + self.select_text = select_text async def choose_action(self): from pages import ChooserPage - options = [{'label': 'Navigate' if self.is_folder else 'Select', 'value': 0}, + options = [{'label': 'Navigate' if self.is_folder else self.select_text, 'value': 0}, {'label': 'Delete', 'value': 1}] selection = await ChooserPage(options=options).show() From e0aa333b0cb093ede95050a8d0320c158d212d1a Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 31 Jan 2023 13:34:19 -0600 Subject: [PATCH 058/156] PASS1-585: added extensions architecture --- ports/stm32/boards/Passport/manifest.py | 6 +++ .../Passport/modules/extensions/__init__.py | 2 + .../modules/extensions/casa_extension.py | 37 +++++++++++++++ .../Passport/modules/extensions/extensions.py | 15 ++++++ .../modules/extensions/postmix_extension.py | 37 +++++++++++++++ ports/stm32/boards/Passport/modules/menus.py | 23 ++++----- ports/stm32/boards/Passport/modules/ui/ui.py | 47 ++++--------------- 7 files changed, 117 insertions(+), 50 deletions(-) create mode 100644 ports/stm32/boards/Passport/modules/extensions/__init__.py create mode 100644 ports/stm32/boards/Passport/modules/extensions/casa_extension.py create mode 100644 ports/stm32/boards/Passport/modules/extensions/extensions.py create mode 100644 ports/stm32/boards/Passport/modules/extensions/postmix_extension.py diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index 034b6111f..d7cb8e0a3 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -368,4 +368,10 @@ 'wallets/wasabi.py', 'wallets/keeper.py')) +# Extensions +freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules', + ('extensions/extensions.py', + 'extensions/casa_extension.py', + 'extensions/postmix_extension.py')) + include("$(MPY_DIR)/extmod/uasyncio/manifest.py") diff --git a/ports/stm32/boards/Passport/modules/extensions/__init__.py b/ports/stm32/boards/Passport/modules/extensions/__init__.py new file mode 100644 index 000000000..91f15e32f --- /dev/null +++ b/ports/stm32/boards/Passport/modules/extensions/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later diff --git a/ports/stm32/boards/Passport/modules/extensions/casa_extension.py b/ports/stm32/boards/Passport/modules/extensions/casa_extension.py new file mode 100644 index 000000000..651ad1230 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/extensions/casa_extension.py @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# casa_extension.py - Casa extension UI specification + +import lvgl as lv +from flows import MenuFlow +from menus import casa_menu +from utils import is_extension_enabled, toggle_extension_enabled +from styles.colors import CASA_PURPLE, LIGHT_GREY, LIGHT_TEXT, WHITE +import microns + + +# Casa account - account number is zero, but they use a special derivation path +name = 'casa' +casa_account = {'name': 'Casa', 'acct_num': 0} +icon = lv.ICON_CASA + +CasaExtension = { + 'label': 'Casa', + 'name': name, + 'toggle': lambda item: toggle_extension_enabled(name), + 'check': lambda: is_extension_enabled(name), + 'icon': icon, + 'card': { + 'right_icon': icon, + 'header_color': LIGHT_GREY, + 'header_fg_color': LIGHT_TEXT, + 'statusbar': {'title': 'ACCOUNT', 'icon': lv.ICON_FOLDER, 'fg_color': WHITE}, + 'title': casa_account.get('name'), + 'page_micron': microns.PageDot, + 'bg_color': CASA_PURPLE, + 'flow': MenuFlow, + 'args': {'menu': casa_menu, 'is_top_level': True}, + 'account': casa_account + }, +} diff --git a/ports/stm32/boards/Passport/modules/extensions/extensions.py b/ports/stm32/boards/Passport/modules/extensions/extensions.py new file mode 100644 index 000000000..b9067fb28 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/extensions/extensions.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# sw_wallets.py - Software wallet config data for all supported wallets +# + +from .casa_extension import CasaExtension +from .postmix_extension import PostmixExtension + +# Array of all supported software wallets and their attributes. +# Used to build wallet menus and drive their behavior. +supported_extensions = [ + CasaExtension, + PostmixExtension, +] diff --git a/ports/stm32/boards/Passport/modules/extensions/postmix_extension.py b/ports/stm32/boards/Passport/modules/extensions/postmix_extension.py new file mode 100644 index 000000000..d14669760 --- /dev/null +++ b/ports/stm32/boards/Passport/modules/extensions/postmix_extension.py @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later +# +# postmix_extension.py - Postmix extension UI specification + +import lvgl as lv +from flows import MenuFlow +from menus import postmix_menu +from utils import is_extension_enabled, toggle_extension_enabled +from styles.colors import LIGHT_GREY, LIGHT_TEXT, WHITE, RED +import microns + + +# Postmix account for CoinJoin +name = 'postmix' +postmix_account = {'name': 'Postmix', 'acct_num': 2_147_483_646} +icon = lv.ICON_SPIRAL + +PostmixExtension = { + 'label': 'Postmix', + 'name': name, + 'toggle': lambda item: toggle_extension_enabled(name), + 'check': lambda: is_extension_enabled(name), + 'icon': icon, + 'card': { + 'right_icon': icon, + 'header_color': LIGHT_GREY, + 'header_fg_color': LIGHT_TEXT, + 'statusbar': {'title': 'ACCOUNT', 'icon': lv.ICON_FOLDER, 'fg_color': WHITE}, + 'title': postmix_account.get('name'), + 'page_micron': microns.PageDot, + 'bg_color': RED, + 'flow': MenuFlow, + 'args': {'menu': postmix_menu, 'is_top_level': True}, + 'account': postmix_account + }, +} diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index de492bf9b..7d72cdb11 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -279,19 +279,20 @@ def advanced_menu(): # # {'icon': lv.ICON_CHANGE_PIN, 'label': 'Enter Backup Code', 'page': BackupCodePage}, # ] - def extensions_menu(): from utils import is_extension_enabled, toggle_extension_enabled - # from pages import ColorPickerPage - return [ - # {'icon': lv.ICON_INFO, 'label': 'Color Picker', 'page': ColorPickerPage}, - {'icon': lv.ICON_CASA, 'label': 'Casa', 'action': lambda item: toggle_extension_enabled('casa'), - 'is_toggle': True, 'value': lambda: is_extension_enabled('casa')}, - {'icon': lv.ICON_SPIRAL, 'label': 'Postmix', 'action': lambda item: toggle_extension_enabled('postmix'), - 'is_toggle': True, 'value': lambda: is_extension_enabled('postmix')}, - # {'icon': lv.ICON_SETTINGS, 'label': 'BIP85', 'action': lambda item: toggle_extension_enabled('bip85'), - # 'is_toggle': True, 'value': lambda: is_extension_enabled('bip85')}, - ] + from extensions.extensions import supported_extensions + + result = [] + + for extension in supported_extensions: + result.append({'icon': extension['icon'], + 'label': extension['label'], + 'action': extension['toggle'], + 'is_toggle': True, + 'value': extension['check']}) + + return result def settings_menu(): diff --git a/ports/stm32/boards/Passport/modules/ui/ui.py b/ports/stm32/boards/Passport/modules/ui/ui.py index b9a5979c2..6f461c6a1 100644 --- a/ports/stm32/boards/Passport/modules/ui/ui.py +++ b/ports/stm32/boards/Passport/modules/ui/ui.py @@ -199,6 +199,7 @@ def update_cards( from flows import MenuFlow from utils import get_accounts, has_seed from menus import account_menu, casa_menu, plus_menu, postmix_menu + from extensions.extensions import supported_extensions from constants import MAX_ACCOUNTS from styles.colors import CASA_PURPLE, DARK_GREY, LIGHT_GREY, LIGHT_TEXT, WHITE import microns @@ -262,45 +263,13 @@ def update_cards( # Add special accounts - # Casa account - account number is zero, but they use a special derivation path - if common.settings.get('ext.casa.enabled', False): - casa_account = {'name': 'Casa', 'acct_num': 0} - casa_card = { - 'right_icon': lv.ICON_CASA, - 'header_color': LIGHT_GREY, - 'header_fg_color': LIGHT_TEXT, - 'statusbar': {'title': 'ACCOUNT', 'icon': lv.ICON_FOLDER, 'fg_color': WHITE}, - 'title': casa_account.get('name'), - 'page_micron': microns.PageDot, - 'bg_color': CASA_PURPLE, - 'flow': MenuFlow, - 'args': {'menu': casa_menu, 'is_top_level': True}, - 'account': casa_account - } - if len(stash.bip39_passphrase) > 0: - casa_card['icon'] = lv.ICON_PASSPHRASE - - card_descs.append(casa_card) - - # Postmix account for CoinJoin - if common.settings.get('ext.postmix.enabled', False): - postmix_account = {'name': 'Postmix', 'acct_num': 2_147_483_646} - postmix_card = { - 'right_icon': lv.ICON_SPIRAL, - 'header_color': LIGHT_GREY, - 'header_fg_color': LIGHT_TEXT, - 'statusbar': {'title': 'ACCOUNT', 'icon': lv.ICON_FOLDER, 'fg_color': WHITE}, - 'title': postmix_account.get('name'), - 'page_micron': microns.PageDot, - 'bg_color': RED, - 'flow': MenuFlow, - 'args': {'menu': postmix_menu, 'is_top_level': True}, - 'account': postmix_account - } - if len(stash.bip39_passphrase) > 0: - postmix_card['icon'] = lv.ICON_PASSPHRASE - - card_descs.append(postmix_card) + for extension in supported_extensions: + if common.settings.get('ext.{}.enabled'.format(extension['name']), False): + if len(stash.bip39_passphrase) > 0: + extension['card']['icon'] = lv.ICON_PASSPHRASE + else: + extension['card']['icon'] = None + card_descs.append(extension['card']) more_card = { 'statusbar': {'title': 'MORE', 'icon': lv.ICON_ADD_ACCOUNT, 'fg_color': WHITE}, From 795df8234d4069eacaa6b7caed71f952b9ee7b37 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 31 Jan 2023 13:37:40 -0600 Subject: [PATCH 059/156] PASS1-585: removed unused imports --- ports/stm32/boards/Passport/modules/menus.py | 1 - ports/stm32/boards/Passport/modules/ui/ui.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index 7d72cdb11..5111fd856 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -280,7 +280,6 @@ def advanced_menu(): # ] def extensions_menu(): - from utils import is_extension_enabled, toggle_extension_enabled from extensions.extensions import supported_extensions result = [] diff --git a/ports/stm32/boards/Passport/modules/ui/ui.py b/ports/stm32/boards/Passport/modules/ui/ui.py index 6f461c6a1..223888cdd 100644 --- a/ports/stm32/boards/Passport/modules/ui/ui.py +++ b/ports/stm32/boards/Passport/modules/ui/ui.py @@ -5,7 +5,6 @@ import lvgl as lv import common -from styles.colors import RED def get_account_bg(account): @@ -198,10 +197,10 @@ def update_cards( self, is_delete_account=False, stay_on_same_card=False, is_new_account=False, is_init=False): from flows import MenuFlow from utils import get_accounts, has_seed - from menus import account_menu, casa_menu, plus_menu, postmix_menu + from menus import account_menu, plus_menu from extensions.extensions import supported_extensions from constants import MAX_ACCOUNTS - from styles.colors import CASA_PURPLE, DARK_GREY, LIGHT_GREY, LIGHT_TEXT, WHITE + from styles.colors import DARK_GREY, LIGHT_GREY, LIGHT_TEXT, WHITE import microns self.update_cards_pending = False From 0c449bc7971220dc4e5e9ae4add1a63622c0de8c Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 9 Feb 2023 12:24:46 -0600 Subject: [PATCH 060/156] PASS1-585: moved extension menu creation into extensions.py --- .../Passport/modules/extensions/casa_extension.py | 11 +++++++---- .../Passport/modules/extensions/extensions.py | 13 +++++++++---- .../modules/extensions/postmix_extension.py | 11 +++++++---- ports/stm32/boards/Passport/modules/menus.py | 14 ++------------ 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/extensions/casa_extension.py b/ports/stm32/boards/Passport/modules/extensions/casa_extension.py index 651ad1230..2fc7a0bcf 100644 --- a/ports/stm32/boards/Passport/modules/extensions/casa_extension.py +++ b/ports/stm32/boards/Passport/modules/extensions/casa_extension.py @@ -17,11 +17,14 @@ icon = lv.ICON_CASA CasaExtension = { - 'label': 'Casa', 'name': name, - 'toggle': lambda item: toggle_extension_enabled(name), - 'check': lambda: is_extension_enabled(name), - 'icon': icon, + 'menu_item': { + 'icon': icon, + 'label': 'Casa', + 'action': lambda item: toggle_extension_enabled(name), + 'is_toggle': True, + 'value': lambda: is_extension_enabled(name), + }, 'card': { 'right_icon': icon, 'header_color': LIGHT_GREY, diff --git a/ports/stm32/boards/Passport/modules/extensions/extensions.py b/ports/stm32/boards/Passport/modules/extensions/extensions.py index b9067fb28..e95a52bf1 100644 --- a/ports/stm32/boards/Passport/modules/extensions/extensions.py +++ b/ports/stm32/boards/Passport/modules/extensions/extensions.py @@ -1,15 +1,20 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # -# sw_wallets.py - Software wallet config data for all supported wallets +# extensions.py - Config data for all supported extensions # from .casa_extension import CasaExtension from .postmix_extension import PostmixExtension -# Array of all supported software wallets and their attributes. -# Used to build wallet menus and drive their behavior. +# Array of all supported extensions. +# Used to build extension menus and UI cards. supported_extensions = [ CasaExtension, PostmixExtension, ] + +supported_extensions_menu = [ + CasaExtension['menu_item'], + PostmixExtension['menu_item'], +] diff --git a/ports/stm32/boards/Passport/modules/extensions/postmix_extension.py b/ports/stm32/boards/Passport/modules/extensions/postmix_extension.py index d14669760..e23c5338c 100644 --- a/ports/stm32/boards/Passport/modules/extensions/postmix_extension.py +++ b/ports/stm32/boards/Passport/modules/extensions/postmix_extension.py @@ -17,11 +17,14 @@ icon = lv.ICON_SPIRAL PostmixExtension = { - 'label': 'Postmix', 'name': name, - 'toggle': lambda item: toggle_extension_enabled(name), - 'check': lambda: is_extension_enabled(name), - 'icon': icon, + 'menu_item': { + 'icon': icon, + 'label': 'Postmix', + 'action': lambda item: toggle_extension_enabled(name), + 'is_toggle': True, + 'value': lambda: is_extension_enabled(name), + }, 'card': { 'right_icon': icon, 'header_color': LIGHT_GREY, diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index 5111fd856..953ef5cb9 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -280,18 +280,8 @@ def advanced_menu(): # ] def extensions_menu(): - from extensions.extensions import supported_extensions - - result = [] - - for extension in supported_extensions: - result.append({'icon': extension['icon'], - 'label': extension['label'], - 'action': extension['toggle'], - 'is_toggle': True, - 'value': extension['check']}) - - return result + from extensions.extensions import supported_extensions_menu + return supported_extensions_menu def settings_menu(): From 6aaa1fb86d7a2932c713d833adcbe4880498ea53 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Fri, 10 Feb 2023 10:39:30 -0600 Subject: [PATCH 061/156] PASS1-585: added __init__.py to the manifest --- ports/stm32/boards/Passport/manifest.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index d7cb8e0a3..411f1d46d 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -343,7 +343,8 @@ # Wallets freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules', - ('wallets/bitcoin_core.py', + ('wallets/__init__.py', + 'wallets/bitcoin_core.py', 'wallets/bluewallet.py', 'wallets/btcpay.py', 'wallets/caravan.py', @@ -370,7 +371,8 @@ # Extensions freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules', - ('extensions/extensions.py', + ('extensions/__init__.py', + 'extensions/extensions.py', 'extensions/casa_extension.py', 'extensions/postmix_extension.py')) From 4cc5c02dde653f392564a5df6adb0ed70614a025 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 9 Feb 2023 12:43:24 -0600 Subject: [PATCH 062/156] PASS1-647: removed function definitions from file picker flow loop --- .../modules/flows/file_picker_flow.py | 138 +++++++++--------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index d3012a382..e12070c2a 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -14,6 +14,11 @@ from utils import get_file_list +def file_key(f): + (filename, _fullpath, is_folder) = f + return '{}::{}'.format('0' if is_folder else '1', filename.lower()) + + class FilePickerFlow(Flow): def __init__( self, initial_path=None, show_folders=False, enable_parent_nav=False, suffix=None, @@ -27,6 +32,58 @@ def __init__( self.suffix = suffix self.filter_fn = filter_fn self.select_text = select_text + self.status_page = None + self.empty_result = None + self.file_result = None + self.finished = False + + def on_empty_sd_card_change(self, sd_card_present): + if sd_card_present: + return True # This will cause a refresh + else: + self.reset_paths() + self.status_page.set_result(None) + self.goto(self.show_insert_microsd_error) + return False + + async def on_empty_result(self, res): + self.empty_result = res + return True + + def on_exception(self, exception): + self.handle_fatal_error(exception) + return True + + def on_file_sd_card_change(self, sd_card_present): + if not sd_card_present: + self.reset_paths() + self.goto(self.show_insert_microsd_error) + return True + + async def on_file_result(self, res): + # No file selected - go back to previous page + if res is None: + common.page_transition_dir = TRANSITION_DIR_POP + if len(self.paths) <= 1: + self.set_result(None) + self.finished = True + else: + # Go back up a level + self.paths.pop(-1) + return True + + _filename, full_path, is_folder = res + if is_folder: + common.page_transition_dir = TRANSITION_DIR_PUSH + self.paths.append(full_path) + return True + result = await SelectedFileFlow(_filename, full_path, is_folder, self.select_text).run() + if result is not None: + common.page_transition_dir = TRANSITION_DIR_POP + self.set_result(result) + self.finished = True + + return True async def show_file_picker(self): from utils import show_page_with_sd_card @@ -43,10 +100,6 @@ async def show_file_picker(self): suffix=self.suffix, filter_fn=self.filter_fn) - def file_key(f): - (filename, _fullpath, is_folder) = f - return '{}::{}'.format('0' if is_folder else '1', filename.lower()) - files = sorted(files, key=file_key) except CardMissingError: @@ -64,7 +117,7 @@ def file_key(f): icon = lv.ICON_FOLDER if len(files) == 0: - status_page = StatusPage( + self.status_page = StatusPage( text='No files found', card_header={'title': title, 'icon': icon}, icon=lv.LARGE_ICON_ERROR, @@ -73,29 +126,12 @@ def file_key(f): right_micron=None, # No retry micron because the SD card contents can't magically change ) - def on_sd_card_change(sd_card_present): - if sd_card_present: - return True # This will cause a refresh - else: - self.reset_paths() - status_page.set_result(None) - self.goto(self.show_insert_microsd_error) - return False + await show_page_with_sd_card(self.status_page, + self.on_empty_sd_card_change, + self.on_empty_result, + self.on_exception) - result = None - - async def on_result(res): - nonlocal result - result = res - return True - - def on_exception(exception): - self.handle_fatal_error(exception) - return True - - await show_page_with_sd_card(status_page, on_sd_card_change, on_result, on_exception) - - if result is False: + if self.empty_result is False: # When error message is dismissed, only quit the flow entirely if # there's no way back up to a previous level if len(self.paths) <= 1: @@ -111,48 +147,12 @@ def on_exception(exception): card_header={'title': title, 'icon': icon} ) - def on_sd_card_change(sd_card_present): - if not sd_card_present: - self.reset_paths() - self.goto(self.show_insert_microsd_error) - return True - - finished = False - - async def on_result(res): - nonlocal finished - - # No file selected - go back to previous page - if res is None: - common.page_transition_dir = TRANSITION_DIR_POP - if len(self.paths) <= 1: - self.set_result(None) - finished = True - else: - # Go back up a level - self.paths.pop(-1) - return True - - _filename, full_path, is_folder = res - if is_folder: - common.page_transition_dir = TRANSITION_DIR_PUSH - self.paths.append(full_path) - return True - result = await SelectedFileFlow(_filename, full_path, is_folder, self.select_text).run() - if result is not None: - common.page_transition_dir = TRANSITION_DIR_POP - self.set_result(result) - finished = True - - return True - - def on_exception(exception): - self.handle_fatal_error(exception) - return True - - await show_page_with_sd_card(file_picker_page, on_sd_card_change, on_result, on_exception) - - if finished: + await show_page_with_sd_card(file_picker_page, + self.on_file_sd_card_change, + self.on_file_result, + self.on_exception) + + if self.finished: return async def show_insert_microsd_error(self): From 502aa791a4482b0aa227f88970798b6dc6d463d9 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 9 Feb 2023 12:50:04 -0600 Subject: [PATCH 063/156] PASS1-647: removed unnecessary variable --- ports/stm32/boards/Passport/modules/flows/file_picker_flow.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py index e12070c2a..39fda7187 100644 --- a/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/file_picker_flow.py @@ -34,7 +34,6 @@ def __init__( self.select_text = select_text self.status_page = None self.empty_result = None - self.file_result = None self.finished = False def on_empty_sd_card_change(self, sd_card_present): From e20905541ba79776a124185d4f67000ce49ac074 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 10 Feb 2023 16:26:32 +0100 Subject: [PATCH 064/156] PASS1-620: Deprecate UR1. This removes support of UR1 standard. Leaves code to properly detect the UR1 codes and, when the QR code is tried to be decoded an error will be raised. Signed-off-by: Jean-Pierre De Jesus DIAZ --- CHANGELOG.md | 3 + ports/stm32/boards/Passport/manifest.py | 11 -- .../modules/data_codecs/data_sampler.py | 3 +- .../modules/data_codecs/qr_factory.py | 17 +- .../Passport/modules/data_codecs/ur1_codec.py | 79 +++------ .../Passport/modules/data_codecs/ur2_codec.py | 2 +- .../boards/Passport/modules/ur1/__init__.py | 0 .../stm32/boards/Passport/modules/ur1/bc32.py | 65 ------- .../boards/Passport/modules/ur1/bech32.py | 128 -------------- .../Passport/modules/ur1/bech32_version.py | 8 - .../boards/Passport/modules/ur1/decode_ur.py | 167 ------------------ .../boards/Passport/modules/ur1/encode_ur.py | 50 ------ .../boards/Passport/modules/ur1/mini_cbor.py | 63 ------- .../boards/Passport/modules/ur1/utils.py | 7 - .../boards/Passport/modules/views/camera.py | 4 +- .../boards/Passport/modules/wallets/lily.py | 2 +- 16 files changed, 36 insertions(+), 573 deletions(-) delete mode 100644 ports/stm32/boards/Passport/modules/ur1/__init__.py delete mode 100644 ports/stm32/boards/Passport/modules/ur1/bc32.py delete mode 100644 ports/stm32/boards/Passport/modules/ur1/bech32.py delete mode 100644 ports/stm32/boards/Passport/modules/ur1/bech32_version.py delete mode 100644 ports/stm32/boards/Passport/modules/ur1/decode_ur.py delete mode 100644 ports/stm32/boards/Passport/modules/ur1/encode_ur.py delete mode 100644 ports/stm32/boards/Passport/modules/ur1/mini_cbor.py delete mode 100644 ports/stm32/boards/Passport/modules/ur1/utils.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 616c4261d..7342db8bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ SPDX-License-Identifier: GPL-3.0-or-later - Perform more accurate calculation of scan progress. (PASS1-553) - Report to the user when the data contained in a QR code is not a PSBT. (PASS1-553) - Improved the QR code scan error reporting. (PASS1-553) +- Removed support for [UR1] animated QR codes. + +[UR1]: https://github.com/CoboVault/Research/blob/master/papers/bcr-0005-ur.md ## 2.0.6 - Fixed alphanumeric pin entry timing (PASS1-655) diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index 411f1d46d..d954ddbf6 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -278,17 +278,6 @@ ('ui/__init__.py', 'ui/ui.py')) -# UR1 -freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules', - ('ur1/__init__.py', - 'ur1/bc32.py', - 'ur1/bech32_version.py', - 'ur1/bech32.py', - 'ur1/decode_ur.py', - 'ur1/encode_ur.py', - 'ur1/mini_cbor.py', - 'ur1/utils.py')) - # UR2 freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules', ('ur2/__init__.py', diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_sampler.py b/ports/stm32/boards/Passport/modules/data_codecs/data_sampler.py index 96c36fc4a..1797b7f4a 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_sampler.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_sampler.py @@ -9,8 +9,7 @@ # Determine if the provided data matches the format of the sampler. class DataSampler: - # Check if the given bytes look like UR1 data - # Return True if it matches or False if not + # Return True if data matches or False if not @classmethod def sample(cls, data): pass diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py index 0958f888c..b7ad0e427 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py @@ -25,21 +25,10 @@ def make_qr_encoder(qr_type, args): return None -def make_qr_decoder(qr_type): - for entry in qrs: - if entry['type'] == qr_type: - return entry['decoder']() - return None +def make_qr_decoder_from_data(data): + """Given a data sample, return its decoder.""" - -def get_qr_type_for_data(data): - '''Given a data sample, return the QRType of it.''' for entry in qrs: if entry['sampler'].sample(data) is True: - return entry['type'] + return entry['decoder']() return None - - -def get_qr_decoder_for_data(data): - qr_type = get_qr_type_for_data(data) - return make_qr_decoder(qr_type) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py index 1c837bf65..bbb9f60fb 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py @@ -1,76 +1,33 @@ # SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # -# ur1_codec.py +# ur1_sampler.py # # UR 1.0 codec # -import re -from ubinascii import unhexlify from .data_encoder import DataEncoder from .data_decoder import DataDecoder, DecodeError from .data_sampler import DataSampler from .qr_type import QRType -from ur1.decode_ur import decode_ur, extract_single_workload, Workloads -from ur1.encode_ur import encode_ur + +_BC32_CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l' class UR1Decoder(DataDecoder): def __init__(self): - self.workloads = Workloads() - self._received_parts = 0 - self._total_parts = 0 - self.error = None - - def add_data(self, data): - try: - self.workloads.add(data) - except ValueError as exc: - raise DecodeError from exc - - self._received_parts, self._total_parts = self.workloads.get_progress() - - def estimated_percent_complete(self): - return int((self._received_parts * 100) / self._total_parts) + raise DecodeError('''Unsupported format. - def is_complete(self): - return self.workloads.is_complete() - - def decode(self, **kwargs): - # XXX: This should be optional (e.g., PSBT in binary). - # - # But the UR1 standard is deprecated. - return unhexlify(decode_ur(self.workloads.workloads)) +The QR code scanned uses UR1 and it is not supported as it has been \ +superseded by UR2. +''') def qr_type(self): return QRType.UR1 class UR1Encoder(DataEncoder): - def __init__(self, _args): - self.parts = [] - self.next_index = 0 - - # Encode the given data - def encode(self, data, is_binary=False, max_fragment_len=500): - from ubinascii import hexlify - - # Convert from - if isinstance(data, str): - data = data.encode('utf8') - - if not is_binary: - data = hexlify(data) - data = data.decode('utf8') - - self.parts = encode_ur(data, fragment_capacity=max_fragment_len) - - def next_part(self): - from utils import to_str - part = self.parts[self.next_index] - self.next_index = (self.next_index + 1) % len(self.parts) - return part.upper() + pass class UR1Sampler(DataSampler): @@ -78,9 +35,23 @@ class UR1Sampler(DataSampler): # Return True if it matches or False if not @classmethod def sample(cls, data): - r = re.compile('^ur:bytes/') # Don't look for the n of m count anymore - m = r.match(data.lower()) - return m is not None + data = data.lower() + + if not data.startswith('ur:'): + return False + + pieces = data.split('/') + if not (2 <= len(pieces) <= 4): + return False + + # UR1 and UR2 can have a somewhat similar URI format but the BC32 + # vs bytewords encoding differentiates them. + fragment = pieces[-1] + for i in range(len(fragment)): + if _BC32_CHARSET.find(fragment[i]) == -1: + return False + + return True # Number of bytes required to successfully recognize this format @classmethod diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index aec13bd39..64f881c81 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -99,7 +99,7 @@ def next_part(self): class UR2Sampler(DataSampler): - # Check if the given bytes look like UR1 data + # Check if the given bytes look like UR2 data # Return True if it matches or False if not @classmethod def sample(cls, data): diff --git a/ports/stm32/boards/Passport/modules/ur1/__init__.py b/ports/stm32/boards/Passport/modules/ur1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/ports/stm32/boards/Passport/modules/ur1/bc32.py b/ports/stm32/boards/Passport/modules/ur1/bc32.py deleted file mode 100644 index 0914d9842..000000000 --- a/ports/stm32/boards/Passport/modules/ur1/bc32.py +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: GPL-3.0-or-later -# -from .bech32 import encode, decode -from .bech32_version import Bech32_Version_Origin, Bech32_Version_Bis -from ubinascii import hexlify -import gc - - -def convert_bits(data, from_bits, to_bits, pad): - acc = 0 - bits = 0 - new_size = int(len(data) * from_bits / to_bits) - if pad: - new_size += 1 - - ret = bytearray(new_size) - maxv = (1 << to_bits) - 1 - i = 0 - - for p in range(len(data)): - value = data[p] - if value < 0 or value >> from_bits != 0: - return None - - acc = (acc << from_bits) | value - bits += from_bits - while bits >= to_bits: - bits -= to_bits - ret[i] = (acc >> bits) & maxv - i += 1 - - if pad: - if bits > 0: - ret[i] = (acc << (to_bits - bits)) & maxv - else: - ret = ret[:-1] - elif bits >= from_bits or (acc << (to_bits - bits)) & maxv: - return None - - return ret - -# NOTE: Segwit functions not needed, so not ported - - -def encode_bc32_data(data): - u82u5 = convert_bits(data, 8, 5, True) - # print('u82u5={}'.format(u82u5)) - res = u82u5 - if u82u5 is None: - raise ValueError('Invalid bc32 data') - else: - return encode(None, res, Bech32_Version_Bis) - - -def decode_bc32_data(data): - result = decode(data) - if result is not None: - b = bytearray(result[1]) - res = convert_bits(b, 5, 8, False) - if res is not None: - return hexlify(res).decode() - return None - else: - return None diff --git a/ports/stm32/boards/Passport/modules/ur1/bech32.py b/ports/stm32/boards/Passport/modules/ur1/bech32.py deleted file mode 100644 index cb55246f4..000000000 --- a/ports/stm32/boards/Passport/modules/ur1/bech32.py +++ /dev/null @@ -1,128 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: GPL-3.0-or-later -# -from .bech32_version import Bech32_Version_Origin, Bech32_Version_Bis - -CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l' -GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3] - - -def polymod(values): - chk = 1 - for p in range(len(values)): - top = chk >> 25 - chk = ((chk & 0x1FFFFFF) << 5) ^ values[p] - for i in range(6): - if (top >> i) & 1: - chk ^= GENERATOR[i] - - return chk - - -def hrp_expand(hrp): - ret = [] - for p in range(len(hrp)): - ret.append(ord(hrp[p]) >> 5) - - ret.append(0) - for p in range(len(hrp)): - ret.append(ord(hrp[p]) & 31) - - return ret - - -def verify_checksum(hrp, data, version): - header = [] - if hrp: - header = hrp_expand(hrp) - else: - header = [0] - check = 1 if version == Bech32_Version_Origin else 0x3fffffff - header.extend(data) - return polymod(header) == check - - -def create_checksum(hrp, data, bech32_version): - if hrp is not None: - values = hrp_expand(hrp) - values.extend(data) - values.extend([0, 0, 0, 0, 0, 0]) - else: - values = [0] - values.extend(data) - values.extend([0, 0, 0, 0, 0, 0]) - - check = 1 if bech32_version == Bech32_Version_Origin else 0x3fffffff - - mod = polymod(values) ^ check - ret = [] - for p in range(6): - ret.append((mod >> (5 * (5 - p))) & 31) - - return bytearray(ret) - - -def encode(hrp, data, version): - checksum = create_checksum(hrp, data, version) - combined = data + checksum - if hrp is not None: - ret = hrp + '1' - else: - ret = '' - - for p in range(len(combined)): - ret += CHARSET[combined[p]] - - return ret - - -def decode_bc32(bech_string): - data = [] - for p in range(len(bech_string)): - d = CHARSET.find(bech_string[p]) - if d == -1: - return None - data.append(d) - - if not verify_checksum(None, data, Bech32_Version_Bis): - return None - - # We return a tuple here instead of a JS object - return (None, data[0:len(data) - 6]) - - -def decode(bech_string): - has_lower = False - has_upper = False - bech_len = len(bech_string) - for p in range(bech_len): - if ord(bech_string[p]) < 33 or ord(bech_string[p]) > 126: - return None - if ord(bech_string[p]) >= 97 and ord(bech_string[p]) <= 122: - has_lower = True - if ord(bech_string[p]) >= 65 and ord(bech_string[p]) <= 90: - has_upper = True - - if has_lower and has_upper: - return None - - bech_string = bech_string.lower() - pos = bech_string.rfind('1') - if pos == -1: - return decode_bc32(bech_string) - - if pos < 1 or pos + 7 > bech_len or bech_len > 90: - return None - - hrp = bech_string[0:pos] - data = [] - for p in range(pos + 1, bech_len): - d = CHARSET.find(bech_string[p]) - if d == -1: - return None - data.append(d) - - if not verify_checksum(hrp, data, Bech32_Version_Origin): - return None - - return (hrp, data[0: len(data) - 6]) diff --git a/ports/stm32/boards/Passport/modules/ur1/bech32_version.py b/ports/stm32/boards/Passport/modules/ur1/bech32_version.py deleted file mode 100644 index 98b0abe22..000000000 --- a/ports/stm32/boards/Passport/modules/ur1/bech32_version.py +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: GPL-3.0-or-later -# - -from micropython import const - -Bech32_Version_Origin = const(1) -Bech32_Version_Bis = const(2) diff --git a/ports/stm32/boards/Passport/modules/ur1/decode_ur.py b/ports/stm32/boards/Passport/modules/ur1/decode_ur.py deleted file mode 100644 index 16c727216..000000000 --- a/ports/stm32/boards/Passport/modules/ur1/decode_ur.py +++ /dev/null @@ -1,167 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: GPL-3.0-or-later -# -from .mini_cbor import decode_simple_cbor -from .bc32 import decode_bc32_data -from ubinascii import unhexlify as a2b_hex, hexlify as b2a_hex - - -def check_and_get_sequence(sequence): - pieces = sequence.upper().split('OF') - if len(pieces) != 2: - raise ValueError('Invalid sequence definition') - - (index, total) = pieces - return (int(index), int(total)) - - -def check_digest(digest, payload): - import foundation - - decoded = decode_bc32_data(payload) - if decoded is None: - raise ValueError('Unable to decode payload: {}'.format(payload)) - - decoded_bytes = a2b_hex(decoded) - sha = bytearray(32) - foundation.sha256(decoded_bytes, sha) - decoded_digest = b2a_hex(sha).decode() # bytearray - comp_digest = decode_bc32_data(digest) - if comp_digest != decoded_digest: - raise ValueError('Invalid digest:\n digest={}\n payload={}\nssSspayload digest={}'.format( - digest, payload, decoded_digest)) - - -def check_ur_header(ur, type='bytes'): - if ur.upper() != 'ur:{}'.format(type).upper(): - raise ValueError('Invalid UR header: {}'.format(ur)) - - -def deal_with_single_workload(workload, type='bytes'): - pieces = workload.split('/') - num_pieces = len(pieces) - - if num_pieces == 2: - check_ur_header(pieces[0], type) - return pieces[1] - elif num_pieces == 3: - check_ur_header(pieces[0], type) - digest = pieces[1] - fragment = pieces[2] - check_digest(digest, fragment) - return fragment - elif num_pieces == 4: - check_ur_header(pieces[0], type) - check_and_get_sequence(pieces[1]) - digest = pieces[2] - fragment = pieces[3] - check_digest(digest, fragment) - return fragment - else: - raise ValueError('Invalid workload pieces length: expected 2, 3 or 4, but got {}'.format(num_pieces)) - - -def deal_with_multiple_workloads(workloads, type='bytes'): - num_workloads = len(workloads) - fragments = ['' for i in range(num_workloads)] - digest = None - for workload in workloads: - # print('workload = {}'.format(workload)) - pieces = workload.split('/') - # print('pieces = {}'.format(pieces)) - check_ur_header(pieces[0], type) - (index, total) = check_and_get_sequence(pieces[1]) - if total != num_workloads: - raise ValueError('Invalid workload length') - - if digest is not None and digest != pieces[2]: - raise ValueError('Invalid workload digest mismatch') - - digest = pieces[2] - if fragments[index - 1] != '': - raise ValueError('Invalid workload: fragment at index {} has already been set'.format(index)) - - fragments[index - 1] = pieces[3] - - payload = ''.join(fragments) - - check_digest(digest, payload) - return payload - - -def get_bc32_payload(workloads, type='bytes'): - try: - num_workloads = len(workloads) - if num_workloads == 1: - return deal_with_single_workload(workloads[0], type) - else: - return deal_with_multiple_workloads(workloads, type) - except Exception as e: - raise ValueError('Invalid workloads: {}'.format(e)) - - -def decode_ur(workloads, type='bytes'): - bc32_payload = get_bc32_payload(workloads, type) - cbor_payload = decode_bc32_data(bc32_payload) - if cbor_payload is None: - raise ValueError('Invalid CBOR data') - - result = decode_simple_cbor(cbor_payload) - return result - - -def extract_single_workload(workload): - pieces = workload.upper().split('/') - num_pieces = len(pieces) - - if num_pieces == 2 or num_pieces == 3: - return (1, 1) - elif num_pieces == 4: - return check_and_get_sequence(pieces[1]) - else: - raise ValueError('Invalid workload pieces length: expected 2, 3, or 4, but got {}'.format(num_pieces)) - - -class Workloads: - def __init__(self): - self.num_workloads = None - self.workloads = None - - def add(self, workload): - (index, total) = extract_single_workload(workload) - - # Convert from 0 to 1 based index - index -= 1 - - if self.workloads is None: - self.num_workloads = total - self.workloads = [None] * self.num_workloads - elif self.num_workloads != total: - raise ValueError('Workload total changed from {} to {}!'.format(self.num_workloads, total)) - - if index < 0 or index >= self.num_workloads: - raise ValueError('Workload index {} is out of range: [0, {})'.format(index, self.num_workloads)) - - if self.workloads[index] is not None and self.workloads[index] != workload: - raise ValueError('Received a second workload for index {} that is different than the first one:\n old: {}\n new: {}'.format( # nopep8 - index, self.workloads[index], workload)) - - # We have to make a copy of the workload string here because it's actually a buffer coming from the - # modfoundation C code and it gets reused, so the contents changes out from under us if we don't - # make a copy! - self.workloads[index] = '{}'.format(workload) - - def is_complete(self): - for w in range(self.num_workloads): - if self.workloads[w] is None: - return False - - return True - - def get_progress(self): - num_parts = 0 - for w in range(self.num_workloads): - if self.workloads[w] is not None: - num_parts += 1 - - return (num_parts, self.num_workloads) diff --git a/ports/stm32/boards/Passport/modules/ur1/encode_ur.py b/ports/stm32/boards/Passport/modules/ur1/encode_ur.py deleted file mode 100644 index 2f707365b..000000000 --- a/ports/stm32/boards/Passport/modules/ur1/encode_ur.py +++ /dev/null @@ -1,50 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: GPL-3.0-or-later -# -from .mini_cbor import encode_simple_cbor -from .bc32 import encode_bc32_data -from .utils import compose3 -from ubinascii import hexlify - - -def compose_ur(payload, type='bytes'): - return 'ur:{}/{}'.format(type, payload) - - -def compose_digest(payload, digest): - return '{}/{}'.format(digest, payload) - - -def compose_sequencing(payload, index, total): - return '{}of{}/{}'.format(index + 1, total, payload) - - -def compose_headers_to_fragments(fragments, digest, type='bytes'): - if len(fragments) == 1: - return [compose_ur(fragments[0])] - - result = [] - for index, f in enumerate(fragments): - c = compose3( - lambda payload: compose_ur(payload, type), - lambda payload: compose_sequencing(payload, index, len(fragments)), - lambda payload: compose_digest(payload, digest), - ) - result.append(c(f)) - - return result - - -def encode_ur(payload, fragment_capacity=1000): - import foundation - - cbor_payload = encode_simple_cbor(payload) - bc32_payload = encode_bc32_data(cbor_payload) - digest = bytearray(32) - foundation.sha256(cbor_payload, digest) - bc32_digest = encode_bc32_data(digest) - fragments = [bc32_payload[i:i + fragment_capacity] for i in range(0, len(bc32_payload), fragment_capacity)] - if not fragments: - raise ValueError('Unexpected error when encoding') - - return compose_headers_to_fragments(fragments, bc32_digest, 'bytes') diff --git a/ports/stm32/boards/Passport/modules/ur1/mini_cbor.py b/ports/stm32/boards/Passport/modules/ur1/mini_cbor.py deleted file mode 100644 index 095beccea..000000000 --- a/ports/stm32/boards/Passport/modules/ur1/mini_cbor.py +++ /dev/null @@ -1,63 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: GPL-3.0-or-later -# -from ubinascii import hexlify -from ubinascii import unhexlify as a2b_hex - -# This an simple cbor implementation which is just using on BCR-05 - - -def compose_header(length): - if length > 0 and length <= 23: - header = bytearray(1) - header[0] = 0x40 + length - elif length >= 24 and length <= 255: - tag = bytearray(1) - tag[0] = 0x58 - header = tag + length.to_bytes(1, 'big') - elif length >= 256 and length <= 65535: - tag = bytearray(1) - tag[0] = 0x59 - header = tag + length.to_bytes(2, 'big') - elif length >= 65536 and length <= 2 ** 32 - 1: - tag = bytearray(1) - tag[0] = 0x60 - header = tag + length.to_bytes(4, 'big') - else: - raise ValueError('length is too big') - - return header - - -def encode_simple_cbor(data): - buffer_data = a2b_hex(data) - buffer_len = len(buffer_data) - if buffer_len <= 0 or buffer_len >= 2 ** 32: - raise ValueError('length is too big') - - header = compose_header(buffer_len) - - encoded = header + buffer_data - return encoded - - -def decode_simple_cbor(data): - data_buffer = a2b_hex(data) - - data_len = len(data_buffer) - if data_len <= 0: - raise ValueError('invalid length (<=0)') - - header = data_buffer[0] - if header < 0x58: - data_length = header - 0x40 - return hexlify(data_buffer[1:1 + data_length]).decode() - elif header == 0x58: - data_length = int.from_bytes(data_buffer[1:2], 'big') - return hexlify(data_buffer[2:2 + data_length]).decode() - elif header == 0x59: - data_length = int.from_bytes(data_buffer[1:3], 'big') - return hexlify(data_buffer[3:3 + data_length]).decode() - elif header == 0x60: - data_length = int.from_bytes(data_buffer[1:5], 'big') - return hexlify(data_buffer[5:5 + data_length]).decode() diff --git a/ports/stm32/boards/Passport/modules/ur1/utils.py b/ports/stm32/boards/Passport/modules/ur1/utils.py deleted file mode 100644 index ba1484e9c..000000000 --- a/ports/stm32/boards/Passport/modules/ur1/utils.py +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: GPL-3.0-or-later -# - - -def compose3(f, g, h): - return lambda x: f(g(h(x))) diff --git a/ports/stm32/boards/Passport/modules/views/camera.py b/ports/stm32/boards/Passport/modules/views/camera.py index 4c0b4e892..fd6681cc9 100644 --- a/ports/stm32/boards/Passport/modules/views/camera.py +++ b/ports/stm32/boards/Passport/modules/views/camera.py @@ -11,7 +11,7 @@ from views import View from styles import Stylize from styles.colors import WHITE -from data_codecs.qr_factory import get_qr_decoder_for_data +from data_codecs.qr_factory import make_qr_decoder_from_data class Camera(View): @@ -175,7 +175,7 @@ def update(self): return if self.qr_decoder is None: - self.qr_decoder = get_qr_decoder_for_data(data) + self.qr_decoder = make_qr_decoder_from_data(data) self.qr_decoder.add_data(data) diff --git a/ports/stm32/boards/Passport/modules/wallets/lily.py b/ports/stm32/boards/Passport/modules/wallets/lily.py index 91e39a838..bbc31617e 100644 --- a/ports/stm32/boards/Passport/modules/wallets/lily.py +++ b/ports/stm32/boards/Passport/modules/wallets/lily.py @@ -19,7 +19,7 @@ 'import_microsd': read_multisig_config_from_microsd} ], 'export_modes': [ - # {'id': 'qr', 'label': 'QR Code', 'qr_type': QRType.UR1}, + # {'id': 'qr', 'label': 'QR Code', 'qr_type': QRType.UR2}, {'id': 'microsd', 'label': 'microSD', 'filename_pattern': '{sd}/{xfp}-lily.json', 'filename_pattern_multisig': '{sd}/{xfp}-lily-multisig.json'} ] From 8f310c7d96b72319f7d2b50d0aa26536f9146a7e Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 11:56:50 +0100 Subject: [PATCH 065/156] PASS1-663: Update version.txt Signed-off-by: Jean-Pierre De Jesus DIAZ --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 703cec9e2..6a0ca2d59 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.6 \ No newline at end of file +2.0.7 \ No newline at end of file From 19c207ef43c200566593e98311216029e853b9c4 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 14 Feb 2023 11:35:58 -0600 Subject: [PATCH 066/156] updated changelog --- CHANGELOG.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7342db8bc..b337fed74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,22 @@ SPDX-License-Identifier: GPL-3.0-or-later --> ## Head +- Improved self-send transaction information formatting (PASS1-638) + +## 2.0.7 - Perform more accurate calculation of scan progress. (PASS1-553) - Report to the user when the data contained in a QR code is not a PSBT. (PASS1-553) - Improved the QR code scan error reporting. (PASS1-553) -- Removed support for [UR1] animated QR codes. +- Removed support for [UR1] animated QR codes (PASS1-620) +- Improved Founder's Edition screen performance (PASS1-576) +- Automatically generate hash files using "just hash" (PASS1-605) +- Added a success screen after multisig imports (PASS1-593) +- Improved file display error handling (PASS1-584) +- Added option to delete files from the SD card (PASS1-618) +- Added Casa health check via SD card (PASS1-595) +- Added multisig config export via QR and SD card (PASS1-631) +- Fixed multisig config descriptions (PASS1-643) +- Erase PSBTs from external flash after signing (PASS1-345) [UR1]: https://github.com/CoboVault/Research/blob/master/papers/bcr-0005-ur.md From a4d9375c837c6c7e5babcba4e2237a9fc081be20 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 12:00:13 +0100 Subject: [PATCH 067/156] PASS1-662: Use build-essential for Dockerfile Includes gcc, g++, make and libc. Signed-off-by: Jean-Pierre De Jesus DIAZ --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 704fe9cc5..018d59035 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ FROM ubuntu:20.04 AS cross_build ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ - apt-get install -y git make gcc-arm-none-eabi python3 gcc && \ + apt-get install -y build-essential git gcc-arm-none-eabi python3 && \ rm -rf /var/lib/apt/lists/* COPY drivers /workspace/passport2/drivers COPY docs /workspace/passport2/docs @@ -24,7 +24,7 @@ FROM ubuntu:20.04 AS cosign_build ARG DEBIAN_FRONTEND=noninteractive WORKDIR /workspace RUN apt-get update && \ - apt-get install -y git make libssl-dev gcc && \ + apt-get install -y build-essential git libssl-dev && \ rm -rf /var/lib/apt/lists/* COPY ports/stm32/boards/Passport/tools/cosign /workspace/passport2/ports/stm32/boards/Passport/tools/cosign COPY ports/stm32/boards/Passport/include /workspace/passport2/ports/stm32/boards/Passport/include @@ -41,6 +41,6 @@ COPY --from=cross_build \ /workspace/passport2/mpy-cross/mpy-cross /usr/bin/mpy-cross ENV PATH="${PATH}:~/bin" RUN apt-get update && \ - apt-get install -y make gcc-arm-none-eabi autotools-dev automake libtool python3 curl libffi-dev pkg-config && \ + apt-get install -y build-essential gcc-arm-none-eabi autotools-dev automake libtool python3 curl libffi-dev pkg-config && \ rm -rf /var/lib/apt/lists/* && \ curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin From f400f72f39855a6d11d4a759166156b98dc82f01 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 12:00:38 +0100 Subject: [PATCH 068/156] PASS1-662: Remove init recipe Unused. Signed-off-by: Jean-Pierre De Jesus DIAZ --- Justfile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Justfile b/Justfile index b5ac61960..28c5d6b21 100644 --- a/Justfile +++ b/Justfile @@ -14,12 +14,6 @@ firmware_path := base_path + '/build-Passport/' # build: docker-build firmware-build bootloader-build # build: docker-build (build-bootloader "mono") (build-bootloader "color") (build-firmware "mono") (build-firmware "color") -init: - # Ensure submodules are cloned - git submodule update --init --recursive - # Setup the image converter tool - cd tools/lv_img_conv && npm install - # build the dependency docker image build-docker: #!/usr/bin/env bash From 4a936af06c2a5a0b7cbc52ffc953f3c430ee6c35 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 17:33:34 +0100 Subject: [PATCH 069/156] PASS1-662: Capitalize recipe descriptions Signed-off-by: Jean-Pierre De Jesus DIAZ --- Justfile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Justfile b/Justfile index 28c5d6b21..3509e5dba 100644 --- a/Justfile +++ b/Justfile @@ -20,7 +20,7 @@ build-docker: set -exo pipefail docker build -t ${DOCKER_REGISTRY_BASE}{{docker_image}} . -# build the firmware inside docker +# Build the firmware inside docker build-firmware screen="mono": #!/usr/bin/env bash set -exo pipefail @@ -31,7 +31,7 @@ build-firmware screen="mono": ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c 'just build {{screen}} MPY_CROSS=/usr/bin/mpy-cross' -# build the bootloader inside docker +# Build the bootloader inside docker build-bootloader screen="mono": #!/usr/bin/env bash set -exo pipefail @@ -42,10 +42,10 @@ build-bootloader screen="mono": ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c 'just build {{screen}}' -# build the docker image and get the tools from it +# Build the docker image and get the tools from it tools: build-docker cosign-tool add-secrets-tool word-list-gen-tool -# get cosign tool from built docker image +# Get cosign tool from built docker image cosign-tool: #!/usr/bin/env bash set -exo pipefail @@ -56,7 +56,7 @@ cosign-tool: ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c 'cp /usr/bin/cosign cosign' -# get add-secrets tool from built docker image +# Get add-secrets tool from built docker image add-secrets-tool: #!/usr/bin/env bash set -exo pipefail @@ -67,7 +67,7 @@ add-secrets-tool: ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c 'make -C ports/stm32/boards/Passport/tools/add-secrets' -# get word_list_gen tool from built docker image +# Get word_list_gen tool from built docker image word-list-gen-tool: #!/usr/bin/env bash set -exo pipefail @@ -78,7 +78,7 @@ word-list-gen-tool: ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c 'gcc word_list_gen.c bip39_words.c bytewords_words.c -o word_list_gen' -# run the built firmware through SHA256 +# Run the built firmware through SHA256 verify-sha sha: #!/usr/bin/env bash sha=$(shasum -a 256 {{firmware_path}} | awk '{print $1}') @@ -91,7 +91,7 @@ verify-sha sha: echo "ERROR: Hashes DO NOT match!" fi -# sign the built firmware using a private key and the cosign tool +# Sign the built firmware using a private key and the cosign tool sign keypath version screen="mono": (build-firmware screen) #!/usr/bin/env bash set -exo pipefail @@ -105,7 +105,7 @@ sign keypath version screen="mono": (build-firmware screen) ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c "just cosign_filepath=build-Passport/firmware-$SCREEN.bin cosign_keypath={{keypath}} sign {{version}} {{screen}} MPY_CROSS=/usr/bin/mpy-cross" -# clean firmware build +# Clean firmware build clean: docker run --rm -v "$PWD":/workspace \ -u $(id -u):$(id -g) \ @@ -114,7 +114,7 @@ clean: ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c "make clean BOARD=Passport" -# clean bootloader build +# Clean bootloader build clean-bootloader: docker run --rm -v "$PWD":/workspace \ -u $(id -u):$(id -g) \ @@ -123,7 +123,7 @@ clean-bootloader: ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c "just clean" -# clean simulator build +# Clean simulator build clean-simulator: docker run --rm -v "$PWD":/workspace \ -u $(id -u):$(id -g) \ From 818ce46687a21970a8ffbaa618796b7ce4775729 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 17:37:29 +0100 Subject: [PATCH 070/156] PASS1-662: Simplify docker registry variable Signed-off-by: Jean-Pierre De Jesus DIAZ --- .github/workflows/validate_and_build.yaml | 42 ++++++++++++----------- Justfile | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/.github/workflows/validate_and_build.yaml b/.github/workflows/validate_and_build.yaml index 3cd388ec4..e28f29613 100644 --- a/.github/workflows/validate_and_build.yaml +++ b/.github/workflows/validate_and_build.yaml @@ -51,11 +51,13 @@ jobs: build-firmware: runs-on: ubuntu-20.04 needs: [lint-py, lint-c, lint-reuse] + services: registry: image: registry:2 ports: - 5000:5000 + steps: - name: Checkout uses: actions/checkout@v2 @@ -91,10 +93,10 @@ jobs: # echo "$SIGNING_KEY" > ports/stm32/signing_key.pem # version=$(cat version.txt) - # just DOCKER_REGISTRY_BASE="$D_BASE" sign signing_key.pem "${version}" mono + # just sign signing_key.pem "${version}" mono # env: # SIGNING_KEY: ${{ secrets.UserSigningKey }} - # D_BASE: localhost:5000/ + # DOCKER_REGISTRY_BASE: localhost:5000/ # - name: Upload unsigned mono firmware file # uses: actions/upload-artifact@v2 @@ -109,19 +111,19 @@ jobs: # path: ports/stm32/build-Passport/firmware-MONO-key-user.bin - name: Clean firmware between different screen builds - run: just DOCKER_REGISTRY_BASE="$D_BASE" clean + run: just clean env: - D_BASE: localhost:5000/ + DOCKER_REGISTRY_BASE: localhost:5000/ - name: Build the color firmware run: | echo "$SIGNING_KEY" > ports/stm32/signing_key.pem version=$(cat version.txt) - just DOCKER_REGISTRY_BASE="$D_BASE" sign signing_key.pem "${version}" color + just sign signing_key.pem "${version}" color env: SIGNING_KEY: ${{ secrets.UserSigningKey }} - D_BASE: localhost:5000/ + DOCKER_REGISTRY_BASE: localhost:5000/ - name: Upload unsigned color firmware file uses: actions/upload-artifact@v2 @@ -136,9 +138,9 @@ jobs: path: ports/stm32/build-Passport/firmware-COLOR-key-user.bin # - name: Build the mono bootloader - # run: just DOCKER_REGISTRY_BASE="$D_BASE" build-bootloader mono + # run: just build-bootloader mono # env: - # D_BASE: localhost:5000/ + # DOCKER_REGISTRY_BASE: localhost:5000/ # - name: Upload mono bootloader # uses: actions/upload-artifact@v2 @@ -147,14 +149,14 @@ jobs: # path: ports/stm32/boards/Passport/bootloader/arm/release/bootloader-MONO.bin - name: Clean bootloader between different screen builds - run: just DOCKER_REGISTRY_BASE="$D_BASE" clean-bootloader + run: just clean-bootloader env: - D_BASE: localhost:5000/ + DOCKER_REGISTRY_BASE: localhost:5000/ - name: Build the color bootloader - run: just DOCKER_REGISTRY_BASE="$D_BASE" build-bootloader color + run: just build-bootloader color env: - D_BASE: localhost:5000/ + DOCKER_REGISTRY_BASE: localhost:5000/ - name: Upload color bootloader uses: actions/upload-artifact@v2 @@ -163,20 +165,20 @@ jobs: path: ports/stm32/boards/Passport/bootloader/arm/release/bootloader-COLOR.bin - name: Build and make tools available - run: just DOCKER_REGISTRY_BASE="$D_BASE" tools + run: just tools env: - D_BASE: localhost:5000/ + DOCKER_REGISTRY_BASE: localhost:5000/ # - name: Build the mono simulator # run: | - # just DOCKER_REGISTRY_BASE="$D_BASE" clean-simulator - # just DOCKER_REGISTRY_BASE="$D_BASE" build-simulator mono + # just clean-simulator + # just build-simulator mono # env: - # D_BASE: localhost:5000/ + # DOCKER_REGISTRY_BASE: localhost:5000/ - name: Build the color simulator run: | - just DOCKER_REGISTRY_BASE="$D_BASE" clean-simulator - just DOCKER_REGISTRY_BASE="$D_BASE" build-simulator color + just clean-simulator + just build-simulator color env: - D_BASE: localhost:5000/ + DOCKER_REGISTRY_BASE: localhost:5000/ diff --git a/Justfile b/Justfile index 3509e5dba..508a77f35 100644 --- a/Justfile +++ b/Justfile @@ -3,7 +3,7 @@ # # Justfile - Root-level justfile for Passport -export DOCKER_REGISTRY_BASE := '' +export DOCKER_REGISTRY_BASE := env_var_or_default('DOCKER_REGISTRY_BASE', '') commit_sha := `git rev-parse HEAD` docker_image := 'foundation-devices/firmware-builder:' + commit_sha From 1e007a582e60852498ab623e39c6a16e0730d127 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 17:47:18 +0100 Subject: [PATCH 071/156] PASS1-662: Remove simulatordir variable Signed-off-by: Jean-Pierre De Jesus DIAZ --- Justfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Justfile b/Justfile index 508a77f35..ebf6826fd 100644 --- a/Justfile +++ b/Justfile @@ -144,11 +144,11 @@ build-simulator screen="mono": sim screen="mono" ext="": just simulator/sim {{screen}} {{ext}} -simulatordir := `pwd` + "/simulator" # Run unit tests. test: just simulator/build color - cd ports/stm32/boards/Passport/modules/tests/; python3 -m pytest . --simulatordir={{simulatordir}} + cd ports/stm32/boards/Passport/modules/tests; \ + python3 -m pytest . --simulatordir=$(pwd)/simulator # Lint the codebase. lint: From 07a11c70b388f0188bd9303027d1842d14ebbba6 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 17:51:18 +0100 Subject: [PATCH 072/156] PASS1-662: Use 4 spaces indentation Signed-off-by: Jean-Pierre De Jesus DIAZ --- Justfile | 146 +++++++++++++++++++++++++++---------------------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/Justfile b/Justfile index ebf6826fd..9d133c478 100644 --- a/Justfile +++ b/Justfile @@ -47,109 +47,109 @@ tools: build-docker cosign-tool add-secrets-tool word-list-gen-tool # Get cosign tool from built docker image cosign-tool: - #!/usr/bin/env bash - set -exo pipefail - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c 'cp /usr/bin/cosign cosign' + #!/usr/bin/env bash + set -exo pipefail + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -w /workspace \ + --entrypoint bash \ + ${DOCKER_REGISTRY_BASE}{{docker_image}} \ + -c 'cp /usr/bin/cosign cosign' # Get add-secrets tool from built docker image add-secrets-tool: - #!/usr/bin/env bash - set -exo pipefail - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c 'make -C ports/stm32/boards/Passport/tools/add-secrets' + #!/usr/bin/env bash + set -exo pipefail + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -w /workspace \ + --entrypoint bash \ + ${DOCKER_REGISTRY_BASE}{{docker_image}} \ + -c 'make -C ports/stm32/boards/Passport/tools/add-secrets' # Get word_list_gen tool from built docker image word-list-gen-tool: - #!/usr/bin/env bash - set -exo pipefail - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/ports/stm32/boards/Passport/tools/word_list_gen \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c 'gcc word_list_gen.c bip39_words.c bytewords_words.c -o word_list_gen' + #!/usr/bin/env bash + set -exo pipefail + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -w /workspace/ports/stm32/boards/Passport/tools/word_list_gen \ + --entrypoint bash \ + ${DOCKER_REGISTRY_BASE}{{docker_image}} \ + -c 'gcc word_list_gen.c bip39_words.c bytewords_words.c -o word_list_gen' # Run the built firmware through SHA256 verify-sha sha: - #!/usr/bin/env bash - sha=$(shasum -a 256 {{firmware_path}} | awk '{print $1}') + #!/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 + 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 screen="mono": (build-firmware screen) - #!/usr/bin/env bash - set -exo pipefail - - SCREEN={{screen}} - SCREEN=`echo ${SCREEN^^}` - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/{{base_path}} \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "just cosign_filepath=build-Passport/firmware-$SCREEN.bin cosign_keypath={{keypath}} sign {{version}} {{screen}} MPY_CROSS=/usr/bin/mpy-cross" + #!/usr/bin/env bash + set -exo pipefail + + SCREEN={{screen}} + SCREEN=`echo ${SCREEN^^}` + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -w /workspace/{{base_path}} \ + --entrypoint bash \ + ${DOCKER_REGISTRY_BASE}{{docker_image}} \ + -c "just cosign_filepath=build-Passport/firmware-$SCREEN.bin cosign_keypath={{keypath}} sign {{version}} {{screen}} MPY_CROSS=/usr/bin/mpy-cross" # Clean firmware build clean: - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/{{base_path}} \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "make clean BOARD=Passport" + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -w /workspace/{{base_path}} \ + --entrypoint bash \ + ${DOCKER_REGISTRY_BASE}{{docker_image}} \ + -c "make clean BOARD=Passport" # Clean bootloader build clean-bootloader: - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/{{base_path}}/boards/Passport/bootloader \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "just clean" + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -w /workspace/{{base_path}}/boards/Passport/bootloader \ + --entrypoint bash \ + ${DOCKER_REGISTRY_BASE}{{docker_image}} \ + -c "just clean" # Clean simulator build clean-simulator: - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/simulator \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "just clean" + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -w /workspace/simulator \ + --entrypoint bash \ + ${DOCKER_REGISTRY_BASE}{{docker_image}} \ + -c "just clean" build-simulator screen="mono": - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/simulator \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "just build {{screen}} MPY_CROSS=/usr/bin/mpy-cross" + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -w /workspace/simulator \ + --entrypoint bash \ + ${DOCKER_REGISTRY_BASE}{{docker_image}} \ + -c "just build {{screen}} MPY_CROSS=/usr/bin/mpy-cross" # Run the simulator. sim screen="mono" ext="": - just simulator/sim {{screen}} {{ext}} + just simulator/sim {{screen}} {{ext}} # Run unit tests. test: - just simulator/build color - cd ports/stm32/boards/Passport/modules/tests; \ - python3 -m pytest . --simulatordir=$(pwd)/simulator + just simulator/build color + cd ports/stm32/boards/Passport/modules/tests; \ + python3 -m pytest . --simulatordir=$(pwd)/simulator # Lint the codebase. lint: - just ports/stm32/lint \ No newline at end of file + just ports/stm32/lint \ No newline at end of file From 041c8283b26eadf5dbd9391f6fd9a6c0fd716dce Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 20:57:34 +0100 Subject: [PATCH 073/156] PASS1-662: Fix verify-sha recipe Signed-off-by: Jean-Pierre De Jesus DIAZ --- Justfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Justfile b/Justfile index 9d133c478..ffb1a311b 100644 --- a/Justfile +++ b/Justfile @@ -78,10 +78,11 @@ word-list-gen-tool: ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c 'gcc word_list_gen.c bip39_words.c bytewords_words.c -o word_list_gen' -# Run the built firmware through SHA256 -verify-sha sha: +# Build the firmware and check its SHA256. +verify-sha sha screen="mono": #!/usr/bin/env bash - sha=$(shasum -a 256 {{firmware_path}} | awk '{print $1}') + + sha=$(shasum -a 256 ports/stm32/build-Passport/firmware-{{uppercase(screen)}}.bin | awk '{print $1}') echo -e "Expected SHA:\t{{sha}}" echo -e "Actual SHA:\t${sha}" From 4485e063eeef0ece6c23a5255c6b37f9f95a157e Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 21:16:18 +0100 Subject: [PATCH 074/156] PASS1-662: Make dep5 machine readable Signed-off-by: Jean-Pierre De Jesus DIAZ --- .reuse/dep5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.reuse/dep5 b/.reuse/dep5 index 992dbfcf3..baa1d61ef 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -1,6 +1,6 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream - Name: Passport -Upstream - Contact: hello@foundationdevices.com +Upstream-Name: Passport +Upstream-Contact: hello@foundationdevices.com Source: https://git.example.com/FoundationDevices/passport2 Files: From 5f639ac7a3c08dc3d8f85fda29d9bfbc6d76ab36 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 23:50:05 +0100 Subject: [PATCH 075/156] PASS1-662: Fix verify-sha recipe Signed-off-by: Jean-Pierre De Jesus DIAZ --- Justfile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Justfile b/Justfile index ffb1a311b..4d7a8b995 100644 --- a/Justfile +++ b/Justfile @@ -78,18 +78,22 @@ word-list-gen-tool: ${DOCKER_REGISTRY_BASE}{{docker_image}} \ -c 'gcc word_list_gen.c bip39_words.c bytewords_words.c -o word_list_gen' -# Build the firmware and check its SHA256. +# Verify the built firmware through SHA256 verify-sha sha screen="mono": #!/usr/bin/env bash - sha=$(shasum -a 256 ports/stm32/build-Passport/firmware-{{uppercase(screen)}}.bin | awk '{print $1}') + if [ -z "${sha}" ]; then + exit 1 + fi + 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!" + exit 1 fi # Sign the built firmware using a private key and the cosign tool From 927b6d002a4d0feaf8bc6a64e87e7b2a363bd6f3 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 14 Feb 2023 23:54:42 +0100 Subject: [PATCH 076/156] PASS1-662: Optimize Dockerfile Signed-off-by: Jean-Pierre De Jesus DIAZ --- .github/workflows/validate_and_build.yaml | 286 ++++++++++++---------- .gitignore | 1 + Dockerfile | 67 +++-- Justfile | 157 +++--------- 4 files changed, 224 insertions(+), 287 deletions(-) diff --git a/.github/workflows/validate_and_build.yaml b/.github/workflows/validate_and_build.yaml index e28f29613..d7525a537 100644 --- a/.github/workflows/validate_and_build.yaml +++ b/.github/workflows/validate_and_build.yaml @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. +# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # # validate_and_build.yaml - GitHub actions for Passport @@ -6,51 +6,44 @@ name: Validate and Build on: [push] jobs: - lint-py: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.9 - uses: actions/setup-python@v2 - with: - python-version: '3.9' - cache: 'pip' - - name: Install pycodestyle - run: pip install pycodestyle - - name: Run pycodestyle - run: | - STYLE_TEMP=$(mktemp) - - if ! pycodestyle --exclude trezor-firmware,unused_modules,graphics.py,translations --statistics ports/stm32/boards/Passport | tee "$STYLE_TEMP" - then - sed -n -e 's/^\(.*\.py\):\([[:digit:]]\+\):\([[:digit:]]\+\): \(E[[:digit:]]\+\) \(.*\)$/::error file=\1,line=\2,col=\3,title=\4::\5/p' < "$STYLE_TEMP" - sed -n -e 's/^\(.*\.py\):\([[:digit:]]\+\):\([[:digit:]]\+\): \(W[[:digit:]]\+\) \(.*\)$/::warning file=\1,line=\2,col=\3,title=\4::\5/p' < "$STYLE_TEMP" - exit 1 - fi - - lint-c: + lint: + name: Lint runs-on: ubuntu-20.04 + + services: + registry: + image: registry:2 + ports: + - 5000:5000 + steps: - uses: actions/checkout@v2 - - name: Analysing the code - uses: jidicula/clang-format-action@7f6b4bf5a7eb211c0872364ccd8072ff8a77ac44 with: - clang-format-version: '10' - check-path: ./ports/stm32 - exclude-regex: trezor-firmware - continue-on-error: true + fetch-depth: 0 + - uses: docker/setup-buildx-action@v1 + with: + driver-opts: network=host + - uses: docker/build-push-action@v2 + with: + push: true + context: . + cache-from: type=gha + cache-to: type=gha + tags: localhost:5000/foundation-devices/passport2:latest + - uses: extractions/setup-just@aa5d15c144db4585980a44ebfdd2cf337c4f14cb + - run: echo "DOCKER_IMAGE=localhost:5000/foundation-devices/passport2:latest" >> $GITHUB_ENV - lint-reuse: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - name: REUSE Compliance Check - uses: fsfe/reuse-action@v1 - continue-on-error: true + - name: Lint the codebase + run: just lint build-firmware: + name: Build Firmware runs-on: ubuntu-20.04 - needs: [lint-py, lint-c, lint-reuse] + needs: [lint] + + strategy: + matrix: + screen: ["mono", "color"] services: registry: @@ -59,126 +52,151 @@ jobs: - 5000:5000 steps: - - name: Checkout - uses: actions/checkout@v2 + - uses: actions/checkout@v2 with: fetch-depth: 0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + - uses: docker/setup-buildx-action@v1 with: driver-opts: network=host - - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Build the dependency Docker image - uses: docker/build-push-action@v2 + - uses: docker/build-push-action@v2 with: push: true - tags: localhost:5000/foundation-devices/firmware-builder:${{ github.sha }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache - - - name: Setup just - uses: extractions/setup-just@aa5d15c144db4585980a44ebfdd2cf337c4f14cb - - # - name: Build the mono firmware - # run: | - # echo "$SIGNING_KEY" > ports/stm32/signing_key.pem - # version=$(cat version.txt) - - # just sign signing_key.pem "${version}" mono - # env: - # SIGNING_KEY: ${{ secrets.UserSigningKey }} - # DOCKER_REGISTRY_BASE: localhost:5000/ - - # - name: Upload unsigned mono firmware file - # uses: actions/upload-artifact@v2 - # with: - # name: firmware-MONO.bin - # path: ports/stm32/build-Passport/firmware-MONO.bin - - # - name: Upload signed mono firmware file - # uses: actions/upload-artifact@v2 - # with: - # name: firmware-MONO-key-user.bin - # path: ports/stm32/build-Passport/firmware-MONO-key-user.bin - - - name: Clean firmware between different screen builds - run: just clean - env: - DOCKER_REGISTRY_BASE: localhost:5000/ - - - name: Build the color firmware + context: . + cache-from: type=gha + cache-to: type=gha + tags: localhost:5000/foundation-devices/passport2:latest + - uses: extractions/setup-just@aa5d15c144db4585980a44ebfdd2cf337c4f14cb + - run: | + echo "DOCKER_IMAGE=localhost:5000/foundation-devices/passport2:latest" >> $GITHUB_ENV + echo "SCREEN_MODE=$(echo "color" | tr a-z A-Z)" >> $GITHUB_ENV + + - name: Build run: | echo "$SIGNING_KEY" > ports/stm32/signing_key.pem version=$(cat version.txt) - just sign signing_key.pem "${version}" color + just sign signing_key.pem "${version}" ${{ matrix.color }} env: SIGNING_KEY: ${{ secrets.UserSigningKey }} - DOCKER_REGISTRY_BASE: localhost:5000/ - - name: Upload unsigned color firmware file + - name: Upload firmware (unsigned) uses: actions/upload-artifact@v2 with: - name: firmware-COLOR.bin - path: ports/stm32/build-Passport/firmware-COLOR.bin + name: firmware-${{ env.SCREEN_MODE }}.bin + path: ports/stm32/build-Passport/firmware-${{ env.SCREEN_MODE }}.bin - - name: Upload signed color firmware file + - name: Upload firmware (signed) uses: actions/upload-artifact@v2 with: - name: firmware-COLOR-key-user.bin - path: ports/stm32/build-Passport/firmware-COLOR-key-user.bin - - # - name: Build the mono bootloader - # run: just build-bootloader mono - # env: - # DOCKER_REGISTRY_BASE: localhost:5000/ + name: firmware-${{ env.SCREEN_MODE }}-key-user.bin + path: ports/stm32/build-Passport/firmware-${{ env.SCREEN_MODE }}-key-user.bin - # - name: Upload mono bootloader - # uses: actions/upload-artifact@v2 - # with: - # name: bootloader-MONO.bin - # path: ports/stm32/boards/Passport/bootloader/arm/release/bootloader-MONO.bin + build-bootloader: + name: Build Bootloader + runs-on: ubuntu-20.04 + needs: [lint, build-firmware] - - name: Clean bootloader between different screen builds - run: just clean-bootloader - env: - DOCKER_REGISTRY_BASE: localhost:5000/ + # TODO: PASS1-665. + strategy: + matrix: + screen: ["color"] - - name: Build the color bootloader - run: just build-bootloader color - env: - DOCKER_REGISTRY_BASE: localhost:5000/ + services: + registry: + image: registry:2 + ports: + - 5000:5000 - - name: Upload color bootloader + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: docker/setup-buildx-action@v1 + with: + driver-opts: network=host + - uses: docker/build-push-action@v2 + with: + push: true + context: . + cache-from: type=gha + cache-to: type=gha + tags: localhost:5000/foundation-devices/passport2:latest + - uses: extractions/setup-just@aa5d15c144db4585980a44ebfdd2cf337c4f14cb + - run: | + echo "DOCKER_IMAGE=localhost:5000/foundation-devices/passport2:latest" >> $GITHUB_ENV + echo "SCREEN_MODE=$(echo "color" | tr a-z A-Z)" >> $GITHUB_ENV + + - name: Build + run: just build-bootloader ${{ matrix.screen }} + + - name: Upload bootloader uses: actions/upload-artifact@v2 with: - name: bootloader-COLOR.bin - path: ports/stm32/boards/Passport/bootloader/arm/release/bootloader-COLOR.bin + name: bootloader-${{ env.SCREEN_MODE }}.bin + path: ports/stm32/boards/Passport/bootloader/arm/release/bootloader-${{ env.SCREEN_MODE }}.bin - - name: Build and make tools available - run: just tools - env: - DOCKER_REGISTRY_BASE: localhost:5000/ + build-simulator: + name: Build Simulator + runs-on: ubuntu-20.04 + needs: [lint, build-firmware] - # - name: Build the mono simulator - # run: | - # just clean-simulator - # just build-simulator mono - # env: - # DOCKER_REGISTRY_BASE: localhost:5000/ + strategy: + matrix: + screen: ["mono", "color"] - - name: Build the color simulator - run: | - just clean-simulator - just build-simulator color - env: - DOCKER_REGISTRY_BASE: localhost:5000/ + services: + registry: + image: registry:2 + ports: + - 5000:5000 + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: docker/setup-buildx-action@v1 + with: + driver-opts: network=host + - uses: docker/build-push-action@v2 + with: + push: true + context: . + cache-from: type=gha + cache-to: type=gha + tags: localhost:5000/foundation-devices/passport2:latest + - uses: extractions/setup-just@aa5d15c144db4585980a44ebfdd2cf337c4f14cb + - run: echo "DOCKER_IMAGE=localhost:5000/foundation-devices/passport2:latest" >> $GITHUB_ENV + + - name: Build + run: just build-simulator ${{ matrix.screen }} + + build-tools: + name: Build Tools + runs-on: ubuntu-20.04 + needs: [lint] + + services: + registry: + image: registry:2 + ports: + - 5000:5000 + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: docker/setup-buildx-action@v1 + with: + driver-opts: network=host + - uses: docker/build-push-action@v2 + with: + push: true + context: . + cache-from: type=gha + cache-to: type=gha + tags: localhost:5000/foundation-devices/passport2:latest + - uses: extractions/setup-just@aa5d15c144db4585980a44ebfdd2cf337c4f14cb + - run: echo "DOCKER_IMAGE=localhost:5000/foundation-devices/passport2:latest" >> $GITHUB_ENV + + - name: Build + run: just tools diff --git a/.gitignore b/.gitignore index 22437a3a0..7201d375c 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,7 @@ genrst/ # Passport ###################### +mpy-cross/mpy-cross-docker ports/stm32/boards/Passport/tools/cosign/x86 ports/stm32/boards/Passport/tools/add-secrets/x86 ports/stm32/boards/Passport/bootloader/dev-secrets/ diff --git a/Dockerfile b/Dockerfile index 018d59035..edb1655cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,44 +3,39 @@ # SPDX-License-Identifier: GPL-3.0-or-later # -FROM ubuntu:20.04 AS cross_build -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && \ - apt-get install -y build-essential git gcc-arm-none-eabi python3 && \ - rm -rf /var/lib/apt/lists/* -COPY drivers /workspace/passport2/drivers -COPY docs /workspace/passport2/docs -COPY extmod /workspace/passport2/extmod -COPY lib /workspace/passport2/lib -COPY mpy-cross /workspace/passport2/mpy-cross -COPY py /workspace/passport2/py -COPY ports/stm32/boards/Passport/include /workspace/passport2/ports/stm32/boards/Passport/include -COPY ports/stm32/boards/Passport/common /workspace/passport2/ports/stm32/boards/Passport/common -COPY ports/stm32/boards/Passport/images /workspace/passport2/ports/stm32/boards/Passport/images -WORKDIR /workspace/passport2/mpy-cross -RUN make +FROM ubuntu:20.04 -FROM ubuntu:20.04 AS cosign_build ARG DEBIAN_FRONTEND=noninteractive -WORKDIR /workspace + +# Install packages. +# +# Alphabetic ordering is recommended. RUN apt-get update && \ - apt-get install -y build-essential git libssl-dev && \ + apt-get install -y automake \ + autotools-dev \ + build-essential \ + curl \ + gcc-arm-none-eabi \ + git \ + libffi-dev \ + libssl-dev \ + libtool \ + pkg-config \ + pycodestyle \ + python3 \ + python3-pip && \ rm -rf /var/lib/apt/lists/* -COPY ports/stm32/boards/Passport/tools/cosign /workspace/passport2/ports/stm32/boards/Passport/tools/cosign -COPY ports/stm32/boards/Passport/include /workspace/passport2/ports/stm32/boards/Passport/include -COPY ports/stm32/boards/Passport/common /workspace/passport2/ports/stm32/boards/Passport/common -COPY lib /workspace/passport2/lib -WORKDIR /workspace/passport2/ports/stm32/boards/Passport/tools/cosign -RUN make -FROM ubuntu:20.04 AS firmware_builder -ARG DEBIAN_FRONTEND=noninteractive -COPY --from=cosign_build \ - /workspace/passport2/ports/stm32/boards/Passport/tools/cosign/x86/release/cosign /usr/bin/cosign -COPY --from=cross_build \ - /workspace/passport2/mpy-cross/mpy-cross /usr/bin/mpy-cross -ENV PATH="${PATH}:~/bin" -RUN apt-get update && \ - apt-get install -y build-essential gcc-arm-none-eabi autotools-dev automake libtool python3 curl libffi-dev pkg-config && \ - rm -rf /var/lib/apt/lists/* && \ - curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin +# Install reuse. +RUN pip3 install reuse + +# Install rustup. +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +# Install Rust toolchain. +RUN rustup default 1.67.1 + +# Install just. +RUN cargo install just@^1.13 && \ + mv /root/.cargo/bin/just /usr/local/bin/just diff --git a/Justfile b/Justfile index 4d7a8b995..4b17e981b 100644 --- a/Justfile +++ b/Justfile @@ -1,84 +1,21 @@ # SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. # SPDX-License-Identifier: GPL-3.0-or-later # -# Justfile - Root-level justfile for Passport +# Justfile - Root-level Justfile for Passport -export DOCKER_REGISTRY_BASE := env_var_or_default('DOCKER_REGISTRY_BASE', '') +export DOCKER_IMAGE := env_var_or_default('DOCKER_IMAGE', 'foundation-devices/passport2:latest') -commit_sha := `git rev-parse HEAD` -docker_image := 'foundation-devices/firmware-builder:' + commit_sha -base_path := 'ports/stm32' -firmware_path := base_path + '/build-Passport/' - -# build the docker image and then the firmware and bootloader -# build: docker-build firmware-build bootloader-build -# build: docker-build (build-bootloader "mono") (build-bootloader "color") (build-firmware "mono") (build-firmware "color") - -# build the dependency docker image +# Build the docker image build-docker: - #!/usr/bin/env bash - set -exo pipefail - docker build -t ${DOCKER_REGISTRY_BASE}{{docker_image}} . - -# Build the firmware inside docker -build-firmware screen="mono": - #!/usr/bin/env bash - set -exo pipefail - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/{{base_path}} \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c 'just build {{screen}} MPY_CROSS=/usr/bin/mpy-cross' - -# Build the bootloader inside docker -build-bootloader screen="mono": - #!/usr/bin/env bash - set -exo pipefail - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/{{base_path}}/boards/Passport/bootloader \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c 'just build {{screen}}' - -# Build the docker image and get the tools from it -tools: build-docker cosign-tool add-secrets-tool word-list-gen-tool - -# Get cosign tool from built docker image -cosign-tool: - #!/usr/bin/env bash - set -exo pipefail - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c 'cp /usr/bin/cosign cosign' + docker build -t ${DOCKER_IMAGE} . -# Get add-secrets tool from built docker image -add-secrets-tool: - #!/usr/bin/env bash - set -exo pipefail - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c 'make -C ports/stm32/boards/Passport/tools/add-secrets' +# Build the firmware inside docker. +build-firmware screen="mono": mpy-cross (run-in-docker ("just ports/stm32/build " + screen)) -# Get word_list_gen tool from built docker image -word-list-gen-tool: - #!/usr/bin/env bash - set -exo pipefail - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/ports/stm32/boards/Passport/tools/word_list_gen \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c 'gcc word_list_gen.c bip39_words.c bytewords_words.c -o word_list_gen' +# build the bootloader inside docker +build-bootloader screen="mono": (run-in-docker ("just ports/stm32/boards/Passport/bootloader/build " + screen)) -# Verify the built firmware through SHA256 +# Run the built firmware through SHA256 verify-sha sha screen="mono": #!/usr/bin/env bash sha=$(shasum -a 256 ports/stm32/build-Passport/firmware-{{uppercase(screen)}}.bin | awk '{print $1}') @@ -96,54 +33,28 @@ verify-sha sha screen="mono": exit 1 fi -# Sign the built firmware using a private key and the cosign tool -sign keypath version screen="mono": (build-firmware screen) - #!/usr/bin/env bash - set -exo pipefail +tools: build-add-secrets build-cosign - SCREEN={{screen}} - SCREEN=`echo ${SCREEN^^}` - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/{{base_path}} \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "just cosign_filepath=build-Passport/firmware-$SCREEN.bin cosign_keypath={{keypath}} sign {{version}} {{screen}} MPY_CROSS=/usr/bin/mpy-cross" +# Build the add-secrets tool. +build-add-secrets: (run-in-docker "make -C ports/stm32/boards/Passport/tools/add-secrets") + +# Build the cosign tool. +build-cosign: (run-in-docker "make -C ports/stm32/boards/Passport/tools/cosign") + +# Sign the built firmware using a private key and the cosign tool +sign keypath version screen="mono": (build-firmware screen) (build-cosign) (run-in-docker ("just cosign_filepath=build-Passport/firmware-" + uppercase(screen) + ".bin cosign_keypath=" + keypath + " ports/stm32/sign " + version + " " + screen)) # Clean firmware build -clean: - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/{{base_path}} \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "make clean BOARD=Passport" +clean: (run-in-docker "just ports/stm32/clean") # Clean bootloader build -clean-bootloader: - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/{{base_path}}/boards/Passport/bootloader \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "just clean" +clean-bootloader: (run-in-docker "just ports/stm32/boards/Passport/bootloader/clean") # Clean simulator build -clean-simulator: - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/simulator \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "just clean" +clean-simulator: (run-in-docker "just simulator/clean") -build-simulator screen="mono": - docker run --rm -v "$PWD":/workspace \ - -u $(id -u):$(id -g) \ - -w /workspace/simulator \ - --entrypoint bash \ - ${DOCKER_REGISTRY_BASE}{{docker_image}} \ - -c "just build {{screen}} MPY_CROSS=/usr/bin/mpy-cross" +# Build simulator +build-simulator screen="mono": (run-in-docker ("just simulator/build " + screen)) # Run the simulator. sim screen="mono" ext="": @@ -151,10 +62,22 @@ sim screen="mono" ext="": # Run unit tests. test: - just simulator/build color - cd ports/stm32/boards/Passport/modules/tests; \ - python3 -m pytest . --simulatordir=$(pwd)/simulator + just simulator/build color + cd ports/stm32/boards/Passport/modules/tests; python3 -m pytest . --simulatordir=$(pwd)/simulator # Lint the codebase. -lint: - just ports/stm32/lint \ No newline at end of file +lint: (run-in-docker "just ports/stm32/lint") + +[private] +mpy-cross: (run-in-docker "make -C mpy-cross PROG=mpy-cross-docker BUILD=build-docker") + +[private] +run-in-docker command: + docker run --rm -v "$PWD":/workspace \ + -u $(id -u):$(id -g) \ + -v $(pwd):/workspace \ + -w /workspace \ + -e MPY_CROSS="/workspace/mpy-cross/mpy-cross-docker" \ + --entrypoint bash \ + ${DOCKER_IMAGE} \ + -c 'export PATH=$PATH:/workspace/ports/stm32/boards/Passport/tools/cosign/x86/release;{{command}}' From f69af2ba83039ba47ba1dd0b51497dbf820516d8 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Fri, 17 Feb 2023 13:27:47 -0600 Subject: [PATCH 077/156] SFT-1214: removed clear_psbt calls --- .../Passport/modules/flows/sign_psbt_microsd_flow.py | 9 --------- .../boards/Passport/modules/flows/sign_psbt_qr_flow.py | 4 ---- 2 files changed, 13 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py index 94b62248c..0d69bb1ac 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_microsd_flow.py @@ -54,7 +54,6 @@ async def copy_file_to_flash(self): from pages import ErrorPage from public_constants import TXN_INPUT_OFFSET from tasks import copy_psbt_file_to_external_flash_task - from utils import clear_psbt_flash from errors import Error # TODO: I think this is always a bytes object -- can probably remove this check @@ -72,7 +71,6 @@ async def copy_file_to_flash(self): copy_psbt_file_to_external_flash_task, args=[None, self.file_path, TXN_INPUT_OFFSET]) if error is not None: - await clear_psbt_flash(self.psbt_len) if error == Error.PSBT_TOO_LARGE: await ErrorPage(text='PSBT too large').show() else: @@ -87,25 +85,21 @@ async def copy_file_to_flash(self): async def common_flow(self): from flows import SignPsbtCommonFlow - from utils import clear_psbt_flash # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() if result is None: - await clear_psbt_flash(self.psbt_len) self.set_result(False) else: self.psbt = result self.goto(self.write_signed_transaction) async def show_card_missing(self): - from utils import clear_psbt_flash result = await InsertMicroSDPage().show() if not result: result = QuestionPage(text='Cancel signing this transaction?').show() if result: - await clear_psbt_flash(self.psbt_len) self.set_result(None) self.goto(self.write_signed_transaction) @@ -114,7 +108,6 @@ async def write_signed_transaction(self): from files import CardSlot, CardMissingError, securely_blank_file from utils import HexWriter from pages import ErrorPage - from utils import clear_psbt_flash orig_path, basename = self.file_path.rsplit('/', 1) orig_path += '/' @@ -163,7 +156,6 @@ async def write_signed_transaction(self): self.txid = self.psbt.finalize(fd) securely_blank_file(self.file_path) - await clear_psbt_flash(self.psbt_len) # Success and done! self.goto(self.show_success) @@ -171,7 +163,6 @@ async def write_signed_transaction(self): except OSError as exc: # If this ever changes to not fall through, clear the flash - # await clear_psbt_flash(self.psbt_len) result = await ErrorPage(text='Unable to write!\n\n%s\n\n' % exc).show() # sys.print_exception(exc) # fall thru to try again diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index db42bc4d2..e5740e1b8 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -41,7 +41,6 @@ async def copy_to_flash(self): from tasks import copy_psbt_to_external_flash_task from pages import ErrorPage from public_constants import TXN_INPUT_OFFSET - from utils import clear_psbt_flash from errors import Error gc.collect() # Try to avoid excessive fragmentation @@ -50,7 +49,6 @@ async def copy_to_flash(self): (self.psbt_len, self.output_encoder, error) = await spinner_task( 'Parsing transaction', copy_psbt_to_external_flash_task, args=[None, self.raw_psbt, TXN_INPUT_OFFSET]) if error is not None: - await clear_psbt_flash(self.psbt_len) if error == Error.PSBT_TOO_LARGE: await ErrorPage(text='PSBT too large').show() else: @@ -65,11 +63,9 @@ async def copy_to_flash(self): async def common_flow(self): from flows import SignPsbtCommonFlow - from utils import clear_psbt_flash # This flow validates and signs if all goes well, and returns the signed psbt result = await SignPsbtCommonFlow(self.psbt_len).run() - await clear_psbt_flash(self.psbt_len) if result is None: self.set_result(False) From dbd81311bb595be0db580e4e06b4b16373c6c125 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sat, 11 Feb 2023 20:30:08 +0100 Subject: [PATCH 078/156] SFT-1063: Remove is_binary parameter Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py | 2 +- ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py | 2 +- ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py b/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py index 4af29bd87..8610171c7 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/data_encoder.py @@ -13,7 +13,7 @@ class DataEncoder: def __init__(self): pass - def encode(self, data, is_binary=False, max_fragment_len=None): + def encode(self, data, max_fragment_len=None): pass def next_part(self): diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index c3a28f137..d3e5e3998 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -36,7 +36,7 @@ class QREncoder(DataEncoder): def __init__(self, _args): self.data = None - def encode(self, data, is_binary=False, max_fragment_len=None): + def encode(self, data, max_fragment_len=None): self.data = data def next_part(self): diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index 64f881c81..0539a8479 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -63,7 +63,7 @@ def __init__(self, args): self.prefix = 'bytes' # Encode the given data - def encode(self, data, is_binary=False, max_fragment_len=200): + def encode(self, data, max_fragment_len=200): # print('UR2Encoder: data="{}"'.format(data)) if not hasattr(data, 'cbor'): encoder = CBOREncoder() From 1a4db64c40b27f3c7cd81c134bbebdb14331f665 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sat, 11 Feb 2023 20:39:33 +0100 Subject: [PATCH 079/156] SFT-1063: Remove unused field Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index 0539a8479..d33fba361 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -56,7 +56,6 @@ def qr_type(self): class UR2Encoder(DataEncoder): def __init__(self, args): self.ur_encoder = None - self.type = None if isinstance(args, dict): self.prefix = args['prefix'] or 'bytes' else: From f848056a5d1e89a5adb9afd6353485e3dd8b8d37 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 15 Feb 2023 19:01:56 +0100 Subject: [PATCH 080/156] SFT-1062: Add clean-firmware recipe Signed-off-by: Jean-Pierre De Jesus DIAZ --- Justfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Justfile b/Justfile index 4b17e981b..0d5736ab9 100644 --- a/Justfile +++ b/Justfile @@ -47,6 +47,9 @@ sign keypath version screen="mono": (build-firmware screen) (build-cosign) (run- # Clean firmware build clean: (run-in-docker "just ports/stm32/clean") +# Clean bootloader build +clean-firmware: (run-in-docker "just ports/stm32/clean") + # Clean bootloader build clean-bootloader: (run-in-docker "just ports/stm32/boards/Passport/bootloader/clean") From 13b43305d2d493667a9296ee9704f71f6bc9a627 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 15 Feb 2023 19:08:30 +0100 Subject: [PATCH 081/156] SFT-1062: Fix Docker Rust permissions Signed-off-by: Jean-Pierre De Jesus DIAZ --- Dockerfile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index edb1655cf..6985a40a5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,12 +30,19 @@ RUN apt-get update && \ RUN pip3 install reuse # Install rustup. +ENV RUSTUP_HOME="/rustup" +ENV CARGO_HOME="/cargo" RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y -ENV PATH="/root/.cargo/bin:${PATH}" +ENV PATH="/cargo/bin:${PATH}" # Install Rust toolchain. RUN rustup default 1.67.1 # Install just. RUN cargo install just@^1.13 && \ - mv /root/.cargo/bin/just /usr/local/bin/just + mv /cargo/bin/just /usr/local/bin/just && \ + chmod 755 /usr/local/bin/just + +# Allow all users to use CARGO_HOME and RUSTUP_HOME. +RUN chmod -R 777 /cargo && \ + chmod -R 777 /rustup From e3327b2d14bbb6ac7a65a27087bad5a2fa90514a Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 15 Feb 2023 19:10:10 +0100 Subject: [PATCH 082/156] SFT-1062: Use minimal toolchain Signed-off-by: Jean-Pierre De Jesus DIAZ --- Dockerfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6985a40a5..dc7afe4bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,11 +32,14 @@ RUN pip3 install reuse # Install rustup. ENV RUSTUP_HOME="/rustup" ENV CARGO_HOME="/cargo" -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +RUN mkdir -p /rustup /cargo && \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ + sh -s -- -y --profile minimal --default-toolchain 1.67.1 ENV PATH="/cargo/bin:${PATH}" -# Install Rust toolchain. -RUN rustup default 1.67.1 +# Finish installation of Rust toolchain. +RUN rustup component add clippy && \ + rustup component add rustfmt # Install just. RUN cargo install just@^1.13 && \ From d3d3eabef103fe717fc5e7aa811f0611e243fd90 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 15 Feb 2023 18:18:53 +0100 Subject: [PATCH 083/156] SFT-1062: Update Dockerfile for Rust Signed-off-by: Jean-Pierre De Jesus DIAZ --- Dockerfile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index dc7afe4bf..c289a41a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,11 +39,17 @@ ENV PATH="/cargo/bin:${PATH}" # Finish installation of Rust toolchain. RUN rustup component add clippy && \ - rustup component add rustfmt - -# Install just. -RUN cargo install just@^1.13 && \ + rustup component add rustfmt && \ + rustup target add aarch64-unknown-none && \ + rustup target add thumbv7em-none-eabihf && \ + rustup target add x86_64-unknown-none + +# Install binaries using cargo. +RUN cargo install cbindgen@^0.24 && \ + cargo install just@^1.13 && \ + mv /cargo/bin/cbindgen /usr/local/bin/cbindgen && \ mv /cargo/bin/just /usr/local/bin/just && \ + chmod 755 /usr/local/bin/cbindgen && \ chmod 755 /usr/local/bin/just # Allow all users to use CARGO_HOME and RUSTUP_HOME. From 03f16216a7574055c2898c773b39d10c981d4b10 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 13 Feb 2023 14:24:30 +0100 Subject: [PATCH 084/156] SFT-1063: Switch UR decoder. --- .gitignore | 1 + Justfile | 2 +- extmod/foundation-rust/.cargo/config.toml | 8 + extmod/foundation-rust/.rustfmt.toml | 4 + extmod/foundation-rust/Cargo.lock | 309 +++++++++ extmod/foundation-rust/Cargo.lock.license | 2 + extmod/foundation-rust/Cargo.toml | 41 ++ extmod/foundation-rust/Justfile | 29 + extmod/foundation-rust/cbindgen.toml | 26 + extmod/foundation-rust/include/foundation.h | 473 ++++++++++++++ extmod/foundation-rust/src/bin/sizes.rs | 55 ++ extmod/foundation-rust/src/lib.rs | 22 + extmod/foundation-rust/src/stdout.rs | 22 + extmod/foundation-rust/src/ur/decoder.rs | 185 ++++++ extmod/foundation-rust/src/ur/encoder.rs | 151 +++++ extmod/foundation-rust/src/ur/mod.rs | 102 +++ extmod/foundation-rust/src/ur/registry.rs | 545 ++++++++++++++++ extmod/foundation/modfoundation-ur.h | 613 ++++++++++++++++++ extmod/foundation/modfoundation.c | 2 + ports/stm32/Makefile | 6 +- ports/stm32/boards/Passport/manifest.py | 16 - .../Passport/modules/data_codecs/qr_codec.py | 2 +- .../modules/data_codecs/qr_factory.py | 4 +- .../Passport/modules/data_codecs/ur2_codec.py | 109 +--- .../flows/casa_health_check_qr_flow.py | 3 +- .../modules/flows/connect_wallet_flow.py | 6 +- .../import_multisig_wallet_from_qr_flow.py | 2 +- .../boards/Passport/modules/flows/scv_flow.py | 52 +- .../modules/flows/sign_psbt_qr_flow.py | 45 +- .../Passport/modules/pages/scan_qr_page.py | 7 +- .../Passport/modules/pages/show_qr_page.py | 4 +- .../tasks/create_wallet_export_task.py | 7 +- .../boards/Passport/modules/ur2/__init__.py | 3 - .../boards/Passport/modules/ur2/bytewords.py | 149 ----- .../boards/Passport/modules/ur2/cbor_lite.py | 356 ---------- .../boards/Passport/modules/ur2/constants.py | 10 - .../Passport/modules/ur2/fountain_decoder.py | 267 -------- .../Passport/modules/ur2/fountain_encoder.py | 152 ----- .../Passport/modules/ur2/fountain_utils.py | 61 -- .../Passport/modules/ur2/random_sampler.py | 65 -- ports/stm32/boards/Passport/modules/ur2/ur.py | 228 ------- .../boards/Passport/modules/ur2/ur_decoder.py | 133 ---- .../boards/Passport/modules/ur2/ur_encoder.py | 56 -- .../boards/Passport/modules/ur2/utils.py | 88 --- .../boards/Passport/modules/ur2/xoshiro256.py | 166 ----- .../boards/Passport/modules/views/qrcode.py | 2 +- .../boards/Passport/modules/wallets/casa.py | 86 +-- .../boards/Passport/modules/wallets/envoy.py | 11 +- .../modules/wallets/generic_json_wallet.py | 9 +- .../modules/wallets/multisig_import.py | 2 +- ports/stm32/boards/Passport/mpconfigboard.mk | 2 + ports/stm32/boards/Passport/passport.ld | 6 +- py/mkrules.mk | 2 +- py/py.mk | 30 + 54 files changed, 2782 insertions(+), 1957 deletions(-) create mode 100644 extmod/foundation-rust/.cargo/config.toml create mode 100644 extmod/foundation-rust/.rustfmt.toml create mode 100644 extmod/foundation-rust/Cargo.lock create mode 100644 extmod/foundation-rust/Cargo.lock.license create mode 100644 extmod/foundation-rust/Cargo.toml create mode 100644 extmod/foundation-rust/Justfile create mode 100644 extmod/foundation-rust/cbindgen.toml create mode 100644 extmod/foundation-rust/include/foundation.h create mode 100644 extmod/foundation-rust/src/bin/sizes.rs create mode 100644 extmod/foundation-rust/src/lib.rs create mode 100644 extmod/foundation-rust/src/stdout.rs create mode 100644 extmod/foundation-rust/src/ur/decoder.rs create mode 100644 extmod/foundation-rust/src/ur/encoder.rs create mode 100644 extmod/foundation-rust/src/ur/mod.rs create mode 100644 extmod/foundation-rust/src/ur/registry.rs create mode 100644 extmod/foundation/modfoundation-ur.h delete mode 100644 ports/stm32/boards/Passport/modules/ur2/__init__.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/bytewords.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/cbor_lite.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/constants.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/fountain_utils.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/random_sampler.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/ur.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/ur_decoder.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/ur_encoder.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/utils.py delete mode 100644 ports/stm32/boards/Passport/modules/ur2/xoshiro256.py diff --git a/.gitignore b/.gitignore index 7201d375c..2def6475d 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,7 @@ genrst/ # Passport ###################### +extmod/foundation-rust/target mpy-cross/mpy-cross-docker ports/stm32/boards/Passport/tools/cosign/x86 ports/stm32/boards/Passport/tools/add-secrets/x86 diff --git a/Justfile b/Justfile index 0d5736ab9..791b57354 100644 --- a/Justfile +++ b/Justfile @@ -69,7 +69,7 @@ test: cd ports/stm32/boards/Passport/modules/tests; python3 -m pytest . --simulatordir=$(pwd)/simulator # Lint the codebase. -lint: (run-in-docker "just ports/stm32/lint") +lint: (run-in-docker "just ports/stm32/lint") (run-in-docker "just extmod/foundation-rust/lint") [private] mpy-cross: (run-in-docker "make -C mpy-cross PROG=mpy-cross-docker BUILD=build-docker") diff --git a/extmod/foundation-rust/.cargo/config.toml b/extmod/foundation-rust/.cargo/config.toml new file mode 100644 index 000000000..720ee44d2 --- /dev/null +++ b/extmod/foundation-rust/.cargo/config.toml @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later + +[target.thumbv7em-none-eabihf] +rustflags = [ + "--cfg", "dtcm", + "--cfg", "sram4", +] diff --git a/extmod/foundation-rust/.rustfmt.toml b/extmod/foundation-rust/.rustfmt.toml new file mode 100644 index 000000000..6d7e7f523 --- /dev/null +++ b/extmod/foundation-rust/.rustfmt.toml @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later + +max_width = 80 diff --git a/extmod/foundation-rust/Cargo.lock b/extmod/foundation-rust/Cargo.lock new file mode 100644 index 000000000..60df720ec --- /dev/null +++ b/extmod/foundation-rust/Cargo.lock @@ -0,0 +1,309 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atomic-polyfill" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d299f547288d6db8d5c3a2916f7b2f66134b15b8c1ac1c4357dd3b8752af7bb2" +dependencies = [ + "critical-section", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + +[[package]] +name = "critical-section" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "foundation" +version = "0.1.0" +dependencies = [ + "heapless", + "minicbor", + "ur-foundation", + "uuid", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "git+https://github.com/japaric/heapless#644653bf3b831c6bb4963be2de24804acf5e5001" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "minicbor" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d319d47468f164e5138b1c629bdd82ea3da0784ed1d41a22f8e0bcef76c2ae52" +dependencies = [ + "minicbor-derive", +] + +[[package]] +name = "minicbor-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1154809406efdb7982841adb6311b3d095b46f78342dd646736122fe6b19e267" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +dependencies = [ + "siphasher", +] + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "spin" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "ur" +version = "0.3.0" +source = "git+https://github.com/Foundation-Devices/ur-rs?branch=dev#2e6563f804572251535b18bdab0dd0b9ba77f062" +dependencies = [ + "bitcoin_hashes", + "crc", + "heapless", + "itertools", + "minicbor", + "phf", + "rand_xoshiro", + "uuid", +] + +[[package]] +name = "ur-foundation" +version = "0.1.0" +source = "git+https://github.com/Foundation-Devices/rust-ur-foundation?branch=dev-v0.1.0#0ae542143ba9232d734f58a0bee1b22d9a0517a2" +dependencies = [ + "heapless", + "hex", + "minicbor", + "ur", + "uuid", +] + +[[package]] +name = "uuid" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" diff --git a/extmod/foundation-rust/Cargo.lock.license b/extmod/foundation-rust/Cargo.lock.license new file mode 100644 index 000000000..3da97ffd2 --- /dev/null +++ b/extmod/foundation-rust/Cargo.lock.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +SPDX-License-Identifier: GPL-3.0-or-later diff --git a/extmod/foundation-rust/Cargo.toml b/extmod/foundation-rust/Cargo.toml new file mode 100644 index 000000000..54b47ec49 --- /dev/null +++ b/extmod/foundation-rust/Cargo.toml @@ -0,0 +1,41 @@ +# SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later + +[package] +name = "foundation" +version = "0.1.0" +edition = "2021" +license = "GPL-3.0-or-later" + +[[bin]] +name = "sizes" +required-features = ["std"] + +[dependencies.minicbor] +version = "0.19" +default-features = false + +[dependencies.heapless] +version = "0.8" +git = "https://github.com/japaric/heapless" +default-features = false + +[dependencies.uuid] +version = "1" +default-features = false + +[dependencies.ur-foundation] +git = "https://github.com/Foundation-Devices/rust-ur-foundation" +branch = "dev-v0.1.0" +default-features = false + +[features] +default = [] +std = [] + +[lib] +crate-type = ["lib", "staticlib"] + +[profile.release] +lto = true +opt-level = 3 diff --git a/extmod/foundation-rust/Justfile b/extmod/foundation-rust/Justfile new file mode 100644 index 000000000..a4e342d67 --- /dev/null +++ b/extmod/foundation-rust/Justfile @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later + +alias g := generate +alias b := build +alias l := lint + +# Generate C bindings header. +generate: build + cbindgen --config cbindgen.toml \ + --crate foundation \ + --output include/foundation.h + +# Build the crate. +build: + cargo build --target thumbv7em-none-eabihf --release + +# Lint the crate. +lint: + cargo clippy --target thumbv7em-none-eabihf + cargo fmt --check + cbindgen --config cbindgen.toml \ + --crate foundation \ + --output include/foundation.h \ + --verify + +# Print size information +sizes: + cargo run --features std diff --git a/extmod/foundation-rust/cbindgen.toml b/extmod/foundation-rust/cbindgen.toml new file mode 100644 index 000000000..283c52ff4 --- /dev/null +++ b/extmod/foundation-rust/cbindgen.toml @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +# SPDX-License-Identifier: GPL-3.0-or-later + +language = "C" +header = """ +/* + * SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */""" +pragma_once = false +include_guard = "FOUNDATION_H" +autogen_warning = """ +/* + * Warning: This file is auto-generated by cbindgen, do not edit. + * + * Read the Justfile in order to re-generate this file. + */""" +include_version = false +usize_is_size_t = true +cpp_compat = true +line_length = 80 +documentation_style = "doxy" +style = "type" + +[export] +exclude = ["putchar"] diff --git a/extmod/foundation-rust/include/foundation.h b/extmod/foundation-rust/include/foundation.h new file mode 100644 index 000000000..d7a2da3a0 --- /dev/null +++ b/extmod/foundation-rust/include/foundation.h @@ -0,0 +1,473 @@ +/* + * SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef FOUNDATION_H +#define FOUNDATION_H + +/* + * Warning: This file is auto-generated by cbindgen, do not edit. + * + * Read the Justfile in order to re-generate this file. + */ + +#include +#include +#include +#include +#include + +/** + * Maximum size of an encoded Uniform Resource. + * + * This value assumes a QR code of version of 16 with ECC L using + * alphanumeric characters. + */ +#define UR_DECODER_MAX_STRING 1408 + +/** + * Maximum sequence count for the decoder. + * + * Must be a power of two. + */ +#define UR_DECODER_MAX_SEQUENCE_COUNT 32 + +/** + * Maximum message length that can be decoded. + */ +#define UR_DECODER_MAX_MESSAGE_LEN (UR_DECODER_MAX_FRAGMENT_LEN * UR_DECODER_MAX_SEQUENCE_COUNT) + +/** + * Maximum number of mixed parts that can be held. + */ +#define UR_DECODER_MAX_MIXED_PARTS (UR_DECODER_MAX_SEQUENCE_COUNT / 4) + +/** + * Size of the decoder queue. + */ +#define UR_DECODER_QUEUE_SIZE 8 + +/** + * Maximum size of an encoded Uniform Resource. + * + * This value assumes a QR code of version of 12 with ECC L using + * alphanumeric characters. + */ +#define UR_ENCODER_MAX_STRING 535 + +/** + * `mainnet` network. + */ +#define UR_NETWORK_MAINNET 0 + +/** + * `testnet` network. + */ +#define UR_NETWORK_TESTNET 1 + +/** + * Maximum number of components that a `crypto-keypath` can have. + */ +#define UR_MAX_PATH_COMPONENTS 4 + +typedef enum { + BTC, +} UR_CoinType; + +typedef enum { + UR_ERROR_KIND_OTHER, + UR_ERROR_KIND_UNSUPPORTED, +} UR_ErrorKind; + +/** + * Passport model. + */ +typedef enum { + /** + * Founders Edition. + */ + PASSPORT_MODEL_FOUNDERS_EDITION, + /** + * Batch 2. + */ + PASSPORT_MODEL_BATCH2, +} UR_PassportModel; + +/** + * Uniform Resource decoder. + */ +typedef struct UR_Decoder UR_Decoder; + +/** + * Uniform Resource encoder. + */ +typedef struct UR_Encoder UR_Encoder; + +typedef struct { + UR_ErrorKind kind; + const char *message; + size_t len; +} UR_Error; + +typedef struct { + UR_CoinType coin_type; + uint64_t network; +} UR_CryptoCoinInfo; + +/** + * Metadata for the complete or partial derivation path of a key. + */ +typedef struct { + /** + * The fingerprint of this key's direct ancestor. + * + * A value of `0` means that the fingerprint is not present. + */ + uint32_t source_fingerprint; + /** + * How many derivations this key is from the master (which is 0). + * + * 0 if this is a public key derived directly from a master key. + */ + uint8_t depth; + /** + * Whether `depth` is present. + */ + bool has_depth; +} UR_CryptoKeypath; + +/** + * Derived `crypto-hdkey`. + */ +typedef struct { + /** + * `true` if this is a private key. + */ + bool is_private; + /** + * The key material. + */ + uint8_t key_data[33]; + /** + * Chain code. + */ + uint8_t chain_code[32]; + /** + * Whether `chain_code` is present. + */ + bool has_chain_code; + /** + * How the key should be used. + */ + UR_CryptoCoinInfo use_info; + /** + * Whether `use_info` is present. + */ + bool has_use_info; + /** + * How the key was derived. + */ + UR_CryptoKeypath origin; + /** + * Whether `origin` is present. + */ + bool has_origin; + /** + * The fingerprint of this key's direct ancestor. + * + * A value of `0` means that the fingerprint is not present. + */ + uint32_t parent_fingerprint; +} UR_DerivedKey; + +/** + * A `crypto-hdkey`. + */ +typedef enum { + DerivedKey, +} UR_HDKey_Tag; + +typedef struct { + UR_HDKey_Tag tag; + union { + struct { + UR_DerivedKey derived_key; + }; + }; +} UR_HDKey; + +/** + * Supply chain validation challenge. + */ +typedef struct { + /** + * The ID challenge. + */ + uint8_t id[32]; + /** + * The signature. + */ + uint8_t signature[64]; +} UR_Challenge; + +/** + * Passport custom `crypto-request`. + */ +typedef struct { + /** + * Transaction ID. + */ + uint8_t transaction_id[16]; + /** + * Supply chain validation challenge. + */ + UR_Challenge scv_challenge; + /** + * Whether SCV challenge is available. + */ + bool has_scv_challenge; + /** + * Request Passport model. + */ + bool passport_model; + /** + * Request Passport firmware version. + */ + bool passport_firmware_version; +} UR_PassportRequest; + +/** + * Supply Chain Validation solution. + */ +typedef struct { + const char *word1; + size_t word1_len; + const char *word2; + size_t word2_len; + const char *word3; + size_t word3_len; + const char *word4; + size_t word4_len; +} UR_Solution; + +/** + * Passport custom `crypto-request`. + */ +typedef struct { + /** + * Transaction ID. + */ + uint8_t transaction_id[16]; + /** + * Supply chain validation challenge. + */ + UR_Solution scv_solution; + /** + * Whether `scv_solution` is present. + */ + bool has_scv_solution; + /** + * Passport model. + */ + UR_PassportModel passport_model; + /** + * Whether `passport_model` present. + */ + bool has_passport_model; + /** + * Passport firmware version. + */ + const char *passport_firmware_version; + /** + * Passport firmware version length. + */ + size_t passport_firmware_version_len; + /** + * Whether `passport_model` present. + */ + bool has_passport_firmware_version; +} UR_PassportResponse; + +/** + * An uniform resource. + */ +typedef enum { + /** + * `bytes`. + */ + Bytes, + /** + * `crypto-hdkey`. + */ + CryptoHDKey, + /** + * `crypto-psbt`. + */ + CryptoPSBT, + /** + * Passport custom `crypto-request`. + */ + PassportRequest, + /** + * Passport custom `crypto-response`. + */ + PassportResponse, +} UR_Value_Tag; + +typedef struct { + const uint8_t *data; + size_t len; +} Bytes_Body; + +typedef struct { + const uint8_t *data; + size_t len; +} CryptoPSBT_Body; + +typedef struct { + UR_Value_Tag tag; + union { + Bytes_Body bytes; + struct { + UR_HDKey crypto_hd_key; + }; + CryptoPSBT_Body crypto_psbt; + struct { + UR_PassportRequest passport_request; + }; + struct { + UR_PassportResponse passport_response; + }; + }; +} UR_Value; + + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern UR_Decoder UR_DECODER; + +extern UR_Encoder UR_ENCODER; + +/** + * Receive an Uniform Resource part. + * + * # Safety + * + * - `ur` must point to valid memory and must have a length of `ur_len` bytes. + */ +bool ur_decoder_receive(UR_Decoder *decoder, + const uint8_t *ur, + size_t ur_len, + UR_Error *error); + +/** + * Returns `true` if the decoder is complete and no more data is needed. + */ +bool ur_decoder_is_complete(UR_Decoder *decoder); + +/** + * Returns the calculated estimated percentage of completion. + */ +uint32_t ur_decoder_estimated_percent_complete(UR_Decoder *decoder); + +/** + * Clear the decoder in order so a new message can be received. + */ +void ur_decoder_clear(UR_Decoder *decoder); + +/** + * Decode the message as an UR value. + */ +bool ur_decoder_decode_message(UR_Decoder *decoder, + UR_Value *value, + UR_Error *error); + +/** + * Returns `true` if the string is an uniform resource, `false` otherwise. + * + * # Safety + * + * - `ur` must point to valid memory and must have a length of `ur_len` bytes. + */ +bool ur_validate(const uint8_t *ur, size_t ur_len); + +/** + * Start the encoder. + * + * # Parameters + * + * - `value` is the uniform resource to encode. + * - `max_fragment_len` is the maximum fragment length in bytes. + * + * # Safety + * + * If the `UR_Value` is of type `Bytes` then the pointer must be a valid value + * and its length too. + * + * This function assumes that is called on the same thread and its not used + * concurrently. + */ +void ur_encoder_start(UR_Encoder *encoder, + const UR_Value *value, + size_t max_chars); + +/** + * Returns the UR corresponding to the next fountain encoded part. + * + * # Safety + * + * This function must not be called if `ur_encoder_start` was not called to + * start the encoder. Or if the data used to start the encoder is freed. + * + * # Return Value + * + * The return value is a NULL terminated string encoded using an uppercase + * alphabet and using only the characters allowed in QR code alphanumeric + * mode. + * + * The pointer is valid until `ur_encoder_next_part` or `ur_encoder_start` + * are called. + */ +void ur_encoder_next_part(UR_Encoder *encoder, const char **ur, size_t *ur_len); + +/** + * Passport custom `crypto-response`. + * Create a new `bytes` UR. + */ +void ur_registry_new_bytes(UR_Value *value, uint8_t *data, size_t len); + +/** + * Create a new derived `crypto-hdkey` UR. + */ +void ur_registry_new_derived_key(UR_Value *value, + bool is_private, + const uint8_t (*key_data)[33], + const uint8_t (*chain_code)[32], + const UR_CryptoCoinInfo *use_info, + const UR_CryptoKeypath *origin, + uint32_t parent_fingerprint); + +/** + * Create a new `crypto-psbt` UR. + */ +void ur_registry_new_crypto_psbt(UR_Value *value, uint8_t *data, size_t len); + +/** + * Create a new Passport ustom `crypto-response` UR. + */ +void ur_registry_new_passport_response(UR_Value *value, + const uint8_t (*transaction_id)[16], + const UR_Solution *solution, + UR_PassportModel passport_model, + const char *passport_firmware_version, + size_t passport_firmware_version_len); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif /* FOUNDATION_H */ diff --git a/extmod/foundation-rust/src/bin/sizes.rs b/extmod/foundation-rust/src/bin/sizes.rs new file mode 100644 index 000000000..03ee12cf7 --- /dev/null +++ b/extmod/foundation-rust/src/bin/sizes.rs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + +use foundation::ur::{ + decoder::{ + UR_Decoder, UR_DECODER_MAX_FRAGMENT_LEN, UR_DECODER_MAX_MESSAGE_LEN, + UR_DECODER_MAX_MIXED_PARTS, UR_DECODER_MAX_SEQUENCE_COUNT, + UR_DECODER_MAX_STRING, UR_DECODER_QUEUE_SIZE, + }, + encoder::{ + UR_Encoder, UR_ENCODER_MAX_FRAGMENT_LEN, UR_ENCODER_MAX_MESSAGE_LEN, + UR_ENCODER_MAX_SEQUENCE_COUNT, UR_ENCODER_MAX_STRING, + }, +}; +use std::mem::size_of; + +fn main() { + println!("{: <22} | {: <8} | {: <8}", "", "Decoder", "Encoder"); + println!( + "{: <22} | {: <8} | {: <8}", + "Max. Sequence Count", + UR_DECODER_MAX_SEQUENCE_COUNT, + UR_ENCODER_MAX_SEQUENCE_COUNT + ); + println!( + "{: <22} | {: <8} | {: <8}", + "Max. UR String Length", UR_DECODER_MAX_STRING, UR_ENCODER_MAX_STRING + ); + println!( + "{: <22} | {: <8} | {: <8}", + "Max. Fragment Length", + UR_DECODER_MAX_FRAGMENT_LEN, + UR_ENCODER_MAX_FRAGMENT_LEN + ); + println!( + "{: <22} | {: <8} | {: <8}", + "Max. Message Length", + UR_DECODER_MAX_MESSAGE_LEN, + UR_ENCODER_MAX_MESSAGE_LEN + ); + println!( + "{: <22} | {: <8} | {: <8}", + "Max. Mixed Parts", UR_DECODER_MAX_MIXED_PARTS, "Not Applicable" + ); + println!( + "{: <22} | {: <8} | {: <8}", + "Queue Size", UR_DECODER_QUEUE_SIZE, "Not Applicable" + ); + println!( + "{: <22} | {: <8} | {: <8}", + "Structure Size", + size_of::(), + size_of::() + ); +} diff --git a/extmod/foundation-rust/src/lib.rs b/extmod/foundation-rust/src/lib.rs new file mode 100644 index 000000000..837851b78 --- /dev/null +++ b/extmod/foundation-rust/src/lib.rs @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(non_camel_case_types)] + +pub mod ur; + +/// cbindgen:ignore +#[cfg(not(feature = "std"))] +mod stdout; + +#[panic_handler] +#[cfg(all(not(feature = "std"), not(test)))] +fn panic_handler(info: &core::panic::PanicInfo) -> ! { + use core::fmt::Write; + + let mut stdout = stdout::Stdout; + writeln!(stdout, "{}", info).ok(); + + loop {} +} diff --git a/extmod/foundation-rust/src/stdout.rs b/extmod/foundation-rust/src/stdout.rs new file mode 100644 index 000000000..24c57dca6 --- /dev/null +++ b/extmod/foundation-rust/src/stdout.rs @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + +use core::{ffi::c_int, fmt}; + +pub struct Stdout; + +impl fmt::Write for Stdout { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for &c in s.as_bytes() { + unsafe { + putchar(c as c_int); + } + } + + Ok(()) + } +} + +extern "C" { + fn putchar(c: c_int) -> c_int; +} diff --git a/extmod/foundation-rust/src/ur/decoder.rs b/extmod/foundation-rust/src/ur/decoder.rs new file mode 100644 index 000000000..1d2367385 --- /dev/null +++ b/extmod/foundation-rust/src/ur/decoder.rs @@ -0,0 +1,185 @@ +// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + +//! Decoder. + +use core::{slice, str}; + +use ur::UR; +use ur_foundation::ur; + +use crate::ur::{max_fragment_len, registry::UR_Value, UR_Error}; + +/// Maximum size of an encoded Uniform Resource. +/// +/// This value assumes a QR code of version of 16 with ECC L using +/// alphanumeric characters. +pub const UR_DECODER_MAX_STRING: usize = 1408; + +/// Maximum sequence count for the decoder. +/// +/// Must be a power of two. +pub const UR_DECODER_MAX_SEQUENCE_COUNT: usize = 32; + +/// Maximum fragment length. +pub const UR_DECODER_MAX_FRAGMENT_LEN: usize = + max_fragment_len(UR_DECODER_MAX_STRING); + +/// Maximum message length that can be decoded. +pub const UR_DECODER_MAX_MESSAGE_LEN: usize = + UR_DECODER_MAX_FRAGMENT_LEN * UR_DECODER_MAX_SEQUENCE_COUNT; + +/// Maximum number of mixed parts that can be held. +pub const UR_DECODER_MAX_MIXED_PARTS: usize = UR_DECODER_MAX_SEQUENCE_COUNT / 4; + +/// Size of the decoder queue. +pub const UR_DECODER_QUEUE_SIZE: usize = 8; + +/// Maximum length of the UR type. +/// cbindgen:ignore +pub const UR_DECODER_MAX_UR_TYPE: usize = "crypto-coin-info".len(); + +/// Statically allocted decoder. +#[no_mangle] +#[used] +#[cfg_attr(dtcm, link_section = ".dtcm")] +pub static mut UR_DECODER: UR_Decoder = UR_Decoder { + inner: ur::HeaplessDecoder::new_heapless(), +}; + +/// Uniform Resource decoder. +pub struct UR_Decoder { + inner: ur::HeaplessDecoder< + UR_DECODER_MAX_MESSAGE_LEN, + UR_DECODER_MAX_MIXED_PARTS, + UR_DECODER_MAX_FRAGMENT_LEN, + UR_DECODER_MAX_SEQUENCE_COUNT, + UR_DECODER_QUEUE_SIZE, + UR_DECODER_MAX_UR_TYPE, + >, +} + +/// Receive an Uniform Resource part. +/// +/// # Safety +/// +/// - `ur` must point to valid memory and must have a length of `ur_len` bytes. +#[no_mangle] +pub unsafe extern "C" fn ur_decoder_receive( + decoder: &mut UR_Decoder, + ur: *const u8, + ur_len: usize, + error: &mut UR_Error, +) -> bool { + // SAFETY: ur and ur_len are assumed to be valid. + let ur = unsafe { slice::from_raw_parts(ur, ur_len) }; + + let result = str::from_utf8(ur) + .map_err(|e| unsafe { UR_Error::other(&e) }) + .and_then(|ur| { + UR::parse(ur).map_err(|e| unsafe { UR_Error::other(&e) }) + }) + .and_then(|ur| { + decoder + .inner + .receive(ur) + .map_err(|e| unsafe { UR_Error::other(&e) }) + }); + + match result { + Ok(_) => true, + Err(e) => { + *error = e; + false + } + } +} + +/// Returns `true` if the decoder is complete and no more data is needed. +#[no_mangle] +pub extern "C" fn ur_decoder_is_complete(decoder: &mut UR_Decoder) -> bool { + decoder.inner.is_complete() +} + +/// Returns the calculated estimated percentage of completion. +#[no_mangle] +pub extern "C" fn ur_decoder_estimated_percent_complete( + decoder: &mut UR_Decoder, +) -> u32 { + (decoder.inner.estimated_percent_complete() * 100.0) as u32 +} + +/// Clear the decoder in order so a new message can be received. +#[no_mangle] +pub extern "C" fn ur_decoder_clear(decoder: &mut UR_Decoder) { + decoder.inner.clear(); +} + +/// Decode the message as an UR value. +#[no_mangle] +pub extern "C" fn ur_decoder_decode_message( + decoder: &mut UR_Decoder, + value: &mut UR_Value, + error: &mut UR_Error, +) -> bool { + let message = decoder + .inner + .message() + .map_err(|e| unsafe { UR_Error::other(&e) }) + .map(|v| { + v.ok_or_else(|| unsafe { + UR_Error::other(&"Decoder still needs more data") + }) + }); + + let message = match message { + Ok(Ok(v)) => v, + Err(e) | Ok(Err(e)) => { + *error = e; + return false; + } + }; + + let result = unsafe { + UR_Value::from_ur( + decoder + .inner + .ur_type() + .expect("decoder should already contain the UR type"), + message, + ) + }; + *value = match result { + Ok(v) => v, + Err(e) => { + *error = e; + return false; + } + }; + + true +} + +/// Returns `true` if the string is an uniform resource, `false` otherwise. +/// +/// # Safety +/// +/// - `ur` must point to valid memory and must have a length of `ur_len` bytes. +#[no_mangle] +pub unsafe extern "C" fn ur_validate(ur: *const u8, ur_len: usize) -> bool { + // SAFETY: ur and ur_len are assumed to be valid. + let ur = unsafe { slice::from_raw_parts(ur, ur_len) }; + if let Ok(Ok(ur)) = str::from_utf8(ur).map(UR::parse) { + let bytewords = ur + .as_bytewords() + .expect("Parsed URs shouldn't be in a deserialized variant"); + + return ur::bytewords::validate( + bytewords, + ur::bytewords::Style::Minimal, + ) + .is_ok(); + } + + false +} diff --git a/extmod/foundation-rust/src/ur/encoder.rs b/extmod/foundation-rust/src/ur/encoder.rs new file mode 100644 index 000000000..f81da1734 --- /dev/null +++ b/extmod/foundation-rust/src/ur/encoder.rs @@ -0,0 +1,151 @@ +// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + +//! Encoder. + +use core::{ffi::c_char, fmt::Write}; + +use crate::ur::{ + decoder::UR_DECODER_MAX_MESSAGE_LEN, max_fragment_len, registry::UR_Value, +}; +use ur_foundation::ur; + +/// Maximum size of an encoded Uniform Resource. +/// +/// This value assumes a QR code of version of 12 with ECC L using +/// alphanumeric characters. +pub const UR_ENCODER_MAX_STRING: usize = 535; + +/// Maximum fragment length. +/// +/// This is the maximum fragment length in bytes, this is not for the +/// CBOR encoding or bytewords encoding but one of the equally sized +/// parts that the message is divided into. +/// cbindgen:ignore +pub const UR_ENCODER_MAX_FRAGMENT_LEN: usize = + max_fragment_len(UR_ENCODER_MAX_STRING); + +/// Maximum sequence count for the decoder. +/// +/// Must be a power of two. +/// cbindgen:ignore +pub const UR_ENCODER_MAX_SEQUENCE_COUNT: usize = usize::next_power_of_two( + UR_DECODER_MAX_MESSAGE_LEN / UR_ENCODER_MAX_FRAGMENT_LEN, +); + +/// Maximum message length that can be encoded. +/// cbindgen:ignore +pub const UR_ENCODER_MAX_MESSAGE_LEN: usize = + UR_ENCODER_MAX_FRAGMENT_LEN * UR_ENCODER_MAX_SEQUENCE_COUNT; + +/// Statically allocated encoder. +#[no_mangle] +#[used] +#[cfg_attr(encoder_sram4, link_section = ".sram4")] +pub static mut UR_ENCODER: UR_Encoder = UR_Encoder { + inner: ur::HeaplessEncoder::new_heapless(), +}; + +/// cbindgen:ignore +#[used] +#[cfg_attr(sram4, link_section = ".sram4")] +static mut UR_ENCODER_STRING: heapless::Vec = + heapless::Vec::new(); + +/// cbindgen:ignore +#[used] +#[cfg_attr(sram4, link_section = ".sram4")] +static mut UR_ENCODER_MESSAGE: heapless::Vec = + heapless::Vec::new(); + +/// Uniform Resource encoder. +pub struct UR_Encoder { + inner: ur::HeaplessEncoder< + 'static, + 'static, + UR_ENCODER_MAX_FRAGMENT_LEN, + UR_ENCODER_MAX_SEQUENCE_COUNT, + >, +} + +/// Start the encoder. +/// +/// # Parameters +/// +/// - `value` is the uniform resource to encode. +/// - `max_fragment_len` is the maximum fragment length in bytes. +/// +/// # Safety +/// +/// If the `UR_Value` is of type `Bytes` then the pointer must be a valid value +/// and its length too. +/// +/// This function assumes that is called on the same thread and its not used +/// concurrently. +#[no_mangle] +pub unsafe extern "C" fn ur_encoder_start( + encoder: &mut UR_Encoder, + value: &UR_Value, + max_chars: usize, +) { + // SAFETY: The UR_Value can contain some raw pointers which need to be + // accessed in order to convert it to a `ur::registry::BaseValue` which + // is then encoded below, so the pointers lifetime only need to be valid + // for the scope of this function. + let value = unsafe { value.to_value() }; + + // SAFETY: This code assumes that runs on a single thread. + let message = unsafe { &mut UR_ENCODER_MESSAGE }; + + message.clear(); + value.encode(Writer(message)).expect("Couldn't encode UR"); + + encoder + .inner + .start(value.ur_type(), message, max_fragment_len(max_chars)); +} + +/// Returns the UR corresponding to the next fountain encoded part. +/// +/// # Safety +/// +/// This function must not be called if `ur_encoder_start` was not called to +/// start the encoder. Or if the data used to start the encoder is freed. +/// +/// # Return Value +/// +/// The return value is a NULL terminated string encoded using an uppercase +/// alphabet and using only the characters allowed in QR code alphanumeric +/// mode. +/// +/// The pointer is valid until `ur_encoder_next_part` or `ur_encoder_start` +/// are called. +#[no_mangle] +pub unsafe extern "C" fn ur_encoder_next_part( + encoder: &mut UR_Encoder, + ur: *mut *const c_char, + ur_len: *mut usize, +) { + let part = encoder.inner.next_part(); + + let buf = unsafe { &mut UR_ENCODER_STRING }; + buf.clear(); + write!(buf, "{part}").unwrap(); + buf.push(b'\0').unwrap(); + + *ur = buf.as_ptr() as *const c_char; + *ur_len = buf.len() - 1; +} + +struct Writer<'a, const N: usize>(&'a mut heapless::Vec); + +impl<'a, const N: usize> minicbor::encode::Write for Writer<'a, N> { + type Error = EndOfSlice; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + self.0.extend_from_slice(buf).map_err(|_| EndOfSlice) + } +} + +#[derive(Debug)] +struct EndOfSlice; diff --git a/extmod/foundation-rust/src/ur/mod.rs b/extmod/foundation-rust/src/ur/mod.rs new file mode 100644 index 000000000..84ab27ac2 --- /dev/null +++ b/extmod/foundation-rust/src/ur/mod.rs @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + +//! Uniform Resources. + +use core::{ffi::c_char, fmt, fmt::Write}; +use ur::fountain::part::Part; +use ur_foundation::ur; + +/// cbindgen:ignore +#[used] +#[cfg_attr(sram4, link_section = ".sram4")] +static mut UR_ERROR: heapless::String<256> = heapless::String::new(); + +pub const fn max_fragment_len(max_characters: usize) -> usize { + const MAX_UR_PREFIX: usize = "ur:crypto-coin-info/".len() + + digit_count(u32::MAX as usize) + + "-".len() + + digit_count(u32::MAX as usize) + + "/".len(); + + let max_chars_for_part: usize = max_characters - MAX_UR_PREFIX; + + let max_bytes_for_part: usize = (max_chars_for_part / 2) - 4; + + max_bytes_for_part - Part::max_encoded_len() +} + +/// Count the number of digits in a number. +pub const fn digit_count(v: usize) -> usize { + (v.ilog10() + 1) as usize +} + +#[repr(C)] +pub enum UR_ErrorKind { + UR_ERROR_KIND_OTHER, + UR_ERROR_KIND_UNSUPPORTED, +} + +#[repr(C)] +pub struct UR_Error { + pub kind: UR_ErrorKind, + pub message: *const c_char, + pub len: usize, +} + +impl UR_Error { + /// # Safety + /// + /// - Single thread assumed. + /// - Once a new error is created with `new` any `UR_Error` will contain + /// an invalid message. So the data pointed by `message` should be copied + /// and `UR_Error` must be dropped. + pub unsafe fn new(message: &dyn fmt::Display, kind: UR_ErrorKind) -> Self { + let error = &mut UR_ERROR; + error.clear(); + + if write!(error, "{}", message).is_err() { + write!(error, "Error is too long to display.") + .expect("This error string should fit"); + } + + Self { + kind, + message: error.as_ptr() as *const c_char, + len: error.len(), + } + } + + /// # Safety + /// + /// The same as in [`UR_Error::new`]. + pub unsafe fn other(message: &dyn fmt::Display) -> Self { + Self::new(message, UR_ErrorKind::UR_ERROR_KIND_OTHER) + } + + /// # Safety + /// + /// The same as in [`UR_Error::new`]. + pub unsafe fn unsupported(message: &dyn fmt::Display) -> Self { + Self::new(message, UR_ErrorKind::UR_ERROR_KIND_UNSUPPORTED) + } +} + +pub mod decoder; +pub mod encoder; +pub mod registry; + +#[cfg(test)] +pub mod tests { + use super::*; + + #[test] + fn sanity_test() { + const fn is_power_of_2(x: usize) -> bool { + (x & (x - 1)) == 0 + } + + assert!(is_power_of_2(UR_MAX_SEQUENCE_COUNT)); + assert!(max_fragment_len() > 0); + } +} diff --git a/extmod/foundation-rust/src/ur/registry.rs b/extmod/foundation-rust/src/ur/registry.rs new file mode 100644 index 000000000..5fd7b2a14 --- /dev/null +++ b/extmod/foundation-rust/src/ur/registry.rs @@ -0,0 +1,545 @@ +// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::ur::UR_Error; +use core::{ffi::c_char, num::NonZeroU32, slice, str}; +use ur::registry::{ + crypto_hdkey::{ + BaseHDKey, CoinType, CryptoCoinInfo, CryptoKeypath, DerivedKey, + PathComponent, + }, + crypto_request::Empty, + BaseValue, +}; +use ur_foundation::{ + passport::Model, + registry::passport::{PassportRequest, PassportResponse}, + supply_chain_validation::{Challenge, Solution}, + ur, +}; +use uuid::Uuid; + +/// `mainnet` network. +pub const UR_NETWORK_MAINNET: u32 = 0; + +/// `testnet` network. +pub const UR_NETWORK_TESTNET: u32 = 1; + +/// Maximum number of components that a `crypto-keypath` can have. +pub const UR_MAX_PATH_COMPONENTS: usize = 4; + +/// cbindgen:ignore +type PathComponents = heapless::Vec; +/// cbindgen:ignore +type StandardValue<'a> = BaseValue<'a, Empty, PathComponents>; + +/// cbindgen:ignore +#[derive(Debug)] +pub enum Value<'a> { + Standard(StandardValue<'a>), + PassportRequest(PassportRequest), + PassportResponse(PassportResponse<'a>), +} + +impl<'a> Value<'a> { + pub fn encode( + &self, + w: W, + ) -> Result<(), minicbor::encode::Error> { + match self { + Value::Standard(ref standard) => minicbor::encode(standard, w), + Value::PassportRequest(ref passport_request) => { + minicbor::encode(passport_request, w) + } + Value::PassportResponse(ref passport_response) => { + minicbor::encode(passport_response, w) + } + } + } + + pub fn ur_type(&self) -> &'static str { + match self { + Value::Standard(value) => value.ur_type(), + Value::PassportRequest(_) => "crypto-request", + Value::PassportResponse(_) => "crypto-response", + } + } +} + +/// An uniform resource. +#[repr(C)] +pub enum UR_Value { + /// `bytes`. + Bytes { data: *const u8, len: usize }, + /// `crypto-hdkey`. + CryptoHDKey(UR_HDKey), + /// `crypto-psbt`. + CryptoPSBT { data: *const u8, len: usize }, + /// Passport custom `crypto-request`. + PassportRequest(UR_PassportRequest), + /// Passport custom `crypto-response`. + PassportResponse(UR_PassportResponse), +} + +impl UR_Value { + /// # Safety + /// + /// Read `UR_Error` safety section as if this function fails this function + /// will produce an `UR_Error`. + pub unsafe fn from_ur( + ur_type: &str, + message: &[u8], + ) -> Result { + let value = match ur_type { + "crypto-request" => Value::PassportRequest( + minicbor::decode(message).map_err(|e| UR_Error::other(&e))?, + ), + _ => Value::Standard( + StandardValue::from_ur(ur_type, message) + .map_err(|e| UR_Error::other(&e))?, + ), + }; + + let value = match value { + Value::Standard(StandardValue::Bytes(bytes)) => UR_Value::Bytes { + data: bytes.as_ptr(), + len: bytes.len(), + }, + Value::Standard(StandardValue::CryptoPSBT(psbt)) => { + UR_Value::CryptoPSBT { + data: psbt.as_ptr(), + len: psbt.len(), + } + } + Value::PassportRequest(passport_request) => { + UR_Value::PassportRequest(passport_request.into()) + } + _ => { + return Err(UR_Error::unsupported( + &"Unsupported uniform resource", + )) + } + }; + + Ok(value) + } + + /// # Safety + /// + /// Same safety requirements as on [core::slice::from_raw_parts] when the + /// value is: + /// + /// - `UR_Value::Bytes`. + /// - `UR_Value::CryptoPSBT`. + pub unsafe fn to_value(&self) -> Value<'_> { + match self { + UR_Value::Bytes { data, len } => { + let buf = unsafe { slice::from_raw_parts(*data, *len) }; + Value::Standard(StandardValue::Bytes(buf.into())) + } + UR_Value::CryptoPSBT { data, len } => { + let buf = unsafe { slice::from_raw_parts(*data, *len) }; + Value::Standard(StandardValue::CryptoPSBT(buf.into())) + } + UR_Value::CryptoHDKey(v) => { + Value::Standard(StandardValue::CryptoHDKey(v.into())) + } + UR_Value::PassportRequest(_) => panic!( + "Not implemented as it isn't needed. Should be unreachable" + ), + UR_Value::PassportResponse(v) => Value::PassportResponse(v.into()), + } + } +} + +/// A `crypto-hdkey`. +#[repr(C)] +pub enum UR_HDKey { + DerivedKey(UR_DerivedKey), +} + +impl<'a, C> From<&'a UR_HDKey> for BaseHDKey<'a, C> +where + C: ur::collections::Vec, +{ + fn from(value: &'a UR_HDKey) -> BaseHDKey<'a, C> { + match value { + UR_HDKey::DerivedKey(v) => { + BaseHDKey::DerivedKey(DerivedKey::from(v)) + } + } + } +} + +/// Derived `crypto-hdkey`. +#[repr(C)] +pub struct UR_DerivedKey { + /// `true` if this is a private key. + pub is_private: bool, + /// The key material. + pub key_data: [u8; 33], + /// Chain code. + pub chain_code: [u8; 32], + /// Whether `chain_code` is present. + pub has_chain_code: bool, + /// How the key should be used. + pub use_info: UR_CryptoCoinInfo, + /// Whether `use_info` is present. + pub has_use_info: bool, + /// How the key was derived. + pub origin: UR_CryptoKeypath, + /// Whether `origin` is present. + pub has_origin: bool, + /// The fingerprint of this key's direct ancestor. + /// + /// A value of `0` means that the fingerprint is not present. + pub parent_fingerprint: u32, +} + +impl<'a, C> From<&'a UR_DerivedKey> for DerivedKey<'a, C> +where + C: ur::collections::Vec, +{ + fn from(value: &'a UR_DerivedKey) -> DerivedKey<'a, C> { + DerivedKey { + is_private: value.is_private, + key_data: value.key_data, + chain_code: if value.has_chain_code { + Some(value.chain_code) + } else { + None + }, + use_info: if value.has_use_info { + Some(CryptoCoinInfo::from(&value.use_info)) + } else { + None + }, + origin: if value.has_origin { + Some(CryptoKeypath::from(&value.origin)) + } else { + None + }, + children: None, + parent_fingerprint: NonZeroU32::new(value.parent_fingerprint), + name: None, + note: None, + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub enum UR_CoinType { + BTC, +} + +impl From for CoinType { + fn from(v: UR_CoinType) -> CoinType { + match v { + UR_CoinType::BTC => CoinType::BTC, + } + } +} + +#[repr(C)] +#[derive(Clone)] +pub struct UR_CryptoCoinInfo { + pub coin_type: UR_CoinType, + pub network: u64, +} + +impl From<&UR_CryptoCoinInfo> for CryptoCoinInfo { + fn from(v: &UR_CryptoCoinInfo) -> CryptoCoinInfo { + CryptoCoinInfo { + coin_type: v.coin_type.into(), + network: v.network, + } + } +} + +/// Metadata for the complete or partial derivation path of a key. +#[repr(C)] +#[derive(Clone)] +pub struct UR_CryptoKeypath { + /// The fingerprint of this key's direct ancestor. + /// + /// A value of `0` means that the fingerprint is not present. + pub source_fingerprint: u32, + /// How many derivations this key is from the master (which is 0). + /// + /// 0 if this is a public key derived directly from a master key. + pub depth: u8, + /// Whether `depth` is present. + pub has_depth: bool, +} +impl From> for UR_CryptoKeypath +where + C: ur::collections::Vec, +{ + fn from(v: CryptoKeypath) -> UR_CryptoKeypath { + UR_CryptoKeypath { + source_fingerprint: v + .source_fingerprint + .map(|v| v.get()) + .unwrap_or(0), + depth: v.depth.unwrap_or(0), + has_depth: v.depth.is_some(), + } + } +} + +impl From<&UR_CryptoKeypath> for CryptoKeypath +where + C: ur::collections::Vec, +{ + fn from(v: &UR_CryptoKeypath) -> CryptoKeypath { + CryptoKeypath { + components: C::default(), + source_fingerprint: NonZeroU32::new(v.source_fingerprint), + depth: if v.has_depth { Some(v.depth) } else { None }, + } + } +} + +/// Passport custom `crypto-request`. +#[repr(C)] +pub struct UR_PassportRequest { + /// Transaction ID. + pub transaction_id: [u8; 16], + /// Supply chain validation challenge. + pub scv_challenge: UR_Challenge, + /// Whether SCV challenge is available. + pub has_scv_challenge: bool, + /// Request Passport model. + pub passport_model: bool, + /// Request Passport firmware version. + pub passport_firmware_version: bool, +} + +impl From for UR_PassportRequest { + fn from(v: PassportRequest) -> UR_PassportRequest { + let has_scv_challenge = v.scv_challenge.is_some(); + UR_PassportRequest { + transaction_id: v.transaction_id.into_bytes(), + scv_challenge: v.scv_challenge.map(UR_Challenge::from).unwrap_or( + UR_Challenge { + id: [0; 32], + signature: [0; 64], + }, + ), + has_scv_challenge, + passport_model: v.passport_model, + passport_firmware_version: v.passport_firmware_version, + } + } +} + +/// Supply chain validation challenge. +#[repr(C)] +pub struct UR_Challenge { + /// The ID challenge. + pub id: [u8; 32], + /// The signature. + pub signature: [u8; 64], +} + +impl From for UR_Challenge { + fn from(v: Challenge) -> UR_Challenge { + UR_Challenge { + id: v.id, + signature: v.signature, + } + } +} + +/// Passport custom `crypto-request`. +#[repr(C)] +pub struct UR_PassportResponse { + /// Transaction ID. + pub transaction_id: [u8; 16], + /// Supply chain validation challenge. + pub scv_solution: UR_Solution, + /// Whether `scv_solution` is present. + pub has_scv_solution: bool, + /// Passport model. + pub passport_model: UR_PassportModel, + /// Whether `passport_model` present. + pub has_passport_model: bool, + /// Passport firmware version. + pub passport_firmware_version: *const c_char, + /// Passport firmware version length. + pub passport_firmware_version_len: usize, + /// Whether `passport_model` present. + pub has_passport_firmware_version: bool, +} + +impl<'a> From<&'a UR_PassportResponse> for PassportResponse<'a> { + fn from(v: &'a UR_PassportResponse) -> PassportResponse<'a> { + PassportResponse { + transaction_id: Uuid::from_bytes(v.transaction_id), + scv_solution: if v.has_scv_solution { + Some((&v.scv_solution).into()) + } else { + None + }, + passport_model: if v.has_passport_model { + Some(v.passport_model.into()) + } else { + None + }, + passport_firmware_version: if v.has_passport_firmware_version { + Some(unsafe { + str::from_utf8_unchecked(slice::from_raw_parts( + v.passport_firmware_version as *const u8, + v.passport_firmware_version_len, + )) + }) + } else { + None + }, + } + } +} + +/// Supply Chain Validation solution. +#[repr(C)] +#[derive(Clone)] +pub struct UR_Solution { + pub word1: *const c_char, + pub word1_len: usize, + + pub word2: *const c_char, + pub word2_len: usize, + + pub word3: *const c_char, + pub word3_len: usize, + + pub word4: *const c_char, + pub word4_len: usize, +} + +impl<'a> From<&'a UR_Solution> for Solution<'a> { + fn from(v: &'a UR_Solution) -> Solution<'a> { + Solution { + word1: unsafe { + str::from_utf8_unchecked(slice::from_raw_parts( + v.word1 as *const u8, + v.word1_len, + )) + }, + word2: unsafe { + str::from_utf8_unchecked(slice::from_raw_parts( + v.word2 as *const u8, + v.word2_len, + )) + }, + word3: unsafe { + str::from_utf8_unchecked(slice::from_raw_parts( + v.word3 as *const u8, + v.word3_len, + )) + }, + word4: unsafe { + str::from_utf8_unchecked(slice::from_raw_parts( + v.word4 as *const u8, + v.word4_len, + )) + }, + } + } +} + +/// Passport model. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub enum UR_PassportModel { + /// Founders Edition. + PASSPORT_MODEL_FOUNDERS_EDITION, + /// Batch 2. + PASSPORT_MODEL_BATCH2, +} + +impl From for Model { + fn from(v: UR_PassportModel) -> Model { + match v { + UR_PassportModel::PASSPORT_MODEL_FOUNDERS_EDITION => { + Model::FoundersEdition + } + UR_PassportModel::PASSPORT_MODEL_BATCH2 => Model::Batch2, + } + } +} + +/// Passport custom `crypto-response`. + +/// Create a new `bytes` UR. +#[no_mangle] +pub extern "C" fn ur_registry_new_bytes( + value: &mut UR_Value, + data: *mut u8, + len: usize, +) { + *value = UR_Value::Bytes { data, len }; +} + +/// Create a new derived `crypto-hdkey` UR. +#[no_mangle] +pub extern "C" fn ur_registry_new_derived_key( + value: &mut UR_Value, + is_private: bool, + key_data: &[u8; 33], + chain_code: Option<&[u8; 32]>, + use_info: Option<&UR_CryptoCoinInfo>, + origin: Option<&UR_CryptoKeypath>, + parent_fingerprint: u32, +) { + *value = UR_Value::CryptoHDKey(UR_HDKey::DerivedKey(UR_DerivedKey { + is_private, + key_data: *key_data, + chain_code: chain_code.copied().unwrap_or([0u8; 32]), + has_chain_code: chain_code.is_some(), + use_info: use_info.cloned().unwrap_or(UR_CryptoCoinInfo { + coin_type: UR_CoinType::BTC, + network: 0, + }), + has_use_info: use_info.is_some(), + origin: origin.cloned().unwrap_or(UR_CryptoKeypath { + source_fingerprint: 0, + depth: 0, + has_depth: false, + }), + has_origin: origin.is_some(), + parent_fingerprint, + })); +} + +/// Create a new `crypto-psbt` UR. +#[no_mangle] +pub extern "C" fn ur_registry_new_crypto_psbt( + value: &mut UR_Value, + data: *mut u8, + len: usize, +) { + *value = UR_Value::CryptoPSBT { data, len }; +} +/// Create a new Passport ustom `crypto-response` UR. +#[no_mangle] +pub extern "C" fn ur_registry_new_passport_response( + value: &mut UR_Value, + transaction_id: &[u8; 16], + solution: &UR_Solution, + passport_model: UR_PassportModel, + passport_firmware_version: *const c_char, + passport_firmware_version_len: usize, +) { + *value = UR_Value::PassportResponse(UR_PassportResponse { + transaction_id: *transaction_id, + scv_solution: solution.clone(), + has_scv_solution: true, + passport_model, + has_passport_model: true, + passport_firmware_version, + passport_firmware_version_len, + has_passport_firmware_version: true, + }) +} diff --git a/extmod/foundation/modfoundation-ur.h b/extmod/foundation/modfoundation-ur.h new file mode 100644 index 000000000..79df326ac --- /dev/null +++ b/extmod/foundation/modfoundation-ur.h @@ -0,0 +1,613 @@ + +// SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include "py/obj.h" +#include "foundation.h" + +/// package: foundation.ur + +STATIC const mp_obj_type_t mod_foundation_ur_Value_type; +STATIC const mp_obj_type_t mod_foundation_ur_CoinType_type; +STATIC const mp_obj_type_t mod_foundation_ur_CryptoCoinInfo_type; +STATIC const mp_obj_type_t mod_foundation_ur_CryptoKeypath_type; +STATIC const mp_obj_type_t mod_foundation_ur_PassportRequest_type; + +STATIC struct _mp_obj_PassportRequest_t *mod_foundation_ur_PassportRequest_new(UR_PassportRequest *value); + +/// class Value: +/// """ +/// """ +typedef struct _mp_obj_Value_t { + mp_obj_base_t base; + UR_Value value; +} mp_obj_Value_t; + + +/// def __str__(self) -> str: +/// """ +/// """ +STATIC void mod_foundation_ur_Value_print(const mp_print_t *print, + mp_obj_t o_in, + mp_print_kind_t kind) { + (void) kind; + + mp_obj_Value_t *o = MP_OBJ_TO_PTR(o_in); + + switch (o->value.tag) { + case Bytes: + mp_print_str(print, "UR_Value::Bytes"); + break; + case CryptoHDKey: + mp_print_str(print, "UR_Value::CryptoHDKey"); + break; + case CryptoPSBT: + mp_print_str(print, "UR_Value::CryptoPSBT"); + break; + case PassportRequest: + mp_print_str(print, "UR_Value::PassportRequest"); + break; + default: + mp_print_str(print, "Unknown"); + break; + } +} + +/// def __init__(self) -> None: +/// """ +/// """ +STATIC mp_obj_Value_t *mod_foundation_ur_Value_new(UR_Value *value) { + mp_obj_Value_t *o = m_new_obj(mp_obj_Value_t); + o->base.type = &mod_foundation_ur_Value_type; + memcpy(&o->value, value, sizeof(UR_Value)); + return o; +} + +/// def ur_type(self) -> str: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_Value_ur_type(mp_obj_t self_in) { + mp_obj_Value_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_int(self->value.tag); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_Value_ur_type_obj, mod_foundation_ur_Value_ur_type); + +/// def unwrap_bytes(self) -> bytearray: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_Value_unwrap_bytes(mp_obj_t self_in) { + mp_obj_Value_t *self = MP_OBJ_TO_PTR(self_in); + mp_check_self(self->value.tag == Bytes); + return mp_obj_new_bytearray_by_ref(self->value.bytes.len, (void *)self->value.bytes.data); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_Value_unwrap_bytes_obj, + mod_foundation_ur_Value_unwrap_bytes); + +/// def unwrap_crypto_psbt(self) -> bytearray: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_Value_unwrap_crypto_psbt(mp_obj_t self_in) { + mp_obj_Value_t *self = MP_OBJ_TO_PTR(self_in); + mp_check_self(self->value.tag == CryptoPSBT); + + return mp_obj_new_bytearray_by_ref(self->value.crypto_psbt.len, (void *)self->value.crypto_psbt.data); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_Value_unwrap_crypto_psbt_obj, + mod_foundation_ur_Value_unwrap_crypto_psbt); + +/// def unwrap_passport_request(self) -> PassportRequest: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_Value_unwrap_passport_request(mp_obj_t self_in) { + mp_obj_Value_t *self = MP_OBJ_TO_PTR(self_in); + mp_check_self(self->value.tag == PassportRequest); + + return MP_OBJ_FROM_PTR(mod_foundation_ur_PassportRequest_new(&self->value.passport_request)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_Value_unwrap_passport_request_obj, + mod_foundation_ur_Value_unwrap_passport_request); + +STATIC const mp_rom_map_elem_t mod_foundation_ur_Value_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_BYTES), MP_ROM_INT(Bytes) }, + { MP_ROM_QSTR(MP_QSTR_CRYPTO_HDKEY), MP_ROM_INT(CryptoHDKey) }, + { MP_ROM_QSTR(MP_QSTR_CRYPTO_PSBT), MP_ROM_INT(CryptoPSBT) }, + { MP_ROM_QSTR(MP_QSTR_PASSPORT_REQUEST), MP_ROM_INT(PassportRequest) }, + + { MP_ROM_QSTR(MP_QSTR_ur_type), MP_ROM_PTR(&mod_foundation_ur_Value_ur_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_unwrap_bytes), MP_ROM_PTR(&mod_foundation_ur_Value_unwrap_bytes_obj) }, + { MP_ROM_QSTR(MP_QSTR_unwrap_crypto_psbt), MP_ROM_PTR(&mod_foundation_ur_Value_unwrap_crypto_psbt_obj) }, + { MP_ROM_QSTR(MP_QSTR_unwrap_passport_request), MP_ROM_PTR(&mod_foundation_ur_Value_unwrap_passport_request_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(mod_foundation_ur_Value_locals_dict, mod_foundation_ur_Value_locals_dict_table); + +STATIC const mp_obj_type_t mod_foundation_ur_Value_type = { + { &mp_type_type }, + .name = MP_QSTR_Value, + .print = mod_foundation_ur_Value_print, + .locals_dict = (mp_obj_dict_t *)&mod_foundation_ur_Value_locals_dict, +}; + +/// class CoinType: +/// """ +/// """ +/// +/// BTC = 0 +STATIC const mp_rom_map_elem_t mod_foundation_ur_CoinType_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_BTC), MP_ROM_INT(BTC) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mod_foundation_ur_CoinType_locals_dict, + mod_foundation_ur_CoinType_locals_dict_table); + +STATIC const mp_obj_type_t mod_foundation_ur_CoinType_type = { + { &mp_type_type }, + .name = MP_QSTR_CoinType, + .locals_dict = (mp_obj_dict_t*)&mod_foundation_ur_CoinType_locals_dict, +}; + +/// class CryptoCoinInfo: +/// """ +/// """ +typedef struct _mp_obj_CryptoCoinInfo_t { + mp_obj_base_t base; + UR_CryptoCoinInfo info; +} mp_obj_CryptoCoinInfo_t; + +STATIC mp_obj_t mod_foundation_ur_CryptoCoinInfo_make_new(const mp_obj_type_t *type, + size_t n_args, + size_t n_kw, + const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 2, 2, false); + + mp_obj_CryptoCoinInfo_t *o = m_new_obj(mp_obj_CryptoCoinInfo_t); + o->base.type = &mod_foundation_ur_CryptoCoinInfo_type; + + o->info.coin_type = mp_obj_get_int(args[0]); + o->info.network = mp_obj_get_int(args[1]); + + return MP_OBJ_FROM_PTR(o); +} + +STATIC const mp_obj_type_t mod_foundation_ur_CryptoCoinInfo_type = { + { &mp_type_type }, + .name = MP_QSTR_CryptoCoinInfo, + .make_new = mod_foundation_ur_CryptoCoinInfo_make_new, +}; + +/// class CryptoKeypath: +/// """ +/// """ +typedef struct _mp_obj_CryptoKeypath_t { + mp_obj_base_t base; + UR_CryptoKeypath keypath; +} mp_obj_CryptoKeypath_t; + +STATIC mp_obj_t mod_foundation_ur_CryptoKeypath_make_new(const mp_obj_type_t *type, + size_t n_args, + size_t n_kw, + const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_source_fingerprint, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_depth, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_CryptoKeypath_t *o = m_new_obj(mp_obj_CryptoKeypath_t); + o->base.type = &mod_foundation_ur_CryptoKeypath_type; + + if (args[0].u_obj != MP_OBJ_NULL) { + o->keypath.source_fingerprint = mp_obj_get_int(args[0].u_obj); + } else { + o->keypath.source_fingerprint = 0; + } + + if (args[1].u_obj != MP_OBJ_NULL) { + o->keypath.depth = mp_obj_get_int(args[1].u_obj); + o->keypath.has_depth = true; + } else { + o->keypath.depth = 0; + o->keypath.has_depth = false; + } + + return MP_OBJ_FROM_PTR(o); +} + +STATIC const mp_obj_type_t mod_foundation_ur_CryptoKeypath_type = { + { &mp_type_type }, + .name = MP_QSTR_CryptoKeypath, + .make_new = mod_foundation_ur_CryptoKeypath_make_new, +}; + +/// class PassportRequest: +/// """ +/// """ +typedef struct _mp_obj_PassportRequest_t { + mp_obj_base_t base; + UR_PassportRequest passport_request; +} mp_obj_PassportRequest_t; + +/// def __init__(self) -> None: +/// """ +/// """ +STATIC mp_obj_PassportRequest_t *mod_foundation_ur_PassportRequest_new(UR_PassportRequest *passport_request) { + mp_obj_PassportRequest_t *o = m_new_obj(mp_obj_PassportRequest_t); + o->base.type = &mod_foundation_ur_PassportRequest_type; + memcpy(&o->passport_request, passport_request, sizeof(UR_PassportRequest)); + return o; +} + +STATIC mp_obj_t mod_foundation_ur_PassportRequest_uuid(mp_obj_t self_in) +{ + mp_obj_PassportRequest_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bytes(self->passport_request.transaction_id, 16); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_PassportRequest_uuid_obj, + mod_foundation_ur_PassportRequest_uuid); + +STATIC mp_obj_t mod_foundation_ur_PassportRequest_scv_challenge_id(mp_obj_t self_in) +{ + mp_check_self(self->passport_request.has_scv_challenge); + mp_obj_PassportRequest_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bytes(self->passport_request.scv_challenge.id, 32); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_PassportRequest_scv_challenge_id_obj, + mod_foundation_ur_PassportRequest_scv_challenge_id); + +STATIC mp_obj_t mod_foundation_ur_PassportRequest_scv_challenge_signature(mp_obj_t self_in) +{ + mp_check_self(self->passport_request.has_scv_challenge); + mp_obj_PassportRequest_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bytes(self->passport_request.scv_challenge.signature, 64); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_PassportRequest_scv_challenge_signature_obj, + mod_foundation_ur_PassportRequest_scv_challenge_signature); + +STATIC const mp_rom_map_elem_t mod_foundation_ur_PassportRequest_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&mod_foundation_ur_PassportRequest_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_scv_challenge_id), MP_ROM_PTR(&mod_foundation_ur_PassportRequest_scv_challenge_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_scv_challenge_signature), MP_ROM_PTR(&mod_foundation_ur_PassportRequest_scv_challenge_signature_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(mod_foundation_ur_PassportRequest_locals_dict, + mod_foundation_ur_PassportRequest_locals_dict_table); + +STATIC const mp_obj_type_t mod_foundation_ur_PassportRequest_type = { + { &mp_type_type }, + .name = MP_QSTR_PassportRequest, + .locals_dict = (mp_obj_dict_t*)&mod_foundation_ur_PassportRequest_locals_dict, +}; + +/// def new_bytes(data: bytes) -> Value: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_new_bytes(mp_obj_t data_in) +{ + mp_buffer_info_t data = {0}; + UR_Value value; + + mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); + ur_registry_new_bytes(&value, data.buf, data.len); + return MP_OBJ_FROM_PTR(mod_foundation_ur_Value_new(&value)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_new_bytes_obj, + mod_foundation_ur_new_bytes); + +/// def new_derived_key(key_data=None, +/// is_private=False, +/// chain_code=None, +/// use_info=None, +/// parent_fingerprint=None) -> Value: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_new_derived_key(size_t n_args, + const mp_obj_t *pos_args, + mp_map_t *kw_args) +{ + mp_buffer_info_t key_data = {0}; + mp_buffer_info_t chain_code_info = {0}; + mp_obj_CryptoCoinInfo_t *use_info_obj = NULL; + mp_obj_CryptoKeypath_t *origin_obj = NULL; + UR_Value value = {0}; + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_is_private, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_chain_code, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_use_info, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_origin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_parent_fingerprint, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_get_buffer_raise(args[0].u_obj, &key_data, MP_BUFFER_READ); + if (key_data.len != 33) { + mp_raise_msg(&mp_type_ValueError, + MP_ERROR_TEXT("key_data should be 33 bytes")); + } + + if (args[2].u_obj != MP_OBJ_NULL) { + mp_get_buffer_raise(args[2].u_obj, &chain_code_info, MP_BUFFER_READ); + if (chain_code_info.len != 32) { + mp_raise_msg(&mp_type_ValueError, + MP_ERROR_TEXT("chain_code should be 32 bytes")); + } + } + + if (args[3].u_obj != MP_OBJ_NULL) { + if (!mp_obj_is_type(args[3].u_obj, &mod_foundation_ur_CryptoCoinInfo_type)) { + mp_raise_msg(&mp_type_ValueError, + MP_ERROR_TEXT("use_info should be of type CryptoCoinInfo")); + } + + use_info_obj = MP_OBJ_TO_PTR(args[3].u_obj); + } + + if (args[4].u_obj != MP_OBJ_NULL) { + if (!mp_obj_is_type(args[4].u_obj, &mod_foundation_ur_CryptoKeypath_type)) { + mp_raise_msg(&mp_type_ValueError, + MP_ERROR_TEXT("origin should be of type CryptoKeypath")); + } + + origin_obj = MP_OBJ_TO_PTR(args[4].u_obj); + } + + ur_registry_new_derived_key(&value, + args[0].u_bool, + key_data.buf, + chain_code_info.buf, + &use_info_obj->info, + &origin_obj->keypath, + args[5].u_int); + + return MP_OBJ_FROM_PTR(mod_foundation_ur_Value_new(&value)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_foundation_ur_new_derived_key_obj, + 1, + mod_foundation_ur_new_derived_key); + +/// def new_crypto_psbt(data: bytes) -> Value: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_new_crypto_psbt(mp_obj_t data_in) +{ + mp_buffer_info_t data = {0}; + UR_Value value; + + mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); + ur_registry_new_crypto_psbt(&value, data.buf, data.len); + return MP_OBJ_FROM_PTR(mod_foundation_ur_Value_new(&value)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_new_crypto_psbt_obj, + mod_foundation_ur_new_crypto_psbt); + + +/// def new_passport_response(data: bytes) -> Value: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_new_passport_response(size_t n_args, + const mp_obj_t *pos_args, + mp_map_t *kw_args) +{ + + mp_buffer_info_t uuid = {0}; + UR_Solution solution = {0}; + UR_Value value = {0}; + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_uuid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_word1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_word2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_word3, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_word4, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_model, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_version, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_get_buffer_raise(args[0].u_obj, &uuid, MP_BUFFER_READ); + if (uuid.len != 16) { + mp_raise_msg(&mp_type_ValueError, + MP_ERROR_TEXT("uuid should be 33 bytes")); + } + + GET_STR_DATA_LEN(args[1].u_obj, word1, word1_len); + GET_STR_DATA_LEN(args[2].u_obj, word2, word2_len); + GET_STR_DATA_LEN(args[3].u_obj, word3, word3_len); + GET_STR_DATA_LEN(args[4].u_obj, word4, word4_len); + + solution.word1 = (const char *)word1; + solution.word1_len = word1_len; + solution.word2 = (const char *)word2; + solution.word2_len = word2_len; + solution.word3 = (const char *)word3; + solution.word3_len = word3_len; + solution.word4 = (const char *)word4; + solution.word4_len = word4_len; + + GET_STR_DATA_LEN(args[6].u_obj, passport_firmware_version, passport_firmware_version_len); + + ur_registry_new_passport_response(&value, + uuid.buf, + &solution, + args[5].u_int, + (const char *)passport_firmware_version, + passport_firmware_version_len); + + return MP_OBJ_FROM_PTR(mod_foundation_ur_Value_new(&value)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_foundation_ur_new_passport_response_obj, + 0, + mod_foundation_ur_new_passport_response); + +/// Encoder. + +/// def encoder_start(value, max_fragment_len) -> None: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_encoder_start(mp_obj_t value_in, + mp_obj_t max_fragment_len_in) +{ + mp_obj_Value_t *value = NULL; + mp_int_t max_fragment_len = 0; + + if (!mp_obj_is_type(value_in, &mod_foundation_ur_Value_type)) { + mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("invalid type for value")); + return mp_const_none; + } + + value = MP_OBJ_TO_PTR(value_in); + max_fragment_len = mp_obj_get_int(max_fragment_len_in); + ur_encoder_start(&UR_ENCODER, &value->value, max_fragment_len); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_foundation_ur_encoder_start_obj, + mod_foundation_ur_encoder_start); + +/// def encoder_next_part(ur_type, message, max_fragment_len) -> str: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_encoder_next_part(void) +{ + const char *ur; + size_t ur_len; + + ur_encoder_next_part(&UR_ENCODER, &ur, &ur_len); + + vstr_t vstr; + vstr_init(&vstr, ur_len + 1); + vstr_add_strn(&vstr, ur, ur_len); + + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_foundation_ur_encoder_next_part_obj, + mod_foundation_ur_encoder_next_part); + +/// Decoder. + +/// def decoder_receive(ur_obj) -> None: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_decoder_receive(mp_obj_t ur_obj) +{ + UR_Error error = {0}; + + mp_check_self(mp_obj_is_str(ur_obj)); + GET_STR_DATA_LEN(ur_obj, ur, ur_len); + + if (!ur_decoder_receive(&UR_DECODER, ur, ur_len, &error)) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%.*s"), + error.len, error.message); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_decoder_receive_obj, + mod_foundation_ur_decoder_receive); + +/// def decoder_is_complete() -> bool: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_decoder_is_complete(void) +{ + return ur_decoder_is_complete(&UR_DECODER) ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_foundation_ur_decoder_is_complete_obj, + mod_foundation_ur_decoder_is_complete); + +/// def decoder_estimated_percent_complete() -> int: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_decoder_estimated_percent_complete(void) +{ + return mp_obj_new_int(ur_decoder_estimated_percent_complete(&UR_DECODER)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_foundation_ur_decoder_estimated_percent_complete_obj, + mod_foundation_ur_decoder_estimated_percent_complete); + + +/// def decoder_clear() -> None: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_decoder_clear(void) +{ + ur_decoder_clear(&UR_DECODER); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_foundation_ur_decoder_clear_obj, mod_foundation_ur_decoder_clear); + +/// def decoder_decode_message() -> Value: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_decoder_decode_message(void) +{ + UR_Error error = {0}; + UR_Value value = {0}; + + if (!ur_decoder_decode_message(&UR_DECODER, &value, &error)) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%.*s"), + error.len, error.message); + } + + return MP_OBJ_FROM_PTR(mod_foundation_ur_Value_new(&value)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_foundation_ur_decoder_decode_message_obj, + mod_foundation_ur_decoder_decode_message); + +/// def validate(ur: str) -> bool: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_validate(mp_obj_t ur_obj) +{ + mp_check_self(mp_obj_is_str(ur_obj)); + GET_STR_DATA_LEN(ur_obj, ur, ur_len); + + return ur_validate(ur, ur_len) ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_validate_obj, mod_foundation_ur_validate); + +STATIC const mp_rom_map_elem_t mod_foundation_ur_globals_table[] = { + // Value. + {MP_ROM_QSTR(MP_QSTR_NETWORK_MAINNET), MP_ROM_INT(UR_NETWORK_MAINNET)}, + {MP_ROM_QSTR(MP_QSTR_NETWORK_TESTNET), MP_ROM_INT(UR_NETWORK_TESTNET)}, + {MP_ROM_QSTR(MP_QSTR_PASSPORT_MODEL_FOUNDERS_EDITION), MP_ROM_INT(PASSPORT_MODEL_FOUNDERS_EDITION)}, + {MP_ROM_QSTR(MP_QSTR_PASSPORT_MODEL_BATCH2), MP_ROM_INT(PASSPORT_MODEL_BATCH2)}, + {MP_ROM_QSTR(MP_QSTR_Value), MP_ROM_PTR(&mod_foundation_ur_Value_type)}, + {MP_ROM_QSTR(MP_QSTR_CoinType), MP_ROM_PTR(&mod_foundation_ur_CoinType_type)}, + {MP_ROM_QSTR(MP_QSTR_CryptoCoinInfo), MP_ROM_PTR(&mod_foundation_ur_CryptoCoinInfo_type)}, + {MP_ROM_QSTR(MP_QSTR_CryptoKeypath), MP_ROM_PTR(&mod_foundation_ur_CryptoKeypath_type)}, + {MP_ROM_QSTR(MP_QSTR_PassportRequest), MP_ROM_PTR(&mod_foundation_ur_PassportRequest_type)}, + {MP_ROM_QSTR(MP_QSTR_new_bytes), MP_ROM_PTR(&mod_foundation_ur_new_bytes_obj)}, + {MP_ROM_QSTR(MP_QSTR_new_derived_key), MP_ROM_PTR(&mod_foundation_ur_new_derived_key_obj)}, + {MP_ROM_QSTR(MP_QSTR_new_crypto_psbt), MP_ROM_PTR(&mod_foundation_ur_new_crypto_psbt_obj)}, + {MP_ROM_QSTR(MP_QSTR_new_passport_response), MP_ROM_PTR(&mod_foundation_ur_new_passport_response_obj)}, + + // Encoder. + {MP_ROM_QSTR(MP_QSTR_encoder_start), MP_ROM_PTR(&mod_foundation_ur_encoder_start_obj)}, + {MP_ROM_QSTR(MP_QSTR_encoder_next_part), MP_ROM_PTR(&mod_foundation_ur_encoder_next_part_obj)}, + + // Decoder. + {MP_ROM_QSTR(MP_QSTR_decoder_receive), MP_ROM_PTR(&mod_foundation_ur_decoder_receive_obj)}, + {MP_ROM_QSTR(MP_QSTR_decoder_is_complete), MP_ROM_PTR(&mod_foundation_ur_decoder_is_complete_obj)}, + {MP_ROM_QSTR(MP_QSTR_decoder_estimated_percent_complete), MP_ROM_PTR(&mod_foundation_ur_decoder_estimated_percent_complete_obj)}, + {MP_ROM_QSTR(MP_QSTR_decoder_clear), MP_ROM_PTR(&mod_foundation_ur_decoder_clear_obj)}, + {MP_ROM_QSTR(MP_QSTR_decoder_decode_message), MP_ROM_PTR(&mod_foundation_ur_decoder_decode_message_obj)}, + {MP_ROM_QSTR(MP_QSTR_validate), MP_ROM_PTR(&mod_foundation_ur_validate_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(mod_foundation_ur_globals, mod_foundation_ur_globals_table); + +STATIC const mp_obj_module_t mod_foundation_ur_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&mod_foundation_ur_globals, +}; diff --git a/extmod/foundation/modfoundation.c b/extmod/foundation/modfoundation.c index cdb1a15cc..6186929db 100644 --- a/extmod/foundation/modfoundation.c +++ b/extmod/foundation/modfoundation.c @@ -26,6 +26,7 @@ #include "modfoundation-bip39.h" #include "modfoundation-qr.h" +#include "modfoundation-ur.h" /// package: foundation @@ -111,6 +112,7 @@ STATIC const mp_rom_map_elem_t foundation_module_globals_table[] = { {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation)}, {MP_ROM_QSTR(MP_QSTR_bip39), MP_ROM_PTR(&mod_foundation_bip39_module)}, {MP_ROM_QSTR(MP_QSTR_qr), MP_ROM_PTR(&mod_foundation_qr_module)}, + {MP_ROM_QSTR(MP_QSTR_ur), MP_ROM_PTR(&mod_foundation_ur_module)}, {MP_ROM_QSTR(MP_QSTR_convert_rgb565_to_grayscale), MP_ROM_PTR(&mod_foundation_convert_rgb565_to_grayscale_obj)}, {MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&mod_foundation_sha256_obj)}, }; diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index cb648700a..94d45d283 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -131,7 +131,7 @@ endif LDFLAGS += -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref LDFLAGS += --defsym=_estack_reserve=8 -LIBS = "$(shell $(CC) $(CFLAGS) -print-libgcc-file-name)" +LIBS += "$(shell $(CC) $(CFLAGS) -print-libgcc-file-name)" # Remove uncalled code from the final image. CFLAGS += -fdata-sections -ffunction-sections @@ -630,7 +630,7 @@ endef define GENERATE_ELF $(ECHO) "LINK $(1)" - $(Q)$(LD) $(LDFLAGS) -o $(1) $(2) $(LDFLAGS_MOD) $(LIBS) + $(Q)$(LD) $(LDFLAGS) -o $(1) $(2) --print-memory-usage $(LDFLAGS_MOD) $(LIBS) $(Q)$(SIZE) $(1) $(if $(filter-out $(TEXT0_ADDR),0x08000000), \ $(ECHO) "INFO: this build requires mboot to be installed first") @@ -723,7 +723,7 @@ $(BUILD)/firmware.pack.dfu: $(BUILD)/firmware.dfu $(MBOOT_PACK_KEYS_FILE) $(BUILD)/firmware.hex: $(BUILD)/firmware.elf $(call GENERATE_HEX,$@,$^) -$(BUILD)/firmware.elf: $(OBJ) +$(BUILD)/firmware.elf: $(OBJ) $(FOUNDATION_RUST_LIB) $(call GENERATE_ELF,$@,$^) PLLVALUES = boards/pllvalues.py diff --git a/ports/stm32/boards/Passport/manifest.py b/ports/stm32/boards/Passport/manifest.py index d954ddbf6..0a393b777 100644 --- a/ports/stm32/boards/Passport/manifest.py +++ b/ports/stm32/boards/Passport/manifest.py @@ -278,22 +278,6 @@ ('ui/__init__.py', 'ui/ui.py')) -# UR2 -freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules', - ('ur2/__init__.py', - 'ur2/bytewords.py', - 'ur2/cbor_lite.py', - 'ur2/constants.py', - 'ur2/fountain_encoder.py', - 'ur2/fountain_decoder.py', - 'ur2/fountain_utils.py', - 'ur2/random_sampler.py', - 'ur2/ur_decoder.py', - 'ur2/ur_encoder.py', - 'ur2/ur.py', - 'ur2/utils.py', - 'ur2/xoshiro256.py')) - # Views freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules', ('views/__init__.py', diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py index d3e5e3998..eeba5668c 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py @@ -33,7 +33,7 @@ def qr_type(self): class QREncoder(DataEncoder): - def __init__(self, _args): + def __init__(self): self.data = None def encode(self, data, max_fragment_len=None): diff --git a/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py b/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py index b7ad0e427..7e1a0fe8f 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/qr_factory.py @@ -18,10 +18,10 @@ ] -def make_qr_encoder(qr_type, args): +def make_qr_encoder(qr_type): for entry in qrs: if entry['type'] == qr_type: - return entry['encoder'](args) + return entry['encoder']() return None diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index d33fba361..bb96be74a 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -13,105 +13,64 @@ from .data_sampler import DataSampler from .qr_type import QRType -from ur2.ur_decoder import URDecoder, URError -from ur2.ur_encoder import UREncoder - -from ur2.cbor_lite import CBORDecoder, CBOREncoder, CBORError - -from ur2.ur import UR +from foundation import ur class UR2Decoder(DataDecoder): def __init__(self): - self.decoder = URDecoder() + ur.decoder_clear() - # Decode the given data into the expected format def add_data(self, data): try: - return self.decoder.receive_part(data) - except URError as exc: - raise DecodeError from exc + ur.decoder_receive(data.lower()) + except ValueError as exc: + import sys + sys.print_exception(exc) + raise DecodeError(str(exc)) def estimated_percent_complete(self): - return self.decoder.estimated_percent_complete() + return ur.decoder_estimated_percent_complete() def is_complete(self): - return self.decoder.is_complete() - - def decode(self, decode_cbor_bytes=False): - message = self.decoder.result - if decode_cbor_bytes: - try: - cbor_decoder = CBORDecoder(message.cbor) - (message, length) = cbor_decoder.decodeBytes() - except CBORError as exc: - raise DecodeError from exc + return ur.decoder_is_complete() - return message + def decode(self): + try: + return ur.decoder_decode_message() + except ValueError as exc: + import sys + sys.print_exception(exc) + raise DecodeError(str(exc)) def qr_type(self): return QRType.UR2 class UR2Encoder(DataEncoder): - def __init__(self, args): - self.ur_encoder = None - if isinstance(args, dict): - self.prefix = args['prefix'] or 'bytes' - else: - self.prefix = 'bytes' - - # Encode the given data - def encode(self, data, max_fragment_len=200): - # print('UR2Encoder: data="{}"'.format(data)) - if not hasattr(data, 'cbor'): - encoder = CBOREncoder() - # print('UR2: data={}'.format(to_str(data))) - encoder.encodeBytes(data) - data = encoder.get_bytes() - ur_obj = UR(self.prefix, encoder.get_bytes()) - else: - ur_obj = data - - # CBOR length of a UR2 part. Excluding the data itself on bytes which - # must be of the resulting `max_fragment_len`. - # - # 85 # array(5) - # 1A FFFFFFFF # unsigned(0xFFFFFFFF) - # 1B FFFFFFFFFFFFFFFF # unsigned(0xFFFFFFFFFFFFFFFF) - # 1B FFFFFFFFFFFFFFFF # unsigned(0xFFFFFFFFFFFFFFFF) - # 1A FFFFFFFF # unsigned(0xFFFFFFFF) - # 5B FFFFFFFFFFFFFFFF # bytes(0xFFFFFFFFFFFFFFFF) - max_fragment_cbor = 1 + 5 + 9 + 9 + 5 + 2 - - # "ur:" + prefix + "/99-999/" + max-fragment-cbor + CRC - reserved_len = 3 + len(self.prefix) + len("/99-9999/") + max_fragment_cbor + (4 * 2) - - # Divide in half the maximum fragment length as each byteword encoded byte takes two characters. - max_fragment_len = (max_fragment_len - reserved_len) // 2 - self.ur_encoder = UREncoder(ur_obj, max_fragment_len) - - # UR2.0's next_part() returns the initial pieces split into max_fragment_len bytes, but then switches over to - # an infinite series of encodings that combine various pieces of the data in an attempt to fill in any holes missed. + def encode(self, value, max_fragment_len=200): + """Initialize the encoder using the given UR data value""" + + ur.encoder_start(value, max_fragment_len) + def next_part(self): - return self.ur_encoder.next_part() + """Returns the next part of the UR encoder""" + + return ur.encoder_next_part() class UR2Sampler(DataSampler): - # Check if the given bytes look like UR2 data - # Return True if it matches or False if not @classmethod def sample(cls, data): - try: - # Rather than try a complex regex here, we just let the decoder try to decode and if it fails. - # it must not be UR2. - decoder = URDecoder() - result = decoder.receive_part(data) - return result - except Exception as e: - return False - - # Number of bytes required to successfully recognize this format + """ + Check if the given bytes look like UR2 data + + :param bytes data: The bytes to check. + :return: True if it matches or False if not. + """ + + return ur.validate(data.lower()) + @classmethod def min_sample_size(cls): + """Number of bytes required to successfully recognize this format.""" return 20 diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index ff19878fb..b6e3c0e0a 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -20,7 +20,7 @@ async def scan_qr(self): from pages import ScanQRPage, ErrorPage import microns - result = await ScanQRPage(right_micron=microns.Checkmark, decode_cbor_bytes=True).show() + result = await ScanQRPage(right_micron=microns.Checkmark).show() if result is None: # User canceled the scan @@ -82,7 +82,6 @@ async def show_signed_message(self): result = await ShowQRPage( qr_type=QRType.UR2, - qr_args={'prefix': 'bytes'}, qr_data=signed_message, caption='Signed Health Check' ).show() diff --git a/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py b/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py index b25bcfeea..f6cc0f764 100644 --- a/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py @@ -270,7 +270,8 @@ async def export_by_qr(self): self.is_multisig(), self.sig_type.get('legacy', False), # Export mode - 'qr']) + 'qr', + self.export_mode['qr_type']]) qr_type = self.export_mode['qr_type'] @@ -326,7 +327,8 @@ async def export_by_microsd(self): self.is_multisig(), self.sig_type.get('legacy', False), # Export mode - 'microsd']) + 'microsd', + None]) data_hash = bytearray(32) foundation.sha256(data, data_hash) diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py index 08fc7c484..9be03e344 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py @@ -16,7 +16,7 @@ async def scan_qr_code(self): from pages import ScanQRPage from multisig_wallet import MultisigWallet - result = await ScanQRPage(decode_cbor_bytes=True).show() + result = await ScanQRPage().show() if result is None: self.set_result(False) return diff --git a/ports/stm32/boards/Passport/modules/flows/scv_flow.py b/ports/stm32/boards/Passport/modules/flows/scv_flow.py index 194c498c7..2c4a60d33 100644 --- a/ports/stm32/boards/Passport/modules/flows/scv_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/scv_flow.py @@ -8,10 +8,11 @@ from pages import ScanQRPage, ShowQRPage, QRScanResult from pages.chooser_page import ChooserPage from styles.colors import HIGHLIGHT_TEXT_HEX -from ur2.ur import EnvoyURCryptoRequest, EnvoyURCryptoResponse, UR from data_codecs.qr_type import QRType from utils import a2b_hex +from ubinascii import hexlify as b2a_hex from pincodes import PinAttempt +from foundation import ur import microns import foundation import passport @@ -55,7 +56,7 @@ async def show_intro(self): async def scan_qr_challenge(self): from utils import recolor - result = await ScanQRPage(left_micron=microns.Cancel, right_micron=None, decode_cbor_bytes=False).show() + result = await ScanQRPage(left_micron=microns.Cancel, right_micron=None).show() # User did not scan anything if result is None: @@ -97,17 +98,13 @@ async def scan_qr_challenge(self): return if self.envoy: - crypto_request = EnvoyURCryptoRequest(cbor=result.data.cbor) - try: - crypto_request.decode() - except: # noqa - await self.show_error("Security Check QR code is invalid.\n" - "The QR code could not be decoded.") - return + passport_request = result.data.unwrap_passport_request() - self.uuid = crypto_request.uuid - challenge = crypto_request.scv_challenge - # print('Envoy: challenge={}'.format(challenge)) + self.uuid = passport_request.uuid() + challenge = { + 'id': passport_request.scv_challenge_id(), + 'signature': passport_request.scv_challenge_signature(), + } else: try: parts = result.data.split(' ') @@ -127,18 +124,21 @@ async def scan_qr_challenge(self): return id_hash = bytearray(32) - foundation.sha256(challenge['id'], id_hash) - signature = a2b_hex(challenge['signature']) - - # print('id_hash={}'.format(id_hash)) - # print('signature={}'.format(signature)) + id_bin = a2b_hex(challenge['id']) if isinstance(challenge['id'], str) else challenge['id'] + id_hex = challenge['id'] if isinstance(challenge['id'], str) else b2a_hex(challenge['id']) + foundation.sha256(id_hex, + id_hash) + if isinstance(challenge['signature'], str): + signature = a2b_hex(challenge['signature']) + else: + signature = challenge['signature'] signature_valid = passport.verify_supply_chain_server_signature(id_hash, signature) if not signature_valid: await self.show_error('Security Check signature is invalid.') return - self.words = PinAttempt.supply_chain_validation_words(a2b_hex(challenge['id'])) + self.words = PinAttempt.supply_chain_validation_words(id_bin) if self.envoy: self.goto(self.show_envoy_scan_msg) @@ -163,11 +163,14 @@ async def show_envoy_response(self): from common import system (version, _, _, _, _) = system.get_software_info() - crypto_response = EnvoyURCryptoResponse(uuid=self.uuid, - words=self.words, - model=EnvoyURCryptoResponse.PASSPORT_MODEL_BATCH2, - version=version) - crypto_response.encode() + crypto_response = ur.new_passport_response(uuid=self.uuid, + word1=self.words[0], + word2=self.words[1], + word3=self.words[2], + word4=self.words[3], + model=ur.PASSPORT_MODEL_BATCH2, + version=version) + result = await ShowQRPage(qr_type=QRType.UR2, qr_data=crypto_response, caption='Scan with Envoy', @@ -248,8 +251,7 @@ def is_valid_envoy_qrcode(result): if ( (result.error is not None) or (result.data is None) or - (not isinstance(result.data, UR)) or - (result.data.type != 'crypto-request') + (not isinstance(result.data, ur.Value)) ): return False diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index e5740e1b8..0dde204f7 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -4,19 +4,21 @@ # sign_psbt_qr_flow.py - Sign a PSBT from a microSD card from flows import Flow +from foundation import ur class SignPsbtQRFlow(Flow): def __init__(self): super().__init__(initial_state=self.scan_transaction, name='SignPsbtQRFlow') self.psbt = None + self.ur_type = None async def scan_transaction(self): from pages import ScanQRPage, ErrorPage import microns # TODO: May need to set statusbar content here and restore it after - result = await ScanQRPage(right_micron=microns.Checkmark, decode_cbor_bytes=True).show() + result = await ScanQRPage(right_micron=microns.Checkmark).show() if result is None: # User canceled the scan self.set_result(False) @@ -27,13 +29,25 @@ async def scan_transaction(self): await ErrorPage(text='Unable to scan QR code.\n\n{}'.format(result.error)).show() self.set_result(False) else: - if isinstance(result.data, str): - await ErrorPage(text='The QR code does not contain a transaction.').show() - self.set_result(False) - else: - self.raw_psbt = result.data + # TODO: handle hex not only UR. Wasn't handled before the UR + # rework too. + if isinstance(result.data, ur.Value): self.qr_type = result.qr_type + self.ur_type = result.data.ur_type() + + if self.ur_type == ur.Value.BYTES: + self.raw_psbt = result.data.unwrap_bytes() + elif self.ur_type == ur.Value.CRYPTO_PSBT: + self.raw_psbt = result.data.unwrap_crypto_psbt() + else: + await ErrorPage(text='The QR code does not contain a transaction.').show() + self.set_result(False) + return + self.goto(self.copy_to_flash) + else: + await ErrorPage(text='The QR code does not contain a transaction.').show() + self.set_result(False) async def copy_to_flash(self): import gc @@ -94,13 +108,16 @@ async def show_signed_transaction(self): gc.collect() - signed_hex = b2a_hex(signed_bytes) + if self.qr_type == QRType.QR: + qr_data = b2a_hex(signed_bytes) + elif self.qr_type == QRType.UR2 and self.ur_type == ur.Value.BYTES: + qr_data = ur.new_bytes(signed_bytes) + elif self.qr_type == QRType.UR2 and self.ur_type == ur.Value.CRYPTO_PSBT: + qr_data = ur.new_crypto_psbt(signed_bytes) + else: + raise RuntimeException("Unsupported output format") - # print('qr_type={}'.format(self.qr_type)) - await ShowQRPage( - qr_type=self.qr_type, - qr_data=signed_bytes if self.qr_type == QRType.UR2 else signed_hex, - # TODO: This shouldn't be hard-coded - qr_args={'prefix': 'crypto-psbt'}, - right_micron=microns.Checkmark).show() + await ShowQRPage(qr_type=self.qr_type, + qr_data=qr_data, + right_micron=microns.Checkmark).show() self.set_result(True) diff --git a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py index b9155cdf9..aff64414c 100644 --- a/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/scan_qr_page.py @@ -26,8 +26,7 @@ def __init__(self, card_header=None, statusbar=None, left_micron=microns.Back, - right_micron=None, - decode_cbor_bytes=False): + right_micron=None): super().__init__(flex_flow=None, card_header=card_header, statusbar=statusbar, @@ -35,8 +34,6 @@ def __init__(self, right_micron=right_micron, extend_timeout=True) - # TODO: Temporary flag until we can cleanup the CBOR handling - self.decode_cbor_bytes = decode_cbor_bytes self.prev_card_header = None self.timer = None self.camera = CameraQRScanner() @@ -109,7 +106,7 @@ def update(self): self.progress_label.set_text(progress_text(self.camera.estimated_percent_complete())) if self.camera.is_complete(): - data = self.camera.qr_decoder.decode(decode_cbor_bytes=self.decode_cbor_bytes) + data = self.camera.qr_decoder.decode() qr_type = self.camera.qr_decoder.qr_type() self.set_result(QRScanResult(data=data, qr_type=qr_type)) diff --git a/ports/stm32/boards/Passport/modules/pages/show_qr_page.py b/ports/stm32/boards/Passport/modules/pages/show_qr_page.py index 3eb81c842..4189a4ee7 100644 --- a/ports/stm32/boards/Passport/modules/pages/show_qr_page.py +++ b/ports/stm32/boards/Passport/modules/pages/show_qr_page.py @@ -34,7 +34,6 @@ class ShowQRPage(Page): def __init__(self, qr_type=QRType.QR, - qr_args=None, qr_data=None, caption=None, card_header=None, @@ -47,7 +46,6 @@ def __init__(self, right_micron=right_micron, extend_timeout=True) self.qr_type = qr_type - self.qr_args = qr_args self.qr_data = qr_data self.caption = caption self.curr_fragment_len = 200 @@ -193,7 +191,7 @@ def on_key(self, key, pressed): def update(self): if self.is_attached(): if self.qr_encoder is None: - self.qr_encoder = make_qr_encoder(self.qr_type, self.qr_args) + self.qr_encoder = make_qr_encoder(self.qr_type) if self.qr_type == QRType.UR2: self.curr_fragment_len = _VERSIONS[self.qr_size_idx]['alphanumeric'] diff --git a/ports/stm32/boards/Passport/modules/tasks/create_wallet_export_task.py b/ports/stm32/boards/Passport/modules/tasks/create_wallet_export_task.py index 0346caec4..183813d25 100644 --- a/ports/stm32/boards/Passport/modules/tasks/create_wallet_export_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/create_wallet_export_task.py @@ -5,10 +5,13 @@ # create_wallet_export_task.py - Run the function that will generate the wallet export data -async def create_wallet_export_task(on_done, export_fn, sw_wallet, addr_type, acct_num, multisig, legacy, export_mode): +async def create_wallet_export_task(on_done, export_fn, sw_wallet, addr_type, + acct_num, multisig, legacy, export_mode, + qr_type): '''This is in a task as some exports could take some time due to cryptography.''' (data, acct_info) = export_fn( sw_wallet=sw_wallet, addr_type=addr_type, acct_num=acct_num, - multisig=multisig, legacy=legacy, export_mode=export_mode) + multisig=multisig, legacy=legacy, export_mode=export_mode, + qr_type=qr_type) await on_done(data, acct_info, None) diff --git a/ports/stm32/boards/Passport/modules/ur2/__init__.py b/ports/stm32/boards/Passport/modules/ur2/__init__.py deleted file mode 100644 index 073546ac4..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# diff --git a/ports/stm32/boards/Passport/modules/ur2/bytewords.py b/ports/stm32/boards/Passport/modules/ur2/bytewords.py deleted file mode 100644 index c3a3a42be..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/bytewords.py +++ /dev/null @@ -1,149 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# bytewords.py -# - -from .utils import crc32_bytes, partition - -BYTEWORDS = 'ableacidalsoapexaquaarchatomauntawayaxisbackbaldbarnbeltbetabiasbluebodybragbrewbulbbuzzcalmcashcatschefcityclawcodecolacookcostcruxcurlcuspcyandarkdatadaysdelidicedietdoordowndrawdropdrumdulldutyeacheasyechoedgeepicevenexamexiteyesfactfairfernfigsfilmfishfizzflapflewfluxfoxyfreefrogfuelfundgalagamegeargemsgiftgirlglowgoodgraygrimgurugushgyrohalfhanghardhawkheathelphighhillholyhopehornhutsicedideaidleinchinkyintoirisironitemjadejazzjoinjoltjowljudojugsjumpjunkjurykeepkenokeptkeyskickkilnkingkitekiwiknoblamblavalazyleaflegsliarlimplionlistlogoloudloveluaulucklungmainmanymathmazememomenumeowmildmintmissmonknailnavyneednewsnextnoonnotenumbobeyoboeomitonyxopenovalowlspaidpartpeckplaypluspoempoolposepuffpumapurrquadquizraceramprealredorichroadrockroofrubyruinrunsrustsafesagascarsetssilkskewslotsoapsolosongstubsurfswantacotasktaxitenttiedtimetinytoiltombtoystriptunatwinuglyundouniturgeuservastveryvetovialvibeviewvisavoidvowswallwandwarmwaspwavewaxywebswhatwhenwhizwolfworkyankyawnyellyogayurtzapszerozestzinczonezoom' # nopep8 -WORD_ARRAY = None - - -def decode_word(word, word_len): - global WORD_ARRAY - global BYTEWORDS - - if len(word) != word_len: - raise ValueError('Invalid Bytewords.') - - dim = 26 - - # Since the first and last letters of each Byteword are unique, - # we can use them as indexes into a two-dimensional lookup table. - # This table is generated lazily. - if WORD_ARRAY is None: - WORD_ARRAY = [-1] * (dim * dim) # create empty array - - for i in range(256): - byteword_offset = i * 4 - x = ord(BYTEWORDS[byteword_offset]) - ord('a') - y = ord(BYTEWORDS[byteword_offset + 3]) - ord('a') - array_offset = y * dim + x - WORD_ARRAY[array_offset] = i - - # If the coordinates generated by the first and last letters are out of bounds, - # or the lookup table contains -1 at the coordinates, then the word is not valid. - x = ord(word[0].lower()) - ord('a') - y = ord((word[3 if len(word) == 4 else 1]).lower()) - ord('a') - if not (0 <= x and x < dim and 0 <= y and y < dim): - raise ValueError('Invalid Bytewords.') - - offset = y * dim + x - value = WORD_ARRAY[offset] - if value == -1: - raise ValueError('Invalid Bytewords.') - - # If we're decoding a full four-letter word, verify that the two middle letters are correct. - if len(word) == 4: - byteword_offset = value * 4 - c1 = word[1].lower() - c2 = word[2].lower() - if c1 != BYTEWORDS[byteword_offset + 1] or c2 != BYTEWORDS[byteword_offset + 2]: - raise ValueError('Invalid Bytewords.') - - # Successful decode. - return value - - -def get_word(index): - byteword_offset = index * 4 - return BYTEWORDS[byteword_offset:byteword_offset + 4] - - -def get_minimal_word(index): - byteword_offset = index * 4 - return BYTEWORDS[byteword_offset] + BYTEWORDS[byteword_offset + 3] - - -def encode(buf, separator): - words = [] - for i in range(len(buf)): - byte = buf[i] - words.append(get_word(byte)) - - return separator.join(words) - - -def add_crc(buf): - crc_buf = crc32_bytes(buf) - return buf + crc_buf - - -def encode_with_separator(buf, separator): - crc_buf = add_crc(buf) - return encode(crc_buf, separator) - - -def encode_minimal(buf): - result = '' - - crc_buf = add_crc(buf) - for i in range(len(crc_buf)): - byte = crc_buf[i] - result += get_minimal_word(byte) - - return result - - -def decode(s, separator, word_len): - buf = bytearray() - - if word_len == 4: - words = s.split(separator) - else: - words = partition(s, 2) - - for word in words: - buf.append(decode_word(word, word_len)) - - if len(buf) < 5: - raise ValueError('Invalid Bytewords.') - - # Validate checksum - body = buf[0:-4] - body_checksum = buf[-4:] - checksum = crc32_bytes(body) - if checksum != body_checksum: - raise ValueError('Invalid Bytewords.') - - return body - - -Bytewords_Style_standard = 1 -Bytewords_Style_uri = 2 -Bytewords_Style_minimal = 3 - - -class Bytewords: - @staticmethod - def encode(style, bytes): - if style == Bytewords_Style_standard: - return encode_with_separator(bytes, ' ') - elif style == Bytewords_Style_uri: - return encode_with_separator(bytes, '-') - elif style == Bytewords_Style_minimal: - return encode_minimal(bytes) - else: - assert(False) - - @staticmethod - def decode(style, str): - if style == Bytewords_Style_standard: - return decode(str, ' ', 4) - elif style == Bytewords_Style_uri: - return decode(str, '-', 4) - elif style == Bytewords_Style_minimal: - return decode(str, 0, 2) - else: - assert(False) diff --git a/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py b/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py deleted file mode 100644 index 7caf9c2b6..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/cbor_lite.py +++ /dev/null @@ -1,356 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# cbor_lite.py -# - -# From: https://bitbucket.org/isode/cbor-lite/raw/6c770624a97e3229e3f200be092c1b9c70a60ef1/include/cbor-lite/codec.h - -# This file is part of CBOR-lite which is copyright Isode Limited -# and others and released under a MIT license. For details, see the -# COPYRIGHT.md file in the top-level folder of the CBOR-lite software -# distribution. - -from micropython import const - - -class CBORError(Exception): - pass - - -def bit_length(n): - return len(bin(abs(n))) - 2 - - -Flag_None = const(0) -Flag_Require_Minimal_Encoding = const(1) - -Tag_Major_unsignedInteger = const(0) -Tag_Major_negativeInteger = const(1 << 5) -Tag_Major_byteString = const(2 << 5) -Tag_Major_textString = const(3 << 5) -Tag_Major_array = const(4 << 5) -Tag_Major_map = const(5 << 5) -Tag_Major_semantic = const(6 << 5) -Tag_Major_floatingPoint = const(7 << 5) -Tag_Major_simple = const(7 << 5) -Tag_Major_mask = const(0xe0) - -Tag_Minor_length1 = const(24) -Tag_Minor_length2 = const(25) -Tag_Minor_length4 = const(26) -Tag_Minor_length8 = const(27) - -Tag_Minor_false = const(20) -Tag_Minor_true = const(21) -Tag_Minor_null = const(22) -Tag_Minor_undefined = const(23) -Tag_Minor_half_float = const(25) -Tag_Minor_singleFloat = const(26) -Tag_Minor_doubleFloat = const(27) - -Tag_Minor_dateTime = const(0) -Tag_Minor_epochDateTime = const(1) -Tag_Minor_positiveBignum = const(2) -Tag_Minor_negativeBignum = const(3) -Tag_Minor_decimalFraction = const(4) -Tag_Minor_bigFloat = const(5) -Tag_Minor_convertBase64Url = const(21) -Tag_Minor_convertBase64 = const(22) -Tag_Minor_convertBase16 = const(23) -Tag_Minor_cborEncodedData = const(24) -Tag_Minor_uri = const(32) -Tag_Minor_base64Url = const(33) -Tag_Minor_base64 = const(34) -Tag_Minor_regex = const(35) -Tag_Minor_mimeMessage = const(36) -Tag_Minor_embeddedJSON = const(262) -Tag_Minor_selfDescribeCbor = const(55799) -Tag_Minor_mask = const(0x1f) -Tag_Undefined = Tag_Major_semantic + Tag_Minor_undefined - - -def get_byte_length(value): - if value < 24: - return 0 - - return (bit_length(value) + 7) // 8 - - -class CBOREncoder: - def __init__(self): - self.buf = bytearray() - - def get_bytes(self): - return self.buf - - def encodeTagAndAdditional(self, tag, additional): - self.buf.append(tag + additional) - return 1 - - def encodeTagAndValue(self, tag, value): - length = get_byte_length(value) - - # 5-8 bytes required, use 8 bytes - if length >= 5 and length <= 8: - self.encodeTagAndAdditional(tag, Tag_Minor_length8) - self.buf.append((value >> 56) & 0xff) - self.buf.append((value >> 48) & 0xff) - self.buf.append((value >> 40) & 0xff) - self.buf.append((value >> 32) & 0xff) - self.buf.append((value >> 24) & 0xff) - self.buf.append((value >> 16) & 0xff) - self.buf.append((value >> 8) & 0xff) - self.buf.append(value & 0xff) - - # 3-4 bytes required, use 4 bytes - elif length == 3 or length == 4: - self.encodeTagAndAdditional(tag, Tag_Minor_length4) - self.buf.append((value >> 24) & 0xff) - self.buf.append((value >> 16) & 0xff) - self.buf.append((value >> 8) & 0xff) - self.buf.append(value & 0xff) - - elif length == 2: - self.encodeTagAndAdditional(tag, Tag_Minor_length2) - self.buf.append((value >> 8) & 0xff) - self.buf.append(value & 0xff) - - elif length == 1: - self.encodeTagAndAdditional(tag, Tag_Minor_length1) - self.buf.append(value & 0xff) - - elif length == 0: - self.encodeTagAndAdditional(tag, value) - - else: - raise CBORError( - "Unsupported byte length of {} for value in encodeTagAndValue()".format(length)) - - encoded_size = 1 + length - return encoded_size - - def encodeTagSemantic(self, value): - return self.encodeTagAndValue(Tag_Major_semantic, value) - - def encodeUndefined(self, value): - return self.encodeTagAndValue(Tag_Major_semantic, value) - - def encodeUnsigned(self, value): - return self.encodeTagAndValue(Tag_Major_unsignedInteger, value) - - def encodeNegative(self, value): - return self.encodeTagAndValue(Tag_Major_negativeInteger, value) - - def encodeInteger(self, value): - if value >= 0: - return self.encodeUnsigned(value) - else: - return self.encodeNegative(value) - - def encodeBool(self, value): - return self.encodeTagAndValue(Tag_Major_simple, Tag_Minor_true if value else Tag_Minor_false) - - def encodeBytes(self, value): - length = self.encodeTagAndValue(Tag_Major_byteString, len(value)) - self.buf += value - return length + len(value) - - def encodeEncodedBytesPrefix(self, value): - length = self.encodeTagAndValue( - Tag_Major_semantic, Tag_Minor_cborEncodedData) - return length + self.encodeTagAndAdditional(Tag_Major_bytestring, value) - - def encodeEncodedBytes(self, value): - length = self.encodeTagAndValue( - Tag_Major_semantic, Tag_Minor_cborEncodedData) - return length + self.encodeBytes(value) - - def encodeText(self, value): - str_len = len(value) - length = self.encodeTagAndValue(Tag_Major_textString, str_len) - # print(bytes(value, 'utf8')) - self.buf.extend(bytes(value, 'utf8')) - return length + str_len - - def encodeArraySize(self, value): - return self.encodeTagAndValue(Tag_Major_array, value) - - def encodeMapSize(self, value): - return self.encodeTagAndValue(Tag_Major_map, value) - - def encodeJSON(self, value): - length = self.encodeTagAndValue( - Tag_Major_semantic, Tag_Minor_embeddedJSON) - return length + self.encodeBytes(value) - - -class CBORDecoder: - def __init__(self, buf): - self.buf = buf - self.pos = 0 - - def decodeTagAndAdditional(self, flags=Flag_None): - if self.pos == len(self.buf): - raise CBORError("Not enough input") - octet = self.buf[self.pos] - self.pos += 1 - tag = octet & Tag_Major_mask - additional = octet & Tag_Minor_mask - return (tag, additional, 1) - - def decodeTagAndValue(self, flags): - end = len(self.buf) - - if self.pos == end: - raise CBORError("Not enough input") - - (tag, additional, length) = self.decodeTagAndAdditional(flags) - if additional < Tag_Minor_length1: - value = additional - return (tag, value, length) - - value = 0 - if additional == Tag_Minor_length8: - if end - self.pos < 8: - raise CBORError("Not enough input") - for shift in [56, 48, 40, 32, 24, 16, 8, 0]: - value |= self.buf[self.pos] << shift - self.pos += 1 - if ((flags & Flag_Require_Minimal_Encoding) and value == 0): - raise CBORError("Encoding not minimal") - return (tag, value, self.pos) - elif additional == Tag_Minor_length4: - if end - self.pos < 4: - raise CBORError("Not enough input") - for shift in [24, 16, 8, 0]: - value |= self.buf[self.pos] << shift - self.pos += 1 - if ((flags & Flag_Require_Minimal_Encoding) and value == 0): - raise CBORError("Encoding not minimal") - return (tag, value, self.pos) - elif additional == Tag_Minor_length2: - if end - self.pos < 2: - raise CBORError("Not enough input") - for shift in [8, 0]: - value |= self.buf[self.pos] << shift - self.pos += 1 - if ((flags & Flag_Require_Minimal_Encoding) and value == 0): - raise CBORError("Encoding not minimal") - return (tag, value, self.pos) - elif additional == Tag_Minor_length1: - if end - self.pos < 1: - raise CBORError("Not enough input") - value |= self.buf[self.pos] - self.pos += 1 - if ((flags & Flag_Require_Minimal_Encoding) and value == 0): - raise CBORError("Encoding not minimal") - return (tag, value, self.pos) - - raise CBORError("Bad additional value") - - def decodeTagSemantic(self, flags=Flag_None): - (tag, value, length) = self.decodeTagAndValue(flags) - if tag != Tag_Major_semantic: - raise CBORError("Expected Tag_Major_semantic, but found {}".format(tag)) - return (value, length) - - def decodeUndefined(self, flags=Flag_None): - (tag, value, length) = self.decodeTagAndValue(flags) - if tag != Tag_Major_semantic: - raise CBORError("Expected Tag_Major_semantic ({}), but found {}".format( - Tag_Major_semantic, tag)) - return (value, length) - - def decodeUnsigned(self, flags=Flag_None): - (tag, value, length) = self.decodeTagAndValue(flags) - if tag != Tag_Major_unsignedInteger: - raise CBORError("Expected Tag_Major_unsignedInteger ({}), but found {}".format( - Tag_Major_unsignedInteger, tag)) - return (value, length) - - def decodeNegative(self, flags=Flag_None): - (tag, value, length) = self.decodeTagAndValue(flags) - if tag != Tag_Major_negativeInteger: - raise CBORError( - "Expected Tag_Major_negativeInteger, but found {}".format(tag)) - return (value, length) - - def decodeInteger(self, flags=Flag_None): - (tag, value, length) = self.decodeTagAndValue(flags) - if tag == Tag_Major_unsignedInteger: - return (value, length) - elif tag == Tag_Major_negativeInteger: - # TODO: Need to properly test negative integers (although we don't use them). Need to use struct.unpack()? - return (-1 - value, length) - - def decodeBool(self, flags=Flag_None): - (tag, value, length) = self.decodeTagAndValue(flags) - if tag == Tag_Major_simple: - if value == Tag_Minor_true: - return (True, length) - elif value == Tag_Minor_false: - return (False, length) - raise CBORError("Not a Boolean") - raise CBORError("Not Simple/Boolean") - - def decodeBytes(self, flags=Flag_None): - # First value is the length of the bytes that follow - (tag, byte_length, size_length) = self.decodeTagAndValue(flags) - if tag != Tag_Major_byteString: - raise CBORError("Not a byteString") - - end = len(self.buf) - if end - self.pos < byte_length: - raise CBORError("Not enough input") - - value = bytes(self.buf[self.pos: self.pos + byte_length]) - self.pos += byte_length - return (value, size_length + byte_length) - - def decodeEncodedBytesPrefix(self, flags=Flag_None): - (tag, value, length1) = self.decodeTagAndValue(flags) - if tag != Tag_Major_semantic or value != Tag_Minor_cborEncodedData: - raise CBORError("Not CBOR Encoded Data") - - (tag, value, length2) = self.decodeTagAndValue(flags) - if tag != Tag_Major_byteString: - raise CBORError("Not byteString") - - return (tag, value, length1 + length2) - - def decodeEncodedBytes(self, flags=Flag_None): - (tag, minor_tag, tag_length) = self.decodeTagAndValue(flags) - if tag != Tag_Major_semantic or minor_tag != Tag_Minor_cborEncodedData: - raise CBORError("Not CBOR Encoded Data") - - (value, length) = self.decodeBytes(flags) - return (value, tag_length + length) - - def decodeText(self, flags=Flag_None): - # First value is the length of the bytes that follow - (tag, byte_length, size_length) = self.decodeTagAndValue(flags) - if tag != Tag_Major_textString: - raise CBORError("Not a textString") - - end = len(self.buf) - if end - self.pos < byte_length: - raise CBORError("Not enough input") - - value = bytes(self.buf[self.pos: self.pos + byte_length]) - self.pos += byte_length - return (value, size_length + byte_length) - - def decodeArraySize(self, flags=Flag_None): - (tag, value, length) = self.decodeTagAndValue(flags) - - if tag != Tag_Major_array: - raise CBORError( - "Expected Tag_Major_array, but found {}".format(tag)) - return (value, length) - - def decodeMapSize(self, flags=Flag_None): - (tag, value, length) = self.decodeTagAndValue(flags) - if tag != Tag_Major_map: - raise CBORError("Expected Tag_Major_map, but found {}".format(tag)) - return (value, length) diff --git a/ports/stm32/boards/Passport/modules/ur2/constants.py b/ports/stm32/boards/Passport/modules/ur2/constants.py deleted file mode 100644 index b5c49eb4a..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/constants.py +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# constants.py -# - -from micropython import const - -MAX_UINT32 = const(0xffffffff) -MAX_UINT64 = const(0xffffffffffffffff) diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py deleted file mode 100644 index bcb204a85..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_decoder.py +++ /dev/null @@ -1,267 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# fountain_decoder.py -# - -from .fountain_utils import choose_fragments, contains, is_strict_subset, set_difference -from .utils import join_lists, join_bytes, crc32_int, xor_with, take_first -from utils import bytes_to_hex_str - - -class FountainError(Exception): - pass - - -class FountainDecoder: - class Part: - def __init__(self, indexes, data): - self.indexes = frozenset(indexes) - self.data = data - - @classmethod - def from_encoder_part(cls, p): - return cls(choose_fragments(p.seq_num, p.seq_len, p.checksum), p.data[:]) - - def indexes(self): - return self.indexes - - def data(self): - return self.data - - def is_simple(self): - return len(self.indexes) == 1 - - def index(self): - # TODO: Find a more efficient way of doing this (measure performance overhead first) - return list(self.indexes)[0] - - # FountainDecoder - def __init__(self): - self.received_part_indexes = set() - self.processed_parts_count = 0 - self.result = None - self.expected_part_indexes = None - self.expected_fragment_len = None - self.expected_message_len = None - self.expected_checksum = None - self.simple_parts = {} - self.mixed_parts = {} - self.queued_parts = [] - - def expected_part_count(self): - if self.expected_part_indexes is None: - return 0 - return len(self.expected_part_indexes) - - def is_complete(self): - return self.result is not None - - def estimated_percent_complete(self): - if self.is_complete(): - return 100 - if self.expected_part_indexes is None: - return 0 - estimated_input_parts = self.expected_part_count() * 1.75 - return int(min(0.99, self.processed_parts_count / estimated_input_parts) * 100) - - def receive_part(self, encoder_part): - # Don't process the part if we're already done - if self.is_complete(): - return False - - # Don't continue if this part doesn't validate - if not self.validate_part(encoder_part): - raise FountainError('Invalid part') - - # Add this part to the queue - p = FountainDecoder.Part.from_encoder_part(encoder_part) - self.enqueue(p) - - # Process the queue until we're done or the queue is empty - while not self.is_complete() and len(self.queued_parts) != 0: - self.process_queue_item() - - # Keep track of how many parts we've processed - # - # NOTE: We should only increment this if we haven't processed this part - # before. - if encoder_part.seq_num - 1 not in self.received_part_indexes: - self.processed_parts_count += 1 - - # self.print_part_end() - - return True - - # Join all the fragments of a message together, throwing away any padding - @staticmethod - def join_fragments(fragments, message_len): - message = join_bytes(fragments) - return take_first(message, message_len) - - def enqueue(self, p): - self.queued_parts.append(p) - - def process_queue_item(self): - part = self.queued_parts.pop(0) - # self.print_part(part) - - if part.is_simple(): - self.process_simple_part(part) - else: - self.process_mixed_part(part) - # self.print_state() - - def reduce_mixed_by(self, p): - # Reduce all the current mixed parts by the given part - reduced_parts = [] - for value in self.mixed_parts.values(): - reduced_parts.append(self.reduce_part_by_part(value, p)) - - # Collect all the remaining mixed parts - new_mixed = {} - for reduced_part in reduced_parts: - # If this reduced part is now simple - if reduced_part.is_simple(): - # Add it to the queue - self.enqueue(reduced_part) - else: - # Otherwise, add it to the dict of current mixed parts - new_mixed[reduced_part.indexes] = reduced_part - - self.mixed_parts = new_mixed - - def reduce_part_by_part(self, a, b): - # If the fragments mixed into `b` are a strict (proper) subset of those in `a`... - if is_strict_subset(b.indexes, a.indexes): - # The new fragments in the revised part are `a` - `b`. - new_indexes = set_difference(a.indexes, b.indexes) - # The new data in the revised part are `a` XOR `b` - new_data = xor_with(bytearray(a.data), b.data) - return self.Part(new_indexes, new_data) - else: - # `a` is not reducible by `b`, so return a - return a - - def process_simple_part(self, p): - # Don't process duplicate parts - fragment_index = p.index() - if contains(self.received_part_indexes, fragment_index): - return - - # Record this part - self.simple_parts[p.indexes] = p - if fragment_index not in self.received_part_indexes: - self.received_part_indexes.add(fragment_index) - self.processed_parts_count += 1 - - # If we've received all the parts - if self.received_part_indexes == self.expected_part_indexes: - # Reassemble the message from its fragments - sorted_parts = [] - for value in self.simple_parts.values(): - sorted_parts.append(value) - - sorted_parts.sort(key=lambda a: a.index()) - - fragments = [] - for part in sorted_parts: - fragments.append(part.data) - - message = self.join_fragments(fragments, self.expected_message_len) - - # Verify the message checksum and note success or failure - checksum = crc32_int(message) - if checksum == self.expected_checksum: - result = bytes(message) - self.result = result - else: - raise FountainError('Invalid part checksum') - else: - # Reduce all the mixed parts by this part - self.reduce_mixed_by(p) - - def process_mixed_part(self, p): - # Don't process duplicate parts - for r in self.mixed_parts.values(): - if r == p.indexes: - return - - # Reduce this part by all the others - p2 = p - for r in self.simple_parts.values(): - p2 = self.reduce_part_by_part(p2, r) - - for r in self.mixed_parts.values(): - p2 = self.reduce_part_by_part(p2, r) - - # If the part is now simple - if p2.is_simple(): - # Add it to the queue - self.enqueue(p2) - else: - # Reduce all the mixed parts by this one - self.reduce_mixed_by(p2) - # Record this new mixed part - self.mixed_parts[p2.indexes] = p2 - - def validate_part(self, p): - # If this is the first part we've seen - if self.expected_part_indexes is None: - # Record the things that all the other parts we see will have to match to be valid. - self.expected_part_indexes = set() - for i in range(p.seq_len): - self.expected_part_indexes.add(i) - - self.expected_message_len = p.message_len - self.expected_checksum = p.checksum - self.expected_fragment_len = len(p.data) - else: - # If this part's values don't match the first part's values, throw away the part - if self.expected_part_count() != p.seq_len: - return False - if self.expected_message_len != p.message_len: - return False - if self.expected_checksum != p.checksum: - return False - if self.expected_fragment_len != len(p.data): - return False - - # This part should be processed - return True - - # debugging - def indexes_to_string(self, indexes): - i = sorted(indexes) - s = [str(j) for j in i] - return '[{}]'.format(', '.join(s)) - - # DEBUG CODE - # - # def result_description(self): - # if self.result is None: - # return 'None' - # - # return '{} bytes'.format(len(self.result)) - # - # def print_part(self, p): - # print('part indexes: {}'.format(self.indexes_to_string(p.indexes))) - # - # def print_part_end(self): - # expected = self.expected_part_count() if self.expected_part_indexes != None else 'None' - # percent = int(round(self.estimated_percent_complete() * 100)) - # print("processed: {}, expected: {}, received: {}, percent: {}%".format( - # self.processed_parts_count, expected, len(self.received_part_indexes), percent)) - # - # def print_state(self): - # parts = self.expected_part_count() if self.expected_part_indexes != None else 'None' - # received = self.indexes_to_string(self.received_part_indexes) - # mixed = [] - # for indexes, p in self.mixed_parts.items(): - # mixed.append(self.indexes_to_string(indexes)) - # - # mixed_s = "[{}]".format(', '.join(mixed)) - # queued = len(self.queued_parts) - # res = self.result_description() - # print('parts: {}, received: {}, mixed: {}, queued: {}, result: {}'.format( - # parts, received, mixed_s, queued, res)) diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py b/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py deleted file mode 100644 index e782cf403..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_encoder.py +++ /dev/null @@ -1,152 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# fountain_encoder.py -# - -import math -from .cbor_lite import CBORDecoder, CBOREncoder -from .fountain_utils import choose_fragments -from .utils import split, crc32_int, xor_into, data_to_hex -from .constants import MAX_UINT32, MAX_UINT64 - - -class InvalidHeader(Exception): - pass - - -class Part: - - def __init__(self, seq_num, seq_len, message_len, checksum, data): - self.seq_num = seq_num - self.seq_len = seq_len - self.message_len = message_len - self.checksum = checksum - self.data = data - - @staticmethod - def from_cbor(cbor_buf): - try: - decoder = CBORDecoder(cbor_buf) - (array_size, _) = decoder.decodeArraySize() - if array_size != 5: - raise InvalidHeader() - - (seq_num, _) = decoder.decodeUnsigned() - if seq_num > MAX_UINT64: - raise InvalidHeader() - - (seq_len, _) = decoder.decodeUnsigned() - if seq_len > MAX_UINT64: - raise InvalidHeader() - - (message_len, _) = decoder.decodeUnsigned() - if message_len > MAX_UINT64: - raise InvalidHeader() - - (checksum, _) = decoder.decodeUnsigned() - if checksum > MAX_UINT64: - raise InvalidHeader() - - (data, _) = decoder.decodeBytes() - - return Part(seq_num, seq_len, message_len, checksum, data) - except Exception as err: - raise InvalidHeader() - - def cbor(self): - encoder = CBOREncoder() - encoder.encodeArraySize(5) - encoder.encodeInteger(self.seq_num) - encoder.encodeInteger(self.seq_len) - encoder.encodeInteger(self.message_len) - encoder.encodeInteger(self.checksum) - encoder.encodeBytes(self.data) - return encoder.get_bytes() - - def seq_num(self): - return self.seq_num - - def seq_len(self): - return self.seq_len - - def message_len(self): - return self.message_len - - def checksum(self): - return self.checksum - - def data(self): - return self.data - - def description(self): - return "seqNum:{}, seqLen:{}, messageLen:{}, checksum:{}, data:{}".format( - self.seq_num, self.seq_len, self.message_len, self.checksum, data_to_hex(self.data)) - - -class FountainEncoder: - def __init__(self, message, max_fragment_len, first_seq_num=0, min_fragment_len=10): - assert(len(message) <= MAX_UINT32) - self.message_len = len(message) - self.checksum = crc32_int(message) - self.fragment_len = FountainEncoder.find_nominal_fragment_length( - self.message_len, min_fragment_len, max_fragment_len) - self.fragments = FountainEncoder.partition_message( - message, self.fragment_len) - self.seq_num = first_seq_num - - @staticmethod - def find_nominal_fragment_length(message_len, min_fragment_len, max_fragment_len): - assert(message_len > 0) - assert(min_fragment_len > 0) - assert(max_fragment_len >= min_fragment_len) - max_fragment_count = message_len // min_fragment_len - fragment_len = None - - for fragment_count in range(1, max_fragment_count + 1): - fragment_len = math.ceil(message_len / fragment_count) - if fragment_len <= max_fragment_len: - break - - assert(fragment_len is not None) - return fragment_len - - @staticmethod - def partition_message(message, fragment_len): - remaining = message - fragments = [] - while len(remaining) != 0: - (fragment, remaining) = split(remaining, fragment_len) - padding = fragment_len - len(fragment) - while padding > 0: - fragment.append(0) - padding -= 1 - fragments.append(fragment) - - return fragments - - def seq_len(self): - return len(self.fragments) - - # This becomes `true` when the minimum number of parts - # to relay the complete message have been generated - def is_complete(self): - return self.seq_num >= self.seq_len() - - # True if only a single part will be generated. - def is_single_part(self): - return self.seq_len() == 1 - - def next_part(self): - self.seq_num += 1 - self.seq_num = self.seq_num % MAX_UINT32 # wrap at period 2^32 - indexes = choose_fragments(self.seq_num, self.seq_len(), self.checksum) - mixed = self.mix(indexes) - data = bytes(mixed) - return Part(self.seq_num, self.seq_len(), self.message_len, self.checksum, data) - - def mix(self, indexes): - result = [0] * self.fragment_len - for index in indexes: - xor_into(result, self.fragments[index]) - return result diff --git a/ports/stm32/boards/Passport/modules/ur2/fountain_utils.py b/ports/stm32/boards/Passport/modules/ur2/fountain_utils.py deleted file mode 100644 index 3826ab796..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/fountain_utils.py +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# fountain_utils.py -# - -from .random_sampler import RandomSampler -from .utils import int_to_bytes -from .xoshiro256 import Xoshiro256 - -# Fisher-Yates shuffle - - -def shuffled(items, rng): - remaining = items - result = [] - while len(remaining) > 0: - index = rng.next_int(0, len(remaining) - 1) - item = remaining.pop(index) - result.append(item) - - return result - - -def choose_degree(seq_len, rng): - degree_probabilities = [] - for i in range(1, seq_len + 1): - degree_probabilities.append(1.0 / i) - - degree_chooser = RandomSampler(degree_probabilities) - return degree_chooser.next(lambda: rng.next_double()) + 1 - - -def choose_fragments(seq_num, seq_len, checksum): - # The first `seq_len` parts are the "pure" fragments, not mixed with any - # others. This means that if you only generate the first `seq_len` parts, - # then you have all the parts you need to decode the message. - if seq_num <= seq_len: - return set([seq_num - 1]) - else: - seed = int_to_bytes(seq_num) + int_to_bytes(checksum) - rng = Xoshiro256.from_bytes(seed) - degree = choose_degree(seq_len, rng) - indexes = [] - - for i in range(seq_len): - indexes.append(i) - shuffled_indexes = shuffled(indexes, rng) - return set(shuffled_indexes[0:degree]) - - -def contains(set_or_list, el): - return el in set_or_list - - -def is_strict_subset(a, b): - return a.issubset(b) - - -def set_difference(a, b): - return a.difference(b) diff --git a/ports/stm32/boards/Passport/modules/ur2/random_sampler.py b/ports/stm32/boards/Passport/modules/ur2/random_sampler.py deleted file mode 100644 index 0c3999b27..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/random_sampler.py +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# random_sampler.py -# - - -class RandomSampler: - - def __init__(self, probs): - for p in probs: - assert(p > 0) - - # Normalize given probabilities - total = sum(probs) - assert(total > 0) - - n = len(probs) - - P = [] - for p in probs: - P.append((p * float(n)) / total) - - S = [] - L = [] - - # Set separate index lists for small and large probabilities: - for i in reversed(range(0, n)): - # at variance from Schwarz, we reverse the index order - if P[i] < 1: - S.append(i) - else: - L.append(i) - - # Work through index lists - _probs = [0] * n - _aliases = [0] * n - - while len(S) > 0 and len(L) > 0: - a = S.pop() # Schwarz's l - g = L.pop() # Schwarz's g - _probs[a] = P[a] - _aliases[a] = g - P[g] += P[a] - 1 - if P[g] < 1: - S.append(g) - else: - L.append(g) - - while len(L) > 0: - _probs[L.pop()] = 1 - - while len(S) > 0: - # can only happen through numeric instability - _probs[S.pop()] = 1 - - self.probs = _probs - self.aliases = _aliases - - def next(self, rng_func): - r1 = rng_func() - r2 = rng_func() - n = len(self.probs) - i = int(float(n) * r1) - return i if r2 < self.probs[i] else self.aliases[i] diff --git a/ports/stm32/boards/Passport/modules/ur2/ur.py b/ports/stm32/boards/Passport/modules/ur2/ur.py deleted file mode 100644 index 43869ece7..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/ur.py +++ /dev/null @@ -1,228 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# ur.py -# - -from .utils import is_ur_type -from .cbor_lite import CBORDecoder, CBOREncoder -from micropython import const - -_TAG_UUID = const(37) -_UUID_LEN = const(16) - - -class URException(Exception): - pass - - -class InvalidType(URException): - pass - - -class InvalidUuid(URException): - pass - - -class InvalidScvChallenge(URException): - pass - - -class UR: - - def __init__(self, type, cbor): - if not is_ur_type(type): - raise InvalidType() - - self.type = type - self.cbor = cbor - self.cbor_decoder = None - self.cbor_encoder = None - - def __eq__(self, obj): - if obj is None: - return False - return self.type == obj.type and self.cbor == obj.cbor - - def decode(self): - self.cbor_decoder = CBORDecoder(self.cbor) - - def encode(self): - self.cbor_encoder = CBOREncoder() - self.cbor = self.cbor_encoder.get_bytes() - return self.cbor - - -class URBytes(UR): - """Undifferentiated byte string""" - - def __init__(self, cbor=None, data=None): - super().__init__('bytes', cbor) - self.data = data - - def decode(self): - super().decode() - self.data, length = self.cbor_decoder.decodeBytes() - - def encode(self): - super().encode() - - self.cbor_encoder.encodeBytes(self.data) - self.cbor = self.cbor_encoder.get_bytes() - return self.cbor - - -class URCryptoRequest(UR): - """ - crypto-request uniform resource - - See: - - https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2021-001-request.md - - https://github.com/BlockchainCommons/crypto-commons/blob/master/Docs/ur-99-request-response.md - """ - - def __init__(self, cbor=None): - """ - Initialize UR crypto-request - - Raises an InvalidType exception if type is not crypto-request. - """ - - super().__init__('crypto-request', cbor) - - self.uuid = None - - def decode(self): - super().decode() - - (size, _) = self.cbor_decoder.decodeMapSize() - for _ in range(0, size): - self.cbor_decoder.decodeUnsigned() - (tag, length) = self.cbor_decoder.decodeTagSemantic() - # decode - if tag == _TAG_UUID: - self._decode_uuid() - else: - self._decode_tag(tag) - - def _decode_uuid(self): - (self.uuid, length) = self.cbor_decoder.decodeBytes() - if len(self.uuid) != _UUID_LEN: - raise InvalidUuid() - - def _decode_tag(self, tag): - """Decode a tag from a crypto-request map""" - pass - - -class URCryptoResponse(UR): - """crypto-response uniform resource""" - - def __init__(self, cbor=None, uuid=None): - super().__init__('crypto-response', cbor) - - self.uuid = uuid - self.encode_map_size = 1 - - def encode(self): - super().encode() - - self.cbor_encoder.encodeMapSize(self.encode_map_size) - - self.cbor_encoder.encodeUnsigned(1) - self.cbor_encoder.encodeTagSemantic(_TAG_UUID) - self.cbor_encoder.encodeBytes(self.uuid) - - self.cbor = self.cbor_encoder.get_bytes() - return self.cbor - - -class EnvoyURCryptoRequest(URCryptoRequest): - """Envoy crypto-request uniform resource""" - - _TAG_SCV_CHALLENGE_REQUEST = const(710) - _TAG_PASSPORT_MODEL_REQUEST = const(720) - _TAG_PASSPORT_FIRMWARE_VERSION_REQUEST = const(770) - - def __init__(self, cbor=None): - super().__init__(cbor=cbor) - - self.scv_challenge = None - - def _decode_tag(self, tag): - if tag == _TAG_SCV_CHALLENGE_REQUEST: - self._decode_scv_challenge() - elif tag == _TAG_PASSPORT_MODEL_REQUEST: - self._decode_passport_model_request() - elif tag == _TAG_PASSPORT_FIRMWARE_VERSION_REQUEST: - self._decode_passport_firmware_version_request() - - def _decode_scv_challenge(self): - self.scv_challenge = {} - (size, _) = self.cbor_decoder.decodeMapSize() - if size != 3: - raise InvalidScvChallenge() - - for _ in range(0, size): - (index, _) = self.cbor_decoder.decodeUnsigned() - (text, _) = self.cbor_decoder.decodeText() - if index == 1: - self.scv_challenge['id'] = text - elif index == 2: - self.scv_challenge['signature'] = text - - def _decode_passport_model_request(self): - self.cbor_decoder.decodeUnsigned() - - def _decode_passport_firmware_version_request(self): - self.cbor_decoder.decodeUnsigned() - - -class EnvoyURCryptoResponse(URCryptoResponse): - """Envoy crypto-response uniform resource""" - - _TAG_SCV_CHALLENGE_RESPONSE = const(711) - _TAG_PASSPORT_MODEL_RESPONSE = const(721) - _TAG_PASSPORT_FIRMWARE_VERSION_RESPONSE = const(771) - - PASSPORT_MODEL_FOUNDERS_EDITION = 1 - PASSPORT_MODEL_BATCH2 = 2 - - def __init__(self, uuid=None, words=None, model=PASSPORT_MODEL_BATCH2, version=None): - super().__init__(uuid=uuid) - - self.words = words - self.encode_map_size = 4 - self.model = model - self.version = version - - def encode(self): - super().encode() - - self.cbor_encoder.encodeUnsigned(2) - self.cbor_encoder.encodeTagSemantic(_TAG_SCV_CHALLENGE_RESPONSE) - - self.cbor_encoder.encodeMapSize(4) - - self.cbor_encoder.encodeUnsigned(1) - self.cbor_encoder.encodeText(self.words[0]) - - self.cbor_encoder.encodeUnsigned(2) - self.cbor_encoder.encodeText(self.words[1]) - - self.cbor_encoder.encodeUnsigned(3) - self.cbor_encoder.encodeText(self.words[2]) - - self.cbor_encoder.encodeUnsigned(4) - self.cbor_encoder.encodeText(self.words[3]) - - self.cbor_encoder.encodeUnsigned(3) - self.cbor_encoder.encodeTagSemantic(_TAG_PASSPORT_MODEL_RESPONSE) - self.cbor_encoder.encodeUnsigned(self.model) - - self.cbor_encoder.encodeUnsigned(4) - self.cbor_encoder.encodeTagSemantic(_TAG_PASSPORT_FIRMWARE_VERSION_RESPONSE) - self.cbor_encoder.encodeText(self.version) - - self.cbor = self.cbor_encoder.get_bytes() - return self.cbor diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py deleted file mode 100644 index 64ce50c25..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/ur_decoder.py +++ /dev/null @@ -1,133 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# ur_decoder.py -# - -from .ur import UR -from .fountain_encoder import FountainEncoder, Part as FountainEncoderPart -from .fountain_decoder import FountainDecoder, FountainError -from .bytewords import * -from .utils import drop_first, is_ur_type - - -class URError(Exception): - pass - - -class URDecoder: - def __init__(self): - self.fountain_decoder = FountainDecoder() - self._expected_type = None - self.result = None - - @staticmethod - def decode(str): - (type, components) = URDecoder.parse(str) - if len(components) == 0: - raise URError('invalid path length') - - body = components[0] - return URDecoder.decode_by_type(type, body) - - @staticmethod - def decode_by_type(type, body): - cbor = Bytewords.decode(Bytewords_Style_minimal, body) - return UR(type, cbor) - - @staticmethod - def parse(str): - # Don't consider case - lowered = str.lower() - - # Validate URI scheme - if not lowered.startswith('ur:'): - raise URError('Invalid scheme') - - path = drop_first(lowered, 3) - - # Split the remainder into path components - components = path.split('/') - - # Make sure there are at least two path components - if len(components) < 2: - raise URError('malformed UR path components') - - # Validate the type - type = components[0] - if not is_ur_type(type): - raise URError('invalid UR type') - - comps = components[1:] # Don't include the ur type - return (type, comps) - - @staticmethod - def parse_sequence_component(str): - comps = str.split('-') - if len(comps) != 2: - raise URError('Invalid sequence component') - seq_num = int(comps[0]) - seq_len = int(comps[1]) - # print('seq_num={} seq_len={}'.format(seq_num, seq_len)) - if seq_num < 1 or seq_len < 1: - raise URError('Invalid sequence numbers') - return (seq_num, seq_len) - - def validate_part(self, type): - if self._expected_type is None: - if not is_ur_type(type): - return False - self._expected_type = type - return True - else: - return type == self._expected_type - - def receive_part(self, str): - # Don't process the part if we're already done - if self.result is not None: - return False - - # Don't continue if this part doesn't validate - (type, components) = URDecoder.parse(str) - if not self.validate_part(type): - return False - - # If this is a single-part UR then we're done - if len(components) == 1: - body = components[0] - self.result = self.decode_by_type(type, body) - return True - - # Multi-part URs must have two path components: seq/fragment - if len(components) != 2: - raise InvalidPathLength() - seq = components[0] - fragment = components[1] - - # Parse the sequence component and the fragment, and make sure they agree. - (seq_num, seq_len) = URDecoder.parse_sequence_component(seq) - - try: - cbor = Bytewords.decode(Bytewords_Style_minimal, fragment) - except ValueError as exc: - raise URError from exc - - part = FountainEncoderPart.from_cbor(cbor) - if seq_num != part.seq_num or seq_len != part.seq_len: - raise URError('Sequence number mismatch') - - # Process the part - try: - self.fountain_decoder.receive_part(part) - if self.fountain_decoder.is_complete(): - self.result = UR(type, self.fountain_decoder.result) - except FountainError as exc: - raise URError('Invalid part data') from exc - - return True - - def estimated_percent_complete(self): - return self.fountain_decoder.estimated_percent_complete() - - def is_complete(self): - return self.result is not None diff --git a/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py b/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py deleted file mode 100644 index 5cb1a8caa..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/ur_encoder.py +++ /dev/null @@ -1,56 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# ur_encoder.py -# - -from .fountain_encoder import FountainEncoder -from .bytewords import * - - -class UREncoder: - # Start encoding a (possibly) multi-part UR. - def __init__(self, ur, max_fragment_len, first_seq_num=0, min_fragment_len=10): - self.ur = ur - self.fountain_encoder = FountainEncoder( - ur.cbor, max_fragment_len, first_seq_num, min_fragment_len) - - # Encode a single-part UR. - @staticmethod - def encode(ur): - body = Bytewords.encode(Bytewords_Style_minimal, ur.cbor) - return UREncoder.encode_ur([ur.type, body]) - - # `True` if the minimal number of parts to transmit the message have been - # generated. Parts generated when this is `true` will be fountain codes - # containing various mixes of the part data. - def is_complete(self): - return self.fountain_encoder.is_complete() - - # `True` if this UR can be contained in a single part. If `True`, repeated - # calls to `next_part()` will all return the same single-part UR. - def is_single_part(self): - return self.fountain_encoder.is_single_part() - - def next_part(self): - part = self.fountain_encoder.next_part() - if self.is_single_part(): - return UREncoder.encode(self.ur) - else: - return UREncoder.encode_part(self.ur.type, part) - - @staticmethod - def encode_part(type, part): - seq = '{}-{}'.format(part.seq_num, part.seq_len) - body = Bytewords.encode(Bytewords_Style_minimal, part.cbor()) - result = UREncoder.encode_ur([type, seq, body]) - return result - - @staticmethod - def encode_uri(scheme, path_components): - path = '/'.join(path_components) - return ':'.join([scheme, path]) - - @staticmethod - def encode_ur(path_components): - return UREncoder.encode_uri('ur', path_components) diff --git a/ports/stm32/boards/Passport/modules/ur2/utils.py b/ports/stm32/boards/Passport/modules/ur2/utils.py deleted file mode 100644 index 0c9672c03..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/utils.py +++ /dev/null @@ -1,88 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# utils.py - - -def bit_length(n): - return len(bin(abs(n))) - 2 - - -def crc32_int(buf): - from trezorcrypto import crc - return crc.crc32(buf) - - -def crc32_bytes(buf): - n = crc32_int(buf) - return n.to_bytes((bit_length(n) + 7) // 8, 'big') - - -def data_to_hex(buf): - return ''.join('{:02x}'.format(x) for x in buf) - - -def int_to_bytes(n): - # return n.to_bytes((n.bit_length() + 7) // 8, 'big') - return n.to_bytes(4, 'big') - - -def bytes_to_int(buf): - return int.from_bytes(buf, 'big') - - -def string_to_bytes(s): - return bytes(s, 'utf8') - - -def is_ur_type(type): - for ch in type: - if not (ch >= 'a' and ch <= 'z') and not (ch >= '0' and ch <= '9') and ch != '-': - return False - - return True - - -def partition(s, n): - return [s[i:i + n] for i in range(0, len(s), n)] - -# Split the given sequence into two parts returned in a tuple -# The first entry in the tuple has the first `count` values. -# The second entry in the tuple has the remaining values. - - -def split(buf, count): - return (buf[0:count], buf[count:]) - - -def join_lists(lists): - # return [y for x in lists for y in x] - return sum(lists, []) - - -def join_bytes(list_of_ba): - out = bytearray() - for ba in list_of_ba: - out.extend(ba) - return out - - -def xor_into(target, source): - count = len(target) - assert(count == len(source)) # Must be the same length - for i in range(count): - target[i] ^= source[i] - - -def xor_with(a, b): - target = a - xor_into(target, b) - return target - - -def take_first(s, count): - return s[0:count] - - -def drop_first(s, count): - return s[count:] diff --git a/ports/stm32/boards/Passport/modules/ur2/xoshiro256.py b/ports/stm32/boards/Passport/modules/ur2/xoshiro256.py deleted file mode 100644 index 10ffce6ca..000000000 --- a/ports/stm32/boards/Passport/modules/ur2/xoshiro256.py +++ /dev/null @@ -1,166 +0,0 @@ -# SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -# SPDX-License-Identifier: BSD-2-Clause-Patent -# -# xoshiro256.py -# - -import sys -from trezorcrypto import sha256 - -from ur2.utils import string_to_bytes, int_to_bytes -from ur2.constants import MAX_UINT64 - -# Original Info: -# Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) - -# To the extent possible under law, the author has dedicated all copyright -# and related and neighboring rights to this software to the public domain -# worldwide. This software is distributed without any warranty. - -# See . - -# This is xoshiro256** 1.0, one of our all-purpose, rock-solid -# generators. It has excellent (sub-ns) speed, a state (256 bits) that is -# large enough for any parallel application, and it passes all tests we -# are aware of. - -# For generating just floating-point numbers, xoshiro256+ is even faster. - -# The state must be seeded so that it is not everywhere zero. If you have -# a 64-bit seed, we suggest to seed a splitmix64 generator and use its -# output to fill s. - - -def rotl(x, k): - return ((x << k) | (x >> (64 - k))) & MAX_UINT64 - - -JUMP = [0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, - 0xa9582618e03fc9aa, 0x39abdc4529b1661c] -LONG_JUMP = [0x76e15d3efefdcbbf, 0xc5004e441c522fb3, - 0x77710069854ee241, 0x39109bb02acbe635] - - -class Xoshiro256: - def __init__(self, arr=None): - self.s = [0] * 4 - if arr is not None: - self.s[0] = arr[0] - self.s[1] = arr[1] - self.s[2] = arr[2] - self.s[3] = arr[3] - - def _set_s(self, arr): - for i in range(4): - o = i * 8 - v = 0 - for n in range(8): - v <<= 8 - v |= (arr[o + n]) - self.s[i] = v - - def _hash_then_set_s(self, buf): - m = sha256() - m.update(buf) - digest = m.digest() - self._set_s(digest) - - @classmethod - def from_int8_array(cls, arr): - x = Xoshiro256() - x._set_s(arr) - return x - - @classmethod - def from_bytes(cls, buf): - x = Xoshiro256() - x._hash_then_set_s(buf) - return x - - @classmethod - def from_crc32(cls, crc32): - x = Xoshiro256() - buf = int_to_bytes(crc32) - x._hash_then_set_s(buf) - return x - - @classmethod - def from_string(cls, s): - x = Xoshiro256() - buf = string_to_bytes(s) - x._hash_then_set_s(buf) - return x - - def next(self): - result = (rotl((self.s[1] * 5) & MAX_UINT64, 7) * 9) & MAX_UINT64 - t = (self.s[1] << 17) & MAX_UINT64 - - self.s[2] ^= self.s[0] - self.s[3] ^= self.s[1] - self.s[1] ^= self.s[2] - self.s[0] ^= self.s[3] - - self.s[2] ^= t - - self.s[3] = rotl(self.s[3], 45) & MAX_UINT64 - - return result - - def next_double(self): - m = float(MAX_UINT64) + 1 - nxt = self.next() - return nxt / m - - def next_int(self, low, high): - return int(self.next_double() * (high - low + 1) + low) & MAX_UINT64 - - def next_byte(self): - return self.next_int(0, 255) - - def next_data(self, count): - result = bytearray() - for i in range(count): - result.append(self.next_byte()) - return result - - def jump(self): - global JUMP - - s0 = 0 - s1 = 0 - s2 = 0 - s3 = 0 - for i in range(len(JUMP)): - for b in range(64): - if JUMP[i] & (1 << b): - s0 ^= self.s[0] - s1 ^= self.s[1] - s2 ^= self.s[2] - s3 ^= self.s[3] - self.next() - - self.s[0] = s0 - self.s[1] = s1 - self.s[2] = s2 - self.s[3] = s3 - - def long_jump(self): - global LONG_JUMP - - s0 = 0 - s1 = 0 - s2 = 0 - s3 = 0 - for i in range(len(LONG_JUMP)): - for b in range(64): - if LONG_JUMP[i] & (1 << b): - s0 ^= self.s[0] - s1 ^= self.s[1] - s2 ^= self.s[2] - s3 ^= self.s[3] - self.next() - - self.s[0] = s0 - self.s[1] = s1 - self.s[2] = s2 - self.s[3] = s3 diff --git a/ports/stm32/boards/Passport/modules/views/qrcode.py b/ports/stm32/boards/Passport/modules/views/qrcode.py index dec3181ce..acbef763a 100644 --- a/ports/stm32/boards/Passport/modules/views/qrcode.py +++ b/ports/stm32/boards/Passport/modules/views/qrcode.py @@ -75,7 +75,7 @@ def get_version_for_data(self, encoded_data): for i in range(1, sram4.MAX_QR_VERSION + 1): if alphanumeric_capacity_by_version[i] >= enc_len: return i - raise QRCodeException() + raise QRCodeException("Cannot fit {} in a QR code ({} bytes)".format(encoded_data, len(encoded_data))) def update(self, encoded_data): if self.res is None: diff --git a/ports/stm32/boards/Passport/modules/wallets/casa.py b/ports/stm32/boards/Passport/modules/wallets/casa.py index 13c1bb732..1fd354fe3 100644 --- a/ports/stm32/boards/Passport/modules/wallets/casa.py +++ b/ports/stm32/boards/Passport/modules/wallets/casa.py @@ -9,11 +9,16 @@ import stash from utils import xfp2str from data_codecs.qr_type import QRType -from ur2.cbor_lite import CBOREncoder -from ur2.ur import UR +from foundation import ur -def create_casa_export(sw_wallet=None, addr_type=None, acct_num=0, multisig=False, legacy=False, export_mode='qr',): +def create_casa_export(sw_wallet=None, + addr_type=None, + acct_num=0, + multisig=False, + legacy=False, + export_mode='qr', + qr_type=QRType.UR2): # Get public details about wallet. # # simple text format: @@ -24,69 +29,22 @@ def create_casa_export(sw_wallet=None, addr_type=None, acct_num=0, multisig=Fals chain = chains.current_chain() - if export_mode == 'qr': - # crypto-hdkey spec: https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-007-hdkey.md - # - # Casa `crypto-hdkey` CDDL: - # { - # is-private: false, - # key-data: bytes, - # chain-code: bytes, - # use-info: { - # type: cointype-btc, - # network: testnet-btc - # }, - # origin: { - # source-fingerprint: uint32, - # depth: uint8 - # }, - # parent-fingerprint: uint32 - # } + if export_mode == 'qr' and qr_type == QRType.UR2: with stash.SensitiveValues() as sv: - # Encoder - encoder = CBOREncoder() is_mainnet = chain.ctype == 'BTC' - pk = sv.node.public_key() - cc = sv.node.chain_code() - - # Map size of 6 - encoder.encodeMapSize(6) - # Tag 2: is-private - encoder.encodeUnsigned(2) - encoder.encodeBool(False) - # Tag 3: key-data - encoder.encodeUnsigned(3) - encoder.encodeBytes(bytearray(pk)) - # Tag 4: chain-code - encoder.encodeUnsigned(4) - encoder.encodeBytes(bytearray(cc)) - # Tag 5 (305): use-info - encoder.encodeUnsigned(5) - encoder.encodeUndefined(305) - encoder.encodeMapSize(2) - # use-info Tag 1: type 0 = BTC - encoder.encodeUnsigned(1) - encoder.encodeUnsigned(0) - # use-info Tag 2: network 0 = Mainnet=0, Testnet=1 - encoder.encodeUnsigned(2) - encoder.encodeUnsigned(0 if is_mainnet else 1) - # Tag 6 (304): origin - encoder.encodeUnsigned(6) - encoder.encodeUndefined(304) - encoder.encodeMapSize(2) - # origin Tag 2: source-fingerprint - encoder.encodeUnsigned(2) - encoder.encodeUnsigned(int(xfp2str(settings.get('xfp')), 16)) - # origin Tag 3: depth = 0 (Always depth zero for Casa) - encoder.encodeUnsigned(3) - encoder.encodeUnsigned(0) - # Tag 8: parent-fingerprint - encoder.encodeUnsigned(8) - encoder.encodeUnsigned(0) - - import binascii - print('encoder.get_bytes() = {}'.format(binascii.hexlify(bytearray(encoder.get_bytes())))) - return (UR('crypto-hdkey', encoder.get_bytes()), None) + + network = ur.NETWORK_TESTNET if is_mainnet else ur.NETWORK_TESTNET + use_info = ur.CryptoCoinInfo(ur.CoinType.BTC, network) + origin = ur.CryptoKeypath(source_fingerprint=int(xfp2str(settings.get('xfp')), 16), + depth=0) + + crypto_hdkey = ur.new_derived_key(sv.node.public_key(), + is_private=False, + chain_code=sv.node.chain_code(), + use_info=use_info, + origin=origin) + + return (crypto_hdkey, None) else: with stash.SensitiveValues() as sv: s = '''\ diff --git a/ports/stm32/boards/Passport/modules/wallets/envoy.py b/ports/stm32/boards/Passport/modules/wallets/envoy.py index 078f8c47b..fbdad1a88 100644 --- a/ports/stm32/boards/Passport/modules/wallets/envoy.py +++ b/ports/stm32/boards/Passport/modules/wallets/envoy.py @@ -11,13 +11,20 @@ from utils import to_str, get_accounts from data_codecs.qr_type import QRType from public_constants import AF_CLASSIC, AF_P2WPKH +from foundation import ur # from .multisig_json import create_multisig_json_wallet # from .multisig_import import read_multisig_config_from_qr, read_multisig_config_from_microsd from .utils import get_bip_num_from_addr_type -def create_envoy_export(sw_wallet=None, addr_type=None, acct_num=0, multisig=False, legacy=False, export_mode='qr'): +def create_envoy_export(sw_wallet=None, + addr_type=None, + acct_num=0, + multisig=False, + legacy=False, + export_mode='qr', + qr_type=QRType.UR2): # Generate line-by-line JSON details about wallet. # # Adapted from Electrum format, but simplified for Envoy use @@ -73,7 +80,7 @@ def create_envoy_export(sw_wallet=None, addr_type=None, acct_num=0, multisig=Fal msg = ujson.dumps(rv) # print('msg={}'.format(to_str(msg))) - return (msg, accts) + return (ur.new_bytes(msg), accts) EnvoyWallet = { diff --git a/ports/stm32/boards/Passport/modules/wallets/generic_json_wallet.py b/ports/stm32/boards/Passport/modules/wallets/generic_json_wallet.py index ec7fe4c76..f6bfc2943 100644 --- a/ports/stm32/boards/Passport/modules/wallets/generic_json_wallet.py +++ b/ports/stm32/boards/Passport/modules/wallets/generic_json_wallet.py @@ -16,6 +16,8 @@ from utils import xfp2str, to_str from common import settings from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH, AF_P2WSH_P2SH, AF_P2WSH +from data_codecs.qr_type import QRType +from foundation import ur def create_generic_json_wallet(sw_wallet=None, @@ -23,7 +25,8 @@ def create_generic_json_wallet(sw_wallet=None, acct_num=0, multisig=False, legacy=False, - export_mode='qr'): + export_mode='qr', + qr_type=QRType.UR2): # Generate data that other programers will use to import from (single-signer) chain = chains.current_chain() @@ -65,4 +68,8 @@ def create_generic_json_wallet(sw_wallet=None, rv[name]['_pub'] = zp msg = ujson.dumps(rv) + + if export_mode == 'qr' and qr_type == QRType.UR2: + return (ur.new_bytes(msg), accts) + return (msg, accts) diff --git a/ports/stm32/boards/Passport/modules/wallets/multisig_import.py b/ports/stm32/boards/Passport/modules/wallets/multisig_import.py index da2c5fa13..355acebfa 100644 --- a/ports/stm32/boards/Passport/modules/wallets/multisig_import.py +++ b/ports/stm32/boards/Passport/modules/wallets/multisig_import.py @@ -16,7 +16,7 @@ async def read_multisig_config_from_qr(): from pages import ScanQRPage - return await ScanQRPage(decode_cbor_bytes=True).show() + return await ScanQRPage().show() async def read_multisig_config_from_microsd(): diff --git a/ports/stm32/boards/Passport/mpconfigboard.mk b/ports/stm32/boards/Passport/mpconfigboard.mk index d527308c9..42b125b8b 100644 --- a/ports/stm32/boards/Passport/mpconfigboard.mk +++ b/ports/stm32/boards/Passport/mpconfigboard.mk @@ -93,3 +93,5 @@ ifeq ($(SCREEN_MODE), COLOR) lcd-st7789.c st7789.c) CFLAGS += -DSCREEN_MODE_COLOR=1 endif + +RUST_TARGET := thumbv7em-none-eabihf diff --git a/ports/stm32/boards/Passport/passport.ld b/ports/stm32/boards/Passport/passport.ld index 01a9944aa..d70f134a4 100644 --- a/ports/stm32/boards/Passport/passport.ld +++ b/ports/stm32/boards/Passport/passport.ld @@ -11,7 +11,7 @@ MEMORY FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K FLASH_ISR (rx) : ORIGIN = BL_FW_BASE, LENGTH = FLASH_ISR_SIZE FLASH_TEXT (rx) : ORIGIN = BL_FW_BASE + FLASH_ISR_SIZE, LENGTH = FLASH_TEXT_SIZE - DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Used for storage cache */ + DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM */ RAM_D2 (rw) : ORIGIN = 0x30000000, LENGTH = 288K /* D2 SRAM (128K + 128 + 32K) */ SRAM4 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K @@ -41,6 +41,10 @@ SECTIONS KEEP(*(.dma_buffers)) } >RAM_D2 + .dtcm (NOLOAD) : { + KEEP(*(.dtcm)) + } >DTCM + .sram4 (NOLOAD) : { KEEP(*(.sram4)) } >SRAM4 diff --git a/py/mkrules.mk b/py/mkrules.mk index 1859a6569..60c63ae37 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -179,7 +179,7 @@ ifneq ($(PROG),) # Build a standalone executable (unix does this) all: $(PROG) -$(PROG): $(OBJ) +$(PROG): $(OBJ) $(FOUNDATION_RUST_LIB) $(ECHO) "LINK $@" # Do not pass COPT here - it's *C* compiler optimizations. For example, # we may want to compile using Thumb, but link with non-Thumb libc. diff --git a/py/py.mk b/py/py.mk index b85939aea..6fb46815b 100644 --- a/py/py.mk +++ b/py/py.mk @@ -134,6 +134,36 @@ endif ifeq ($(SCREEN_MODE),MONO) SRC_MOD += $(sort $(subst $(TOP)/,,$(shell find $(TOP)/ports/stm32/boards/Passport/images/mono -type f -name "*.c"))) endif + + +ifeq ($(RUST_TARGET),) + UNAME_M ?= $(shell uname -m) + + ifeq ($(UNAME_M),x86_64) + RUST_ARCH ?= x86_64 + else ifeq ($(UNAME_M),arm) + RUST_ARCH ?= arm + else ifeq ($(UNAME_M),arm64) + RUST_ARCH ?= aarch64 + endif + + RUST_TARGET ?= $(RUST_ARCH)-unknown-none +endif + +FOUNDATION_RUST ?= $(TOP)/extmod/foundation-rust +FOUNDATION_RUST_SRC ?= $(wildcard $(FOUNDATION_RUST)/src/*.rs) \ + $(FOUNDATION_RUST)/Cargo.lock \ + $(FOUNDATION_RUST)/Cargo.toml \ + $(FOUNDATION_RUST)/cbindgen.toml + +FOUNDATION_RUST_LIB ?= $(FOUNDATION_RUST)/target/$(RUST_TARGET)/release/libfoundation.a + +CFLAGS_MOD += -I$(FOUNDATION_RUST)/include +LDFLAGS_MOD += -L$(shell dirname $(FOUNDATION_RUST_LIB)) -lfoundation + +$(FOUNDATION_RUST_LIB): $(FOUNDATION_RUST_SRC) + $(ECHO) "CARGO foundation-rust" + @cargo build --manifest-path $(FOUNDATION_RUST)/Cargo.toml --target $(RUST_TARGET) --release # FOUNDATION CHANGE: END From 518d23f647a660b8734ae9f2828214e7dbaee44b Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sat, 18 Feb 2023 00:13:46 +0100 Subject: [PATCH 085/156] SFT-1062: Fix CI matrix Signed-off-by: Jean-Pierre De Jesus DIAZ --- .github/workflows/validate_and_build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate_and_build.yaml b/.github/workflows/validate_and_build.yaml index d7525a537..68a02aeae 100644 --- a/.github/workflows/validate_and_build.yaml +++ b/.github/workflows/validate_and_build.yaml @@ -68,7 +68,7 @@ jobs: - uses: extractions/setup-just@aa5d15c144db4585980a44ebfdd2cf337c4f14cb - run: | echo "DOCKER_IMAGE=localhost:5000/foundation-devices/passport2:latest" >> $GITHUB_ENV - echo "SCREEN_MODE=$(echo "color" | tr a-z A-Z)" >> $GITHUB_ENV + echo "SCREEN_MODE=$(echo "${{ matrix.screen }}" | tr a-z A-Z)" >> $GITHUB_ENV - name: Build run: | @@ -124,7 +124,7 @@ jobs: - uses: extractions/setup-just@aa5d15c144db4585980a44ebfdd2cf337c4f14cb - run: | echo "DOCKER_IMAGE=localhost:5000/foundation-devices/passport2:latest" >> $GITHUB_ENV - echo "SCREEN_MODE=$(echo "color" | tr a-z A-Z)" >> $GITHUB_ENV + echo "SCREEN_MODE=$(echo ${{ matrix.screen }} | tr a-z A-Z)" >> $GITHUB_ENV - name: Build run: just build-bootloader ${{ matrix.screen }} From 7f02f7c98fadf8c99533428d272afc7535d0389f Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 14:19:28 +0100 Subject: [PATCH 086/156] SFT-1248: Fix Rust tests Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/src/ur/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extmod/foundation-rust/src/ur/mod.rs b/extmod/foundation-rust/src/ur/mod.rs index 84ab27ac2..df3e1c9ac 100644 --- a/extmod/foundation-rust/src/ur/mod.rs +++ b/extmod/foundation-rust/src/ur/mod.rs @@ -96,7 +96,9 @@ pub mod tests { (x & (x - 1)) == 0 } - assert!(is_power_of_2(UR_MAX_SEQUENCE_COUNT)); - assert!(max_fragment_len() > 0); + assert!(is_power_of_2(decoder::UR_DECODER_MAX_SEQUENCE_COUNT)); + assert!(is_power_of_2(encoder::UR_ENCODER_MAX_SEQUENCE_COUNT)); + assert!(max_fragment_len(decoder::UR_DECODER_MAX_STRING) > 0); + assert!(max_fragment_len(encoder::UR_ENCODER_MAX_STRING) > 0); } } From cede3e3c4a11f31f9cead0f48d01d01659c1adb0 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 14:08:02 +0100 Subject: [PATCH 087/156] SFT-1248: Check for Rust code tests Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/Justfile | 1 + 1 file changed, 1 insertion(+) diff --git a/extmod/foundation-rust/Justfile b/extmod/foundation-rust/Justfile index a4e342d67..c5d7bbe2e 100644 --- a/extmod/foundation-rust/Justfile +++ b/extmod/foundation-rust/Justfile @@ -23,6 +23,7 @@ lint: --crate foundation \ --output include/foundation.h \ --verify + cargo test --features std # Print size information sizes: From 0b18064cb2c8c6462055b11983a02f2690c1838d Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 14:30:44 +0100 Subject: [PATCH 088/156] SFT-1250: Set correct compile flags for UR Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/Passport/mpconfigboard.mk b/ports/stm32/boards/Passport/mpconfigboard.mk index 42b125b8b..1d275318d 100644 --- a/ports/stm32/boards/Passport/mpconfigboard.mk +++ b/ports/stm32/boards/Passport/mpconfigboard.mk @@ -95,3 +95,4 @@ ifeq ($(SCREEN_MODE), COLOR) endif RUST_TARGET := thumbv7em-none-eabihf +export RUSTFLAGS := --cfg dtcm --cfg sram4 From e2a479bee0fba35b994f3bd32e7452ac1543774d Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 14:53:48 +0100 Subject: [PATCH 089/156] SFT-1251: Make on_result async Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../stm32/boards/Passport/modules/pages/insert_microsd_page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/pages/insert_microsd_page.py b/ports/stm32/boards/Passport/modules/pages/insert_microsd_page.py index 393a29828..0d03e33d3 100644 --- a/ports/stm32/boards/Passport/modules/pages/insert_microsd_page.py +++ b/ports/stm32/boards/Passport/modules/pages/insert_microsd_page.py @@ -37,7 +37,7 @@ def on_sd_card_change(sd_card_present): return sd_card_present - def on_result(res): + async def on_result(res): nonlocal result result = res return True From 618521de124623cb9bc3f54b822c641cd209a3d4 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 14:57:53 +0100 Subject: [PATCH 090/156] SFT-1252: Remove reverted change from change log Signed-off-by: Jean-Pierre De Jesus DIAZ --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b337fed74..3873ab31e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,6 @@ SPDX-License-Identifier: GPL-3.0-or-later - Added Casa health check via SD card (PASS1-595) - Added multisig config export via QR and SD card (PASS1-631) - Fixed multisig config descriptions (PASS1-643) -- Erase PSBTs from external flash after signing (PASS1-345) [UR1]: https://github.com/CoboVault/Research/blob/master/papers/bcr-0005-ur.md From d3a425069f36dfced5b16735618576b8c61e3337 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 14:59:50 +0100 Subject: [PATCH 091/156] SFT-1252: Include UR in change log Signed-off-by: Jean-Pierre De Jesus DIAZ --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3873ab31e..27f458d49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ SPDX-License-Identifier: GPL-3.0-or-later - Added Casa health check via SD card (PASS1-595) - Added multisig config export via QR and SD card (PASS1-631) - Fixed multisig config descriptions (PASS1-643) +- Improved the UR animated QR codes encoder and decoder to allow signing +bigger transactions. (SFT-1063) [UR1]: https://github.com/CoboVault/Research/blob/master/papers/bcr-0005-ur.md From 8e8ef1fe07c87acf4f12420c28dd89895ce532b5 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 20:15:51 +0100 Subject: [PATCH 092/156] SFT-1257: Update DEVELOPMENT.md Signed-off-by: Jean-Pierre De Jesus DIAZ --- DEVELOPMENT.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 735f2f1cd..817f29111 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -28,6 +28,14 @@ to install to a different folder, and just update command paths appropriately. ### Install Dependencies Several tools are required for building Passport. +#### Install Rust Toolchain + + rustup default 1.67.1 + rustup target add aarch64-unknown-none # For the simulator. Only if on macOS with an M1 CPU. + rustup target add thumbv7em-none-eabihf + rustup target add x86_64-unknown-none + cargo install cbindgen + #### Cross-Compiler Toolchain The cross compiler enables your PC to build code for the STM32H753 MCU used by Passport. Use the following commands to install and build the cross compiler and MicroPython tools. From 36c3a4fab89f966d380bc8e1c0a4b77445475c33 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 20:23:07 +0100 Subject: [PATCH 093/156] SFT-1258: Clean Rust target Signed-off-by: Jean-Pierre De Jesus DIAZ --- py/mkrules.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/py/mkrules.mk b/py/mkrules.mk index 60c63ae37..29a3e32b3 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -217,6 +217,7 @@ lib $(LIBMICROPYTHON): $(OBJ) clean: $(RM) -rf $(BUILD) $(CLEAN_EXTRA) + cargo clean --manifest-path $(FOUNDATION_RUST)/Cargo.toml .PHONY: clean # Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup. From ab6492bf7020253c5bba43611f532801f906c9f3 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 20:34:54 +0100 Subject: [PATCH 094/156] SFT-1254: Fix multisig wallet export Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/wallets/multisig_json.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/wallets/multisig_json.py b/ports/stm32/boards/Passport/modules/wallets/multisig_json.py index f842d116f..25b274413 100644 --- a/ports/stm32/boards/Passport/modules/wallets/multisig_json.py +++ b/ports/stm32/boards/Passport/modules/wallets/multisig_json.py @@ -16,6 +16,8 @@ from utils import xfp2str from common import settings from public_constants import AF_P2SH, AF_P2WSH, AF_P2WSH_P2SH +from data_codecs.qr_type import QRType +from foundation import ur def create_multisig_json_wallet(sw_wallet=None, @@ -23,7 +25,8 @@ def create_multisig_json_wallet(sw_wallet=None, acct_num=0, multisig=False, legacy=False, - export_mode='qr'): + export_mode='qr', + qr_type=QRType.UR2): fp = uio.StringIO() chain = chains.current_chain() @@ -50,5 +53,8 @@ def create_multisig_json_wallet(sw_wallet=None, xfp = xfp2str(settings.get('xfp', 0)) fp.write(' "xfp": "%s"\n}\n' % xfp) result = fp.getvalue() - # print('xpub json = {}'.format(result)) + + if export_mode == 'qr' and qr_type == QRType.UR2: + return (ur.new_bytes(result), accts) + return (result, accts) From a9f950a0d002733fac6e06039fe2ffaf2c7208b8 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 20:38:40 +0100 Subject: [PATCH 095/156] SFT-1254: Fix other wallets exports Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../stm32/boards/Passport/modules/wallets/bitcoin_core.py | 3 ++- ports/stm32/boards/Passport/modules/wallets/electrum.py | 8 +++++++- ports/stm32/boards/Passport/modules/wallets/wasabi.py | 8 +++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py b/ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py index 85c4a80a2..c571ac045 100644 --- a/ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py +++ b/ports/stm32/boards/Passport/modules/wallets/bitcoin_core.py @@ -22,7 +22,8 @@ def create_bitcoin_core_export(sw_wallet=None, acct_num=0, multisig=False, legacy=False, - export_mode='qr'): + export_mode='qr', + qr_type=None): import ustruct xfp = xfp2str(settings.get('xfp')) diff --git a/ports/stm32/boards/Passport/modules/wallets/electrum.py b/ports/stm32/boards/Passport/modules/wallets/electrum.py index 42ee01f9d..a85d7ab88 100644 --- a/ports/stm32/boards/Passport/modules/wallets/electrum.py +++ b/ports/stm32/boards/Passport/modules/wallets/electrum.py @@ -20,7 +20,13 @@ from .utils import get_bip_num_from_addr_type -def create_electrum_export(sw_wallet=None, addr_type=None, acct_num=0, multisig=False, legacy=False, export_mode='qr'): +def create_electrum_export(sw_wallet=None, + addr_type=None, + acct_num=0, + multisig=False, + legacy=False, + export_mode='qr', + qr_type=None): # Generate line-by-line JSON details about wallet. # # Much reverse engineering of Electrum here. It's a complex legacy file format. diff --git a/ports/stm32/boards/Passport/modules/wallets/wasabi.py b/ports/stm32/boards/Passport/modules/wallets/wasabi.py index b363f4e5c..d5e268cb5 100644 --- a/ports/stm32/boards/Passport/modules/wallets/wasabi.py +++ b/ports/stm32/boards/Passport/modules/wallets/wasabi.py @@ -18,7 +18,13 @@ from common import settings, system -def create_wasabi_export(sw_wallet=None, addr_type=None, acct_num=0, multisig=False, legacy=False, export_mode='qr'): +def create_wasabi_export(sw_wallet=None, + addr_type=None, + acct_num=0, + multisig=False, + legacy=False, + export_mode='qr', + qr_type=None): # Generate the data for a JSON file which Wasabi can open directly as a new wallet. chain = chains.current_chain() From b6e951bdd75ceff7dfdca4e82f9f804b560b18db Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Sun, 19 Feb 2023 20:51:59 +0100 Subject: [PATCH 096/156] SFT-1255: Fix multisig config export Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/flows/export_multisig_qr_flow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py index 859932925..9b00b8906 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_qr_flow.py @@ -4,6 +4,7 @@ # export_multisig_qr_flow.py - Export a multisig wallet via QR code from flows import Flow +from foundation import ur class ExportMultisigQRFlow(Flow): @@ -20,5 +21,5 @@ async def show_qr_code(self): from data_codecs.qr_type import QRType from multisig_wallet import MultisigWallet - await ShowQRPage(qr_type=QRType.UR2, qr_data=self.ms_text).show() + await ShowQRPage(qr_type=QRType.UR2, qr_data=ur.new_bytes(self.ms_text)).show() self.set_result(True) From 05a54b468c76e5bb2d3af1e5a8a7b62c6958e5a1 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 16 Feb 2023 17:13:02 -0600 Subject: [PATCH 097/156] SFT-928: added return after self.back() when backing out of verify address QR scan --- ports/stm32/boards/Passport/modules/flows/verify_address_flow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py b/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py index da8bc6f38..e9451e210 100644 --- a/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/verify_address_flow.py @@ -79,6 +79,7 @@ async def scan_address(self): if not self.back(): self.set_result(False) return + return elif result.is_failure(): await ErrorPage(text='Unable to scan QR code.').show() self.set_result(False) From fa45ec89772bf79a5cae3363c1a06df2a6281f87 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 20 Feb 2023 13:04:13 +0100 Subject: [PATCH 098/156] SFT-1259: Use only UR2 as QR type Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/flows/casa_health_check_qr_flow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index b6e3c0e0a..33c72f4c7 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -9,6 +9,7 @@ from utils import validate_sign_text, spinner_task from tasks import sign_text_file_task from public_constants import AF_CLASSIC, RFC_SIGNATURE_TEMPLATE +from data_codecs.qr_type import QRType class CasaHealthCheckQRFlow(Flow): @@ -57,7 +58,6 @@ async def scan_qr(self): self.subpath = subpath - self.qr_type = result.qr_type self.goto(self.sign_health_check) async def sign_health_check(self): @@ -74,7 +74,6 @@ async def sign_health_check(self): async def show_signed_message(self): from ubinascii import b2a_base64 - from data_codecs.qr_type import QRType sig = b2a_base64(self.signature).decode('ascii').strip() From 135e50c0fcc3a0d154ea462fd5fdfbffe6a08fd9 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 20 Feb 2023 13:04:56 +0100 Subject: [PATCH 099/156] SFT-1259: Fix Casa Health Check QR flow Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../modules/flows/casa_health_check_qr_flow.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index 33c72f4c7..7d7e29ca5 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -10,6 +10,7 @@ from tasks import sign_text_file_task from public_constants import AF_CLASSIC, RFC_SIGNATURE_TEMPLATE from data_codecs.qr_type import QRType +from foundation import ur class CasaHealthCheckQRFlow(Flow): @@ -29,12 +30,17 @@ async def scan_qr(self): else: # Got a scan result (aka QRScanResult). if result.is_failure(): - await ErrorPage(text='Unable to scan QR code.'.show()) + await ErrorPage(text='Unable to scan QR code.\n\n{}'.format(result.error)).show() self.set_result(False) else: - # print('result.data={}'.format(result.data)) + if not isinstance(result.data, ur.Value): + await ErrorPage(text='Unable to scan QR code.\n\nNot an Uniform Resource.').show() + self.set_result(False) + return + try: - self.lines = result.data.decode('utf-8').split('\n') + data = result.data.unwrap_bytes() + self.lines = data.decode('utf-8').split('\n') except Exception as e: await ErrorPage('Health check format is invalid.').show() return From 32e44e344ef8610b6f96e921a71c30616c9fea6e Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 20 Feb 2023 13:15:51 +0100 Subject: [PATCH 100/156] SFT-1260: Remove double allocation Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../modules/flows/casa_health_check_microsd_flow.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py index 495735428..57ce8e5ef 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py @@ -4,16 +4,17 @@ # casa_health_check_flow.py - Scan and process a Casa health check QR code in `crypto-request` format from flows import Flow +from files import CardSlot, CardMissingError +from pages.insert_microsd_page import InsertMicroSDPage def is_health_check(filename): - from files import CardSlot + filename = filename.lower() - # print('filenmame={}'.format(filename)) - if '-signed' in filename.lower(): + if '-signed' in filename: return False - if '-hc' in filename.lower(): + if '-hc' in filename: return True return False From 8ac414e017d9865317ad7bfc66b688176cfc7b79 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 20 Feb 2023 13:16:32 +0100 Subject: [PATCH 101/156] SFT-1260: Fix Casa Health Check via microSD Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../flows/casa_health_check_microsd_flow.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py index 57ce8e5ef..ff4920d7e 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py @@ -47,14 +47,21 @@ async def parse_message(self): from files import CardSlot from pages import ErrorPage - with open(self.file_path, 'r') as fd: - try: - self.lines = fd.read().split('\n') - except Exception as e: - await ErrorPage(text='Health check format is invalid.').show() - self.set_result(False) - return - self.goto(self.common_flow) + try: + with CardSlot() as _card: + with open(self.file_path, 'r') as fd: + try: + self.lines = fd.read().split('\n') + except Exception as e: + await ErrorPage(text='Health check format is invalid.').show() + self.set_result(False) + return + + self.goto(self.common_flow) + except CardMissingError: + result = await InsertMicroSDPage().show() + if not result: + self.back() async def common_flow(self): from flows import CasaHealthCheckCommonFlow From d799b30f7735fa3a322a0bdad54748a65eef4c2a Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 20 Feb 2023 13:39:10 +0100 Subject: [PATCH 102/156] SFT-1262: Handle memory errors after signing Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../modules/flows/sign_psbt_qr_flow.py | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index 0dde204f7..d42d4f156 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -5,6 +5,7 @@ from flows import Flow from foundation import ur +from pages import ErrorPage class SignPsbtQRFlow(Flow): @@ -96,15 +97,20 @@ async def show_signed_transaction(self): import microns # Copy signed txn into a bytearray and show the data as a UR - signed_bytes = None - with BytesIO() as bfd: - with self.output_encoder(bfd) as fd: - # Always serialize back to PSBT for QR codes - self.psbt.serialize(fd) - bfd.seek(0) - signed_bytes = bfd.read() - # print('len(signed_bytes)={}'.format(len(signed_bytes))) - # print('signed_bytes={}'.format(signed_bytes)) + try: + signed_bytes = None + with BytesIO() as bfd: + with self.output_encoder(bfd) as fd: + # Always serialize back to PSBT for QR codes + self.psbt.serialize(fd) + bfd.seek(0) + signed_bytes = bfd.read() + # print('len(signed_bytes)={}'.format(len(signed_bytes))) + # print('signed_bytes={}'.format(signed_bytes)) + except MemoryError as e: + await ErrorPage(text='Transaction is too complex: {}'.format(e)).show() + self.set_result(False) + return gc.collect() From 52442ad79b048c7553aef6d25f641778ec22ab3c Mon Sep 17 00:00:00 2001 From: Ken Carpenter <62639971+FoundationKen@users.noreply.github.com> Date: Mon, 20 Feb 2023 08:09:07 -0800 Subject: [PATCH 103/156] Update casa_health_check_qr_flow.py --- .../boards/Passport/modules/flows/casa_health_check_qr_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index 7d7e29ca5..edb044d7c 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -34,7 +34,7 @@ async def scan_qr(self): self.set_result(False) else: if not isinstance(result.data, ur.Value): - await ErrorPage(text='Unable to scan QR code.\n\nNot an Uniform Resource.').show() + await ErrorPage(text='Unable to scan QR code.\n\nNot a Uniform Resource.').show() self.set_result(False) return From 6a2b49561feb3f12d761ee72bedb58dc768db4fc Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 21 Feb 2023 16:03:17 +0100 Subject: [PATCH 104/156] SFT-1263: Rename modpassport-sram4 Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modpassport-mem.h | 105 ++++++++++++++++++ .../stm32/boards/Passport/modpassport-sram4.h | 105 ------------------ ports/stm32/boards/Passport/modpassport.c | 4 +- .../boards/Passport/modules/ext_settings.py | 6 +- ports/stm32/boards/Passport/modules/psbt.py | 6 +- .../copy_psbt_file_to_external_flash_task.py | 4 +- .../tasks/copy_psbt_to_external_flash_task.py | 10 +- .../boards/Passport/modules/views/qrcode.py | 10 +- .../sim_modules/passport/{sram4.py => mem.py} | 0 9 files changed, 125 insertions(+), 125 deletions(-) create mode 100644 ports/stm32/boards/Passport/modpassport-mem.h delete mode 100644 ports/stm32/boards/Passport/modpassport-sram4.h rename simulator/sim_modules/passport/{sram4.py => mem.py} (100%) diff --git a/ports/stm32/boards/Passport/modpassport-mem.h b/ports/stm32/boards/Passport/modpassport-mem.h new file mode 100644 index 000000000..35a270914 --- /dev/null +++ b/ports/stm32/boards/Passport/modpassport-mem.h @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "py/obj.h" +#include "py/objarray.h" + +#include "../../../../lib/lv_bindings/lvgl/lvgl.h" + +#include "framebuffer.h" + +/** + * @brief Passport maximum supported QR version that can be rendered. + * + * @note Keep in sync with modfoundation.c QRCode class. + */ +#define PASSPORT_MAX_QR_VERSION (13) + +/** + * @brief Attribute used to allocate a static variable in the + * SRAM4 section. + */ +#define MP_SRAM4 __attribute__((section(".sram4"))) + +/** + * @brief Create a compile-time bytearray by reference. + * + * Same behaviour as `mp_obj_new_bytearray_by_ref` (bytearray_at in Python side) + * but statically allocated. + * + * @param obj The object name. + * @param ptr The pointer to the data. + * @param len The length of the data. + */ +#define MP_OBJ_BYTEARRAY_BY_REF(obj, ptr, ptr_len) \ + mp_obj_array_t obj = { \ + .base = {&mp_type_bytearray}, \ + .typecode = BYTEARRAY_TYPECODE, \ + .free = 0, \ + .len = ptr_len, \ + .items = ptr, \ + } + +/// package: passport.mem + +/// ext_settings_buf: bytearray +STATIC MP_SRAM4 uint8_t mod_passport_mem_ext_settings_buf[16 * 1024]; +STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_mem_ext_settings_buf_obj, + mod_passport_mem_ext_settings_buf, + sizeof(mod_passport_mem_ext_settings_buf)); + +/// tmp_buf: bytearray +STATIC MP_SRAM4 uint8_t mod_passport_mem_tmp_buf[1024]; +STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_mem_tmp_buf_obj, + mod_passport_mem_tmp_buf, + sizeof(mod_passport_mem_tmp_buf)); +/// psbt_tmp256: bytearray +STATIC MP_SRAM4 uint8_t mod_passport_mem_psbt_tmp256[256]; +STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_mem_psbt_tmp256_obj, + mod_passport_mem_psbt_tmp256, + sizeof(mod_passport_mem_psbt_tmp256)); + +/// qrcode_buffer: bytearray +STATIC MP_SRAM4 uint8_t mod_passport_mem_qrcode_buffer[LV_QRCODE_IMG_BUF_SIZE(LCD_HOR_RES)]; +STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_mem_passport_qrcode_buffer_obj, + mod_passport_mem_qrcode_buffer, + sizeof(mod_passport_mem_qrcode_buffer)); + +/// qrcode_modules_buffer: bytearray +STATIC MP_SRAM4 uint8_t mod_passport_mem_qrcode_modules_buffer[LV_QRCODE_MODULES_BUF_SIZE(PASSPORT_MAX_QR_VERSION)]; +STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_mem_qrcode_modules_buffer_obj, + mod_passport_mem_qrcode_modules_buffer, + sizeof(mod_passport_mem_qrcode_modules_buffer)); + +/// def qrcode_buffer_clear() -> None: +/// """ +/// Clear the QR code buffer +/// +/// Sets all bytes to 0, except the color palette which is at the start of the buffer (4 * 2 bytes). +/// """ +STATIC mp_obj_t mod_passport_mem_qrcode_buffer_clear(void) +{ + memset(mod_passport_mem_qrcode_buffer + (4 * 2), 0, sizeof(mod_passport_mem_qrcode_buffer) - (4 * 2)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_passport_mem_qrcode_buffer_clear_obj, + mod_passport_mem_qrcode_buffer_clear); + +STATIC const mp_rom_map_elem_t mod_passport_mem_globals_table[] = { + {MP_ROM_QSTR(MP_QSTR_MAX_QR_VERSION), MP_ROM_INT(PASSPORT_MAX_QR_VERSION)}, + {MP_ROM_QSTR(MP_QSTR_ext_settings_buf), MP_ROM_PTR(&mod_passport_mem_ext_settings_buf_obj)}, + {MP_ROM_QSTR(MP_QSTR_tmp_buf), MP_ROM_PTR(&mod_passport_mem_tmp_buf_obj)}, + {MP_ROM_QSTR(MP_QSTR_psbt_tmp256), MP_ROM_PTR(&mod_passport_mem_psbt_tmp256_obj)}, + {MP_ROM_QSTR(MP_QSTR_qrcode_buffer), MP_ROM_PTR(&mod_passport_mem_passport_qrcode_buffer_obj)}, + {MP_ROM_QSTR(MP_QSTR_qrcode_modules_buffer), MP_ROM_PTR(&mod_passport_mem_qrcode_modules_buffer_obj)}, + {MP_ROM_QSTR(MP_QSTR_qrcode_buffer_clear), MP_ROM_PTR(&mod_passport_mem_qrcode_buffer_clear_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(mod_passport_mem_globals, mod_passport_mem_globals_table); + +STATIC const mp_obj_module_t mod_passport_mem_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t*)&mod_passport_mem_globals, +}; diff --git a/ports/stm32/boards/Passport/modpassport-sram4.h b/ports/stm32/boards/Passport/modpassport-sram4.h deleted file mode 100644 index fb07f6f84..000000000 --- a/ports/stm32/boards/Passport/modpassport-sram4.h +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-FileCopyrightText: © 2020 Foundation Devices, Inc. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include - -#include "py/obj.h" -#include "py/objarray.h" - -#include "../../../../lib/lv_bindings/lvgl/lvgl.h" - -#include "framebuffer.h" - -/** - * @brief Passport maximum supported QR version that can be rendered. - * - * @note Keep in sync with modfoundation.c QRCode class. - */ -#define PASSPORT_MAX_QR_VERSION (13) - -/** - * @brief Attribute used to allocate a static variable in the - * SRAM4 section. - */ -#define MP_SRAM4 __attribute__((section(".sram4"))) - -/** - * @brief Create a compile-time bytearray by reference. - * - * Same behaviour as `mp_obj_new_bytearray_by_ref` (bytearray_at in Python side) - * but statically allocated. - * - * @param obj The object name. - * @param ptr The pointer to the data. - * @param len The length of the data. - */ -#define MP_OBJ_BYTEARRAY_BY_REF(obj, ptr, ptr_len) \ - mp_obj_array_t obj = { \ - .base = {&mp_type_bytearray}, \ - .typecode = BYTEARRAY_TYPECODE, \ - .free = 0, \ - .len = ptr_len, \ - .items = ptr, \ - } - -/// package: passport.sram4 - -/// ext_settings_buf: bytearray -STATIC MP_SRAM4 uint8_t mod_passport_sram4_ext_settings_buf[16 * 1024]; -STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_sram4_ext_settings_buf_obj, - mod_passport_sram4_ext_settings_buf, - sizeof(mod_passport_sram4_ext_settings_buf)); - -/// tmp_buf: bytearray -STATIC MP_SRAM4 uint8_t mod_passport_sram4_tmp_buf[1024]; -STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_sram4_tmp_buf_obj, - mod_passport_sram4_tmp_buf, - sizeof(mod_passport_sram4_tmp_buf)); -/// psbt_tmp256: bytearray -STATIC MP_SRAM4 uint8_t mod_passport_psbt_tmp256[256]; -STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_sram4_psbt_tmp256_obj, - mod_passport_psbt_tmp256, - sizeof(mod_passport_psbt_tmp256)); - -/// qrcode_buffer: bytearray -STATIC MP_SRAM4 uint8_t mod_passport_sram4_qrcode_buffer[LV_QRCODE_IMG_BUF_SIZE(LCD_HOR_RES)]; -STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_sram4_passport_qrcode_buffer_obj, - mod_passport_sram4_qrcode_buffer, - sizeof(mod_passport_sram4_qrcode_buffer)); - -/// qrcode_modules_buffer: bytearray -STATIC MP_SRAM4 uint8_t mod_passport_sram4_qrcode_modules_buffer[LV_QRCODE_MODULES_BUF_SIZE(PASSPORT_MAX_QR_VERSION)]; -STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_sram4_qrcode_modules_buffer_obj, - mod_passport_sram4_qrcode_modules_buffer, - sizeof(mod_passport_sram4_qrcode_modules_buffer)); - -/// def qrcode_buffer_clear() -> None: -/// """ -/// Clear the QR code buffer -/// -/// Sets all bytes to 0, except the color palette which is at the start of the buffer (4 * 2 bytes). -/// """ -STATIC mp_obj_t mod_passport_sram4_qrcode_buffer_clear(void) -{ - memset(mod_passport_sram4_qrcode_buffer + (4 * 2), 0, sizeof(mod_passport_sram4_qrcode_buffer) - (4 * 2)); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_passport_sram4_qrcode_buffer_clear_obj, - mod_passport_sram4_qrcode_buffer_clear); - -STATIC const mp_rom_map_elem_t mod_passport_sram4_globals_table[] = { - {MP_ROM_QSTR(MP_QSTR_MAX_QR_VERSION), MP_ROM_INT(PASSPORT_MAX_QR_VERSION)}, - {MP_ROM_QSTR(MP_QSTR_ext_settings_buf), MP_ROM_PTR(&mod_passport_sram4_ext_settings_buf_obj)}, - {MP_ROM_QSTR(MP_QSTR_tmp_buf), MP_ROM_PTR(&mod_passport_sram4_tmp_buf_obj)}, - {MP_ROM_QSTR(MP_QSTR_psbt_tmp256), MP_ROM_PTR(&mod_passport_sram4_psbt_tmp256_obj)}, - {MP_ROM_QSTR(MP_QSTR_qrcode_buffer), MP_ROM_PTR(&mod_passport_sram4_passport_qrcode_buffer_obj)}, - {MP_ROM_QSTR(MP_QSTR_qrcode_modules_buffer), MP_ROM_PTR(&mod_passport_sram4_qrcode_modules_buffer_obj)}, - {MP_ROM_QSTR(MP_QSTR_qrcode_buffer_clear), MP_ROM_PTR(&mod_passport_sram4_qrcode_buffer_clear_obj)}, -}; -STATIC MP_DEFINE_CONST_DICT(mod_passport_sram4_globals, mod_passport_sram4_globals_table); - -STATIC const mp_obj_module_t mod_passport_sram4_module = { - .base = {&mp_type_module}, - .globals = (mp_obj_dict_t*)&mod_passport_sram4_globals, -}; diff --git a/ports/stm32/boards/Passport/modpassport.c b/ports/stm32/boards/Passport/modpassport.c index a8876cea2..1f9165d40 100644 --- a/ports/stm32/boards/Passport/modpassport.c +++ b/ports/stm32/boards/Passport/modpassport.c @@ -10,10 +10,10 @@ #include "modpassport-boardrev.h" #include "modpassport-camera.h" #include "modpassport-fuelgauge.h" +#include "modpassport-mem.h" #include "modpassport-noise.h" #include "modpassport-powermon.h" #include "modpassport-settingsflash.h" -#include "modpassport-sram4.h" #include "modpassport-system.h" #include "uECC.h" @@ -89,7 +89,7 @@ STATIC const mp_rom_map_elem_t passport_module_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_Powermon), MP_ROM_PTR(&mod_passport_Powermon_type)}, {MP_ROM_QSTR(MP_QSTR_SettingsFlash), MP_ROM_PTR(&mod_passport_SettingsFlash_type)}, #endif - {MP_ROM_QSTR(MP_QSTR_sram4), MP_ROM_PTR(&mod_passport_sram4_module)}, + {MP_ROM_QSTR(MP_QSTR_mem), MP_ROM_PTR(&mod_passport_mem_module)}, {MP_ROM_QSTR(MP_QSTR_System), MP_ROM_PTR(&mod_passport_System_type)}}; STATIC MP_DEFINE_CONST_DICT(passport_module_globals, passport_module_globals_table); diff --git a/ports/stm32/boards/Passport/modules/ext_settings.py b/ports/stm32/boards/Passport/modules/ext_settings.py index 6c085129e..b58b125af 100644 --- a/ports/stm32/boards/Passport/modules/ext_settings.py +++ b/ports/stm32/boards/Passport/modules/ext_settings.py @@ -25,7 +25,7 @@ from sffile import SFFile from utils import to_str, call_later_ms from constants import SPI_FLASH_SECTOR_SIZE -from passport import sram4 +from passport import mem class ExtSettings: @@ -137,7 +137,7 @@ def load(self): # print('i={}: {}'.format(i, bytes_to_hex_str(b))) if i != (self.slot_size / 32 - 1): - sram4.ext_settings_buf[i * 32:(i * 32) + 32] = b + mem.ext_settings_buf[i * 32:(i * 32) + 32] = b chk.update(b) else: expect = b @@ -155,7 +155,7 @@ def load(self): # loads() can't work from a byte array, and converting to # bytes here would copy it; better to use file emulation. - fd = BytesIO(sram4.ext_settings_buf) + fd = BytesIO(mem.ext_settings_buf) d = ujson.load(fd) except BaseException: # One in 65k or so chance to come here w/ garbage decoded, so diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index 050298181..cbafcca47 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -16,7 +16,7 @@ import history import sys from sffile import SizerFile -from passport import sram4 +from passport import mem from public_constants import MAX_SIGNERS from multisig_wallet import MultisigWallet, disassemble_multisig_mn from exceptions import FatalPSBTIssue, FraudulentChangeOutput @@ -146,12 +146,12 @@ def get_hash256(fd, poslen, hasher=None): fd.seek(pos) while ll: - here = fd.readinto(sram4.psbt_tmp256) + here = fd.readinto(mem.psbt_tmp256) if not here: break if here > ll: here = ll - rv.update(memoryview(sram4.psbt_tmp256)[0:here]) + rv.update(memoryview(mem.psbt_tmp256)[0:here]) ll -= here if hasher: diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py index 819aec900..1a64b5d8d 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_file_to_external_flash_task.py @@ -14,13 +14,13 @@ async def copy_psbt_file_to_external_flash_task(on_done, on_progress, filename, offset): # sign a PSBT file found on a microSD card - from passport import sram4 + from passport import mem from sffile import SFFile from errors import Error from files import CardSlot from utils import HexStreamer, Base64Streamer, HexWriter, Base64Writer - # TODO: This used to be sram4.tmp_buf, but copying to there fails sometimes + # TODO: This used to be mem.tmp_buf, but copying to there fails sometimes tmp_buf = bytearray(1024) # copy buffer into external SPI Flash diff --git a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py index 06273b854..3a2ba8d91 100644 --- a/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py +++ b/ports/stm32/boards/Passport/modules/tasks/copy_psbt_to_external_flash_task.py @@ -15,7 +15,7 @@ async def copy_psbt_to_external_flash_task(on_done, on_progress, data, offset): # sign a PSBT file found on a microSD card from uio import BytesIO - from passport import sram4 + from passport import mem from sffile import SFFile from errors import Error from utils import HexStreamer, Base64Streamer, HexWriter, Base64Writer @@ -57,15 +57,15 @@ def output_encoder(x): await out.erase() while 1: - n = fd.readinto(sram4.tmp_buf) + n = fd.readinto(mem.tmp_buf) # print('sign copy to SPI flash 1: n={}'.format(n)) if not n: break - if n == len(sram4.tmp_buf): - abuf = sram4.tmp_buf + if n == len(mem.tmp_buf): + abuf = mem.tmp_buf else: - abuf = memoryview(sram4.tmp_buf)[0:n] + abuf = memoryview(mem.tmp_buf)[0:n] if not decoder: out.write(abuf) diff --git a/ports/stm32/boards/Passport/modules/views/qrcode.py b/ports/stm32/boards/Passport/modules/views/qrcode.py index acbef763a..372691116 100644 --- a/ports/stm32/boards/Passport/modules/views/qrcode.py +++ b/ports/stm32/boards/Passport/modules/views/qrcode.py @@ -4,7 +4,7 @@ # qrcode.py - Wrapper for LVGL QR code widget import lvgl as lv -from passport import sram4 +from passport import mem from styles.colors import WHITE, BLACK from .view import View @@ -54,11 +54,11 @@ def configure_canvas_buffer(self): self.res = min(content_width, content_height) # Make the QR Code have a size of the content size. - self.lvgl_root.set_buffer(sram4.qrcode_buffer, + self.lvgl_root.set_buffer(mem.qrcode_buffer, content_width, content_height, - sram4.qrcode_modules_buffer, - sram4.MAX_QR_VERSION, + mem.qrcode_modules_buffer, + mem.MAX_QR_VERSION, BLACK, WHITE) def unmount(self): @@ -72,7 +72,7 @@ def reset_sizing(self): def get_version_for_data(self, encoded_data): enc_len = len(encoded_data) - for i in range(1, sram4.MAX_QR_VERSION + 1): + for i in range(1, mem.MAX_QR_VERSION + 1): if alphanumeric_capacity_by_version[i] >= enc_len: return i raise QRCodeException("Cannot fit {} in a QR code ({} bytes)".format(encoded_data, len(encoded_data))) diff --git a/simulator/sim_modules/passport/sram4.py b/simulator/sim_modules/passport/mem.py similarity index 100% rename from simulator/sim_modules/passport/sram4.py rename to simulator/sim_modules/passport/mem.py From 3da6971f46388938f8510a06d7538987373524ef Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 21 Feb 2023 16:13:51 +0100 Subject: [PATCH 105/156] SFT-1263: Add FixedBytesIO class Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation/modfoundation.c | 172 +++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 5 deletions(-) diff --git a/extmod/foundation/modfoundation.c b/extmod/foundation/modfoundation.c index 6186929db..74e269f63 100644 --- a/extmod/foundation/modfoundation.c +++ b/extmod/foundation/modfoundation.c @@ -13,6 +13,7 @@ #include "py/obj.h" #include "py/objstr.h" +#include "py/stream.h" #include "py/runtime.h" #include "image_conversion.h" @@ -30,6 +31,8 @@ /// package: foundation +STATIC const mp_obj_type_t mp_type_fixedbytesio; + /// def convert_rgb565_to_grayscale(rgb565: bytearray, /// grayscale: bytearray, /// hor_res: int, @@ -94,11 +97,169 @@ STATIC mp_obj_t mod_foundation_sha256(mp_obj_t data, mp_obj_t digest) } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_foundation_sha256_obj, mod_foundation_sha256); -/* - * Add additional class local dictionary table and data structure here - * And add the Class name and MP_ROM_PTR() to the globals table - * below - */ +/// class FixedBytesIO: +/// """ +/// """ +typedef struct _mp_obj_fixedbytesio_t { + mp_obj_base_t base; + vstr_t vstr; + mp_uint_t pos; +} mp_obj_fixedbytesio_t; + +STATIC void fixedbytesio_check_open(const mp_obj_fixedbytesio_t *o) { + if (o->vstr.buf == NULL || o->vstr.alloc == 0) { + mp_raise_ValueError(MP_ERROR_TEXT("I/O operation on closed file")); + } +} + +/// def __init__(self, buf: bytearray) -> None: +/// """ +/// """ +STATIC mp_obj_t fixedbytesio_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + + mp_obj_fixedbytesio_t *o = m_new_obj(mp_obj_fixedbytesio_t); + o->base.type = &mp_type_fixedbytesio; + + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE); + vstr_init_fixed_buf(&o->vstr, bufinfo.len, bufinfo.buf); + return MP_OBJ_FROM_PTR(o); +} + +STATIC void fixedbytesio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_printf(print, "", MP_OBJ_TO_PTR(self_in)); +} + +STATIC mp_uint_t fixedbytesio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_fixedbytesio_t *o = MP_OBJ_TO_PTR(o_in); + fixedbytesio_check_open(o); + if (o->vstr.len <= o->pos) { + return 0; + } + + mp_uint_t remaining = o->vstr.len - o->pos; + if (size > remaining) { + size = remaining; + } + memcpy(buf, o->vstr.buf + o->pos, size); + o->pos += size; + return size; +} + +STATIC mp_uint_t fixedbytesio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_fixedbytesio_t *o = MP_OBJ_TO_PTR(o_in); + fixedbytesio_check_open(o); + + mp_uint_t new_pos = o->pos + size; + if (new_pos < size || new_pos > o->vstr.alloc) { + *errcode = MP_EFBIG; + return MP_STREAM_ERROR; + } + + // If there was a seek past EOF, clear the hole + if (o->pos > o->vstr.len) { + memset(o->vstr.buf + o->vstr.len, 0, o->pos - o->vstr.len); + } + memcpy(o->vstr.buf + o->pos, buf, size); + o->pos = new_pos; + if (new_pos > o->vstr.len) { + o->vstr.len = new_pos; + } + + return size; +} + +STATIC mp_uint_t fixedbytesio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mp_obj_fixedbytesio_t *o = MP_OBJ_TO_PTR(o_in); + switch (request) { + case MP_STREAM_SEEK: { + struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg; + mp_uint_t ref = 0; + switch (s->whence) { + case MP_SEEK_CUR: + ref = o->pos; + break; + case MP_SEEK_END: + ref = o->vstr.len; + break; + } + mp_uint_t new_pos = ref + s->offset; + + // For MP_SEEK_SET, offset is unsigned + if (s->whence != MP_SEEK_SET && s->offset < 0) { + if (new_pos > ref) { + // Negative offset from SEEK_CUR or SEEK_END went past 0. + // CPython sets position to 0, POSIX returns an EINVAL error + new_pos = 0; + } + } else if (new_pos < ref) { + // positive offset went beyond the limit of mp_uint_t + *errcode = MP_EINVAL; // replace with MP_EOVERFLOW when defined + return MP_STREAM_ERROR; + } + s->offset = o->pos = new_pos; + return 0; + } + case MP_STREAM_FLUSH: + return 0; + case MP_STREAM_CLOSE: + vstr_clear(&o->vstr); + o->vstr.alloc = 0; + o->vstr.len = 0; + o->pos = 0; + return 0; + default: + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } +} + +STATIC mp_obj_t fixedbytesio_getvalue(mp_obj_t self_in) { + mp_obj_fixedbytesio_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bytearray_by_ref(self->vstr.len, self->vstr.buf); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fixedbytesio_getvalue_obj, fixedbytesio_getvalue); + +STATIC mp_obj_t fixedbytesio___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return mp_stream_close(args[0]); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fixedbytesio___exit___obj, 4, 4, fixedbytesio___exit__); + +STATIC const mp_rom_map_elem_t fixedbytesio_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) }, + { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) }, + { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&fixedbytesio_getvalue_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&fixedbytesio___exit___obj) }, +}; + + +STATIC MP_DEFINE_CONST_DICT(fixedbytesio_locals_dict, fixedbytesio_locals_dict_table); + +STATIC const mp_stream_p_t fixedbytesio_stream_p = { + .read = fixedbytesio_read, + .write = fixedbytesio_write, + .ioctl = fixedbytesio_ioctl, +}; + +STATIC const mp_obj_type_t mp_type_fixedbytesio = { + { &mp_type_type }, + .name = MP_QSTR_FixedBytesIO, + .print = fixedbytesio_print, + .make_new = fixedbytesio_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &fixedbytesio_stream_p, + .locals_dict = (mp_obj_dict_t *)&fixedbytesio_locals_dict, +}; /* Module Global configuration */ /* Define all properties of the module. @@ -110,6 +271,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_foundation_sha256_obj, mod_foundation_sha25 STATIC const mp_rom_map_elem_t foundation_module_globals_table[] = { {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_foundation)}, + {MP_ROM_QSTR(MP_QSTR_FixedBytesIO), MP_ROM_PTR(&mp_type_fixedbytesio)}, {MP_ROM_QSTR(MP_QSTR_bip39), MP_ROM_PTR(&mod_foundation_bip39_module)}, {MP_ROM_QSTR(MP_QSTR_qr), MP_ROM_PTR(&mod_foundation_qr_module)}, {MP_ROM_QSTR(MP_QSTR_ur), MP_ROM_PTR(&mod_foundation_ur_module)}, From 30fbe3e16534cac06c7dfe5831b7034b37c1600d Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 21 Feb 2023 16:29:40 +0100 Subject: [PATCH 106/156] SFT-1263: Replace BytesIO with FixedBytesIO Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modpassport-mem.h | 13 +++++++++++++ .../Passport/modules/flows/sign_psbt_qr_flow.py | 6 +++--- simulator/sim_modules/passport/mem.py | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modpassport-mem.h b/ports/stm32/boards/Passport/modpassport-mem.h index 35a270914..6fa3415eb 100644 --- a/ports/stm32/boards/Passport/modpassport-mem.h +++ b/ports/stm32/boards/Passport/modpassport-mem.h @@ -24,6 +24,12 @@ */ #define MP_SRAM4 __attribute__((section(".sram4"))) +/** + * @brief Attribute used to allocate a static variable in the + * SRAM4 section. + */ +#define MP_DTCM __attribute__((section(".dtcm"))) + /** * @brief Create a compile-time bytearray by reference. * @@ -45,6 +51,12 @@ /// package: passport.mem +/// psbt_output: bytearray +STATIC MP_DTCM uint8_t mod_passport_mem_psbt_output[26 * 1024]; +STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_mem_psbt_output_obj, + mod_passport_mem_psbt_output, + sizeof(mod_passport_mem_psbt_output)); + /// ext_settings_buf: bytearray STATIC MP_SRAM4 uint8_t mod_passport_mem_ext_settings_buf[16 * 1024]; STATIC MP_OBJ_BYTEARRAY_BY_REF(mod_passport_mem_ext_settings_buf_obj, @@ -90,6 +102,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_passport_mem_qrcode_buffer_clear_obj, STATIC const mp_rom_map_elem_t mod_passport_mem_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_MAX_QR_VERSION), MP_ROM_INT(PASSPORT_MAX_QR_VERSION)}, + {MP_ROM_QSTR(MP_QSTR_psbt_output), MP_ROM_PTR(&mod_passport_mem_psbt_output_obj)}, {MP_ROM_QSTR(MP_QSTR_ext_settings_buf), MP_ROM_PTR(&mod_passport_mem_ext_settings_buf_obj)}, {MP_ROM_QSTR(MP_QSTR_tmp_buf), MP_ROM_PTR(&mod_passport_mem_tmp_buf_obj)}, {MP_ROM_QSTR(MP_QSTR_psbt_tmp256), MP_ROM_PTR(&mod_passport_mem_psbt_tmp256_obj)}, diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index d42d4f156..45570d3cf 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -4,7 +4,8 @@ # sign_psbt_qr_flow.py - Sign a PSBT from a microSD card from flows import Flow -from foundation import ur +from foundation import FixedBytesIO, ur +from passport import mem from pages import ErrorPage @@ -90,7 +91,6 @@ async def common_flow(self): async def show_signed_transaction(self): import gc - from uio import BytesIO from pages import ShowQRPage from data_codecs.qr_type import QRType from ubinascii import hexlify as b2a_hex @@ -99,7 +99,7 @@ async def show_signed_transaction(self): # Copy signed txn into a bytearray and show the data as a UR try: signed_bytes = None - with BytesIO() as bfd: + with FixedBytesIO(mem.psbt_output) as bfd: with self.output_encoder(bfd) as fd: # Always serialize back to PSBT for QR codes self.psbt.serialize(fd) diff --git a/simulator/sim_modules/passport/mem.py b/simulator/sim_modules/passport/mem.py index 2ab8e0437..f3d358583 100644 --- a/simulator/sim_modules/passport/mem.py +++ b/simulator/sim_modules/passport/mem.py @@ -17,6 +17,7 @@ def _alloc(ln): return bytearray(ln) +psbt_output = _alloc(26 * 1024) ext_settings_buf = _alloc(16 * 1024) tmp_buf = _alloc(1024) psbt_tmp256 = _alloc(256) From 1a007df764543b4453e5ba15238013f40deda3a8 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 17:42:05 +0100 Subject: [PATCH 107/156] SFT-1275: Put encoder on SRAM4. Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/src/ur/encoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/foundation-rust/src/ur/encoder.rs b/extmod/foundation-rust/src/ur/encoder.rs index f81da1734..6028328db 100644 --- a/extmod/foundation-rust/src/ur/encoder.rs +++ b/extmod/foundation-rust/src/ur/encoder.rs @@ -41,7 +41,7 @@ pub const UR_ENCODER_MAX_MESSAGE_LEN: usize = /// Statically allocated encoder. #[no_mangle] #[used] -#[cfg_attr(encoder_sram4, link_section = ".sram4")] +#[cfg_attr(sram4, link_section = ".sram4")] pub static mut UR_ENCODER: UR_Encoder = UR_Encoder { inner: ur::HeaplessEncoder::new_heapless(), }; From a511325e520d02c633b56fbe988a65b329572924 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 19:30:27 +0100 Subject: [PATCH 108/156] SFT-1273: Write bytes without adding them Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/psbt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index cbafcca47..c2a6c5257 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -216,7 +216,8 @@ def parse(self, fd): def write(self, out_fd, ktype, val, key=b''): # serialize helper: write w/ size and key byte out_fd.write(ser_compact_size(1 + len(key))) - out_fd.write(bytes([ktype]) + key) + out_fd.write(bytes([ktype])) + out_fd.write(key) if isinstance(val, tuple): (pos, ll) = val From 27d78fa025b96100a9f3f8b00fae77afcb710961 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 22 Feb 2023 13:27:39 -0600 Subject: [PATCH 109/156] SFT-1277: fixed health check SD card errors --- .../Passport/modules/flows/casa_health_check_microsd_flow.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py index ff4920d7e..eb9508a80 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_microsd_flow.py @@ -101,8 +101,9 @@ async def write_signed_file(self): else: # Attempt to write-out the transaction try: - with open(out_full, 'w') as fd: - fd.write(self.signed_message) + with CardSlot() as _card: + with open(out_full, 'w') as fd: + fd.write(self.signed_message) except OSError as exc: result = await ErrorPage(text='Unable to write!\n\n%s\n\n' % exc).show() # sys.print_exception(exc) From 2e262142d894f296386c12fc521af1933991d8ea Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 20:36:19 +0100 Subject: [PATCH 110/156] SFT-1273: Remove unused ser_push_int function Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/serializations.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/serializations.py b/ports/stm32/boards/Passport/modules/serializations.py index 55fe02771..6414a8af2 100644 --- a/ports/stm32/boards/Passport/modules/serializations.py +++ b/ports/stm32/boards/Passport/modules/serializations.py @@ -205,20 +205,6 @@ def ser_push_data(dd): return bytes([76, ll]) + dd # 0x4c = 76 => OP_PUSHDATA1 + size + data -def ser_push_int(n): - # push a small integer onto the stack - from opcodes import OP_0, OP_1, OP_16, OP_PUSHDATA1 - - if n == 0: - return bytes([OP_0]) - elif 1 <= n <= 16: - return bytes([OP_1 + n - 1]) - elif n <= 255: - return bytes([1, n]) - - raise ValueError(n) - - def disassemble(script): # Very limited script disassembly # yeilds (int / bytes, opcode) for each part of the script From d9fa05e4569ef95beae68f4a44caa681cb648b82 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 20:36:59 +0100 Subject: [PATCH 111/156] SFT-1273: Remove unused read_varint function Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/psbt.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index c2a6c5257..3ba5f450e 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -52,19 +52,6 @@ # return self.rv.digest() -def read_varint(v): - # read "compact sized" int from a few bytes. - assert not isinstance(v, tuple), v - nit = v[0] - if nit == 253: - return unpack_from(" Date: Wed, 22 Feb 2023 20:38:09 +0100 Subject: [PATCH 112/156] SFT-1273: Remove unused CTransaction class Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/serializations.py | 103 ------------------ 1 file changed, 103 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/serializations.py b/ports/stm32/boards/Passport/modules/serializations.py index 6414a8af2..6006b9a28 100644 --- a/ports/stm32/boards/Passport/modules/serializations.py +++ b/ports/stm32/boards/Passport/modules/serializations.py @@ -487,107 +487,4 @@ def is_null(self): return False return True - -class CTransaction(object): - def __init__(self, tx=None): - if tx is None: - self.nVersion = 1 - self.vin = [] - self.vout = [] - self.wit = CTxWitness() - self.nLockTime = 0 - self.sha256 = None - self.hash = None - else: - import copy # not supported - self.nVersion = tx.nVersion - self.vin = copy.deepcopy(tx.vin) - self.vout = copy.deepcopy(tx.vout) - self.nLockTime = tx.nLockTime - self.sha256 = tx.sha256 - self.hash = tx.hash - self.wit = copy.deepcopy(tx.wit) - - def deserialize(self, f): - self.nVersion = struct.unpack(" 21000000 * COIN: - return False - return True - - def __repr__(self): - return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \ - % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) - # EOF From 7ceb37ea800cf1f0002b4d5abc1912e9600e3978 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 20:39:14 +0100 Subject: [PATCH 113/156] SFT-1273: Remove unused CTxWitness Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/serializations.py | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/serializations.py b/ports/stm32/boards/Passport/modules/serializations.py index 6006b9a28..da2c43647 100644 --- a/ports/stm32/boards/Passport/modules/serializations.py +++ b/ports/stm32/boards/Passport/modules/serializations.py @@ -459,32 +459,4 @@ def __repr__(self): def is_null(self): return self.scriptWitness.is_null() - -class CTxWitness(object): - def __init__(self): - self.vtxinwit = [] - - def deserialize(self, f): - for i in range(len(self.vtxinwit)): - self.vtxinwit[i].deserialize(f) - - def serialize(self): - r = b"" - # This is different than the usual vector serialization -- - # we omit the length of the vector, which is required to be - # the same length as the transaction's vin vector. - for x in self.vtxinwit: - r += x.serialize() - return r - - def __repr__(self): - return "CTxWitness(%s)" % \ - (';'.join([repr(x) for x in self.vtxinwit])) - - def is_null(self): - for x in self.vtxinwit: - if not x.is_null(): - return False - return True - # EOF From 6047f4aac466761d5f95757ab75ae0ceaee2cb1d Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 20:48:45 +0100 Subject: [PATCH 114/156] SFT-1273: Remove unused is_null functions Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/psbt.py | 4 ++-- ports/stm32/boards/Passport/modules/serializations.py | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index 3ba5f450e..44ece24fb 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -1411,15 +1411,15 @@ def wr(*a): for idx, inp in enumerate(self.inputs): # print('Input {}: free mem={}'.format(idx, gc.mem_free())) + gc.collect() # Give collector a chance to run to help avoid fragmentation inp.serialize(out_fd, idx) out_fd.write(b'\0') - gc.collect() # Give collector a chance to run to help avoid fragmentation for idx, outp in enumerate(self.outputs): # print('Output {}: free mem={}'.format(idx, gc.mem_free())) + gc.collect() # Give collector a chance to run to help avoid fragmentation outp.serialize(out_fd, idx) out_fd.write(b'\0') - gc.collect() # Give collector a chance to run to help avoid fragmentation # def sign_it(self): # # txn is approved. sign all inputs we can sign. add signatures diff --git a/ports/stm32/boards/Passport/modules/serializations.py b/ports/stm32/boards/Passport/modules/serializations.py index da2c43647..728446e62 100644 --- a/ports/stm32/boards/Passport/modules/serializations.py +++ b/ports/stm32/boards/Passport/modules/serializations.py @@ -437,11 +437,6 @@ def __repr__(self): return "CScriptWitness(%s)" % \ (",".join([bytes_to_hex_str(x) for x in self.stack])) - def is_null(self): - if self.stack: - return False - return True - class CTxInWitness(object): def __init__(self): @@ -456,7 +451,4 @@ def serialize(self): def __repr__(self): return repr(self.scriptWitness) - def is_null(self): - return self.scriptWitness.is_null() - # EOF From 9d43ee6b83d32f56117a65e954d238e67aad5c88 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 18:29:38 +0100 Subject: [PATCH 115/156] SFT-1271: Add error kind for single part URs Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/include/foundation.h | 1 + extmod/foundation-rust/src/ur/decoder.rs | 23 ++++++++++++++------- extmod/foundation-rust/src/ur/mod.rs | 1 + 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/extmod/foundation-rust/include/foundation.h b/extmod/foundation-rust/include/foundation.h index d7a2da3a0..d03dc812a 100644 --- a/extmod/foundation-rust/include/foundation.h +++ b/extmod/foundation-rust/include/foundation.h @@ -78,6 +78,7 @@ typedef enum { typedef enum { UR_ERROR_KIND_OTHER, UR_ERROR_KIND_UNSUPPORTED, + UR_ERROR_KIND_NOT_MULTI_PART, } UR_ErrorKind; /** diff --git a/extmod/foundation-rust/src/ur/decoder.rs b/extmod/foundation-rust/src/ur/decoder.rs index 1d2367385..3b46302e6 100644 --- a/extmod/foundation-rust/src/ur/decoder.rs +++ b/extmod/foundation-rust/src/ur/decoder.rs @@ -6,7 +6,7 @@ use core::{slice, str}; use ur::UR; -use ur_foundation::ur; +use ur_foundation::{ur, ur::decoder::Error}; use crate::ur::{max_fragment_len, registry::UR_Value, UR_Error}; @@ -78,14 +78,23 @@ pub unsafe extern "C" fn ur_decoder_receive( .map_err(|e| unsafe { UR_Error::other(&e) }) .and_then(|ur| { UR::parse(ur).map_err(|e| unsafe { UR_Error::other(&e) }) - }) - .and_then(|ur| { - decoder - .inner - .receive(ur) - .map_err(|e| unsafe { UR_Error::other(&e) }) }); + let ur = match result { + Ok(ur) => ur, + Err(e) => { + *error = e; + return false; + } + }; + + let result = decoder.inner.receive(ur).map_err(|e| match e { + Error::NotMultiPart => unsafe { + UR_Error::new(&e, super::UR_ErrorKind::UR_ERROR_KIND_NOT_MULTI_PART) + }, + _ => unsafe { UR_Error::other(&e) }, + }); + match result { Ok(_) => true, Err(e) => { diff --git a/extmod/foundation-rust/src/ur/mod.rs b/extmod/foundation-rust/src/ur/mod.rs index df3e1c9ac..11ea069f5 100644 --- a/extmod/foundation-rust/src/ur/mod.rs +++ b/extmod/foundation-rust/src/ur/mod.rs @@ -35,6 +35,7 @@ pub const fn digit_count(v: usize) -> usize { pub enum UR_ErrorKind { UR_ERROR_KIND_OTHER, UR_ERROR_KIND_UNSUPPORTED, + UR_ERROR_KIND_NOT_MULTI_PART, } #[repr(C)] From 9040fb83abe7031e734a3a008c91e3f8282622ef Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 23 Feb 2023 11:17:14 +0100 Subject: [PATCH 116/156] SFT-1282: Optimize Rust for small binaries Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/Cargo.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extmod/foundation-rust/Cargo.toml b/extmod/foundation-rust/Cargo.toml index 54b47ec49..cec0253f0 100644 --- a/extmod/foundation-rust/Cargo.toml +++ b/extmod/foundation-rust/Cargo.toml @@ -37,5 +37,7 @@ std = [] crate-type = ["lib", "staticlib"] [profile.release] -lto = true -opt-level = 3 +lto = "fat" +opt-level = "z" +codegen-units = 1 +strip = true From ccf5cdf7ee5840cbce7dcc2bf084465408b7608a Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 23 Feb 2023 17:37:28 +0100 Subject: [PATCH 117/156] SFT-1302: Fix multisig import Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/flows/connect_wallet_flow.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py b/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py index f6cc0f764..b0391acd4 100644 --- a/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py @@ -30,6 +30,7 @@ from wallets.constants import EXPORT_MODE_MICROSD, EXPORT_MODE_QR from wallets.sw_wallets import supported_software_wallets from utils import random_hex, spinner_task +from foundation import ur import common import microns import foundation @@ -418,7 +419,11 @@ async def import_multisig_config_from_qr(self): try: # Mulitsig config should be a bytes-like object that we decode to a string - self.multisig_import_data = scan_result.data.decode('utf-8') + if isinstance(scan_result.data, ur.Value): + self.multisig_import_data = scan_result.data.unwrap_bytes().decode('utf-8') + elif isinstance(scan_result.data, str): + self.multisig_import_data = scan_result.data + # from utils import to_str # print('MS Data: {}'.format(to_str(self.multisig_import_data))) except BaseException as e: From 39bf685b931d801a557c4da187616ec50d7775fa Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 18:54:34 +0100 Subject: [PATCH 118/156] SFT-1271: Add exceptions for UR errors Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation/modfoundation-ur.h | 52 +++++++++++++++++-- .../Passport/modules/data_codecs/ur2_codec.py | 14 ++--- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/extmod/foundation/modfoundation-ur.h b/extmod/foundation/modfoundation-ur.h index 79df326ac..1ba13ff80 100644 --- a/extmod/foundation/modfoundation-ur.h +++ b/extmod/foundation/modfoundation-ur.h @@ -4,6 +4,7 @@ #include #include "py/obj.h" +#include "py/objexcept.h" #include "foundation.h" /// package: foundation.ur @@ -15,6 +16,46 @@ STATIC const mp_obj_type_t mod_foundation_ur_CryptoKeypath_type; STATIC const mp_obj_type_t mod_foundation_ur_PassportRequest_type; STATIC struct _mp_obj_PassportRequest_t *mod_foundation_ur_PassportRequest_new(UR_PassportRequest *value); +STATIC NORETURN void mod_foundation_ur_raise(UR_Error *error); + +/// class OtherError(Exception): +/// """ +/// """ +STATIC MP_DEFINE_EXCEPTION(OtherError, Exception); + +/// class UnsupportedError(Exception): +/// """ +/// """ +STATIC MP_DEFINE_EXCEPTION(UnsupportedError, Exception); + +/// class NotMultiPartError(Exception): +/// """ +/// """ +STATIC MP_DEFINE_EXCEPTION(NotMultiPartError, Exception); + +STATIC NORETURN void mod_foundation_ur_raise(UR_Error *error) { + const mp_obj_type_t *type; + + switch (error->kind) { + case UR_ERROR_KIND_OTHER: + type = &mp_type_OtherError; + break; + case UR_ERROR_KIND_UNSUPPORTED: + type = &mp_type_UnsupportedError; + break; + case UR_ERROR_KIND_NOT_MULTI_PART: + type = &mp_type_UnsupportedError; + break; + default: + type = &mp_type_RuntimeError; + break; + } + + mp_raise_msg_varg(type, + MP_ERROR_TEXT("%.*s"), + error->len, + error->message); +} /// class Value: /// """ @@ -506,8 +547,7 @@ STATIC mp_obj_t mod_foundation_ur_decoder_receive(mp_obj_t ur_obj) GET_STR_DATA_LEN(ur_obj, ur, ur_len); if (!ur_decoder_receive(&UR_DECODER, ur, ur_len, &error)) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%.*s"), - error.len, error.message); + mod_foundation_ur_raise(&error); } return mp_const_none; @@ -556,8 +596,7 @@ STATIC mp_obj_t mod_foundation_ur_decoder_decode_message(void) UR_Value value = {0}; if (!ur_decoder_decode_message(&UR_DECODER, &value, &error)) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%.*s"), - error.len, error.message); + mod_foundation_ur_raise(&error); } return MP_OBJ_FROM_PTR(mod_foundation_ur_Value_new(&value)); @@ -578,6 +617,11 @@ STATIC mp_obj_t mod_foundation_ur_validate(mp_obj_t ur_obj) STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_validate_obj, mod_foundation_ur_validate); STATIC const mp_rom_map_elem_t mod_foundation_ur_globals_table[] = { + /// Errors. + {MP_ROM_QSTR(MP_QSTR_OtherError), MP_ROM_PTR(&mp_type_OtherError)}, + {MP_ROM_QSTR(MP_QSTR_UnsupportedError), MP_ROM_PTR(&mp_type_UnsupportedError)}, + {MP_ROM_QSTR(MP_QSTR_NotMultiPartError), MP_ROM_PTR(&mp_type_UnsupportedError)}, + // Value. {MP_ROM_QSTR(MP_QSTR_NETWORK_MAINNET), MP_ROM_INT(UR_NETWORK_MAINNET)}, {MP_ROM_QSTR(MP_QSTR_NETWORK_TESTNET), MP_ROM_INT(UR_NETWORK_TESTNET)}, diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index bb96be74a..a15e71788 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -23,9 +23,11 @@ def __init__(self): def add_data(self, data): try: ur.decoder_receive(data.lower()) - except ValueError as exc: - import sys - sys.print_exception(exc) + except ur.NotMultiPartError as exc: + raise DecodeError(str(exc)) + except ur.UnsupportedError as exc: + raise DecodeError("Unsupported UR.\n\n{}".format(str(exc))) + except ur.OtherError as exc: raise DecodeError(str(exc)) def estimated_percent_complete(self): @@ -37,10 +39,10 @@ def is_complete(self): def decode(self): try: return ur.decoder_decode_message() - except ValueError as exc: - import sys - sys.print_exception(exc) + except ur.Other as exc: raise DecodeError(str(exc)) + except ur.Unsupported as exc: + raise DecodeError("Unsupported UR.\n\n{}".format(str(exc))) def qr_type(self): return QRType.UR2 From 8a622b29d1e27ef2b16275cdfae2467396a2f60f Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 22:14:22 +0100 Subject: [PATCH 119/156] SFT-1271: Add decoder_is_empty function Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/include/foundation.h | 5 +++++ extmod/foundation-rust/src/ur/decoder.rs | 6 ++++++ extmod/foundation/modfoundation-ur.h | 10 ++++++++++ 3 files changed, 21 insertions(+) diff --git a/extmod/foundation-rust/include/foundation.h b/extmod/foundation-rust/include/foundation.h index d03dc812a..ae1cd6f9e 100644 --- a/extmod/foundation-rust/include/foundation.h +++ b/extmod/foundation-rust/include/foundation.h @@ -380,6 +380,11 @@ uint32_t ur_decoder_estimated_percent_complete(UR_Decoder *decoder); */ void ur_decoder_clear(UR_Decoder *decoder); +/** + * Returns `true` if the decoder doesn't contain any data. + */ +bool ur_decoder_is_empty(UR_Decoder *decoder); + /** * Decode the message as an UR value. */ diff --git a/extmod/foundation-rust/src/ur/decoder.rs b/extmod/foundation-rust/src/ur/decoder.rs index 3b46302e6..17127e9da 100644 --- a/extmod/foundation-rust/src/ur/decoder.rs +++ b/extmod/foundation-rust/src/ur/decoder.rs @@ -124,6 +124,12 @@ pub extern "C" fn ur_decoder_clear(decoder: &mut UR_Decoder) { decoder.inner.clear(); } +/// Returns `true` if the decoder doesn't contain any data. +#[no_mangle] +pub extern "C" fn ur_decoder_is_empty(decoder: &mut UR_Decoder) -> bool { + decoder.inner.is_empty() +} + /// Decode the message as an UR value. #[no_mangle] pub extern "C" fn ur_decoder_decode_message( diff --git a/extmod/foundation/modfoundation-ur.h b/extmod/foundation/modfoundation-ur.h index 1ba13ff80..628a758de 100644 --- a/extmod/foundation/modfoundation-ur.h +++ b/extmod/foundation/modfoundation-ur.h @@ -587,6 +587,15 @@ STATIC mp_obj_t mod_foundation_ur_decoder_clear(void) } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_foundation_ur_decoder_clear_obj, mod_foundation_ur_decoder_clear); +/// def decoder_is_empty() -> bool: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_decoder_is_empty(void) +{ + return ur_decoder_is_empty(&UR_DECODER) ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_foundation_ur_decoder_is_empty_obj, mod_foundation_ur_decoder_is_empty); + /// def decoder_decode_message() -> Value: /// """ /// """ @@ -646,6 +655,7 @@ STATIC const mp_rom_map_elem_t mod_foundation_ur_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_decoder_is_complete), MP_ROM_PTR(&mod_foundation_ur_decoder_is_complete_obj)}, {MP_ROM_QSTR(MP_QSTR_decoder_estimated_percent_complete), MP_ROM_PTR(&mod_foundation_ur_decoder_estimated_percent_complete_obj)}, {MP_ROM_QSTR(MP_QSTR_decoder_clear), MP_ROM_PTR(&mod_foundation_ur_decoder_clear_obj)}, + {MP_ROM_QSTR(MP_QSTR_decoder_is_empty), MP_ROM_PTR(&mod_foundation_ur_decoder_is_empty_obj)}, {MP_ROM_QSTR(MP_QSTR_decoder_decode_message), MP_ROM_PTR(&mod_foundation_ur_decoder_decode_message_obj)}, {MP_ROM_QSTR(MP_QSTR_validate), MP_ROM_PTR(&mod_foundation_ur_validate_obj)}, }; From 5c71c211e1fea105e351a4d068ba566e09b246d6 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 22 Feb 2023 21:54:20 +0100 Subject: [PATCH 120/156] SFT-1271: Decode single part URs Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/Cargo.lock | 1 + extmod/foundation-rust/Cargo.toml | 5 ++ extmod/foundation-rust/include/foundation.h | 12 +++ extmod/foundation-rust/src/bin/sizes.rs | 25 +++--- extmod/foundation-rust/src/ur/decoder.rs | 78 ++++++++++++++++++- extmod/foundation-rust/src/ur/mod.rs | 10 +++ extmod/foundation/modfoundation-ur.h | 21 +++++ .../Passport/modules/data_codecs/ur2_codec.py | 21 ++++- 8 files changed, 160 insertions(+), 13 deletions(-) diff --git a/extmod/foundation-rust/Cargo.lock b/extmod/foundation-rust/Cargo.lock index 60df720ec..4f836a02c 100644 --- a/extmod/foundation-rust/Cargo.lock +++ b/extmod/foundation-rust/Cargo.lock @@ -62,6 +62,7 @@ version = "0.1.0" dependencies = [ "heapless", "minicbor", + "ur", "ur-foundation", "uuid", ] diff --git a/extmod/foundation-rust/Cargo.toml b/extmod/foundation-rust/Cargo.toml index 54b47ec49..5cbd39c28 100644 --- a/extmod/foundation-rust/Cargo.toml +++ b/extmod/foundation-rust/Cargo.toml @@ -24,6 +24,11 @@ default-features = false version = "1" default-features = false +[dependencies.ur] +git = "https://github.com/Foundation-Devices/ur-rs" +branch = "dev" +default-features = false + [dependencies.ur-foundation] git = "https://github.com/Foundation-Devices/rust-ur-foundation" branch = "dev-v0.1.0" diff --git a/extmod/foundation-rust/include/foundation.h b/extmod/foundation-rust/include/foundation.h index ae1cd6f9e..65ca32e30 100644 --- a/extmod/foundation-rust/include/foundation.h +++ b/extmod/foundation-rust/include/foundation.h @@ -345,6 +345,8 @@ typedef struct { + + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -401,6 +403,16 @@ bool ur_decoder_decode_message(UR_Decoder *decoder, */ bool ur_validate(const uint8_t *ur, size_t ur_len); +/** + * # Safety + * + * Same as in `ur_decoder_decode_message` + */ +bool ur_decode_single_part(const uint8_t *ur, + size_t ur_len, + UR_Value *value, + UR_Error *error); + /** * Start the encoder. * diff --git a/extmod/foundation-rust/src/bin/sizes.rs b/extmod/foundation-rust/src/bin/sizes.rs index 03ee12cf7..d5b3c5d45 100644 --- a/extmod/foundation-rust/src/bin/sizes.rs +++ b/extmod/foundation-rust/src/bin/sizes.rs @@ -5,7 +5,8 @@ use foundation::ur::{ decoder::{ UR_Decoder, UR_DECODER_MAX_FRAGMENT_LEN, UR_DECODER_MAX_MESSAGE_LEN, UR_DECODER_MAX_MIXED_PARTS, UR_DECODER_MAX_SEQUENCE_COUNT, - UR_DECODER_MAX_STRING, UR_DECODER_QUEUE_SIZE, + UR_DECODER_MAX_SINGLE_PART_MESSAGE_LEN, UR_DECODER_MAX_STRING, + UR_DECODER_QUEUE_SIZE, }, encoder::{ UR_Encoder, UR_ENCODER_MAX_FRAGMENT_LEN, UR_ENCODER_MAX_MESSAGE_LEN, @@ -15,39 +16,45 @@ use foundation::ur::{ use std::mem::size_of; fn main() { - println!("{: <22} | {: <8} | {: <8}", "", "Decoder", "Encoder"); + println!("{: <34} | {: <8} | {: <8}", "", "Decoder", "Encoder"); println!( - "{: <22} | {: <8} | {: <8}", + "{: <34} | {: <8} | {: <8}", "Max. Sequence Count", UR_DECODER_MAX_SEQUENCE_COUNT, UR_ENCODER_MAX_SEQUENCE_COUNT ); println!( - "{: <22} | {: <8} | {: <8}", + "{: <34} | {: <8} | {: <8}", "Max. UR String Length", UR_DECODER_MAX_STRING, UR_ENCODER_MAX_STRING ); println!( - "{: <22} | {: <8} | {: <8}", + "{: <34} | {: <8} | {: <8}", "Max. Fragment Length", UR_DECODER_MAX_FRAGMENT_LEN, UR_ENCODER_MAX_FRAGMENT_LEN ); println!( - "{: <22} | {: <8} | {: <8}", + "{: <34} | {: <8} | {: <8}", "Max. Message Length", UR_DECODER_MAX_MESSAGE_LEN, UR_ENCODER_MAX_MESSAGE_LEN ); println!( - "{: <22} | {: <8} | {: <8}", + "{: <34} | {: <8} | {: <8}", + "Max. Message Length (Single-Part)", + UR_DECODER_MAX_SINGLE_PART_MESSAGE_LEN, + "TODO" + ); + println!( + "{: <34} | {: <8} | {: <8}", "Max. Mixed Parts", UR_DECODER_MAX_MIXED_PARTS, "Not Applicable" ); println!( - "{: <22} | {: <8} | {: <8}", + "{: <34} | {: <8} | {: <8}", "Queue Size", UR_DECODER_QUEUE_SIZE, "Not Applicable" ); println!( - "{: <22} | {: <8} | {: <8}", + "{: <34} | {: <8} | {: <8}", "Structure Size", size_of::(), size_of::() diff --git a/extmod/foundation-rust/src/ur/decoder.rs b/extmod/foundation-rust/src/ur/decoder.rs index 17127e9da..001ea814a 100644 --- a/extmod/foundation-rust/src/ur/decoder.rs +++ b/extmod/foundation-rust/src/ur/decoder.rs @@ -8,7 +8,9 @@ use core::{slice, str}; use ur::UR; use ur_foundation::{ur, ur::decoder::Error}; -use crate::ur::{max_fragment_len, registry::UR_Value, UR_Error}; +use crate::ur::{ + max_fragment_len, max_message_len, registry::UR_Value, UR_Error, +}; /// Maximum size of an encoded Uniform Resource. /// @@ -29,6 +31,10 @@ pub const UR_DECODER_MAX_FRAGMENT_LEN: usize = pub const UR_DECODER_MAX_MESSAGE_LEN: usize = UR_DECODER_MAX_FRAGMENT_LEN * UR_DECODER_MAX_SEQUENCE_COUNT; +/// Maximum message length for a single part UR. +pub const UR_DECODER_MAX_SINGLE_PART_MESSAGE_LEN: usize = + max_message_len(UR_DECODER_MAX_STRING); + /// Maximum number of mixed parts that can be held. pub const UR_DECODER_MAX_MIXED_PARTS: usize = UR_DECODER_MAX_SEQUENCE_COUNT / 4; @@ -47,6 +53,14 @@ pub static mut UR_DECODER: UR_Decoder = UR_Decoder { inner: ur::HeaplessDecoder::new_heapless(), }; +/// cbindgen:ignore +#[used] +#[cfg_attr(dtcm, link_section = ".dtcm")] +static mut UR_DECODER_SINGLE_PART_MESSAGE: heapless::Vec< + u8, + UR_DECODER_MAX_SINGLE_PART_MESSAGE_LEN, +> = heapless::Vec::new(); + /// Uniform Resource decoder. pub struct UR_Decoder { inner: ur::HeaplessDecoder< @@ -198,3 +212,65 @@ pub unsafe extern "C" fn ur_validate(ur: *const u8, ur_len: usize) -> bool { false } + +/// # Safety +/// +/// Same as in `ur_decoder_decode_message` +#[no_mangle] +pub unsafe extern "C" fn ur_decode_single_part( + ur: *const u8, + ur_len: usize, + value: &mut UR_Value, + error: &mut UR_Error, +) -> bool { + // SAFETY: ur and ur_len are assumed to be valid. + let ur = unsafe { slice::from_raw_parts(ur, ur_len) }; + + let result = str::from_utf8(ur) + .map_err(|e| unsafe { UR_Error::other(&e) }) + .and_then(|ur| { + UR::parse(ur).map_err(|e| unsafe { UR_Error::other(&e) }) + }); + + let ur = match result { + Ok(ur) => ur, + Err(e) => { + *error = e; + return false; + } + }; + + let message = unsafe { &mut UR_DECODER_SINGLE_PART_MESSAGE }; + message.clear(); + message + .resize(UR_DECODER_MAX_SINGLE_PART_MESSAGE_LEN, 0) + .expect("Message buffer should have the same size as in the constant"); + + let result = ur::bytewords::decode_to_slice( + ur.as_bytewords() + .expect("Uniform Resource should contain bytewords"), + message, + ur::bytewords::Style::Minimal, + ) + .map_err(|e| unsafe { UR_Error::other(&e) }); + + match result { + Ok(len) => message.truncate(len), + Err(e) => { + *error = e; + return false; + } + } + + let result = unsafe { UR_Value::from_ur(ur.as_type(), message) }; + + *value = match result { + Ok(v) => v, + Err(e) => { + *error = e; + return false; + } + }; + + true +} diff --git a/extmod/foundation-rust/src/ur/mod.rs b/extmod/foundation-rust/src/ur/mod.rs index 11ea069f5..d1cb9d739 100644 --- a/extmod/foundation-rust/src/ur/mod.rs +++ b/extmod/foundation-rust/src/ur/mod.rs @@ -26,6 +26,16 @@ pub const fn max_fragment_len(max_characters: usize) -> usize { max_bytes_for_part - Part::max_encoded_len() } +pub const fn max_message_len(max_characters: usize) -> usize { + const MAX_UR_PREFIX: usize = "ur:crypto-coin-info/".len(); + + let max_chars_for_message: usize = max_characters - MAX_UR_PREFIX; + + let max_bytes_for_message: usize = (max_chars_for_message / 2) - 4; + + max_bytes_for_message +} + /// Count the number of digits in a number. pub const fn digit_count(v: usize) -> usize { (v.ilog10() + 1) as usize diff --git a/extmod/foundation/modfoundation-ur.h b/extmod/foundation/modfoundation-ur.h index 628a758de..a5390736b 100644 --- a/extmod/foundation/modfoundation-ur.h +++ b/extmod/foundation/modfoundation-ur.h @@ -625,6 +625,26 @@ STATIC mp_obj_t mod_foundation_ur_validate(mp_obj_t ur_obj) } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_validate_obj, mod_foundation_ur_validate); +/// def decode_single_part(ur: str) -> bool: +/// """ +/// """ +STATIC mp_obj_t mod_foundation_ur_decode_single_part(mp_obj_t ur_obj) +{ + UR_Error error = {0}; + UR_Value value = {0}; + + mp_check_self(mp_obj_is_str(ur_obj)); + GET_STR_DATA_LEN(ur_obj, ur, ur_len); + + if (!ur_decode_single_part(ur, ur_len, &value, &error)) { + mod_foundation_ur_raise(&error); + } + + return MP_OBJ_FROM_PTR(mod_foundation_ur_Value_new(&value)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_ur_decode_single_part_obj, + mod_foundation_ur_decode_single_part); + STATIC const mp_rom_map_elem_t mod_foundation_ur_globals_table[] = { /// Errors. {MP_ROM_QSTR(MP_QSTR_OtherError), MP_ROM_PTR(&mp_type_OtherError)}, @@ -658,6 +678,7 @@ STATIC const mp_rom_map_elem_t mod_foundation_ur_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_decoder_is_empty), MP_ROM_PTR(&mod_foundation_ur_decoder_is_empty_obj)}, {MP_ROM_QSTR(MP_QSTR_decoder_decode_message), MP_ROM_PTR(&mod_foundation_ur_decoder_decode_message_obj)}, {MP_ROM_QSTR(MP_QSTR_validate), MP_ROM_PTR(&mod_foundation_ur_validate_obj)}, + {MP_ROM_QSTR(MP_QSTR_decode_single_part), MP_ROM_PTR(&mod_foundation_ur_decode_single_part_obj)}, }; STATIC MP_DEFINE_CONST_DICT(mod_foundation_ur_globals, mod_foundation_ur_globals_table); diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index a15e71788..b27eaa67f 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -19,12 +19,24 @@ class UR2Decoder(DataDecoder): def __init__(self): ur.decoder_clear() + self.value = None def add_data(self, data): + data = data.lower() + try: - ur.decoder_receive(data.lower()) + ur.decoder_receive(data) except ur.NotMultiPartError as exc: - raise DecodeError(str(exc)) + if ur.decoder_is_empty(): + try: + self.value = ur.decode_single_part(data) + except ur.UnsupportedError as exc: + raise DecodeError("Unsupported UR.\n\n{}".format(str(exc))) + except ur.OtherError as exc: + raise DecodeError(str(exc)) + else: + raise DecodeError("""\ +Received single-part UR when multi-part reception was already in place""") except ur.UnsupportedError as exc: raise DecodeError("Unsupported UR.\n\n{}".format(str(exc))) except ur.OtherError as exc: @@ -38,11 +50,14 @@ def is_complete(self): def decode(self): try: - return ur.decoder_decode_message() + if self.value is None: + self.value = ur.decoder_decode_message() except ur.Other as exc: raise DecodeError(str(exc)) except ur.Unsupported as exc: raise DecodeError("Unsupported UR.\n\n{}".format(str(exc))) + finally: + return self.value def qr_type(self): return QRType.UR2 From 2e54e235667cc97c56596d16d449dc3d5b36354f Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 23 Feb 2023 18:55:12 +0100 Subject: [PATCH 121/156] SFT-1271: Update ur-rs version Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extmod/foundation-rust/Cargo.lock b/extmod/foundation-rust/Cargo.lock index 4f836a02c..07b4daccc 100644 --- a/extmod/foundation-rust/Cargo.lock +++ b/extmod/foundation-rust/Cargo.lock @@ -261,9 +261,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14" dependencies = [ "proc-macro2", "quote", @@ -279,7 +279,7 @@ checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "ur" version = "0.3.0" -source = "git+https://github.com/Foundation-Devices/ur-rs?branch=dev#2e6563f804572251535b18bdab0dd0b9ba77f062" +source = "git+https://github.com/Foundation-Devices/ur-rs?branch=dev#69297429b4ff6444e049883f79305df678130b30" dependencies = [ "bitcoin_hashes", "crc", From 1a06ce68c0d6cbf524d03ffa1f2838b07f83a041 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 23 Feb 2023 19:24:25 +0100 Subject: [PATCH 122/156] SFT-1305: Use same message size for encoder and decoder Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/src/ur/encoder.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extmod/foundation-rust/src/ur/encoder.rs b/extmod/foundation-rust/src/ur/encoder.rs index 6028328db..01388f2b1 100644 --- a/extmod/foundation-rust/src/ur/encoder.rs +++ b/extmod/foundation-rust/src/ur/encoder.rs @@ -35,8 +35,7 @@ pub const UR_ENCODER_MAX_SEQUENCE_COUNT: usize = usize::next_power_of_two( /// Maximum message length that can be encoded. /// cbindgen:ignore -pub const UR_ENCODER_MAX_MESSAGE_LEN: usize = - UR_ENCODER_MAX_FRAGMENT_LEN * UR_ENCODER_MAX_SEQUENCE_COUNT; +pub const UR_ENCODER_MAX_MESSAGE_LEN: usize = UR_DECODER_MAX_MESSAGE_LEN; /// Statically allocated encoder. #[no_mangle] From 123315aba8303c67e5e5fb71675b6a426efa138b Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 23 Feb 2023 20:07:37 +0100 Subject: [PATCH 123/156] SFT-1306: Use getvalue instead of read Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../boards/Passport/modules/flows/sign_psbt_qr_flow.py | 5 +++-- ports/stm32/boards/Passport/modules/utils.py | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index 45570d3cf..721b7f8f2 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -97,14 +97,15 @@ async def show_signed_transaction(self): import microns # Copy signed txn into a bytearray and show the data as a UR + # try: + signed_bytes = None try: - signed_bytes = None with FixedBytesIO(mem.psbt_output) as bfd: with self.output_encoder(bfd) as fd: # Always serialize back to PSBT for QR codes self.psbt.serialize(fd) bfd.seek(0) - signed_bytes = bfd.read() + signed_bytes = bfd.getvalue() # print('len(signed_bytes)={}'.format(len(signed_bytes))) # print('signed_bytes={}'.format(signed_bytes)) except MemoryError as e: diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index e601f635c..a1e93c4bb 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -452,6 +452,9 @@ def readinto(self, buf): buf[0:len(b)] = b return len(b) + def getvalue(self): + return self.fd.getvalue() + class Base64Writer: # Emulate a file/stream but convert binary to Base64 as they write @@ -481,6 +484,9 @@ def write(self, buf): assert tmp[-2:-1] != b'=', tmp self.fd.write(tmp[:-1]) + def getvalue(self): + return self.fd.getvalue() + def swab32(n): # endian swap: 32 bits From 183d757abf6b505fde6ac6051a9e211f9dd3e027 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 23 Feb 2023 19:29:37 +0100 Subject: [PATCH 124/156] SFT-1305: Adjust decoder parameters Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/include/foundation.h | 6 +++--- extmod/foundation-rust/src/ur/decoder.rs | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/extmod/foundation-rust/include/foundation.h b/extmod/foundation-rust/include/foundation.h index d7a2da3a0..2d0f2e948 100644 --- a/extmod/foundation-rust/include/foundation.h +++ b/extmod/foundation-rust/include/foundation.h @@ -31,17 +31,17 @@ * * Must be a power of two. */ -#define UR_DECODER_MAX_SEQUENCE_COUNT 32 +#define UR_DECODER_MAX_SEQUENCE_COUNT 128 /** * Maximum message length that can be decoded. */ -#define UR_DECODER_MAX_MESSAGE_LEN (UR_DECODER_MAX_FRAGMENT_LEN * UR_DECODER_MAX_SEQUENCE_COUNT) +#define UR_DECODER_MAX_MESSAGE_LEN (24 * 1024) /** * Maximum number of mixed parts that can be held. */ -#define UR_DECODER_MAX_MIXED_PARTS (UR_DECODER_MAX_SEQUENCE_COUNT / 4) +#define UR_DECODER_MAX_MIXED_PARTS 8 /** * Size of the decoder queue. diff --git a/extmod/foundation-rust/src/ur/decoder.rs b/extmod/foundation-rust/src/ur/decoder.rs index 1d2367385..5d9334180 100644 --- a/extmod/foundation-rust/src/ur/decoder.rs +++ b/extmod/foundation-rust/src/ur/decoder.rs @@ -19,18 +19,17 @@ pub const UR_DECODER_MAX_STRING: usize = 1408; /// Maximum sequence count for the decoder. /// /// Must be a power of two. -pub const UR_DECODER_MAX_SEQUENCE_COUNT: usize = 32; +pub const UR_DECODER_MAX_SEQUENCE_COUNT: usize = 128; /// Maximum fragment length. pub const UR_DECODER_MAX_FRAGMENT_LEN: usize = max_fragment_len(UR_DECODER_MAX_STRING); /// Maximum message length that can be decoded. -pub const UR_DECODER_MAX_MESSAGE_LEN: usize = - UR_DECODER_MAX_FRAGMENT_LEN * UR_DECODER_MAX_SEQUENCE_COUNT; +pub const UR_DECODER_MAX_MESSAGE_LEN: usize = 24 * 1024; /// Maximum number of mixed parts that can be held. -pub const UR_DECODER_MAX_MIXED_PARTS: usize = UR_DECODER_MAX_SEQUENCE_COUNT / 4; +pub const UR_DECODER_MAX_MIXED_PARTS: usize = 8; /// Size of the decoder queue. pub const UR_DECODER_QUEUE_SIZE: usize = 8; From e9bfbd24344d529a3c43d836ebf16c0e6f58366b Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 23 Feb 2023 20:22:37 +0100 Subject: [PATCH 125/156] SFT-1303: Add Rustup to DEVELOPMENT.md Signed-off-by: Jean-Pierre De Jesus DIAZ --- DEVELOPMENT.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 817f29111..08885f605 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -30,6 +30,8 @@ Several tools are required for building Passport. #### Install Rust Toolchain +First install the `rustup` tool from [rustup.rs](https://rustup.rs/). + rustup default 1.67.1 rustup target add aarch64-unknown-none # For the simulator. Only if on macOS with an M1 CPU. rustup target add thumbv7em-none-eabihf From 2ac2b0517b58b7234110a3578e87198443e04d59 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 23 Feb 2023 19:18:33 +0100 Subject: [PATCH 126/156] SFT-1304: Show error when sequence count is too big Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/src/ur/decoder.rs | 25 +++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/extmod/foundation-rust/src/ur/decoder.rs b/extmod/foundation-rust/src/ur/decoder.rs index 36ebc9ce6..c1be1ec22 100644 --- a/extmod/foundation-rust/src/ur/decoder.rs +++ b/extmod/foundation-rust/src/ur/decoder.rs @@ -3,7 +3,7 @@ //! Decoder. -use core::{slice, str}; +use core::{fmt, slice, str}; use ur::UR; use ur_foundation::{ur, ur::decoder::Error}; @@ -91,6 +91,14 @@ pub unsafe extern "C" fn ur_decoder_receive( .map_err(|e| unsafe { UR_Error::other(&e) }) .and_then(|ur| { UR::parse(ur).map_err(|e| unsafe { UR_Error::other(&e) }) + }) + .and_then(|ur| match ur.sequence_count() { + Some(n) if n > UR_DECODER_MAX_SEQUENCE_COUNT as u32 => { + Err(unsafe { + UR_Error::other(&TooManySequences { sequence_count: n }) + }) + } + _ => Ok(ur), }); let ur = match result { @@ -273,3 +281,18 @@ pub unsafe extern "C" fn ur_decode_single_part( true } + +struct TooManySequences { + sequence_count: u32, +} + +impl fmt::Display for TooManySequences { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "The UR contains more sequences than we can handle.\n\nMaximum sequence count supported: {}.\n\nMessage sequence count: {}.", + UR_DECODER_MAX_SEQUENCE_COUNT, + self.sequence_count, + ) + } +} From e6b730c465d8a344ac8fc2f13e6e351db56e2e10 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 24 Feb 2023 20:17:35 +0100 Subject: [PATCH 127/156] SFT-1366: Use single variable only Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index 721b7f8f2..39a71e1be 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -81,12 +81,11 @@ async def common_flow(self): from flows import SignPsbtCommonFlow # This flow validates and signs if all goes well, and returns the signed psbt - result = await SignPsbtCommonFlow(self.psbt_len).run() + self.psbt = await SignPsbtCommonFlow(self.psbt_len).run() - if result is None: + if self.psbt is None: self.set_result(False) else: - self.psbt = result self.goto(self.show_signed_transaction) async def show_signed_transaction(self): From e8dcc1f9fad0de778b35b851639e291185f663a5 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 27 Feb 2023 10:17:00 +0100 Subject: [PATCH 128/156] SFT-1366: Always initialize unknown to a dict Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/psbt.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index 44ece24fb..64f66d851 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -157,7 +157,7 @@ class psbtProxy: def __init__(self): self.fd = None - # self.unknown = {} + self.unknown = {} def __getattr__(self, nm): if nm in self.blank_flds: @@ -306,8 +306,6 @@ def store(self, kt, key, val): elif kt == PSBT_OUT_WITNESS_SCRIPT: self.witness_script = val else: - if not self.unknown: - self.unknown = {} self.unknown[key] = val def serialize(self, out_fd, my_idx): @@ -325,9 +323,8 @@ def wr(*a): if self.witness_script: wr(PSBT_OUT_WITNESS_SCRIPT, self.witness_script) - if self.unknown: - for k in self.unknown: - wr(k[0], self.unknown[k], k[1:]) + for k in self.unknown: + wr(k[0], self.unknown[k], k[1:]) def validate(self, out_idx, txo, my_xfp, active_multisig): # Do things make sense for this output? @@ -781,8 +778,6 @@ def store(self, kt, key, val): self.sighash = unpack(' Date: Mon, 27 Feb 2023 10:18:19 +0100 Subject: [PATCH 129/156] SFT-1366: Remove HashNDump commented class Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/psbt.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index 64f66d851..96fac31a2 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -36,21 +36,6 @@ # print some things # DEBUG = const(1) -# class HashNDump: -# def __init__(self, d=None): -# self.rv = trezorcrypto.sha256() -# print('Hashing: ', end='') -# if d: -# self.update(d) -# -# def update(self, d): -# print(b2a_hex(d), end=' ') -# self.rv.update(d) -# -# def digest(self): -# print(' END') -# return self.rv.digest() - def seq_to_str(seq): # take a set or list of numbers and show a tidy list in order. From b42130241841c4bb815dce0d017b2bd3be6ab8a7 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 27 Feb 2023 10:43:17 +0100 Subject: [PATCH 130/156] SFT-1366: Use constant for PSBT magic Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/psbt.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index 96fac31a2..4b858b549 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -36,6 +36,8 @@ # print some things # DEBUG = const(1) +_MAGIC = b'psbt\xff' + def seq_to_str(seq): # take a set or list of numbers and show a tidy list in order. @@ -1329,7 +1331,7 @@ def consider_keys(self): def read_psbt(cls, fd): # read in a PSBT file. Captures fd and keeps it open. hdr = fd.read(5) - if hdr != b'psbt\xff': + if hdr != _MAGIC: raise ValueError("bad hdr") rv = cls() @@ -1353,7 +1355,7 @@ def serialize(self, out_fd, upgrade_txn=False): def wr(*a): self.write(out_fd, *a) - out_fd.write(b'psbt\xff') + out_fd.write(_MAGIC) if upgrade_txn and self.is_complete(): # write out the ready-to-transmit txn From 72d45b0a3cd876f866331e7366776301f93aa6e4 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 27 Feb 2023 10:44:06 +0100 Subject: [PATCH 131/156] SFT-1366: Remove PSBT serialization memory code Serialization uses a fixed buffer so it doesn't consume any extra memory. Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/psbt.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index 4b858b549..e8c19d281 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -1382,23 +1382,14 @@ def wr(*a): for k in self.unknown: wr(k[0], self.unknown[k], k[1:]) - # import micropython - # print('======================================') - # micropython.mem_info(1) - # print('======================================') - # sep between globals and inputs out_fd.write(b'\0') for idx, inp in enumerate(self.inputs): - # print('Input {}: free mem={}'.format(idx, gc.mem_free())) - gc.collect() # Give collector a chance to run to help avoid fragmentation inp.serialize(out_fd, idx) out_fd.write(b'\0') for idx, outp in enumerate(self.outputs): - # print('Output {}: free mem={}'.format(idx, gc.mem_free())) - gc.collect() # Give collector a chance to run to help avoid fragmentation outp.serialize(out_fd, idx) out_fd.write(b'\0') From dce35f46ecd2ad052392d12ec52a8d90b14fe642 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 27 Feb 2023 18:53:59 +0100 Subject: [PATCH 132/156] SFT-1366: Delete PSBT object after serialization. Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py index 39a71e1be..a8251afea 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_qr_flow.py @@ -112,6 +112,7 @@ async def show_signed_transaction(self): self.set_result(False) return + self.psbt = None gc.collect() if self.qr_type == QRType.QR: From 71288ca4790cde6962bf45e7f394ced5043000ec Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 27 Feb 2023 15:59:01 -0600 Subject: [PATCH 133/156] SFT-1370: fixed error in multisig import --- .../modules/flows/import_multisig_wallet_from_qr_flow.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py index 9be03e344..64b47e81c 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py @@ -4,6 +4,7 @@ # import_multisig_wallet_from_qr_flow.py - Import a multisig wallet from a QR code from flows import Flow +from foundation import ur class ImportMultisigWalletFromQRFlow(Flow): @@ -13,7 +14,7 @@ def __init__(self): self.error = None async def scan_qr_code(self): - from pages import ScanQRPage + from pages import ScanQRPage, ErrorPage from multisig_wallet import MultisigWallet result = await ScanQRPage().show() @@ -25,7 +26,11 @@ async def scan_qr_code(self): await ErrorPage(text='Unable to scan QR code.').show() return - data = result.data + if not isinstance(result.data, ur.Value): + await ErrorPage(text='Bad QR format.').show() + return + + data = result.data.unwrap_bytes() if isinstance(data, (bytes, bytearray)): data = data.decode('utf-8') From 011f10aabfb1151a01fd5d9de84b6718530ed9f9 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 27 Feb 2023 16:03:10 -0600 Subject: [PATCH 134/156] SFT-1370: moved ur import into function --- .../modules/flows/import_multisig_wallet_from_qr_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py index 64b47e81c..fd9ffdbbb 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_from_qr_flow.py @@ -4,7 +4,6 @@ # import_multisig_wallet_from_qr_flow.py - Import a multisig wallet from a QR code from flows import Flow -from foundation import ur class ImportMultisigWalletFromQRFlow(Flow): @@ -16,6 +15,7 @@ def __init__(self): async def scan_qr_code(self): from pages import ScanQRPage, ErrorPage from multisig_wallet import MultisigWallet + from foundation import ur result = await ScanQRPage().show() if result is None: From bc1eb473a4b37f182ff616a31e0f37ba098fca3e Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 28 Feb 2023 14:40:52 +0100 Subject: [PATCH 135/156] SFT-1372: Fix single part URs completion Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../stm32/boards/Passport/modules/data_codecs/ur2_codec.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py index b27eaa67f..2da37133d 100644 --- a/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py +++ b/ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py @@ -43,9 +43,15 @@ def add_data(self, data): raise DecodeError(str(exc)) def estimated_percent_complete(self): + if self.value is not None: + return 100 + return ur.decoder_estimated_percent_complete() def is_complete(self): + if self.value is not None: + return True + return ur.decoder_is_complete() def decode(self): From 61fb285881005656f9417bd615ed160e98435ab9 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Tue, 28 Feb 2023 14:41:33 +0100 Subject: [PATCH 136/156] SFT-1372: Use ur.Value for Health Check response Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../Passport/modules/flows/casa_health_check_qr_flow.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py index edb044d7c..af87814f3 100644 --- a/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/casa_health_check_qr_flow.py @@ -83,7 +83,10 @@ async def show_signed_message(self): sig = b2a_base64(self.signature).decode('ascii').strip() - signed_message = RFC_SIGNATURE_TEMPLATE.format(addr=self.address, msg=self.text, blockchain='BITCOIN', sig=sig) + signed_message = ur.new_bytes(RFC_SIGNATURE_TEMPLATE.format(addr=self.address, + msg=self.text, + blockchain='BITCOIN', + sig=sig)) result = await ShowQRPage( qr_type=QRType.UR2, From 0c497bbc14cfda1ffb355ad4ce1fc7a7bb494dce Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 23 Feb 2023 15:21:12 -0600 Subject: [PATCH 137/156] SFT-1201: fixed sd summary export to be similar to backup flow --- .../Passport/modules/flows/export_summary_flow.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/export_summary_flow.py b/ports/stm32/boards/Passport/modules/flows/export_summary_flow.py index 056e7fd8a..3f8ff4524 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_summary_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_summary_flow.py @@ -28,19 +28,14 @@ async def confirm_export(self): self.set_result(False) async def do_export(self): - if not _try_microsd(): - result = await InsertMicroSDPage().show() - if not result: - self.set_result(False) - else: - return # Will cause this state to rerun and check the card again - (error,) = await spinner_task('Exporting wallet summary', export_summary_task, ['public.txt']) if error is None: await SuccessPage(text='Exported successfully.').show() self.set_result(True) elif error is Error.MICROSD_CARD_MISSING: - return + result = await InsertMicroSDPage().show() + if not result: + self.set_result(False) elif error is Error.FILE_WRITE_ERROR: await ErrorPage(text='Unable to export summary file. Error writing to file.').show() self.set_result(False) From d7652c2565fcc673c591de88fe62dec7d7805009 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 1 Mar 2023 11:41:01 +0100 Subject: [PATCH 138/156] SFT-1388: Fix import of InsertMicroSDPage Signed-off-by: Jean-Pierre De Jesus DIAZ --- .../Passport/modules/flows/export_multisig_microsd_flow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py index 2d2faef15..59fdc67e1 100644 --- a/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/export_multisig_microsd_flow.py @@ -56,6 +56,7 @@ async def create_file(self): return async def show_insert_microsd_error(self): + from pages import InsertMicroSDPage result = await InsertMicroSDPage().show() if not result: self.set_result(False) From cf7dd2438feb98e65478f5549fc0cdf93baaf151 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Mon, 30 Jan 2023 16:10:20 -0600 Subject: [PATCH 139/156] PASS1-638: stop showing self-send as huge fee --- ports/stm32/boards/Passport/modules/psbt.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index e8c19d281..99d127501 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -1135,12 +1135,16 @@ def consider_outputs(self): if sending_to_self: self.warnings.append(('Self-Send', 'All outputs are being sent back to this wallet.')) - - if fee > total_non_change_out: - self.warnings.append(('Huge Fee', 'Network fee is larger than the amount you are sending.')) - elif per_fee >= 5: - self.warnings.append(('Big Fee', 'Network fee is more than ' - '5%% of total non-change value (%.1f%%).' % per_fee)) + per_fee = (fee / self.total_value_out) * 100 + if per_fee >= 5: + self.warnings.append(('Big Fee', 'Network fee is more than ' + '5%% of total non-change value (%.1f%%).' % per_fee)) + else: + if fee > total_non_change_out: + self.warnings.append(('Huge Fee', 'Network fee is larger than the amount you are sending.')) + elif per_fee >= 5: + self.warnings.append(('Big Fee', 'Network fee is more than ' + '5%% of total non-change value (%.1f%%).' % per_fee)) # Enforce policy related to change outputs self.consider_dangerous_change(self.my_xfp) From a2b1272e8955408929766bc065cf9966a712a5c0 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 1 Feb 2023 12:18:51 -0600 Subject: [PATCH 140/156] PASS1-638: showed self-send amounts --- .../Passport/modules/flows/sign_psbt_common_flow.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py index 24401a902..6fadc95c7 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py @@ -74,7 +74,18 @@ async def show_transaction_details(self): if first: # All outputs are change, so no amount is being "sent" to another wallet - outputs.write('\n{}\nNone'.format(recolor(HIGHLIGHT_TEXT_HEX, 'Amount'))) + # outputs.write('\n{}\nNone'.format(recolor(HIGHLIGHT_TEXT_HEX, 'Amount'))) + # All outputs are change, but we want to show the amount of the self-send + first = True + for idx, tx_out in self.psbt.output_iter(): + outp = self.psbt.outputs[idx] + + if first: + frist = False + else: + outputs.write('\n') + + outputs.write(self.render_output(tx_out)) # print('total_out={} total_in={} # change={}'.format=(self.psbt.total_value_out, self.psbt.total_value_in, From 32b1557b0cf98de816cd0278b12cb88b81991baf Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 1 Feb 2023 12:22:15 -0600 Subject: [PATCH 141/156] PASS1-638: removed old code --- .../boards/Passport/modules/flows/sign_psbt_common_flow.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py index 6fadc95c7..f19dc9ac4 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py @@ -73,8 +73,6 @@ async def show_transaction_details(self): outputs.write(self.render_output(tx_out)) if first: - # All outputs are change, so no amount is being "sent" to another wallet - # outputs.write('\n{}\nNone'.format(recolor(HIGHLIGHT_TEXT_HEX, 'Amount'))) # All outputs are change, but we want to show the amount of the self-send first = True for idx, tx_out in self.psbt.output_iter(): From c5db96c3a643a562ecc9d1aaa099681350f9485c Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 2 Feb 2023 09:31:18 -0600 Subject: [PATCH 142/156] PASS1-638: fixed typo in "first" --- .../boards/Passport/modules/flows/sign_psbt_common_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py index f19dc9ac4..0433f3fd4 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py @@ -79,7 +79,7 @@ async def show_transaction_details(self): outp = self.psbt.outputs[idx] if first: - frist = False + first = False else: outputs.write('\n') From ba966b8afe41a8bb4b5782e047f5342509d74ee4 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Tue, 14 Feb 2023 10:47:50 -0600 Subject: [PATCH 143/156] PASS1-638: changed formatting of self-send outputs --- .../modules/flows/sign_psbt_common_flow.py | 24 +++++++------------ ports/stm32/boards/Passport/modules/psbt.py | 8 +++---- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py index 0433f3fd4..aca3253f8 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py @@ -59,10 +59,14 @@ async def show_transaction_details(self): try: outputs = uio.StringIO() + if self.psbt.self_send: + outputs.write("\n{}\n".format(recolor(HIGHLIGHT_TEXT_HEX, 'Self-Send'))) + first = True for idx, tx_out in self.psbt.output_iter(): outp = self.psbt.outputs[idx] - if outp.is_change: + # Show change outputs if this is a self-send + if outp.is_change and not self.psbt.self_send: continue if first: @@ -72,19 +76,6 @@ async def show_transaction_details(self): outputs.write(self.render_output(tx_out)) - if first: - # All outputs are change, but we want to show the amount of the self-send - first = True - for idx, tx_out in self.psbt.output_iter(): - outp = self.psbt.outputs[idx] - - if first: - first = False - else: - outputs.write('\n') - - outputs.write(self.render_output(tx_out)) - # print('total_out={} total_in={} # change={}'.format=(self.psbt.total_value_out, self.psbt.total_value_in, # self.psbt.total_value_in - self.psbt.total_value_out)) @@ -95,7 +86,10 @@ async def show_transaction_details(self): card_header={'title': 'Transaction Details'} ).show() if result: - self.goto(self.show_change) + if self.psbt.self_send: + self.goto(self.show_warnings) + else: + self.goto(self.show_change) else: self.set_result(None) diff --git a/ports/stm32/boards/Passport/modules/psbt.py b/ports/stm32/boards/Passport/modules/psbt.py index 99d127501..89e45e46e 100644 --- a/ports/stm32/boards/Passport/modules/psbt.py +++ b/ports/stm32/boards/Passport/modules/psbt.py @@ -832,6 +832,7 @@ def __init__(self): self.total_value_in = None self.presigned_inputs = set() self.multisig_import_needs_approval = False + self.self_send = False # when signing segwit stuff, there is some re-use of hashes self.hashPrevouts = None @@ -1120,7 +1121,6 @@ def consider_outputs(self): pass # check fee is reasonable - sending_to_self = False total_non_change_out = self.total_value_out - total_change # print('total_non_change_out={} self.total_value_out={} total_change={}'.format(total_non_change_out, # self.total_value_out, total_change)) @@ -1128,13 +1128,13 @@ def consider_outputs(self): if self.total_value_out == 0: per_fee = 100 elif total_non_change_out == 0: - sending_to_self = True + self.self_send = True else: # Calculate fee based on non-change output value per_fee = (fee / total_non_change_out) * 100 - if sending_to_self: - self.warnings.append(('Self-Send', 'All outputs are being sent back to this wallet.')) + if self.self_send: + # self.warnings.append(('Self-Send', 'All outputs are being sent back to this wallet.')) per_fee = (fee / self.total_value_out) * 100 if per_fee >= 5: self.warnings.append(('Big Fee', 'Network fee is more than ' From 4117cb99448963b39f4dd750d2e7c38ecf08dc69 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 1 Mar 2023 13:53:05 +0100 Subject: [PATCH 144/156] SFT-1397: Return UR for Electrum export when using QR Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/wallets/electrum.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/wallets/electrum.py b/ports/stm32/boards/Passport/modules/wallets/electrum.py index a85d7ab88..be25a3c27 100644 --- a/ports/stm32/boards/Passport/modules/wallets/electrum.py +++ b/ports/stm32/boards/Passport/modules/wallets/electrum.py @@ -13,6 +13,8 @@ import stash import ujson import chains +from data_codecs.qr_type import QRType +from foundation import ur from utils import xfp2str, to_str # from .multisig_json import create_multisig_json_wallet # from .multisig_import import read_multisig_config_from_qr, read_multisig_config_from_microsd @@ -69,7 +71,10 @@ def create_electrum_export(sw_wallet=None, # Find the derivation path and account number. accts = [{'fmt': addr_type, 'deriv': acct_path, 'acct': acct_num}] msg = ujson.dumps(rv) - # print('msg={}'.format(to_str(msg))) + + if qr_type == QRType.UR2: + return (ur.new_bytes(msg), accts) + return (msg, accts) From 0ded98f203f2e074f3bf4e54f3673947e2f34324 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 1 Mar 2023 14:04:51 +0100 Subject: [PATCH 145/156] SFT-1398: Fix signature of electrum export Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/wallets/electrum.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/wallets/electrum.py b/ports/stm32/boards/Passport/modules/wallets/electrum.py index a85d7ab88..01d53abbe 100644 --- a/ports/stm32/boards/Passport/modules/wallets/electrum.py +++ b/ports/stm32/boards/Passport/modules/wallets/electrum.py @@ -93,7 +93,8 @@ def create_electrum_watch_only_export(sw_wallet=None, acct_num=0, multisig=False, legacy=False, - export_mode=None): + export_mode=None, + qr_type=None): from common import settings mode = get_bip_num_from_addr_type(addr_type, multisig) From 9f5db7012fe667470fcc7ac33b0f24843062687f Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 1 Mar 2023 14:34:56 +0100 Subject: [PATCH 146/156] SFT-1399: Fix vault export function signature Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/wallets/vault.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/wallets/vault.py b/ports/stm32/boards/Passport/modules/wallets/vault.py index e218fe5ba..e60833f2b 100644 --- a/ports/stm32/boards/Passport/modules/wallets/vault.py +++ b/ports/stm32/boards/Passport/modules/wallets/vault.py @@ -11,7 +11,13 @@ from public_constants import AF_CLASSIC, AF_P2WPKH, AF_P2WPKH_P2SH -def create_vault_export(sw_wallet=None, addr_type=None, acct_num=0, multisig=False, legacy=False, export_mode='qr'): +def create_vault_export(sw_wallet=None, + addr_type=None, + acct_num=0, + multisig=False, + legacy=False, + export_mode='qr', + qr_type=None): from common import settings, system chain = chains.current_chain() @@ -31,5 +37,4 @@ def create_vault_export(sw_wallet=None, addr_type=None, acct_num=0, multisig=Fal accts = [{'fmt': AF_P2WPKH, 'deriv': acct_path, 'acct': acct_num}] - # print('msg={}'.format(to_str(msg))) return (msg, accts) From 6620137a9ac83590661c4f7844e689dbdb2fbe18 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 1 Mar 2023 15:02:29 +0100 Subject: [PATCH 147/156] SFT-1401: Remove debug print of Casa export Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/wallets/casa.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/wallets/casa.py b/ports/stm32/boards/Passport/modules/wallets/casa.py index 1fd354fe3..d46c8b455 100644 --- a/ports/stm32/boards/Passport/modules/wallets/casa.py +++ b/ports/stm32/boards/Passport/modules/wallets/casa.py @@ -67,7 +67,6 @@ def create_casa_export(sw_wallet=None, '''.format(nb=chain.name, xpub=chain.serialize_public(sv.node), sym=chain.ctype, ct=chain.b44_cointype, xfp=xfp2str(settings.get('xfp'))) - print('create_casa_export() returning:\n{}'.format(s)) return (s, None) # No 'acct_info' From 30527679430877cda04a3bdee228a43a01bf3071 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Wed, 1 Mar 2023 11:06:29 -0600 Subject: [PATCH 148/156] SFT-1403: changed microSD terminology in multisig menu --- ports/stm32/boards/Passport/modules/menus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index 953ef5cb9..e93603208 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -167,7 +167,7 @@ def multisig_item_menu(): return [ {'icon': lv.ICON_TWO_KEYS, 'label': 'View Details', 'flow': ViewMultisigDetailsFlow}, {'icon': lv.ICON_SCAN_QR, 'label': 'Export via QR', 'flow': ExportMultisigQRFlow}, - {'icon': lv.ICON_MICROSD, 'label': 'Export via SD', 'flow': ExportMultisigMicrosdFlow}, + {'icon': lv.ICON_MICROSD, 'label': 'Export via microSD', 'flow': ExportMultisigMicrosdFlow}, {'icon': lv.ICON_TWO_KEYS, 'label': 'Rename', 'flow': RenameMultisigFlow}, {'icon': lv.ICON_TWO_KEYS, 'label': 'Delete', 'flow': DeleteMultisigFlow}, ] From fff2bf66ecc69ed54706d428fdb151c5cebaa73b Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 1 Mar 2023 20:14:05 +0100 Subject: [PATCH 149/156] SFT-1405: Get integers as unsigned on foundation.ur Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation/modfoundation-ur.h | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/extmod/foundation/modfoundation-ur.h b/extmod/foundation/modfoundation-ur.h index a5390736b..1402f0270 100644 --- a/extmod/foundation/modfoundation-ur.h +++ b/extmod/foundation/modfoundation-ur.h @@ -205,8 +205,8 @@ STATIC mp_obj_t mod_foundation_ur_CryptoCoinInfo_make_new(const mp_obj_type_t *t mp_obj_CryptoCoinInfo_t *o = m_new_obj(mp_obj_CryptoCoinInfo_t); o->base.type = &mod_foundation_ur_CryptoCoinInfo_type; - o->info.coin_type = mp_obj_get_int(args[0]); - o->info.network = mp_obj_get_int(args[1]); + o->info.coin_type = mp_obj_int_get_uint_checked(args[0]); + o->info.network = mp_obj_int_get_uint_checked(args[1]); return MP_OBJ_FROM_PTR(o); } @@ -241,13 +241,13 @@ STATIC mp_obj_t mod_foundation_ur_CryptoKeypath_make_new(const mp_obj_type_t *ty o->base.type = &mod_foundation_ur_CryptoKeypath_type; if (args[0].u_obj != MP_OBJ_NULL) { - o->keypath.source_fingerprint = mp_obj_get_int(args[0].u_obj); + o->keypath.source_fingerprint = mp_obj_int_get_uint_checked(args[0].u_obj); } else { o->keypath.source_fingerprint = 0; } if (args[1].u_obj != MP_OBJ_NULL) { - o->keypath.depth = mp_obj_get_int(args[1].u_obj); + o->keypath.depth = mp_obj_int_get_uint_checked(args[1].u_obj); o->keypath.has_depth = true; } else { o->keypath.depth = 0; @@ -362,7 +362,7 @@ STATIC mp_obj_t mod_foundation_ur_new_derived_key(size_t n_args, { MP_QSTR_chain_code, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_use_info, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_origin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_parent_fingerprint, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_parent_fingerprint, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -400,13 +400,18 @@ STATIC mp_obj_t mod_foundation_ur_new_derived_key(size_t n_args, origin_obj = MP_OBJ_TO_PTR(args[4].u_obj); } + uint32_t source_fingerprint = 0; + if (args[5].u_obj != MP_OBJ_NULL) { + source_fingerprint = mp_obj_int_get_uint_checked(args[5].u_obj); + } + ur_registry_new_derived_key(&value, args[0].u_bool, key_data.buf, chain_code_info.buf, &use_info_obj->info, &origin_obj->keypath, - args[5].u_int); + source_fingerprint); return MP_OBJ_FROM_PTR(mod_foundation_ur_Value_new(&value)); } @@ -441,6 +446,7 @@ STATIC mp_obj_t mod_foundation_ur_new_passport_response(size_t n_args, mp_buffer_info_t uuid = {0}; UR_Solution solution = {0}; UR_Value value = {0}; + uint32_t model = 0; static const mp_arg_t allowed_args[] = { { MP_QSTR_uuid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, @@ -448,7 +454,7 @@ STATIC mp_obj_t mod_foundation_ur_new_passport_response(size_t n_args, { MP_QSTR_word2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_word3, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_word4, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_model, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_model, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_version, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; @@ -475,12 +481,16 @@ STATIC mp_obj_t mod_foundation_ur_new_passport_response(size_t n_args, solution.word4 = (const char *)word4; solution.word4_len = word4_len; + if (args[5].u_obj != MP_OBJ_NULL) { + model = mp_obj_int_get_uint_checked(args[5].u_obj); + } + GET_STR_DATA_LEN(args[6].u_obj, passport_firmware_version, passport_firmware_version_len); ur_registry_new_passport_response(&value, uuid.buf, &solution, - args[5].u_int, + model, (const char *)passport_firmware_version, passport_firmware_version_len); @@ -507,7 +517,7 @@ STATIC mp_obj_t mod_foundation_ur_encoder_start(mp_obj_t value_in, } value = MP_OBJ_TO_PTR(value_in); - max_fragment_len = mp_obj_get_int(max_fragment_len_in); + max_fragment_len = mp_obj_int_get_uint_checked(max_fragment_len_in); ur_encoder_start(&UR_ENCODER, &value->value, max_fragment_len); return mp_const_none; From 1485fb7df5a6b7f494cad6e47efb7ae00a9cbaae Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Thu, 2 Mar 2023 13:08:49 +0100 Subject: [PATCH 150/156] SFT-1407: Fix typos in Rust code documentation Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/include/foundation.h | 6 +++--- extmod/foundation-rust/src/ur/decoder.rs | 4 ++-- extmod/foundation-rust/src/ur/registry.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extmod/foundation-rust/include/foundation.h b/extmod/foundation-rust/include/foundation.h index 26a70a94f..dfb036360 100644 --- a/extmod/foundation-rust/include/foundation.h +++ b/extmod/foundation-rust/include/foundation.h @@ -291,7 +291,7 @@ typedef struct { } UR_PassportResponse; /** - * An uniform resource. + * A uniform resource. */ typedef enum { /** @@ -356,7 +356,7 @@ extern UR_Decoder UR_DECODER; extern UR_Encoder UR_ENCODER; /** - * Receive an Uniform Resource part. + * Receive a Uniform Resource part. * * # Safety * @@ -395,7 +395,7 @@ bool ur_decoder_decode_message(UR_Decoder *decoder, UR_Error *error); /** - * Returns `true` if the string is an uniform resource, `false` otherwise. + * Returns `true` if the string is a uniform resource, `false` otherwise. * * # Safety * diff --git a/extmod/foundation-rust/src/ur/decoder.rs b/extmod/foundation-rust/src/ur/decoder.rs index c1be1ec22..a68e32fae 100644 --- a/extmod/foundation-rust/src/ur/decoder.rs +++ b/extmod/foundation-rust/src/ur/decoder.rs @@ -72,7 +72,7 @@ pub struct UR_Decoder { >, } -/// Receive an Uniform Resource part. +/// Receive a Uniform Resource part. /// /// # Safety /// @@ -196,7 +196,7 @@ pub extern "C" fn ur_decoder_decode_message( true } -/// Returns `true` if the string is an uniform resource, `false` otherwise. +/// Returns `true` if the string is a uniform resource, `false` otherwise. /// /// # Safety /// diff --git a/extmod/foundation-rust/src/ur/registry.rs b/extmod/foundation-rust/src/ur/registry.rs index 5fd7b2a14..03fd04004 100644 --- a/extmod/foundation-rust/src/ur/registry.rs +++ b/extmod/foundation-rust/src/ur/registry.rs @@ -66,7 +66,7 @@ impl<'a> Value<'a> { } } -/// An uniform resource. +/// A uniform resource. #[repr(C)] pub enum UR_Value { /// `bytes`. From 5993c7c3dbc3217cbef4b7d74f4486fb2b7452b7 Mon Sep 17 00:00:00 2001 From: Matt Gleason Date: Thu, 2 Mar 2023 16:05:19 -0600 Subject: [PATCH 151/156] SFT-1415: renamed keeper to bitcoin keeper --- ports/stm32/boards/Passport/modules/wallets/keeper.py | 2 +- ports/stm32/boards/Passport/modules/wallets/sw_wallets.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/wallets/keeper.py b/ports/stm32/boards/Passport/modules/wallets/keeper.py index 7f879fb90..047ae999b 100644 --- a/ports/stm32/boards/Passport/modules/wallets/keeper.py +++ b/ports/stm32/boards/Passport/modules/wallets/keeper.py @@ -10,7 +10,7 @@ from data_codecs.qr_type import QRType KeeperWallet = { - 'label': 'Keeper', + 'label': 'Bitcoin Keeper', 'sig_types': [ {'id': 'single-sig', 'label': 'Single-sig', 'addr_type': None, 'create_wallet': create_generic_json_wallet}, {'id': 'multisig', 'label': 'Multisig', 'addr_type': None, 'create_wallet': create_multisig_json_wallet, diff --git a/ports/stm32/boards/Passport/modules/wallets/sw_wallets.py b/ports/stm32/boards/Passport/modules/wallets/sw_wallets.py index 8ee12ef0d..4dd4f2bb2 100644 --- a/ports/stm32/boards/Passport/modules/wallets/sw_wallets.py +++ b/ports/stm32/boards/Passport/modules/wallets/sw_wallets.py @@ -5,6 +5,7 @@ # from .bitcoin_core import BitcoinCoreWallet +from .keeper import KeeperWallet from .bluewallet import BlueWallet from .btcpay import BtcPayWallet from .casa import CasaWallet @@ -14,7 +15,6 @@ from .envoy import EnvoyWallet # from .fullynoded import FullyNodedWallet # from .gordian import GordianWallet -from .keeper import KeeperWallet # from .lily import LilyWallet from .nunchuk import NunchukWallet from .simple_bitcoin_wallet import SimpleBitcoinWallet @@ -27,6 +27,7 @@ supported_software_wallets = [ EnvoyWallet, BitcoinCoreWallet, + KeeperWallet, BlueWallet, BtcPayWallet, # CaravanWallet, @@ -35,7 +36,6 @@ ElectrumWallet, # FullyNodedWallet, # GordianWallet, - KeeperWallet, # LilyWallet, NunchukWallet, SimpleBitcoinWallet, From 58ca8288397ba3dcaa2b3c5e5f6794b0eba7a719 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 3 Mar 2023 13:40:14 +0100 Subject: [PATCH 152/156] SFT-1428: Fix camera color issue Signed-off-by: Jean-Pierre De Jesus DIAZ --- CHANGELOG.md | 1 + .../boards/Passport/modpassport-camera.h | 19 ------------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27f458d49..131b8d2d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - Fixed multisig config descriptions (PASS1-643) - Improved the UR animated QR codes encoder and decoder to allow signing bigger transactions. (SFT-1063) +- Fix camera color issue. (SFT-1428) [UR1]: https://github.com/CoboVault/Research/blob/master/papers/bcr-0005-ur.md diff --git a/ports/stm32/boards/Passport/modpassport-camera.h b/ports/stm32/boards/Passport/modpassport-camera.h index 516cbb49c..05c2b9882 100644 --- a/ports/stm32/boards/Passport/modpassport-camera.h +++ b/ports/stm32/boards/Passport/modpassport-camera.h @@ -71,10 +71,6 @@ STATIC mp_obj_t mod_passport_camera_snapshot(void) { // that the address is not NULL. uint16_t *framebuffer = framebuffer_camera(); -#ifdef SCREEN_MODE_COLOR - swizzle_u16(framebuffer, CAMERA_HOR_RES, CAMERA_VER_RES); -#endif // SCREEN_MODE_COLOR - // Remove vertical line from the camera. for (int y = 0; y < CAMERA_VER_RES; y++) { int line = y * CAMERA_HOR_RES; @@ -167,18 +163,3 @@ STATIC const mp_obj_module_t mod_passport_camera_module = { .base = {&mp_type_module}, .globals = (mp_obj_dict_t*)&mod_passport_camera_globals, }; - -#ifdef SCREEN_MODE_COLOR -STATIC void swizzle_u16(uint16_t* buffer, int w, int h) { - uint16_t* end = buffer + (w * h); - - while (buffer < end) { - uint16_t c = __builtin_bswap16(*buffer); - uint16_t b = (c & 0xF800) >> 11; - uint16_t g = c & 0x07E0; - uint16_t r = (c & 0x001F) << 11; - *buffer = __builtin_bswap16(r | g | b); - buffer++; - } -} -#endif From 75809c6a36b6ba40320c27a01aa5cd76237eefd2 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 3 Mar 2023 13:52:45 +0100 Subject: [PATCH 153/156] SFT-1429: Change microSD/QR multisig config export title Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/menus.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index e93603208..36fe2e5ed 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -166,8 +166,10 @@ def multisig_item_menu(): return [ {'icon': lv.ICON_TWO_KEYS, 'label': 'View Details', 'flow': ViewMultisigDetailsFlow}, - {'icon': lv.ICON_SCAN_QR, 'label': 'Export via QR', 'flow': ExportMultisigQRFlow}, - {'icon': lv.ICON_MICROSD, 'label': 'Export via microSD', 'flow': ExportMultisigMicrosdFlow}, + {'icon': lv.ICON_SCAN_QR, 'label': 'Export via QR', 'flow': ExportMultisigQRFlow, + 'statusbar': {'title': 'EXPORT'}}, + {'icon': lv.ICON_MICROSD, 'label': 'Export via microSD', 'flow': ExportMultisigMicrosdFlow, + 'statusbar': {'title': 'EXPORT'}}, {'icon': lv.ICON_TWO_KEYS, 'label': 'Rename', 'flow': RenameMultisigFlow}, {'icon': lv.ICON_TWO_KEYS, 'label': 'Delete', 'flow': DeleteMultisigFlow}, ] From aa7641ca5827c82106e507345f73782467fb5845 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 3 Mar 2023 14:42:51 +0100 Subject: [PATCH 154/156] SFT-1432: Don't reset PIN on dev factory reset flow Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py b/ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py index 613ca2869..8dcc49562 100644 --- a/ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/reset_pin_flow.py @@ -16,12 +16,12 @@ # super().__init__(initial_state=self.enter_old_pin, name='ResetPINFlow') # async def enter_old_pin(self): -# self.old_pin = await PINEntryPage( +# (self.old_pin, is_done) = await PINEntryPage( # card_header={'title': 'Enter Current PIN'}, # security_words_message='Remember these Security Words?', # left_micron=microns.Back, # right_micron=microns.Forward).show() -# if self.old_pin is None: +# if not is_done: # self.set_result(None) # return # else: From 886a8283d4b47c1b848dbb2a468e3e4e2a0f7c97 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Fri, 3 Mar 2023 14:37:12 +0100 Subject: [PATCH 155/156] SFT-1431: Fix developer menu entries Signed-off-by: Jean-Pierre De Jesus DIAZ --- ports/stm32/boards/Passport/modules/menus.py | 28 +++++++++----------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/ports/stm32/boards/Passport/modules/menus.py b/ports/stm32/boards/Passport/modules/menus.py index e93603208..ad2e6c8e8 100644 --- a/ports/stm32/boards/Passport/modules/menus.py +++ b/ports/stm32/boards/Passport/modules/menus.py @@ -240,43 +240,41 @@ def advanced_menu(): # LoginFlow, # NewSeedFlow, # SetInitialPINFlow, -# DeveloperFunctionsFlow, -# ResetPINFlow, +# # DeveloperFunctionsFlow, +# # ResetPINFlow, # SpinDelayFlow # ) # from pages import BatteryPage, StatusPage, ShowQRPage # from data_codecs.qr_type import QRType - +# from foundation import ur +# # return [ # {'icon': lv.ICON_BATTERY, 'label': 'Battery', 'page': BatteryPage}, -# {'icon': lv.ICON_ERASE, 'label': 'Factory Reset', -# 'flow': DeveloperFunctionsFlow, 'args': {'fn_name': 'factory_reset'}}, # {'icon': lv.ICON_RETRY, 'label': 'Spin!!!', 'flow': SpinDelayFlow, 'args': {'delay_ms': 10000}}, -# {'icon': lv.ICON_SETTINGS, 'label': 'Dump Settings', -# 'flow': DeveloperFunctionsFlow, 'args': {'fn_name': 'dump_settings'}}, # {'icon': lv.ICON_SCAN_QR, 'label': 'Show Setup QR', 'page': StatusPage, 'args': { # 'text': 'Scan the QR code above with Envoy.', 'icon': lv.LARGE_ICON_SETUP_QR}, 'card_header': {}}, # {'icon': lv.ICON_SCAN_QR, 'label': 'Show Test UR', 'page': ShowQRPage, 'args': { -# 'qr_type': QRType.UR2, 'qr_data': 'sdflkajd lkajdslkajdslkajsdkajdlkajsdflkajdslkjasdlkjadsflkajsdsdfl' + -# 'lkajdslkajdslkajsdkajdlkajsdflkajdslkjasdlkjadsflkajsdflksdflkajd lkajdslkajdslkajsdkajdlkajsdajdslkj' + -# 'asdlkjadsflkajsdflksdflkajd lkajdslkajdslkajsdkajdlkajsdflkajdslkjasdlkjadsflkajsdflksdflkajd lkajds' + -# 'lkajdslkajsdkajdlkajsdflkajdslkjasdlkja'}}, +# 'qr_type': QRType.UR2, 'qr_data': ur.new_bytes('test data' * 10)}}, # {'icon': lv.ICON_SHIELD, 'label': 'Supply Chain', 'flow': ScvFlow}, # {'icon': lv.ICON_ONE_KEY, 'label': 'Login', 'flow': LoginFlow}, # {'icon': lv.ICON_SEED, 'label': 'New Seed', 'flow': NewSeedFlow, 'args': {'refresh_cards_when_done': True}}, -# {'icon': lv.ICON_CHANGE_PIN, 'label': 'Set PIN', 'flow': SetInitialPINFlow}, -# {'icon': lv.ICON_CHANGE_PIN, 'label': 'Reset PIN', 'flow': ResetPINFlow}, +# {'icon': lv.ICON_ONE_KEY, 'label': 'Set PIN', 'flow': SetInitialPINFlow}, +# # {'icon': lv.ICON_ONE_KEY, 'label': 'Reset PIN', 'flow': ResetPINFlow}, +# # {'icon': lv.ICON_ERASE, 'label': 'Factory Reset', +# # 'flow': DeveloperFunctionsFlow, 'args': {'fn_name': 'factory_reset'}}, +# # {'icon': lv.ICON_SETTINGS, 'label': 'Dump Settings', +# # 'flow': DeveloperFunctionsFlow, 'args': {'fn_name': 'dump_settings'}}, # # {'icon': lv.ICON_SETTINGS, 'label': 'I\'m Busy!', 'page': LongTextPage, # # 'args': {'show_busy': True, 'message': 'Signing Transaction...'}}, # # {'icon': lv.ICON_SETTINGS, 'label': 'FCC Test', 'flow': FCCTestFlow}, # # {'icon': lv.ICON_ABOUT, 'label': 'Color Picker', 'page': ColorPickerPage}, -# # {'icon': lv.ICON_CHANGE_PIN, 'label': 'Enter PIN', 'page': PINEntryPage, +# # {'icon': lv.ICON_ONE_KEY, 'label': 'Enter PIN', 'page': PINEntryPage, # # 'args': {'title': 'Enter Initial PIN'}}, # # {'icon': lv.ICON_FOLDER, 'label': 'Rename Account', 'page': TextInputPage, # # 'args': {'card_header': {'title': 'Rename Account', 'icon': lv.ICON_ABOUT, 'right_text': '!!', # # 'bg_color': RED, 'fg_color': FD_BLUE}}}, # # {'icon': lv.ICON_SEED, 'label': 'Enter Seed', 'page': PredictiveTextInputPage}, -# # {'icon': lv.ICON_CHANGE_PIN, 'label': 'Enter Backup Code', 'page': BackupCodePage}, +# # {'icon': lv.ICON_ONE_KEY, 'label': 'Enter Backup Code', 'page': BackupCodePage}, # ] def extensions_menu(): From f0e351db80e5d53ac81068be43081cca069d0a90 Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Mon, 13 Mar 2023 15:25:19 +0100 Subject: [PATCH 156/156] SFT-1526: Update cargo dependencies Signed-off-by: Jean-Pierre De Jesus DIAZ --- extmod/foundation-rust/Cargo.lock | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/extmod/foundation-rust/Cargo.lock b/extmod/foundation-rust/Cargo.lock index 07b4daccc..6febb1ac9 100644 --- a/extmod/foundation-rust/Cargo.lock +++ b/extmod/foundation-rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "atomic-polyfill" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d299f547288d6db8d5c3a2916f7b2f66134b15b8c1ac1c4357dd3b8752af7bb2" +checksum = "c314e70d181aa6053b26e3f7fbf86d1dfff84f816a6175b967666b3506ef7289" dependencies = [ "critical-section", ] @@ -115,9 +115,9 @@ dependencies = [ [[package]] name = "minicbor" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d319d47468f164e5138b1c629bdd82ea3da0784ed1d41a22f8e0bcef76c2ae52" +checksum = "d7005aaf257a59ff4de471a9d5538ec868a21586534fff7f85dd97d4043a6139" dependencies = [ "minicbor-derive", ] @@ -177,18 +177,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "50686e0021c4136d1d453b2dfe059902278681512a34d4248435dc34b6b5c8ec" dependencies = [ "proc-macro2", ] @@ -234,9 +234,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "siphasher" @@ -246,9 +246,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "spin" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dccf47db1b41fa1573ed27ccf5e08e3ca771cb994f776668c5ebda893b248fc" +checksum = "b5d6e0250b93c8427a177b849d144a96d5acc57006149479403d7861ab721e34" dependencies = [ "lock_api", ] @@ -261,9 +261,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "1.0.108" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -272,9 +272,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "ur"