diff --git a/.gitignore b/.gitignore index ac1ade4..80fc24d 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ Carthage/Build *.pkg *.pyc +Package/Python.framework/ +Package/entitlements.plist +Package/config.mk diff --git a/Crypt.xcodeproj/project.pbxproj b/Crypt.xcodeproj/project.pbxproj index 79220f0..6b0c9d5 100644 --- a/Crypt.xcodeproj/project.pbxproj +++ b/Crypt.xcodeproj/project.pbxproj @@ -137,22 +137,22 @@ FCD4FD8C1BEE763C00CF7F48 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1150; ORGANIZATIONNAME = "Graham Gilbert"; TargetAttributes = { FCD4FD931BEE763C00CF7F48 = { CreatedOnToolsVersion = 7.1; - LastSwiftMigration = 0930; + LastSwiftMigration = 1150; }; }; }; buildConfigurationList = FCD4FD8F1BEE763C00CF7F48 /* Build configuration list for PBXProject "Crypt" */; compatibilityVersion = "Xcode 9.3"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, + Base, ); mainGroup = FCD4FD8B1BEE763C00CF7F48; productRefGroup = FCD4FD8B1BEE763C00CF7F48; @@ -216,6 +216,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -258,7 +259,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -270,6 +271,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -306,7 +308,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -322,7 +324,7 @@ CODE_SIGN_IDENTITY = "Mac Developer"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 3.3.1; + CURRENT_PROJECT_VERSION = 4.0; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Crypt/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; @@ -331,8 +333,8 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 3.3.1; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 4.0; PRODUCT_BUNDLE_IDENTIFIER = com.grahamgilbert.Crypt; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -342,7 +344,7 @@ SWIFT_OBJC_BRIDGING_HEADER = "Crypt/Crypt-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; WRAPPER_EXTENSION = bundle; }; name = Debug; @@ -355,7 +357,7 @@ CODE_SIGN_IDENTITY = "Mac Developer"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 3.3.1; + CURRENT_PROJECT_VERSION = 4.0; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Crypt/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; @@ -364,8 +366,8 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 3.3.1; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MARKETING_VERSION = 4.0; PRODUCT_BUNDLE_IDENTIFIER = com.grahamgilbert.Crypt; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -373,7 +375,7 @@ SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = "Crypt/Crypt-Bridging-Header.h"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; WRAPPER_EXTENSION = bundle; }; name = Release; diff --git a/Crypt/Info.plist b/Crypt/Info.plist index 555a090..f672ff5 100644 --- a/Crypt/Info.plist +++ b/Crypt/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 3.3.1 + 4.0 CFBundleSignature ???? CFBundleVersion - 194 + 205 NSHumanReadableCopyright Copyright © 2018 The Crypt Project. All rights reserved. NSPrincipalClass diff --git a/Crypt/Mechanisms/CryptMechanism.swift b/Crypt/Mechanisms/CryptMechanism.swift index 283d4fa..890b638 100644 --- a/Crypt/Mechanisms/CryptMechanism.swift +++ b/Crypt/Mechanisms/CryptMechanism.swift @@ -152,7 +152,7 @@ class CryptMechanism: NSObject { var needsEncryption: Bool { set { os_log("needsEncryption set to %@", log: CryptMechanism.log, type: .default, newValue as CVarArg) - let data = NSKeyedArchiver.archivedData(withRootObject: NSNumber.init(value: newValue)) + guard let data = try? NSKeyedArchiver.archivedData(withRootObject: NSNumber.init(value: newValue), requiringSecureCoding: false) else { return } _ = setHintData(key: needsEncryptionHintKey, data: data as NSData) } @@ -161,10 +161,10 @@ class CryptMechanism: NSObject { guard let data = getHintData(key: needsEncryptionHintKey) else { return false } - guard let value = NSKeyedUnarchiver.unarchiveObject(with: data as Data) else { + guard let value = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NSNumber.self, from: data as Data) else { return false } - return (value as! NSNumber).boolValue + return (value).boolValue } } diff --git a/Package/Distribution-Template b/Package/Distribution-Template index 0a1ecdc..2b574ed 100644 --- a/Package/Distribution-Template +++ b/Package/Distribution-Template @@ -4,9 +4,9 @@ - - - + + + diff --git a/Package/FoundationPlist.py b/Package/FoundationPlist.py deleted file mode 100644 index 1ba059e..0000000 --- a/Package/FoundationPlist.py +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/python -# encoding: utf-8 -# -# Copyright 2009-2014 Greg Neagle. -# -# 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. -"""FoundationPlist.py -- a tool to generate and parse MacOSX .plist files. - -This is intended as a drop-in replacement for Python's included plistlib, -with a few caveats: - - readPlist() and writePlist() operate only on a filepath, - not a file object. - - there is no support for the deprecated functions: - readPlistFromResource() - writePlistToResource() - - there is no support for the deprecated Plist class. - -The Property List (.plist) file format is a simple XML pickle supporting -basic object types, like dictionaries, lists, numbers and strings. -Usually the top level object is a dictionary. - -To write out a plist file, use the writePlist(rootObject, filepath) -function. 'rootObject' is the top level object, 'filepath' is a -filename. - -To parse a plist from a file, use the readPlist(filepath) function, -with a file name. It returns the top level object (again, usually a -dictionary). - -To work with plist data in strings, you can use readPlistFromString() -and writePlistToString(). -""" - -# PyLint cannot properly find names inside Cocoa libraries, so issues bogus -# No name 'Foo' in module 'Bar' warnings. Disable them. -# pylint: disable=E0611 -from Foundation import NSData -from Foundation import NSPropertyListSerialization -from Foundation import NSPropertyListMutableContainers -from Foundation import NSPropertyListXMLFormat_v1_0 -# pylint: enable=E0611 - -# Disable PyLint complaining about 'invalid' camelCase names -# pylint: disable=C0103 - - -class FoundationPlistException(Exception): - """Basic exception for plist errors""" - pass - -class NSPropertyListSerializationException(FoundationPlistException): - """Read/parse error for plists""" - pass - -class NSPropertyListWriteException(FoundationPlistException): - """Write error for plists""" - pass - -def readPlist(filepath): - """ - Read a .plist file from filepath. Return the unpacked root object - (which is usually a dictionary). - """ - plistData = NSData.dataWithContentsOfFile_(filepath) - dataObject, dummy_plistFormat, error = ( - NSPropertyListSerialization. - propertyListFromData_mutabilityOption_format_errorDescription_( - plistData, NSPropertyListMutableContainers, None, None)) - if dataObject is None: - if error: - error = error.encode('ascii', 'ignore') - else: - error = "Unknown error" - errmsg = "%s in file %s" % (error, filepath) - raise NSPropertyListSerializationException(errmsg) - else: - return dataObject - - -def readPlistFromString(data): - '''Read a plist data from a string. Return the root object.''' - try: - plistData = buffer(data) - except TypeError, err: - raise NSPropertyListSerializationException(err) - dataObject, dummy_plistFormat, error = ( - NSPropertyListSerialization. - propertyListFromData_mutabilityOption_format_errorDescription_( - plistData, NSPropertyListMutableContainers, None, None)) - if dataObject is None: - if error: - error = error.encode('ascii', 'ignore') - else: - error = "Unknown error" - raise NSPropertyListSerializationException(error) - else: - return dataObject - - -def writePlist(dataObject, filepath): - ''' - Write 'rootObject' as a plist to filepath. - ''' - plistData, error = ( - NSPropertyListSerialization. - dataFromPropertyList_format_errorDescription_( - dataObject, NSPropertyListXMLFormat_v1_0, None)) - if plistData is None: - if error: - error = error.encode('ascii', 'ignore') - else: - error = "Unknown error" - raise NSPropertyListSerializationException(error) - else: - if plistData.writeToFile_atomically_(filepath, True): - return - else: - raise NSPropertyListWriteException( - "Failed to write plist data to %s" % filepath) - - -def writePlistToString(rootObject): - '''Return 'rootObject' as a plist-formatted string.''' - plistData, error = ( - NSPropertyListSerialization. - dataFromPropertyList_format_errorDescription_( - rootObject, NSPropertyListXMLFormat_v1_0, None)) - if plistData is None: - if error: - error = error.encode('ascii', 'ignore') - else: - error = "Unknown error" - raise NSPropertyListSerializationException(error) - else: - return str(plistData) - - diff --git a/Package/Makefile b/Package/Makefile index 6631565..6db985d 100644 --- a/Package/Makefile +++ b/Package/Makefile @@ -1,35 +1,41 @@ include /usr/local/share/luggage/luggage.make -PB_EXTRA_ARGS+= --info "./PackageInfo" +include config.mk +PB_EXTRA_ARGS+= --info "./PackageInfo" --sign "${DEV_INSTALL_CERT}" TITLE=Crypt GITVERSION=$(shell ./build_no.sh) BUNDLE_VERSION=$(shell /usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "../Crypt/Info.plist") PACKAGE_VERSION=${BUNDLE_VERSION}.${GITVERSION} REVERSE_DOMAIN=com.grahamgilbert PACKAGE_NAME=${TITLE} +PYTHONTOOLDIR=/tmp/relocatable-python PAYLOAD=\ - pack-plugin\ - pack-script-postinstall\ - pack-Library-LaunchDaemons-com.grahamgilbert.crypt.plist \ - pack-checkin \ - pack-script-preinstall + pack-plugin\ + pack-script-postinstall\ + pack-Library-LaunchDaemons-com.grahamgilbert.crypt.plist \ + pack-checkin \ + pack-script-preinstall ################################################# -build: clean-crypt +build: check_variables clean-crypt xcodebuild -project ../Crypt.xcodeproj -configuration Release clean-crypt: rm -rf ../build + @rm -rf Crypt.pkg pack-plugin: build @sudo ${RM} -rf ${WORK_D} @sudo mkdir -p ${WORK_D}/Library/Security/SecurityAgentPlugins @sudo ${CP} -R ../build/Release/Crypt.bundle ${WORK_D}/Library/Security/SecurityAgentPlugins/Crypt.bundle + @sudo codesign --force --deep -s "${DEV_APP_CERT}" ${WORK_D}/Library/Security/SecurityAgentPlugins/Crypt.bundle/Contents/Frameworks/* + @sudo codesign --force --deep -s "${DEV_APP_CERT}" ${WORK_D}/Library/Security/SecurityAgentPlugins/Crypt.bundle/Contents/MacOS/* -pack-checkin: l_Library +pack-checkin: clean-python build-python l_Library @sudo mkdir -p ${WORK_D}/Library/Crypt @sudo ${CP} checkin ${WORK_D}/Library/Crypt/checkin - @sudo ${CP} FoundationPlist.py ${WORK_D}/Library/Crypt/FoundationPlist.py + @sudo ${CP} -R Python.framework ${WORK_D}/Library/Crypt/Python.framework + @sudo /bin/ln -s /Library/Crypt/Python.framework/Versions/3.8/bin/python3 ${WORK_D}/Library/Crypt/python @sudo chown -R root:wheel ${WORK_D}/Library/Crypt @sudo chmod 755 ${WORK_D}/Library/Crypt/checkin @@ -39,3 +45,34 @@ dist: pkg @sudo productbuild --distribution Distribution Crypt-${BUNDLE_VERSION}.pkg @sudo rm -f Crypt.pkg @sudo rm -f Distribution + +notarize: + @./notarize.sh "${APPLE_ACC_USER}" "${APPLE_ACC_PWD}" + +clean-python: + @rm -rf Python.framework + @rm -rf ${WORK_D}/Library/Crypt/Python.framework + @rm -rf entitlements.plist + +build-python: + # Why not just run the make_relocatable_python.py here? + # It can't find the temp folder that the python pkg is expanded into + # if issued directly from Make, so we're currently shelling out until + # we grok the GNU better. PS THANKS SHEA + @rm -rf "${PYTHONTOOLDIR}" + @git clone https://github.com/gregneagle/relocatable-python.git "${PYTHONTOOLDIR}" + @./build_python_framework.sh "${DEV_APP_CERT}" + +check_variables: +ifndef DEV_INSTALL_CERT +$(error "DEV_INSTALL_CERT" is not set) +endif +ifndef DEV_APP_CERT +$(error "DEV_APP_CERT" is not set) +endif +ifndef APPLE_ACC_USER +$(error "APPLE_ACC_USER" is not set) +endif +ifndef APPLE_ACC_PWD +$(error "APPLE_ACC_PWD" is not set) +endif diff --git a/Package/build.sh b/Package/build.sh new file mode 100755 index 0000000..cafd44c --- /dev/null +++ b/Package/build.sh @@ -0,0 +1,11 @@ +#!/bin/zsh +# builds the package and notarizes +# requires a config.mk file in the same directory with some variables defined like below. + +# DEV_INSTALL_CERT=Developer ID Installer: Example, Inc (ABCDEF12345) +# DEV_APP_CERT=Developer ID Application: Example, Inc (ABCDEF12345) +# APPLE_ACC_USER=your_apple_dev_email@example.com +# APPLE_ACC_PWD=your-one-time-app-password + +sudo make pkg +sudo make notarize diff --git a/Package/build_python_framework.sh b/Package/build_python_framework.sh new file mode 100755 index 0000000..40a7fa7 --- /dev/null +++ b/Package/build_python_framework.sh @@ -0,0 +1,26 @@ +#!/bin/zsh +# Build script for Python 3 framework for Sal scripts +TOOLSDIR=$(dirname "$0") +PYTHON_VERSION=3.8.2 + +# build the framework +/tmp/relocatable-python/make_relocatable_python_framework.py \ + --python-version "${PYTHON_VERSION}" \ + --pip-requirements requirements.txt \ + --destination "${TOOLSDIR}" + +DevApp=$1 + +# sign all the bits of python with our Apple Developer ID Installer: cert. +find ${TOOLSDIR}/Python.framework -name '*.pyc' -delete +find ${TOOLSDIR}/Python.framework/Versions/3.8/lib/ -type f -perm -u=x -exec codesign --force --deep --verbose -s "$DevApp" {} \; +find ${TOOLSDIR}/Python.framework/Versions/3.8/bin/ -type f -perm -u=x -exec codesign --force --deep --verbose -s "$DevApp" {} \; +find ${TOOLSDIR}/Python.framework/Versions/3.8/lib/ -type f -name "*dylib" -exec codesign --force --deep --verbose -s "$DevApp" {} \; + +/usr/libexec/PlistBuddy -c "Add :com.apple.security.cs.allow-unsigned-executable-memory bool true" ${TOOLSDIR}/entitlements.plist + +codesign --force --options runtime --entitlements $TOOLSDIR/entitlements.plist --deep --verbose -s "$DevApp" $TOOLSDIR/Python.framework/Versions/3.8/Resources/Python.app/ +codesign --force --deep --options runtime --entitlements $TOOLSDIR/entitlements.plist --deep --verbose -s "$DevApp" $TOOLSDIR/Python.framework/Versions/3.8/bin/* +codesign --force --deep --options runtime --entitlements $TOOLSDIR/entitlements.plist --deep --verbose -s "$DevApp" $TOOLSDIR/Python.framework/Versions/3.8/lib/* +codesign --force --deep --options runtime --entitlements $TOOLSDIR/entitlements.plist --deep --verbose -s "$DevApp" $TOOLSDIR/Python.framework/Versions/3.8/Python +codesign --force --deep --verbose -s "$DevApp" $TOOLSDIR/Python.framework diff --git a/Package/checkin b/Package/checkin index fbc59c9..76b814f 100644 --- a/Package/checkin +++ b/Package/checkin @@ -1,35 +1,29 @@ -#!/usr/bin/python +#!/Library/Crypt/python +import datetime +import json import logging -import subprocess import os -import urllib +import platform +import plistlib +import subprocess import sys -import datetime import syslog -import platform -import json +import urllib from distutils.version import LooseVersion -import FoundationPlist - -from Foundation import NSDate -from Foundation import NSArray -from Foundation import CFPreferencesAppSynchronize -from Foundation import CFPreferencesCopyAppValue -from Foundation import CFPreferencesSetValue -from Foundation import kCFPreferencesAnyUser -from Foundation import kCFPreferencesCurrentHost -from SystemConfiguration import SCDynamicStoreCopyConsoleUser +import Foundation +import SystemConfiguration +BUNDLE_ID = "com.grahamgilbert.crypt" +LOG_FILE = "/var/log/crypt.log" -BUNDLE_ID = 'com.grahamgilbert.crypt' -LOG_FILE = '/var/log/crypt.log' - -logging.basicConfig(format='%(asctime)s - %(levelname)s: %(message)s', - datefmt='%Y-%m-%d %I:%M:%S %p', - level=logging.DEBUG, - filename=LOG_FILE) +logging.basicConfig( + format="%(asctime)s - %(levelname)s: %(message)s", + datefmt="%Y-%m-%d %I:%M:%S %p", + level=logging.DEBUG, + filename=LOG_FILE, +) stdout_logging = logging.StreamHandler() stdout_logging.setFormatter(logging.Formatter()) logging.getLogger().addHandler(stdout_logging) @@ -37,7 +31,7 @@ logging.getLogger().addHandler(stdout_logging) def get_console_user(): """returns the current console user via PyObjc""" - cfuser = SCDynamicStoreCopyConsoleUser(None, None, None) + cfuser = SystemConfiguration.SCDynamicStoreCopyConsoleUser(None, None, None) return cfuser[0] @@ -48,13 +42,13 @@ def get_os_version(only_major_minor=True, as_tuple=False): as_tuple: Boolean. If True, return a tuple of ints, otherwise a string. 100%, completely stolen from Munki. """ - os_version_tuple = platform.mac_ver()[0].split('.') + os_version_tuple = platform.mac_ver()[0].split(".") if only_major_minor: os_version_tuple = os_version_tuple[0:2] if as_tuple: return tuple(map(int, os_version_tuple)) else: - return '.'.join(os_version_tuple) + return ".".join(os_version_tuple) def set_pref(pref_name, pref_value): @@ -64,10 +58,14 @@ def set_pref(pref_name, pref_value): values that control the behavior of crypt may be overridden elsewhere (by MCX, for example)""" try: - CFPreferencesSetValue( - pref_name, pref_value, BUNDLE_ID, - kCFPreferencesAnyUser, kCFPreferencesCurrentHost) - CFPreferencesAppSynchronize(BUNDLE_ID) + Foundation.CFPreferencesSetValue( + pref_name, + pref_value, + BUNDLE_ID, + Foundation.kCFPreferencesAnyUser, + Foundation.kCFPreferencesCurrentHost, + ) + Foundation.CFPreferencesAppSynchronize(BUNDLE_ID) except Exception: pass @@ -81,24 +79,24 @@ def pref(pref_name): - default_prefs defined here. """ default_prefs = { - 'RemovePlist': True, - 'RotateUsedKey': True, - 'OutputPath': '/private/var/root/crypt_output.plist', - 'ValidateKey': True, - 'KeyEscrowInterval': 1, - 'AdditionalCurlOpts': [] + "RemovePlist": True, + "RotateUsedKey": True, + "OutputPath": "/private/var/root/crypt_output.plist", + "ValidateKey": True, + "KeyEscrowInterval": 1, + "AdditionalCurlOpts": [], } - pref_value = CFPreferencesCopyAppValue(pref_name, BUNDLE_ID) + pref_value = Foundation.CFPreferencesCopyAppValue(pref_name, BUNDLE_ID) if pref_value is None: pref_value = default_prefs.get(pref_name) # we're using a default value. We'll write it out to # /Library/Preferences/.plist for admin # discoverability set_pref(pref_name, pref_value) - if isinstance(pref_value, NSDate): + if isinstance(pref_value, Foundation.NSDate): # convert NSDate/CFDates to strings pref_value = str(pref_value) - elif isinstance(pref_value, NSArray): + elif isinstance(pref_value, Foundation.NSArray): pref_value = list(pref_value) return pref_value @@ -107,45 +105,47 @@ def GetMacName(): """ Returns the name of the mac """ - theprocess = ['scutil', '--get', 'ComputerName'] - thename = subprocess.Popen(theprocess, stdin=subprocess.PIPE, - stdout=subprocess.PIPE).communicate()[0] - thename = thename.strip() - return thename + cmd = ["/usr/sbin/scutil", "--get", "ComputerName"] + try: + return subprocess.check_output(cmd).rstrip() + except subprocess.SubprocessError: + return "UNKNOWN_COMPUTERNAME" def curl_escape(s): - return s.encode('utf-8').encode('string_escape').replace('"', '\\"') + return s.replace('"', '\\"') def build_curl_config_file(d): lines = [] for k, v in d.items(): - lines.append('%s = "%s"' % (k, curl_escape(v))) - return '\n'.join(lines) + lines.append(f'{k} = "{curl_escape(v)}"') + return "\n".join(lines) def escrow_key(plist): - logging.info('Attempting to Escrow Key...') - server_url = pref('ServerURL') - logging.debug('ServerURL Pref set to: {0}...'.format(server_url)) + logging.info("Attempting to Escrow Key...") + server_url = pref("ServerURL") + logging.debug(f"ServerURL Pref set to: {server_url}...") if server_url is None: return False if server_url.endswith("/"): - theurl = server_url+"checkin/" + theurl = server_url + "checkin/" else: - theurl = server_url+"/checkin/" + theurl = server_url + "/checkin/" # In the future, we're going to submit the whole plist, but for now... - serial = plist['SerialNumber'] - key = plist['RecoveryKey'] - username = plist['EnabledUser'] + serial = plist["SerialNumber"] + key = plist["RecoveryKey"] + username = plist["EnabledUser"] macname = GetMacName() mydata = [ - ('serial', serial), ('recovery_password', key), - ('username', username), ('macname', macname) + ("serial", serial), + ("recovery_password", key), + ("username", username), + ("macname", macname), ] - mydata = urllib.urlencode(mydata) - config_file = build_curl_config_file({'url': theurl, 'data': mydata}) + mydata = urllib.parse.urlencode(mydata) + config_file = build_curl_config_file({"url": theurl, "data": mydata}) # --fail: Fail silently (no output at all) on server errors. # --silent: Silent mode. Don't show progress meter or error messages. # --show-error: When used with silent, it makes curl show an error message @@ -156,23 +156,22 @@ def escrow_key(plist): # The config file is a text file in which command line arguments can be # written which then will be used as if they were written on the actual # command line. - cmd = ['/usr/bin/curl', '--fail', '--silent', - '--show-error', '--location'] - if pref('AdditionalCurlOpts') and isinstance(pref('AdditionalCurlOpts'), list): - for curl_opt in pref('AdditionalCurlOpts'): + cmd = ["/usr/bin/curl", "--fail", "--silent", "--show-error", "--location"] + if all([pref("AdditionalCurlOpts"), isinstance(pref("AdditionalCurlOpts"), list)]): + for curl_opt in pref("AdditionalCurlOpts"): cmd.append(curl_opt) - cmd.extend(['--config', '-']) - task = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE) - (output, error) = task.communicate(input=config_file) + cmd.extend(["--config", "-"]) + task = subprocess.Popen( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE + ) + (output, error) = task.communicate(input=config_file.encode()) if task.returncode == 0: - logging.info('Key escrow successful.') + logging.info("Key escrow successful.") server_initiated_rotation(output) return True else: - logging.error('Key escrow unsuccessful.') + logging.error("Key escrow unsuccessful.") return False @@ -184,19 +183,19 @@ def server_initiated_rotation(output): try: json_output = json.loads(output) except ValueError: - return '' + return "" - if not pref('RotateUsedKey') or pref('RemovePlist'): + if not pref("RotateUsedKey") or pref("RemovePlist"): # Don't do anything if we don't care about the good stuff - return '' + return "" - output_plist = pref('OutputPath') + output_plist = pref("OutputPath") if not os.path.isfile(output_plist): # Need this to be here too (which it should, but you never know..) - return '' + return "" - if json_output.get('rotation_required', False): - logging.info('Removing output plist for rotation at next login.') + if json_output.get("rotation_required", False): + logging.info("Removing output plist for rotation at next login.") os.remove(output_plist) post_run_command() @@ -208,52 +207,52 @@ def using_recovery_key(): """ macos_version = get_os_version(only_major_minor=False, as_tuple=False) - if LooseVersion(macos_version) >= LooseVersion('10.15'): - logging.info('Checking if using a recovery key is unstable on 10.15. ' - 'Skipping.') + if LooseVersion(macos_version) >= LooseVersion("10.15"): + logging.info( + "Checking if using a recovery key is unstable on 10.15. " "Skipping." + ) return False - cmd = ['/usr/bin/fdesetup', 'usingrecoverykey'] + cmd = ["/usr/bin/fdesetup", "usingrecoverykey"] try: using_key = subprocess.check_output(cmd).strip() except Exception: - logging.warning('fdesetup usingrecoverykey failed to run correctly') + logging.warning("fdesetup usingrecoverykey failed to run correctly") return False - if using_key == 'true': - logging.warning('Detected Recovery Key use.') + if using_key == "true": + logging.warning("Detected Recovery Key use.") return True else: return False def post_run_command(): - run_command = pref('PostRunCommand') - output_plist = pref('OutputPath') + run_command = pref("PostRunCommand") + output_plist = pref("OutputPath") if run_command and not os.path.isfile(output_plist): - logging.info('Running {}'.format(run_command)) + logging.info(f"Running {run_command}") try: output = subprocess.check_output(run_command) logging.info(output) except subprocess.CalledProcessError as e: - logging.error('Failed to run PostRunCommand: {}'.format(e)) + logging.error(f"Failed to run PostRunCommand: {e}") def get_recovery_key(key_location): """Returns recovery key as a string... If we failed to get the proper information, returns an empty string""" # checks to see if recovery key preference is set + try: - keyplist = FoundationPlist.readPlist(key_location) - recovery_key = keyplist['RecoveryKey'].strip() - return recovery_key - except FoundationPlist.NSPropertyListSerializationException: - logging.info( - 'We had trouble getting info from {0}...'.format(key_location)) - return False + with open(key_location, "rb") as fp: + keyplist = plistlib.load(fp) + return keyplist["RecoveryKey"].strip() + except (FileNotFoundError, plistlib.InvalidFileException): + logging.info(f"We had trouble getting info from {key_location}...") + return "" except KeyError: - logging.warning( - 'Problem with Key: "RecoveryKey" in {0}...'.format(key_location)) - return False + logging.warning(f"Problem with Key: RecoveryKey in {key_location}...") + return "" def rotate_invalid_key(plist_path): @@ -265,33 +264,32 @@ def rotate_invalid_key(plist_path): """ # a work aroud for https://github.com/grahamgilbert/crypt/issues/68 if not get_console_user(): - logging.info('Skipping Validation, no user is logged in.') + logging.info("Skipping Validation, no user is logged in.") return True macos_version = get_os_version(only_major_minor=False, as_tuple=False) - if LooseVersion('10.12.5') > LooseVersion(macos_version): - logging.warning('macOS version is too old to run reliably') + if LooseVersion("10.12.5") > LooseVersion(macos_version): + logging.warning("macOS version is too old to run reliably") return False if os.path.isfile(plist_path): recovery_key = get_recovery_key(plist_path) else: - logging.warning('Recovery key is not present on disk') + logging.warning("Recovery key is not present on disk") return False - if recovery_key is not False: - key_is_valid = validate_key(recovery_key) - else: - logging.warning('Could not retrieve recovery key from plist') + if not recovery_key: + logging.warning("Could not retrieve recovery key from plist.") + os.remove(plist_path) return False - if not key_is_valid: - logging.info('Stored recovery key is not valid, removing from disk') + if not validate_key(recovery_key): + logging.info("Stored recovery key is not valid, removing from disk") os.remove(plist_path) return False - logging.info('Stored recovery key is valid.') + logging.info("Stored recovery key is valid.") return True @@ -299,56 +297,65 @@ def validate_key(current_key): """Validates the given recovery key against FileVault, returns True or False accordingly""" - key = {'Password': current_key} - input_plist = FoundationPlist.writePlistToString(key) - cmd = subprocess.Popen(['/usr/bin/fdesetup', 'validaterecovery', - '-inputplist'], - stdout=subprocess.PIPE, stdin=subprocess.PIPE, - stderr=subprocess.PIPE) + key = {"Password": current_key} + input_plist = plistlib.dumps(key) + cmd = subprocess.Popen( + ["/usr/bin/fdesetup", "validaterecovery", "-inputplist"], + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + ) stdout_data, err = cmd.communicate(input=input_plist) if err: logging.error(err) - if stdout_data.strip() == 'true': + if stdout_data.rstrip() == b"true": return True else: - logging.error('Recovery Key could not be validated.') - logging.error('Failed with Error: {}'.format(stdout_data)) + logging.error("Recovery Key could not be validated.") + logging.error(f"Failed with Error: {stdout_data}") return False def rotate_key(current_key, plist): """This rotates the recovery key to something new by using the current recovery key""" - rotate_inputplist = {'Password': current_key} - input_plist = FoundationPlist.writePlistToString(rotate_inputplist) - cmd = subprocess.Popen(['/usr/bin/fdesetup', 'changerecovery', '-personal', - '-outputplist', '-inputplist'], - stdout=subprocess.PIPE, stdin=subprocess.PIPE, - stderr=subprocess.PIPE) + rotate_inputplist = {"Password": current_key} + input_plist = plistlib.dumps(rotate_inputplist) + cmd = subprocess.Popen( + [ + "/usr/bin/fdesetup", + "changerecovery", + "-personal", + "-outputplist", + "-inputplist", + ], + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + ) stdout_data, err = cmd.communicate(input=input_plist) - logging.info('Attempting to rotate Recovery Key.') + logging.info("Attempting to rotate Recovery Key.") try: - output_plist = FoundationPlist.readPlistFromString(stdout_data) - - FoundationPlist.writePlist(output_plist, plist) - logging.info('Recovery Key rotated.') + output_plist = plistlib.loads(stdout_data) + with open(plist, "wb") as fp: + plistlib.dump(output_plist, fp) + logging.info("Recovery Key rotated.") except Exception: if err: - logging.warning('Encountered error Key Rotation: {0}.'.format(err)) + logging.warning(f"Encountered error Key Rotation: {err}.") def get_enabled_user(): """Crypt needs an enabled user in its plist that our normal output doesn't give us so we need to add a user to the plist""" - if pref('SkipUsers'): - nonusers = pref('SkipUsers') + if pref("SkipUsers"): + nonusers = pref("SkipUsers") else: nonusers = [] - fde_users = subprocess.check_output( - ["/usr/bin/fdesetup", "list"]).split('\n') + fde_users = subprocess.check_output(["/usr/bin/fdesetup", "list"]).split("\n") for user in fde_users: - if not user.split(',')[0] in nonusers: - cryptuser = user.split(',')[0] + if not user.split(",")[0] in nonusers: + cryptuser = user.split(",")[0] break return cryptuser @@ -357,68 +364,72 @@ def rotate_if_used(key_path): """Checks to see if the recovery key was used to unlock the machine if it was then use our current key to rotate it""" if not using_recovery_key(): - return '' + return "" if not os.path.isfile(key_path): - logging.warning('Could not locate {0}'.format(key_path)) - rotate_message = 'Recovery Key has been used.. Attempting to Rotate' - logging.info(rotate_message) + logging.warning(f"Could not locate {key_path}") + return "" + logging.info("Recovery Key has been used.. Attempting to Rotate.") current_key = get_recovery_key(key_path) valid_key = validate_key(current_key) if not valid_key: - logging.error('Our current key is not valid') - return '' + logging.error("Our current key is not valid.") + return "" rotate_key(current_key, key_path) def main(): - plist_path = pref('OutputPath') - logging.info('OutputPath Pref is set to: {}'.format(plist_path)) - if pref('RotateUsedKey'): + plist_path = pref("OutputPath") + logging.info(f"OutputPath Pref is set to: {plist_path}") + if pref("RotateUsedKey"): rotate_if_used(plist_path) - if pref('RotateUsedKey') and pref('ValidateKey') and \ - not pref('RemovePlist'): + if pref("RotateUsedKey") and pref("ValidateKey") and not pref("RemovePlist"): rotate_invalid_key(plist_path) post_run_command() if os.path.isfile(plist_path): - plist = FoundationPlist.readPlist(plist_path) + try: + with open(plist_path, "rb") as fp: + plist = plistlib.load(fp) + except plistlib.InvalidFileException as err: + logging.error(f"Failed to read {plist_path} with error: {err}") + exit(-1) # Exit if we've run this within the last hour try: - enableduser = plist['EnabledUser'] + enableduser = plist["EnabledUser"] except KeyError as e: enableduser = get_console_user() - skippedusers = ['root', '_mbsetupuser'] + skippedusers = ["root", "_mbsetupuser"] if not enableduser or enableduser in skippedusers: enableduser = get_enabled_user() - plist['EnabledUser'] = enableduser - if 'last_run' in plist: + plist["EnabledUser"] = enableduser + if "last_run" in plist: try: - escrow_interval = int(pref('KeyEscrowInterval')) + escrow_interval = int(pref("KeyEscrowInterval")) except Exception: escrow_interval = 1 - logging.info('KeyEscrowInterval set to: {} hour(s)...'.format( - escrow_interval)) + logging.info(f"KeyEscrowInterval set to: {escrow_interval} hour(s)...") now = datetime.datetime.now() hour_ago = now - datetime.timedelta(hours=escrow_interval) - if plist['last_run'] > hour_ago: + if plist["last_run"] > hour_ago: logging.info( - 'We escrowed less than {} hour(s) ago. Skipping...'.format( - escrow_interval)) + f"We escrowed less than {escrow_interval} hour(s) ago. Skipping..." + ) sys.exit(0) escrow_result = escrow_key(plist=plist) if escrow_result and os.path.isfile(plist_path): - remove_plist = pref('RemovePlist') - plist['escrow_success'] = True - plist['last_run'] = datetime.datetime.now() - FoundationPlist.writePlist(plist, plist_path) + remove_plist = pref("RemovePlist") + plist["escrow_success"] = True + plist["last_run"] = datetime.datetime.now() + with open(plist_path, "wb") as fp: + plistlib.dump(plist, fp) if remove_plist is True: + logging.info("Removing plist due to configuration.") os.remove(plist_path) - logging.info('Removing plist due to configuration.') else: - os.chmod(plist_path, 0600) - logging.info('Ensuring permissions on plist.') + logging.info("Ensuring permissions on plist.") + os.chmod(plist_path, 600) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/Package/notarize.sh b/Package/notarize.sh new file mode 100755 index 0000000..4066ceb --- /dev/null +++ b/Package/notarize.sh @@ -0,0 +1,64 @@ +#!/bin/zsh +# encoding: utf-8 + +# Borrowed with love from https://github.com/munki/munki/pull/986/files +# Big thanks to https://github.com/lifeunexpected + +# Tip: if you get “You must first sign the relevant contracts online. (1048)” error +# Go to Apple.developer.com and sign in with the account you are trying to notarize the app with and agree to the updated license agreement. + +BUNDLE_ID="com.grahamgilbert.Crypt" +BUNDLE_PKG="./Crypt.pkg" + +if [[ "$1" == "" ]]; then + echo "Couldn't find a 'Apple Developer account e-mail' as argument 1" + exit -1 +else + AppleAcc=$1 +fi +if [[ "$2" == "" ]]; then + echo "Couldn't find an 'Apple Developer app-specific password' as argument 2" + echo "More info at https://support.apple.com/en-us/HT204397" + exit -1 +else + AppleAccPwd=$2 +fi + +# create temporary files +NOTARIZE_APP_LOG=$(mktemp -t notarize-app) +NOTARIZE_INFO_LOG=$(mktemp -t notarize-info) + +# delete temporary files on exit +function finish { + rm "$NOTARIZE_APP_LOG" "$NOTARIZE_INFO_LOG" +} +trap finish EXIT + +# submit app for notarization +echo "Submitting App $BUNDLE_PKG for Notarization." +if ! xcrun altool --notarize-app --primary-bundle-id "$BUNDLE_ID" --username "$AppleAcc" --password "$AppleAccPwd" -f "$BUNDLE_PKG" > "$NOTARIZE_APP_LOG" 2>&1; then + cat "$NOTARIZE_APP_LOG" 1>&2 + exit 1 +fi + +cat "$NOTARIZE_APP_LOG" +RequestUUID=$(awk -F ' = ' '/RequestUUID/ {print $2}' "$NOTARIZE_APP_LOG") + +# check status periodically +while sleep 30 && date; do +echo "Waiting on Apple too approve the notarization so it can be stapled. This can take a few minutes or more. Script auto checks every 30 sec" + # check notarization status + + if ! xcrun altool --notarization-info "$RequestUUID" --username "$AppleAcc" --password "$AppleAccPwd" > "$NOTARIZE_INFO_LOG" 2>&1; then + cat "$NOTARIZE_INFO_LOG" 1>&2 + exit 1 + fi + cat "$NOTARIZE_INFO_LOG" + + # once notarization is complete, run stapler and exit + if ! grep -q "Status: in progress" "$NOTARIZE_INFO_LOG"; then + xcrun stapler staple "$BUNDLE_PKG" + exit $? + fi + +done diff --git a/Package/postinstall b/Package/postinstall index ff7cc0a..bc12349 100644 --- a/Package/postinstall +++ b/Package/postinstall @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/Library/Crypt/python # Copyright 2015 Crypt Project. # @@ -38,84 +38,93 @@ from subprocess import PIPE, STDOUT, Popen system_login_console_plist = "/private/var/tmp/system.login.console.plist" ## Path to authenticate.plist -#authenticate_plist = "/private/var/tmp/authenticate.plist" +# authenticate_plist = "/private/var/tmp/authenticate.plist" ## Mechs that support FV2AuthPlugin -fv2_mechs = ["Crypt:Check,privileged","Crypt:CryptGUI","Crypt:Enablement,privileged"] +fv2_mechs = ["Crypt:Check,privileged", "Crypt:CryptGUI", "Crypt:Enablement,privileged"] fv2_index_mech = "loginwindow:done" fv2_index_offset = 0 + def bash_command(script): try: return subprocess.check_output(script) - except (subprocess.CalledProcessError, OSError), err: - sys.exit("[* Error] **%s** [%s]" % (err, str(script))) + except (subprocess.CalledProcessError, OSError) as err: + sys.exit(f"[* Error] **{err}** [{str(script)}]") + def remove_mechs_in_db(db, mech_list): for mech in mech_list: - for old_mech in filter(lambda x: mech in x, db['mechanisms']): - db['mechanisms'].remove(old_mech) + for old_mech in filter(lambda x: mech in x, db["mechanisms"]): + db["mechanisms"].remove(old_mech) return db + def set_mechs_in_db(db, mech_list, index_mech, index_offset): ## Clear away any previous configs db = remove_mechs_in_db(db, mech_list) ## Add mech_list to db - i = int(db['mechanisms'].index(index_mech)) + index_offset + i = int(db["mechanisms"].index(index_mech)) + index_offset for mech in mech_list: - db['mechanisms'].insert(i, mech) + db["mechanisms"].insert(i, mech) i += 1 return db + def edit_authdb(): ## Export "system.login.console" - system_login_console = bash_command(["/usr/bin/security", "authorizationdb", "read", "system.login.console"]) - f_c = open(system_login_console_plist, 'w') - f_c.write(system_login_console) + system_login_console = bash_command( + ["/usr/bin/security", "authorizationdb", "read", "system.login.console"] + ) + f_c = open(system_login_console_plist, "w") + f_c.write(system_login_console.decode()) f_c.close() ## Export "authenticate" - #authenticate = bash_command(["/usr/bin/security", "authorizationdb", "read", "authenticate"]) - #f_a = open(authenticate_plist, 'w') - #f_a.write(authenticate) - #f_a.close() + # authenticate = bash_command(["/usr/bin/security", "authorizationdb", "read", "authenticate"]) + # f_a = open(authenticate_plist, 'w') + # f_a.write(authenticate) + # f_a.close() ## Leave the for loop. Possible support for ScreenSaver unlock for p in [system_login_console_plist]: ## Parse the plist - d = plistlib.readPlist(p) + with open(p, "rb") as fp: + d = plistlib.load(fp) ## Add FV2 mechs d = set_mechs_in_db(d, fv2_mechs, fv2_index_mech, fv2_index_offset) ## Write out the changes - plistlib.writePlist(d, p) + with open(p, "wb") as fp: + plistlib.dump(d, fp) f_c = open(system_login_console_plist, "r") - p = Popen(["/usr/bin/security", "authorizationdb", "write", "system.login.console"], stdout=PIPE, stdin=PIPE, stderr=PIPE) - stdout_data = p.communicate(input=f_c.read()) + p = Popen( + ["/usr/bin/security", "authorizationdb", "write", "system.login.console"], + stdout=PIPE, + stdin=PIPE, + stderr=PIPE, + ) + stdout_data = p.communicate(input=f_c.read().encode()) f_c.close() - #f_a = open(authenticate_plist, "r") - #p = Popen(["/usr/bin/security", "authorizationdb", "write", "authenticate"], stdout=PIPE, stdin=PIPE, stderr=PIPE) - #stdout_data = p.communicate(input=f_a.read()) - #f_a.close() + # f_a = open(authenticate_plist, "r") + # p = Popen(["/usr/bin/security", "authorizationdb", "write", "authenticate"], stdout=PIPE, stdin=PIPE, stderr=PIPE) + # stdout_data = p.communicate(input=f_a.read()) + # f_a.close() + def check_root(): if not os.geteuid() == 0: sys.exit("\nOnly root can run this script\n") -def check_os(): - OSVersion, _, _ = platform.mac_ver() - OSVersion = int(OSVersion.split('.')[1]) - if OSVersion < 9: - sys.exit("\nOnly OS X 10.9 and above can run this script\n") def main(argv): check_root() - check_os() edit_authdb() -if __name__ == '__main__': + +if __name__ == "__main__": main(sys.argv) diff --git a/Package/preinstall b/Package/preinstall old mode 100644 new mode 100755 index c0ff348..e25cd03 --- a/Package/preinstall +++ b/Package/preinstall @@ -1,64 +1,20 @@ -#!/usr/bin/python - -import os -import shutil -import sys -import platform - -import syslog -syslog.openlog("crypt-preinstall") - -def fail(message, exit=True): - syslog.syslog(syslog.LOG_ALERT, message) - print(message) - if exit: - sys.exit(1) - -def move_old_plist(): - old_plist = '/private/var/root/recovery_key.plist' - new_plist = '/private/var/root/crypt_output.plist' - if os.path.exists('/private/var/root/recovery_key.plist'): - # We have an old recovery key, move it to the new location - try: - shutil.move(old_plist, new_plist) - except: - fail('Could not move old plist to new location') - -def remove_old_app(): - # remove old installdir - old_install_dir = '/usr/local/crypt' - if os.path.exists(old_install_dir): - shutil.rmtree(old_install_dir) - - -def getOsVersion(only_major_minor=True, as_tuple=False): - """Returns an OS version. - Args: - only_major_minor: Boolean. If True, only include major/minor versions. - as_tuple: Boolean. If True, return a tuple of ints, otherwise a string. - """ - os_version_tuple = platform.mac_ver()[0].split('.') - if only_major_minor: - os_version_tuple = os_version_tuple[0:2] - if as_tuple: - return tuple(map(int, os_version_tuple)) - else: - return '.'.join(os_version_tuple) - - -def os_check_abort(): - # abort if less than 10.12 - version_tup = getOsVersion(as_tuple=True) - if version_tup[1] < 12: - fail('ERROR! Crypt 3.0 does not support macOS versions before 10.12..', - exit=False) - fail('ERROR! Please use a previous version of Crypt..') - - -def main(): - os_check_abort() - move_old_plist() - print('crypt-preinstall successful...') - -if __name__ == '__main__': - main() +#!/bin/zsh + +OLD_KEY=/private/var/root/recovery_key.plist +NEW_KEY=/private/var/root/crypt_output.plist +if [[ -f "$OLD_KEY" ]]; then + /bin/mv $OLD_KEY $NEW_KEY +fi + + +# remove old crypt +OLD_CRYPT=/usr/local/crypt +if [[ -d "$OLD_CRYPT" ]]; then + /bin/rm -r $OLD_CRYPT +fi + +# remove old foundationplist, thanks for the memories. +if [[ -f "/Library/Crypt/FoundationPlist.py" ]]; then + /bin/rm -r /Library/Crypt/FoundationPlist.py + /bin/rm -r /Library/Crypt/FoundationPlist.pyc +fi diff --git a/Package/preinstall.old b/Package/preinstall.old new file mode 100644 index 0000000..c0ff348 --- /dev/null +++ b/Package/preinstall.old @@ -0,0 +1,64 @@ +#!/usr/bin/python + +import os +import shutil +import sys +import platform + +import syslog +syslog.openlog("crypt-preinstall") + +def fail(message, exit=True): + syslog.syslog(syslog.LOG_ALERT, message) + print(message) + if exit: + sys.exit(1) + +def move_old_plist(): + old_plist = '/private/var/root/recovery_key.plist' + new_plist = '/private/var/root/crypt_output.plist' + if os.path.exists('/private/var/root/recovery_key.plist'): + # We have an old recovery key, move it to the new location + try: + shutil.move(old_plist, new_plist) + except: + fail('Could not move old plist to new location') + +def remove_old_app(): + # remove old installdir + old_install_dir = '/usr/local/crypt' + if os.path.exists(old_install_dir): + shutil.rmtree(old_install_dir) + + +def getOsVersion(only_major_minor=True, as_tuple=False): + """Returns an OS version. + Args: + only_major_minor: Boolean. If True, only include major/minor versions. + as_tuple: Boolean. If True, return a tuple of ints, otherwise a string. + """ + os_version_tuple = platform.mac_ver()[0].split('.') + if only_major_minor: + os_version_tuple = os_version_tuple[0:2] + if as_tuple: + return tuple(map(int, os_version_tuple)) + else: + return '.'.join(os_version_tuple) + + +def os_check_abort(): + # abort if less than 10.12 + version_tup = getOsVersion(as_tuple=True) + if version_tup[1] < 12: + fail('ERROR! Crypt 3.0 does not support macOS versions before 10.12..', + exit=False) + fail('ERROR! Please use a previous version of Crypt..') + + +def main(): + os_check_abort() + move_old_plist() + print('crypt-preinstall successful...') + +if __name__ == '__main__': + main() diff --git a/Package/requirements.txt b/Package/requirements.txt new file mode 100644 index 0000000..1444339 --- /dev/null +++ b/Package/requirements.txt @@ -0,0 +1 @@ +pyobjc==6.2.1