Skip to content

Commit 9d13997

Browse files
committed
Merge branch 'feature-windows'
2 parents b073e59 + be2b648 commit 9d13997

File tree

5 files changed

+142
-26
lines changed

5 files changed

+142
-26
lines changed

GNUmakefile

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ dist/SLIP-39.app-checkids: SLIP-39.spec
446446
# - Find each dependent key, and look at its SHA fingerprint, and then see if you have
447447
# that one in your System keychain, downloading all the named keys from apple 'til
448448
# you find the one with the matching fingerprint. Grr... Repeat 'til check-signature works.
449-
dist/SLIP-39.app: SLIP-39.spec \
449+
dist/SLIP-39.app: SLIP-39-macOS.spec \
450450
SLIP-39.metadata/entitlements.plist \
451451
images/SLIP-39.icns
452452
@echo "\n\n*** Rebuilding $@, version $(VERSION)..."
@@ -492,7 +492,7 @@ dist/SLIP-39.app: SLIP-39.spec \
492492
# +
493493
# bundle_identifier='ca.kundert.perry.SLIP39')
494494

495-
SLIP-39.spec: SLIP-39.py
495+
SLIP-39-macOS.spec: SLIP-39.py
496496
@echo "\n\n!!! Rebuilding $@; Must be manually edited..."
497497
pyinstaller --noconfirm --windowed --onefile \
498498
--codesign-identity "$(DEVID)" \
@@ -502,6 +502,23 @@ SLIP-39.spec: SLIP-39.py
502502
--hidden-import slip39 \
503503
--collect-data slip39 \
504504
$<
505+
mv SLIP-39.spec $@
506+
@echo "!!! Regenerated $@: must be manually corrected!"
507+
false # Make the build fail if we've regenerated the .spec
508+
509+
510+
dist/SLIP-39.exe: SLIP-39-win32.spec
511+
rm -rf build $@
512+
pyinstaller --noconfirm $<
513+
514+
SLIP-39-win32.spec: SLIP-39.py
515+
@echo "\n\n!!! Rebuilding $@; Must be manually edited..."
516+
pyinstaller --noconfirm --windowed --onefile \
517+
--collect-data shamir_mnemonic \
518+
--hidden-import slip39 \
519+
--collect-data slip39 \
520+
$<
521+
mv SLIP-39.spec $@
505522
@echo "!!! Regenerated $@: must be manually corrected!"
506523
false # Make the build fail if we've regenerated the .spec
507524

