From 132653285039c8402a566dc67e184a768701ccb3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Jun 2020 22:52:30 +0530 Subject: [PATCH] macOS: Notarize the kitty application This required the kitty package to be moved from Frameworks to Resources, because Apple cant codesign .pyc files and its notarization requires everything in Frameworks to be signed. Hopefully that does not break anything. Also removed the kitty-deref-symlink since it is not needed anyway and was only present for backwards compatibility. Fixes #2040 --- bypy/macos/__main__.py | 63 ++++++++++++++++++++++++++++++++++++++++-- docs/changelog.rst | 2 ++ setup.py | 6 ++-- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/bypy/macos/__main__.py b/bypy/macos/__main__.py index 890391c29..21cc34422 100644 --- a/bypy/macos/__main__.py +++ b/bypy/macos/__main__.py @@ -13,6 +13,10 @@ import tempfile import zipfile from bypy.constants import PREFIX, PYTHON, SW, python_major_minor_version +from bypy.macos_sign import ( + codesign, create_entitlements_file, make_certificate_useable, notarize_app, + verify_signature +) from bypy.utils import current_dir, py_compile, run_shell, timeit, walk iv = globals()['init_env'] @@ -76,8 +80,54 @@ def strip_files(files, argv_max=(256 * 1024)): flipwritable(*args) +def files_in(folder): + for record in os.walk(folder): + for f in record[-1]: + yield os.path.join(record[0], f) + + +def expand_dirs(items, exclude=lambda x: x.endswith('.so')): + items = set(items) + dirs = set(x for x in items if os.path.isdir(x)) + items.difference_update(dirs) + for x in dirs: + items.update({y for y in files_in(x) if not exclude(y)}) + return items + + +def do_sign(app_dir): + with current_dir(os.path.join(app_dir, 'Contents')): + # Sign all .so files + so_files = {x for x in files_in('.') if x.endswith('.so')} + codesign(so_files) + # Sign everything else in Frameworks + with current_dir('Frameworks'): + fw = set(glob.glob('*.framework')) + codesign(fw) + items = set(os.listdir('.')) - fw + codesign(expand_dirs(items)) + + # Now sign the main app + codesign(app_dir) + verify_signature(app_dir) + + def sign_app(app_dir, notarize): - pass + # Copied from iTerm2: https://github.com/gnachman/iTerm2/blob/master/iTerm2.entitlements + create_entitlements_file({ + 'com.apple.security.automation.apple-events': True, + 'com.apple.security.cs.allow-jit': True, + 'com.apple.security.device.audio-input': True, + 'com.apple.security.device.camera': True, + 'com.apple.security.personal-information.addressbook': True, + 'com.apple.security.personal-information.calendars': True, + 'com.apple.security.personal-information.location': True, + 'com.apple.security.personal-information.photos-library': True, + }) + with make_certificate_useable(): + do_sign(app_dir) + if notarize: + notarize_app(app_dir) class Freeze(object): @@ -111,6 +161,7 @@ class Freeze(object): self.add_stdlib() self.add_misc_libraries() self.compile_py_modules() + self.fix_dependencies_in_kitty() if not self.dont_strip: self.strip_files() # self.run_shell() @@ -248,6 +299,12 @@ class Freeze(object): if f.endswith('.so'): self.fix_dependencies_in_lib(f) + @flush + def fix_dependencies_in_kitty(self): + for f in walk(join(self.resources_dir, 'kitty')): + if f.endswith('.so'): + self.fix_dependencies_in_lib(f) + @flush def postprocess_package(self, src_path, dest_path): pass @@ -334,8 +391,8 @@ class Freeze(object): print('\nCompiling Python modules') self.remove_bytecode(join(self.resources_dir, 'Python')) py_compile(join(self.resources_dir, 'Python')) - self.remove_bytecode(join(self.frameworks_dir, 'kitty')) - py_compile(join(self.frameworks_dir, 'kitty')) + self.remove_bytecode(join(self.resources_dir, 'kitty')) + py_compile(join(self.resources_dir, 'kitty')) @flush def makedmg(self, d, volname, internet_enable=True, format='ULFO'): diff --git a/docs/changelog.rst b/docs/changelog.rst index 7392a17eb..b3d8fcd01 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -36,6 +36,8 @@ To update |kitty|, :doc:`follow the instructions `. - X11: Recompile keymaps on XkbNewKeyboardNotify events (:iss:`2726`) +- macOS: Notarize the kitty application (:iss:`2040`) + 0.17.4 [2020-05-09] -------------------- diff --git a/setup.py b/setup.py index 27dfe2f43..6375923ff 100755 --- a/setup.py +++ b/setup.py @@ -737,7 +737,7 @@ def build_launcher(args: Options, launcher_dir: str = '.', bundle_type: str = 's elif bundle_type == 'source': cppflags.append('-DFROM_SOURCE') if bundle_type.startswith('macos-'): - klp = '../Frameworks/kitty' + klp = '../Resources/kitty' elif bundle_type.startswith('linux-'): klp = '../{}/kitty'.format(args.libdir_name.strip('/')) elif bundle_type == 'source': @@ -942,9 +942,9 @@ def create_macos_bundle_gunk(dest: str) -> None: os.rename(ddir / 'share', ddir / 'Contents/Resources') os.rename(ddir / 'bin', ddir / 'Contents/MacOS') os.rename(ddir / 'lib', ddir / 'Contents/Frameworks') - os.symlink('kitty', ddir / 'Contents/MacOS/kitty-deref-symlink') + os.rename(ddir / 'Contents/Frameworks/kitty', ddir / 'Contents/Resources/kitty') launcher = ddir / 'Contents/MacOS/kitty' - in_src_launcher = ddir / 'Contents/Frameworks/kitty/kitty/launcher/kitty' + in_src_launcher = ddir / 'Contents/Resources/kitty/kitty/launcher/kitty' if os.path.exists(in_src_launcher): os.remove(in_src_launcher) os.makedirs(os.path.dirname(in_src_launcher), exist_ok=True)