Skip to content

Commit 3256a5d

Browse files
committed
Clean up SLIP39.app signing, work toward macOS App Store deploy
o SLIP39.app seems to be properly signed now o Remove some vertical size from the SLIP39.app for smaller screens
1 parent 8f4eaf1 commit 3256a5d

File tree

6 files changed

+140
-35
lines changed

6 files changed

+140
-35
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ dist/
2424
.vagrant
2525
.pytest_cache/
2626
.cache/
27-
*.spec
2827
.eggs
28+
private_keys

GNUmakefile

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
#
44

55
# Change to your own Apple Developer ID, if you want to code-sign the resultant .app
6-
DEVID ?= Developer ID Application: Perry Kundert (ZD8TVTCXDS)
7-
#DEVID ?= 3rd Party Mac Developer Application: Perry Kundert (ZD8TVTCXDS)
6+
TEAMID ?= ZD8TVTCXDS
7+
DEVID ?= Developer ID Application: Perry Kundert ($(TEAMID))
8+
PKGID ?= 3rd Party Mac Developer Installer: Perry Kundert ($(TEAMID))
89
BUNDLEID ?= ca.kundert.perry.SLIP39
910

1011
# PY[3] is the target Python interpreter. It must have pytest installed.
@@ -19,7 +20,7 @@ PY3TEST = $(PY3) -m pytest $(PYTESTOPTS)
1920

2021
.PHONY: all help test doctest analyze pylint build-check build install upload clean FORCE
2122

22-
all: help
23+
all: help
2324

2425
help:
2526
@echo "GNUmakefile for cpppo. Targets:"
@@ -48,38 +49,87 @@ build-check:
4849
|| ( echo "\n*** Missing Python modules; run:\n\n $(PY3) -m pip install --upgrade pip setuptools wheel build\n" \
4950
&& false )
5051

51-
build: clean wheel app
52+
build: clean wheel app
5253

53-
wheel: dist/slip39-$(VERSION)-py3-none-any.whl
54+
wheel: dist/slip39-$(VERSION)-py3-none-any.whl
5455

5556
dist/slip39-$(VERSION)-py3-none-any.whl: build-check FORCE
5657
$(PY3) -m build
5758
@ls -last dist
5859

5960
# Install from wheel, including all optional extra dependencies
60-
install: dist/slip39-$(VERSION)-py3-none-any.whl FORCE
61+
install: dist/slip39-$(VERSION)-py3-none-any.whl FORCE
6162
$(PY3) -m pip install --force-reinstall $<[gui,serial,json]
6263

63-
# Generate, Sign and Zip the macOS SLIP39.app GUI package
64-
app: dist/SLIP39.app-$(VERSION).zip
64+
65+
app: dist/SLIP39.app
66+
67+
# Generate, Sign and Zip the macOS SLIP39.app GUI package for local/manual installation
68+
app-zip: dist/SLIP39-$(VERSION).app.zip
69+
70+
# Generate, Sign and Pacakage the macOS SLIP39.app GUI package for App Store
71+
app-pkg: dist/SLIP39-$(VERSION).pkg
72+
73+
#
74+
# Build a deployable macOS App
75+
# See: https://gist.github.com/txoof/0636835d3cc65245c6288b2374799c43
76+
# See: https://wiki.lazarus.freepascal.org/Code_Signing_for_macOS
77+
app-upload: dist/SLIP39-$(VERSION).app.zip
78+
xcrun altool --validate-app -f $< -t osx --apiKey 5H98J7LKPC --apiIssuer 5f3b4519-83ae-4e01-8d31-f7db26f68290 \
79+
&& xcrun altool --upload-app -f $< -t osx --apiKey 5H98J7LKPC --apiIssuer 5f3b4519-83ae-4e01-8d31-f7db26f68290 \
80+
81+
dist/SLIP39-$(VERSION).pkg: dist/SLIP39.app FORCE
82+
grep -q "CFBundleVersion" "$</Contents/Info.plist" || sed -i "" -e 's:<dict>:<dict>\n\t<key>CFBundleVersion</key>\n\t<string>0.0.0</string>:' "$</Contents/Info.plist"
83+
sed -i "" -e "s:0.0.0:$(VERSION):" "$</Contents/Info.plist"
84+
codesign --deep --force --options=runtime --timestamp \
85+
--entitlements ./SLIP39.metatdata/entitlements.plist \
86+
--sign "$(DEVID)" \
87+
$<
88+
codesign -dv -r- $<
89+
codesign -vv $<
90+
xcrun altool --validate-app -f $< -t osx --apiKey 5H98J7LKPC --apiIssuer 5f3b4519-83ae-4e01-8d31-f7db26f68290
91+
pkgbuild --install-location /Applications --component $< $@
92+
93+
dist/SLIP39-$(VERSION)-signed.pkg: dist/SLIP39-$(VERSION).pkg
94+
productsign --timestamp --sign "$(PKGID)" $< $@
95+
spctl -vv --assess --type install $@
96+
6597

