diff --git a/build-app.sh b/build-app.sh new file mode 100755 index 0000000..5e89892 --- /dev/null +++ b/build-app.sh @@ -0,0 +1,118 @@ +#!/bin/sh + +# Define colors for log +_info() { echo "\033[1m[INFO]\033[0m $1" ; } +_ok() { echo "\033[32m[OK]\033[0m $1" ; } +_error() { echo "\033[31m[ERROR]\033[0m $1" ; } +_logo() { echo "\033[1m $1\033[0m" ; } + +# Check if architecture is x86_64, because some dependencies are +# throwing errors on arm64. +if [ "$(uname -m)" = arm64 ]; then + _error "You are using arm64 architecture. This script will switch to x86_64 now." + _error "After Terminal-Relaunch, you need to run this script again:" + _logo "---> ./build-app.sh <---" + _info "Press any key to continue ..." + read -r wait + exec arch -x86_64 /bin/zsh +fi + +# Header +echo "" +echo "" +_logo " █▌ ▀▀▀▀▀▀ ║█ ╫█ ▐█µ ▐█ ▄██▀▀██▌ ██ ▀└ █▌ ╒█▌ █µ █▌ " +_logo " ▐█ ███▌ ██ ████ ██ ██ ╟█ ▐█ ▐█ ║█ ╫█ ║██▌ ╓███ " +_logo " ██ ▀▀▀▀▀▀ ╒█Γ└██▓█ █▌ ██▓█▌▐█ ██ ██ ██ ██ ██ ███▀ ██ " +_logo "┌▀ ██ ▀██ ║█ ╙██ └██ ╓██ █▌ ╒█▌ ██ ██ ╒█▌ ╙ ╒█Γ " +_logo " -▀▀▀▀ ╝▀▀▀▀▀▀ ▀▀ ▀ ▀▀ ▀ ▀▀█▀▀ ╘▀▀▀▀▀ ╝▀ ▀██▀ ╝▀ ╝▀ " +_logo " " +_logo " S W I F T G U A R D B U I L D S C R I P T " +_logo " ------------------------------------------------------------------------- " +echo "" +echo "" + +# Ask if the script should start with building the dmg. +_info "This script will build an .app file of swiftGuard. \nContinue? (y/n)" +read -r response +if [ "$response" = "y" ]; then + _ok "Let us begin!" +else + _error "Script aborted." + exit; +fi + +# Check if Python3 is installed and install it if not. +_info "Checking and installing requirements ..." +if test ! "$(which python3)"; then + _info "Python3 is not installed! Installing with Homebrew ..." + /bin/bash -c \ + "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + brew update + brew install python3 +else + _ok "Python3 is installed." +fi + +# Check if architecture is right +_info "Checking if architecture is right (using uname) +If you are using arm64 architecture, this script will switch to x86_64 now." +if [ `uname -m` = arm64 ]; then + _error "You are using arm64 architecture. This script will switch to x86_64 now." + _error "After Terminal-Relaunch, you need to run this script again:\n./build-app.sh" + _info "Press any key to continue ..." + read -r wait + exec arch -x86_64 /bin/zsh +fi + +# Checking for needed source files. +_info "Checking if src/swiftGuard is present (needed for building)." +if [ ! -d "src/swiftGuard" ]; then + _error "No src/swiftGuard directory found. Please clone the whole repository first." + exit 1 +fi + +# Creating dist folder. +mkdir -p dist/ + +# Delete the content of dist folder (to remove old .app builds). +_info "Deleting old builds in /dist folder (all files get deleted!)." +rm -R dist/* + +# Creating build folder. +mkdir -p build/ + +# Delete the content of build folder (to remove old builds). +_info "Deleting old builds in /build folder (all files get deleted!)." +rm -R build/* + +# Check if venv is created and do so if not. +if ! [ -d "./venv" ] ; then + _info "Creating virtual environment, so we do not pollute your system." + python3 -m venv venv +else + _ok "Looks like a virtual environment (venv) is already created." +fi + +# Activate venv and install requirements. +source venv/bin/activate +pip install -r requirements.txt +pip install --upgrade PyInstaller pyinstaller-hooks-contrib + +# Build the app. +_info "Building the .app file. This can take a while ..." +if pyinstaller "pyinstaller.spec" +then + _ok "Pyinstaller successfully created build." +else + _error "Build failed!" + exit 1 +fi + +# Finished: Open finder with the dmg folder. +_ok "swiftGuard.app was successfully created!" +_ok "SCRIPT FINISHED!" +_logo "--> Press any key to open dist folder and exit script... <--" +read -r exit +cd dist || exit +open . +exit diff --git a/build-dmg.sh b/build-dmg.sh index 8c1e11b..a557545 100755 --- a/build-dmg.sh +++ b/build-dmg.sh @@ -1,8 +1,67 @@ #!/bin/sh -echo "[INFO] Creating needed and temp folders ..." +# Define colors for log +_info() { echo "\033[1m[INFO]\033[0m $1" ; } +_ok() { echo "\033[32m[OK]\033[0m $1" ; } +_error() { echo "\033[31m[ERROR]\033[0m $1" ; } +_logo() { echo "\033[1m $1\033[0m" ; } + +# Header +echo "" +echo "" +_logo " █▌ ▀▀▀▀▀▀ ║█ ╫█ ▐█µ ▐█ ▄██▀▀██▌ ██ ▀└ █▌ ╒█▌ █µ █▌ " +_logo " ▐█ ███▌ ██ ████ ██ ██ ╟█ ▐█ ▐█ ║█ ╫█ ║██▌ ╓███ " +_logo " ██ ▀▀▀▀▀▀ ╒█Γ└██▓█ █▌ ██▓█▌▐█ ██ ██ ██ ██ ██ ███▀ ██ " +_logo "┌▀ ██ ▀██ ║█ ╙██ └██ ╓██ █▌ ╒█▌ ██ ██ ╒█▌ ╙ ╒█Γ " +_logo " -▀▀▀▀ ╝▀▀▀▀▀▀ ▀▀ ▀ ▀▀ ▀ ▀▀█▀▀ ╘▀▀▀▀▀ ╝▀ ▀██▀ ╝▀ ╝▀ " +_logo " " +_logo " S W I F T G U A R D B U I L D S C R I P T " +_logo " ------------------------------------------------------------------------- " +echo "" +echo "" + +# Ask if the script should start with building the dmg. +_info "This script will build a dmg file for swiftGuard. Make sure you have built a swiftGuard.app and it is in the /dist folder.\nContinue? (y/n)" +read -r response +if [ "$response" = "y" ]; then + _ok "Let us begin!" +else + _error "Script aborted." + exit; +fi + +# Check if homebrew is installed and install it if not. +_info "Checking if homebrew is installed ..." +if test ! "$(which brew)"; then + _info "Installing homebrew now ..." + /bin/bash -c \ + "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + brew update +else + _ok "Homebrew is installed." + brew update +fi + +# Check if create-dmg is installed and install it if not. +_info "Checking if create-dmg is installed ..." +if test ! "$(which create-dmg)"; then + _info "Installing create-dmg now ..." + brew install create-dmg +else + brew upgrade create-dmg + _ok "create-dmg is installed." +fi + +# Checking if swiftGuard.app is in /dist folder. +_info "Checking if swiftGuard.app is in /dist folder ..." + +if [ ! -d "dist/swiftGuard.app" ]; then + _error "swiftGuard.app not found in /dist folder. Please build the app first (using build-app.sh)." + exit 1 +fi # Create a folder dmg to copy the finished .dmg in it. +_info "Creating needed folders ..." mkdir -p dmg/ # Create a temp folder to copy the .app file to. @@ -11,15 +70,13 @@ mkdir -p dist/dmg-temp # Copy the .app bundle to the dmg-temp folder. cp -R "dist/swiftGuard.app" dist/dmg-temp -echo "[INFO] Deleting content of /dmg folder" - # Delete the content of /dmg folder (to remove old dmgs). +_info "Making sure there is no content in /dmg folder." rm -R dmg/* -echo "[INFO] DMG building started ..." - # Create the DMG. (optional: --eula "LICENSE" \) -create-dmg \ +_info ".dmg building started. This can take a while ..." +if create-dmg \ --volname "swiftGuard" \ --volicon "img/dmg-icon/dmg-icon-macos@2x.icns" \ --background "img/dmg-bg/dmg-bg-macos@2x.png" \ @@ -31,23 +88,28 @@ create-dmg \ --app-drop-link 480 170 \ "dmg/swiftGuard.dmg" \ "dist/dmg-temp/" - -echo "[INFO] Deleting temp files and folders ..." - -# Empty the dmg-temp folder. +then + _ok "create-dmg successfully created .dmg file without errors." +else + _error "create-dmg exited with errors. No .dmg created." + exit 1 +fi + +# Empty and deleting the dmg-temp folder. +_info "Deleting temp files and folders ..." rm -R dist/dmg-temp/* - -# Delete the dmg-temp folder. rm -r dist/dmg-temp -echo "[INFO] Generating sha256 checksum file ..." - # Generate sha256 hash file of installer and check it. -cd dmg +_info "Generating sha256 checksum file of dmg..." +cd dmg || exit sha256sum "swiftGuard.dmg" > SHA256SUM +_info "Validate sha256 checksum ..." sha256sum -c SHA256SUM - -echo "[INFO] swiftGuard.dmg and checksum.sha256 created in /dmg folder" - -echo "[INFO] FINISHED!" +# Finished: Open finder with the dmg folder. +_ok "swiftGuard.dmg and checksum.sha256 created in /dmg folder" +_ok "SCRIPT FINISHED! \nPress any key to open /dmg folder and exit..." +read -r exit +open . +exit diff --git a/build-app.spec b/pyinstaller.spec similarity index 100% rename from build-app.spec rename to pyinstaller.spec diff --git a/requirements.txt b/requirements.txt index 27668d3..60fe8d5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,5 @@ PySide6==6.5.2 darkdetect==0.8.0 black==23.9.1 bandit==1.7.5 +pyinstaller==6.0.0 +pyinstaller-hooks-contrib==2023.9 diff --git a/src/swiftguard/helpers.py b/src/swiftguard/helpers.py index d7f4dc6..227ac9e 100644 --- a/src/swiftguard/helpers.py +++ b/src/swiftguard/helpers.py @@ -173,6 +173,40 @@ def log(svt, msg, verbose=False): log.write(contents) +def config_create(force_restore=False): + # TODO: docstring. + + # If no config file exists, copy the default config file. + if not os.path.isfile(CONFIG_FILE) or force_restore: + try: + # If no config dir exists, create it. + if not os.path.isdir(os.path.dirname(CONFIG_FILE)): + os.mkdir(os.path.dirname(CONFIG_FILE)) + + # Copy config file to config dir or overwrite existing one. + shutil.copy( + os.path.join(APP_PATH, "install", "swiftguard.ini"), + CONFIG_FILE, + ) + + except Exception as e: + # Log error. + log( + 2, + f"Could not create config file at {CONFIG_FILE}! " + f"Error: {e}.", + ) + + # Return exit code 1 (Error occurred). + return 1 + + # Log success. + log(0, f"Created config file at {CONFIG_FILE}.") + + # Return exit code 0 (Success). + return 0 + + def config_load(config): """ The config_load function loads the config file and checks if its @@ -187,9 +221,10 @@ def config_load(config): config.read(CONFIG_FILE, encoding="utf-8") except ( - configparser.MissingSectionHeaderError or configparser.ParsingError + configparser.MissingSectionHeaderError, + configparser.ParsingError, ) as e: - # Log error and exit. + # Log error. log( 2, "Config file is not valid. Please check your config file " @@ -197,12 +232,10 @@ def config_load(config): f"\nError: {e}", ) - # Exit program. + # Exit program. TODO: use exitcodes. sys.exit(1) # Check if config file has all needed sections and options. - # TODO: if not, overwrite config file with default one (new func). - if not config.has_option("Application", "version"): restore_needed = True elif not config.has_option("User", "action"): @@ -216,10 +249,9 @@ def config_load(config): else: restore_needed = False + # Overwrite config file with default one. if restore_needed: - print("okkk restore") - else: - print("okkk no restore") + config_create(force_restore=True) # Defaulting some values if incorrect or not set. default_needed = False @@ -322,19 +354,29 @@ def check_encryption(): # Check exit code of fdesetup for success. if fv_process.returncode != 0: - return fv_process.stderr.strip() + log( + 1, + f"Could not determine encryption status of host system! " + f"Error: {fv_process.stderr.strip()}.", + ) + + return 1 if fv_process.stdout.strip(): # FileVault is enabled. - return True + log(0, "FileVault is enabled (recommended).") + return 0 else: # FileVault is disabled. - return False + log( + 1, "FileVault is disabled. Sensitive data SHOULD be encrypted." + ) + return 0 # Linux: Check if LUKS is enabled (WiP). else: - pass + raise NotImplementedError def startup(): @@ -390,7 +432,8 @@ def startup(): 1, "Looks like swiftGuard has not its needed " "Permission granted! Go to System Preferences -> Security & " - "Privacy -> Privacy -> Automation and add swiftGuard manually! " + "Privacy -> Privacy -> Automation and add swiftGuard " + "manually! " "If done and Warning persists test if swiftGuard can shutdown" "your system by connecting a new USB device. If so, you can " "ignore this warning.", @@ -400,48 +443,18 @@ def startup(): log(0, "Looks like swiftGuard has its needed permission granted.") # Check if user has FileVault enabled (highly recommended). - enc_status = check_encryption() - - if enc_status: - log(0, "FileVault is enabled (recommended).") - - elif not enc_status: - log(1, "FileVault is disabled. Sensitive data SHOULD be encrypted.") - - else: - log( - 1, - f"Could not determine encryption status of host system! Error: " - f"{enc_status}.", - ) + enc_exit_code = check_encryption() - # If no config file exists, copy the default config file. - if not os.path.isfile(CONFIG_FILE): - try: - # If no config dir exists, create it. - if not os.path.isdir(os.path.dirname(CONFIG_FILE)): - os.mkdir(os.path.dirname(CONFIG_FILE)) - - # Copy config file to config dir. - shutil.copy( - os.path.join(APP_PATH, "install", "swiftguard.ini"), - CONFIG_FILE, - ) - - except Exception as e: - # Log error. - log( - 2, - f"Could not create config file at {CONFIG_FILE}! " - f"Error: {e}.", - ) + if enc_exit_code == 1: + # Return error exit code 1 to main program. + return None, 1 - # Return error exit code 1 to main to exit program. - return None, 1 + # Copy default config file to CONFIG_FILE location. + config_exit_code = config_create() - else: - # Log info. - log(0, f"Created config file at {CONFIG_FILE}.") + if config_exit_code == 1: + # Return error exit code 1 to main program. + return None, 1 # Load settings from config file. config_parser = configparser.ConfigParser() @@ -802,15 +815,14 @@ def _check_inside(result, devices): vendor_id = DEVICE_RE[1].findall(result["vendor_id"])[0] except IndexError: # Assume this is not a standard vendor_id (probably - # apple_vendor_id instead of 0x....) + # apple_vendor_id instead of 0x....). vendor_id = result["vendor_id"] # Product ID. try: product_id = DEVICE_RE[1].findall(result["product_id"])[0] except IndexError: - # Assume this is not a standard product_id (probably - # apple_vendor_id instead of 0x....) + # Assume this is not a standard product_id (0x....). product_id = result["product_id"] # Serial number. @@ -878,4 +890,4 @@ def bt_devices(): :return: A list of bluetooth devices """ - return + raise NotImplementedError