SLIP-39.spec renamed to SLIP-39-macOS.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ coll = COLLECT(exe,
5050
app = BUNDLE(coll,
5151
name='SLIP-39.app',
5252
icon='images/SLIP-39.icns',
53-
version='7.2.1',
53+
version='7.3.0',
5454
info_plist={
55-
'CFBundleVersion':'7.2.1',
55+
'CFBundleVersion':'7.3.0',
5656
'CFBundlePackageType':'APPL',
5757
'LSApplicationCategoryType':'public.app-category.finance',
5858
'LSMinimumSystemVersion':'10.15.0',

SLIP-39-win32.spec

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
datas += collect_data_files('slip39')
7+
8+
9+
block_cipher = None
10+
11+
12+
a = Analysis(['SLIP-39.py'],
13+
pathex=[],
14+
binaries=[],
15+
datas=datas,
16+
hiddenimports=['slip39'],
17+
hookspath=[],
18+
hooksconfig={},
19+
runtime_hooks=[],
20+
excludes=[],
21+
win_no_prefer_redirects=False,
22+
win_private_assemblies=False,
23+
cipher=block_cipher,
24+
noarchive=False)
25+
pyz = PYZ(a.pure, a.zipped_data,
26+
cipher=block_cipher)
27+
28+
exe = EXE(pyz,
29+
a.scripts,
30+
a.binaries,
31+
a.zipfiles,
32+
a.datas,
33+
[],
34+
name='SLIP-39',
35+
debug=False,
36+
bootloader_ignore_signals=False,
37+
strip=False,
38+
upx=True,
39+
upx_exclude=[],
40+
runtime_tmpdir=None,
41+
console=False,
42+
disable_windowed_traceback=False,
43+
target_arch=None,
44+
codesign_identity=None,
45+
entitlements_file=None )

slip39/gui/main.py

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424

2525
log = logging.getLogger( __package__ )
2626

27-
font = ('Courier', 14)
28-
font_small = ('Courier', 10)
29-
font_bold = ('Courier', 16, 'bold italic')
27+
28+
disp_points = 14 # if sys.platform == 'darwin' else 9
29+
font = ('Courier', disp_points+0)
30+
font_small = ('Courier', disp_points-4)
31+
font_bold = ('Courier', disp_points+2, 'bold italic')
3032

3133
I_kwds = dict(
3234
change_submits = True,
@@ -638,13 +640,64 @@ def update_seed_recovered( window, values, details, passphrase=None ):
638640
return f"Recovered Seed {recohex!r} doesn't match expected: {window['-SEED-'].get()!r}"
639641

640642

643+
def user_name_full():
644+
full_name = None
645+
if sys.platform == 'darwin':
646+
command = [ '/usr/sbin/scutil' ]
647+
command_input = "show State:/Users/ConsoleUser"
648+
elif sys.platform == 'win32':
649+
command = [ 'net', 'user', os.environ['USERNAME'] ]
650+
command_input = None
651+
else: # assume *nix
652+
command = [ 'getent', 'passwd', os.environ['USER'] ]
653+
command_input = None
654+
655+
subproc = subprocess.run(
656+
command,
657+
input = command_input,
658+
capture_output = True,
659+
encoding = 'UTF-8',
660+
)
661+
assert subproc.returncode == 0 and subproc.stdout, \
662+
f"{' '.join( command )!r} command failed, or no output returned"
663+
664+
if sys.platform == 'darwin':
665+
for li in subproc.stdout.split( '\n' ):
666+
if 'kCGSessionLongUserNameKey' in li:
667+
# eg.: " kCGSessionLongUserNameKey : Perry Kundert"
668+
full_name = li.split( ':' )[1].strip()
669+
break
670+
elif sys.platform == 'win32':
671+
for li in subproc.stdout.split( '\n' ):
672+
if li.startswith( 'Full Name' ):
673+
# eg.: "Full Name IEUser"
674+
full_name = li[9:].strip()
675+
break
676+
else:
677+
# getent="perry:x:1002:1004:Perry Kundert,,,:/home/perry:/bin/bash"
678+
# >>> getent.split(':')
679+
# ['perry', 'x', '1002', '1004', 'Perry Kundert,,,', '/home/perry', '/bin/bash']
680+
pwents = subproc.stdout.split( ':' )
681+
assert len( pwents ) > 4, \
682+
f"Unrecognized passwd entry: {li}"
683+
gecos = pwents[4]
684+
full_name = gecos.split( ',' )[0] # Discard ...,building,room,phone,...
685+
686+
assert full_name, \
687+
"User's full name not found"
688+
log.info( f"Current user's full name: {full_name!r}" )
689+
return full_name
690+
691+
641692
def app(
642693
names = None,
643694
group = None,
644695
threshold = None,
645696
cryptocurrency = None,
646697
edit = None,
647698
passphrase = None,
699+
scaling = None,
700+
no_titlebar = False,
648701
):
649702
"""Convert sequence of group specifications into standard { "<group>": (<needs>, <size>) ... }"""
650703

@@ -677,24 +730,9 @@ def app(
677730
#
678731
# If no name(s) supplied, try to get the User's full name.
679732
#
680-
if not names and sys.platform == 'darwin':
733+
if not names:
681734
try:
682-
scutil = subprocess.run(
683-
[ '/usr/sbin/scutil' ],
684-
input = "show State:/Users/ConsoleUser",
685-
capture_output = True,
686-
encoding = 'UTF-8',
687-
)
688-
print( repr( scutil ))
689-
assert scutil.returncode == 0 and scutil.stdout, \
690-
"'scutil' command failed, or no output returned"
691-
for li in scutil.stdout.split( '\n' ):
692-
if 'kCGSessionLongUserNameKey' in li:
693-
# eg.: " kCGSessionLongUserNameKey : Perry Kundert"
694-
full_name = li.split( ':' )[1].strip()
695-
log.info( f"Current user's full name: {full_name!r}" )
696-
names = [ full_name ]
697-
break
735+
names = [ user_name_full() ]
698736
except Exception as exc:
699737
logging.exception( f"Failed to discover user full name: {exc}" )
700738

@@ -739,7 +777,10 @@ def app(
739777
window['-GROUPS-F-'].expand( expand_x=True )
740778
else:
741779
window = sg.Window(
742-
f"{', '.join( names or [ 'SLIP-39' ] )} Mnemonic Cards", layout, grab_anywhere=True,
780+
f"{', '.join( names or [ 'SLIP-39' ] )} Mnemonic Cards", layout,
781+
grab_anywhere = True,
782+
no_titlebar = no_titlebar,
783+
scaling = scaling,
743784
)
744785
timeout = 0 # First time through w/ new window, refresh immediately
745786

@@ -1050,6 +1091,11 @@ def main( argv=None ):
10501091
ap.add_argument( '--passphrase',
10511092
default=None,
10521093
help="Encrypt the master secret w/ this passphrase, '-' reads it from stdin (default: None/'')" )
1094+
ap.add_argument( '-s', '--scaling',
1095+
default=1, type=float,
1096+
help="Scaling for display (eg. 1.5, 0.5 for high-resolution displays), if not automatically detected")
1097+
ap.add_argument( '--no-titlebar', default=False, action='store_true',
1098+
help="Avoid displaying a title bar and border on main window" )
10531099
ap.add_argument( 'names', nargs="*",
10541100
help="Account names to produce")
10551101
args = ap.parse_args( argv )
@@ -1061,6 +1107,12 @@ def main( argv=None ):
10611107
if args.verbose:
10621108
logging.getLogger().setLevel( log_cfg['level'] )
10631109

1110+
if sys.platform == 'win32':
1111+
# Establishes a common baseline size on macOS and Windows, as long as
1112+
# SetProcessDpiAwareness( 1 ) is set, and scaling == 1.0. Ignored on macOS.
1113+
from ctypes import windll
1114+
windll.shcore.SetProcessDpiAwareness(1)
1115+
10641116
try:
10651117
app(
10661118
names = args.names,
@@ -1069,6 +1121,8 @@ def main( argv=None ):
10691121
cryptocurrency = args.cryptocurrency,
10701122
edit = args.path,
10711123
passphrase = args.passphrase,
1124+
no_titlebar = args.no_titlebar,
1125+
scaling = args.scaling,
10721126
)
10731127
except Exception as exc:
10741128
log.exception( f"Failed running App: {exc}" )

slip39/version.py

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

0 commit comments

Comments
 (0)