6698
#(cd dist; zip -r SLIP39.app-$(VERSION).zip SLIP39.app)
6799
# Create a ZIP archive suitable for notarization.
68-
dist/SLIP39.app-$(VERSION).zip: dist/SLIP39.app
100+
dist/SLIP39-$(VERSION).app.zip: dist/SLIP39.app FORCE
69101
rm -f $@
70-
/usr/bin/ditto -c -k --keepParent "$(PWD)/$<" "$(PWD)/$@"
102+
# grep -q "CFBundleVersion" "$</Contents/Info.plist" || sed -i "" -e 's:<dict>:<dict>\n\t<key>CFBundleVersion</key>\n\t<string>0.0.0</string>:' "$</Contents/Info.plist"
103+
# sed -i "" -e "s:0.0.0:$(VERSION):" "$</Contents/Info.plist"
104+
# cat $</Contents/Info.plist
105+
# codesign -dv -r- $<
106+
# codesign -vv $<
107+
# codesign --deep --force --options=runtime --timestamp \
108+
# --entitlements ./SLIP39.metadata/entitlements.plist \
109+
# --sign "$(DEVID)" \
110+
# $<
111+
codesign -dv -r- $<
112+
codesign -vv $<
113+
/usr/bin/ditto -c -k --keepParent "$<" "$@"
71114
@ls -last dist
72115

73-
# Rebuild the gui; ensure we discard any partial/prior build and gui artifacts
74-
# --codesign-identity "$(DEVID)" # Nope; must change CFBundleShottVersionString before signing? Also different team IDs?
75-
dist/SLIP39.app: SLIP39.py FORCE
116+
# Rebuild the gui App; ensure we discard any partial/prior build and gui artifacts
117+
# The --onefile approach doesn't seem to work, as we need to sign things after packaging.
118+
# We need to customize the SLIP39.spec file (eg. for version), so we do not target SLIP39.py
119+
#
120+
dist/SLIP39.app: SLIP39.spec
76121
rm -rf build $@*
77-
pyinstaller --noconfirm --windowed --onefile \
122+
grep "version='$(VERSION)'" $< || sed -i "" -e "s/version='[0-9.]*'/version='$(VERSION)'/" $<
123+
pyinstaller $<
124+
125+
# Only used for initial creation of SLIP39.spec.
126+
SLIP39.spec: SLIP39.py
127+
pyinstaller --noconfirm --windowed \
128+
--codesign-identity "$(DEVID)" \
78129
--osx-bundle-identifier "$(BUNDLEID)" \
79-
--collect-data shamir_mnemonic $<
80-
sed -i "" -e "s/0.0.0/$(VERSION)/" "$@/Contents/Info.plist"
81-
cat $@/Contents/Info.plist
82-
codesign --force -s "$(DEVID)" $@
130+
--osx-entitlements-file ./SLIP39.metadata/entitlements.plist \
131+
--collect-data shamir_mnemonic \
132+
$<
83133

84134
# Support uploading a new version of slip32 to pypi. Must:
85135
# o advance __version__ number in slip32/version.py

SLIP39.metadata/entitlements.plist

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
</dict>
6+
</plist>

SLIP39.spec

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# -*- mode: python ; coding: utf-8 -*-
2+
from PyInstaller.utils.hooks import collect_data_files
3+
4+
datas = []
5+
datas += collect_data_files('shamir_mnemonic')
6+
7+
8+
block_cipher = None
9+
10+
11+
a = Analysis(['SLIP39.py'],
12+
pathex=[],
13+
binaries=[],
14+
datas=datas,
15+
hiddenimports=[],
16+
hookspath=[],
17+
hooksconfig={},
18+
runtime_hooks=[],
19+
excludes=[],
20+
win_no_prefer_redirects=False,
21+
win_private_assemblies=False,
22+
cipher=block_cipher,
23+
noarchive=False)
24+
pyz = PYZ(a.pure, a.zipped_data,
25+
cipher=block_cipher)
26+
27+
exe = EXE(pyz,
28+
a.scripts,
29+
[],
30+
exclude_binaries=True,
31+
name='SLIP39',
32+
debug=False,
33+
bootloader_ignore_signals=False,
34+
strip=False,
35+
upx=True,
36+
console=False,
37+
disable_windowed_traceback=False,
38+
target_arch=None,
39+
codesign_identity='Developer ID Application: Perry Kundert (ZD8TVTCXDS)',
40+
entitlements_file=None )
41+
coll = COLLECT(exe,
42+
a.binaries,
43+
a.zipfiles,
44+
a.datas,
45+
strip=False,
46+
upx=True,
47+
upx_exclude=[],
48+
name='SLIP39')
49+
app = BUNDLE(coll,
50+
name='SLIP39.app',
51+
icon='images/SLIP39.icns',
52+
bundle_identifier='ca.kundert.perry.SLIP39',
53+
version='6.2.0',
54+
)

