File size: 1,743 Bytes
f592f80 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | """Sign an existing, prepared AFFECTOR release copy from the inside out."""
from pathlib import Path
import argparse,subprocess
p=argparse.ArgumentParser(description=__doc__);p.add_argument('--app',type=Path,required=True);p.add_argument('--identity',required=True);a=p.parse_args();app=a.app.resolve()
if not (app/'Contents/Info.plist').is_file():raise SystemExit('Expected an existing .app bundle')
framework=app/'Contents/Resources/Python.framework'
for name,target in {'Versions/Current':'3.14','Python':'Versions/Current/Python','Resources':'Versions/Current/Resources','Headers':'Versions/Current/Headers'}.items():
link=framework/name
if not link.exists() and not link.is_symlink():link.symlink_to(target)
magic={bytes.fromhex(s) for s in ('cffaedfe','cefaedfe','feedfacf','feedface','cafebabe','cafebabf','bebafeca','bfbafeca')}
def macho(path):
if path.is_symlink() or not path.is_file():return False
with path.open('rb') as f:return f.read(4) in magic
def sign(path):
r=subprocess.run(['codesign','--force','--sign',a.identity,'--timestamp','--options','runtime',str(path)],capture_output=True,text=True)
if r.returncode:raise RuntimeError(str(path)+'\n'+r.stderr)
binaries=sorted((x for x in app.rglob('*') if macho(x)),key=lambda x:len(x.parts),reverse=True)
print('Signing',len(binaries),'native binaries',flush=True)
for i,b in enumerate(binaries):
sign(b)
if (i+1)%25==0:print(i+1,'signed',flush=True)
for b in sorted((x for x in app.rglob('*') if x.is_dir() and not x.is_symlink() and x.suffix in ('.app','.framework','.xpc','.appex')),key=lambda x:len(x.parts),reverse=True):sign(b)
sign(app);subprocess.run(['codesign','--verify','--deep','--strict',str(app)],check=True)
print('Signed and verified',app,flush=True)
|