slip39/gui/main.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,16 @@ def groups_layout( names, group_threshold, groups, passphrase=None ):
7676
sg.Input( sg.user_settings_get_entry( "-target folder-", ""),
7777
key='-TARGET-', size=inputs, **I_kwds ), # noqa: E127
7878
sg.FolderBrowse( **B_kwds ),
79+
sg.Text( "Card size: ", **T_kwds ),
80+
] + [
81+
sg.Radio( f"{cs}", "CS", key=f"-CS-{cs}", default=(cs == CARD), **B_kwds )
82+
for cs in CARD_SIZES
7983
],
8084
[
8185
sg.Text( "Seed Name(s): ", size=prefix, **T_kwds ),
8286
sg.Input( f"{', '.join( names )}", key='-NAMES-', size=inputs, **I_kwds ),
8387
sg.Text( "(default is 'SLIP39...'; comma-separated)", **T_kwds ),
8488
],
85-
[
86-
sg.Text( "Card size: ", size=prefix, **T_kwds ),
87-
] + [
88-
sg.Radio( f"{card}", "CS", key=f"-CS-{card}", default=(card == CARD), **B_kwds )
89-
for card in CARD_SIZES
90-
],
9189
], key='-OUTPUT-F-', **F_kwds ),
9290
],
9391
] + [
@@ -163,6 +161,7 @@ def groups_layout( names, group_threshold, groups, passphrase=None ):
163161
[
164162
sg.Text( "Requires recovery of at least: ", size=prefix, **T_kwds ),
165163
sg.Input( f"{group_threshold}", key='-THRESHOLD-', size=inputs, **I_kwds ),
164+
sg.Button( '+', **B_kwds ),
166165
sg.Text( f"(of {len(groups)} SLIP-39 Recovery Groups)",
167166
key='-RECOVERY-', **T_kwds ), # noqa: E127
168167
],
@@ -172,25 +171,21 @@ def groups_layout( names, group_threshold, groups, passphrase=None ):
172171
key='-PASSPHRASE-', size=inputs, **I_kwds ), # noqa: E127
173172
sg.Text( "(NOT Trezor compatible, and must be saved separately!!)", **T_kwds ),
174173
],
175-
[
176-
sg.Button( '+', **B_kwds ),
177-
],
178174
group_body,
179175
] ),
180176
],
181177
], key='-GROUPS-F-', **F_kwds ),
182178
],
183179
] + [
184180
[
181+
sg.Button( 'Save', **B_kwds ),
182+
sg.Button( 'Exit', **B_kwds ),
185183
sg.Frame( 'Summary', [
186184
[
187185
sg.Text( key='-SUMMARY-', **T_kwds ),
188186
]
189187
], key='-SUMMARY-F-', **F_kwds ),
190188
],
191-
[
192-
sg.Button( 'Save', **B_kwds ), sg.Button( 'Exit', **B_kwds ),
193-
],
194189
[
195190
sg.Frame( 'Status', [
196191
[
@@ -202,7 +197,7 @@ def groups_layout( names, group_threshold, groups, passphrase=None ):
202197
[
203198
sg.Frame( 'SLIP39 Mnemonics Output', [
204199
[
205-
sg.Multiline( "", key='-MNEMONICS-', size=(190,10), font=font_small )
200+
sg.Multiline( "", key='-MNEMONICS-', size=(190,6), font=font_small )
206201
]
207202
], **F_kwds ),
208203
],
@@ -575,7 +570,7 @@ def app(
575570
card = next( c for c in CARD_SIZES if values[f"-CS-{c}"] )
576571
details = write_pdfs(
577572
names = details,
578-
card = card,
573+
card = card,
579574
)
580575
except Exception as exc:
581576
status = f"Error saving PDF(s): {exc}"
@@ -618,7 +613,7 @@ def main( argv=None ):
618613
help="A group name[[<require>/]<size>] (default: <size> = 1, <require> = half of <size>, rounded up, eg. 'Frens(3/5)' )." )
619614
ap.add_argument( '-c', '--cryptocurrency', action='append',
620615
default=[],
621-
help="A crypto name and optional derivation path ('../<range>/<range>' allowed); defaults:" \
616+
help="A crypto name and optional derivation path ('../<range>/<range>' allowed); defaults:"
622617
f" {', '.join( f'{c}:{Account.path_default(c)}' for c in Account.CRYPTOCURRENCIES)}" )
623618
ap.add_argument( '--passphrase',
624619
default=None,

slip39/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version_info__ = ( 6, 1, 0 )
1+
__version_info__ = ( 6, 2, 0 )
22
__version__ = '.'.join( map( str, __version_info__ ))

0 commit comments

Comments
 (0)