#!/bin/sh # CryptoMesh VPN macOS and Debian/Ubuntu installer. Review before running it. # Read the manifest published atomically with each verified desktop release. set -eu # Only invoke main after the entire script has been received. metadata_error() { echo 'Release metadata verification failed. Installation stopped.' >&2 exit 1 } release_field() { # Preserve any embedded/trailing newlines so malformed strings are rejected. field_value=$(plutil -extract "$1" raw -expect "$2" -n -o - "$work_dir/release.json" 2>/dev/null && printf '.') || metadata_error field_value=${field_value%.} } load_release() { curl --fail --show-error --location --proto '=https' --proto-redir '=https' \ --output "$work_dir/release.json" \ 'https://cryptomesh-vpn-downloads.web.app/desktop-update.json' if [ "$platform" = macos ]; then release_field schema_version integer [ "$field_value" = 1 ] || metadata_error release_field build integer build=$field_value case "$build" in ''|0*|*[!0-9]*) metadata_error ;; esac release_field version string version=$field_value release_field platforms.macos.url string download_url=$field_value release_field platforms.macos.sha256 string expected_hash=$field_value release_field platforms.macos.size integer expected_size=$field_value filename=cryptomesh-vpn-macos.dmg else command -v python3 >/dev/null 2>&1 || { echo 'Install python3 with your package manager, then run this command again.' >&2 exit 1 } fields=$(python3 - "$work_dir/release.json" <<'PY' import json, re, sys try: with open(sys.argv[1], encoding="utf-8") as stream: release = json.load(stream) valid_version = isinstance(release.get("version"), str) and re.fullmatch(r"(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)", release["version"]) if not (type(release.get("schema_version")) is int and release["schema_version"] == 1 and type(release.get("build")) is int and release["build"] > 0 and valid_version): raise ValueError() artifact = release["platforms"]["linux"] if not (artifact["url"] == "https://cryptomesh-vpn-downloads.web.app/desktop-v" + release["version"] + "/cryptomesh-vpn-linux-amd64.deb" and isinstance(artifact["sha256"], str) and re.fullmatch(r"[a-f0-9]{64}", artifact["sha256"]) and type(artifact["size"]) is int and artifact["size"] > 0): raise ValueError() print(release["version"], artifact["url"], artifact["sha256"], artifact["size"], sep="\n") except (AssertionError, KeyError, TypeError, ValueError, AttributeError): sys.exit("Release metadata verification failed. Installation stopped.") PY ) version=$(printf '%s\n' "$fields" | sed -n '1p') download_url=$(printf '%s\n' "$fields" | sed -n '2p') expected_hash=$(printf '%s\n' "$fields" | sed -n '3p') expected_size=$(printf '%s\n' "$fields" | sed -n '4p') filename=cryptomesh-vpn-linux-amd64.deb fi case "$version" in ''|*[!0-9.]*) metadata_error ;; esac printf '%s\n' "$version" | LC_ALL=C grep -Eq '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$' || metadata_error [ "$download_url" = "https://cryptomesh-vpn-downloads.web.app/desktop-v$version/$filename" ] || metadata_error case "$expected_hash" in *[!a-f0-9]*) metadata_error ;; esac [ "${#expected_hash}" = 64 ] || metadata_error case "$expected_size" in ''|0*|*[!0-9]*) metadata_error ;; esac } verify_size() { [ "$(wc -c < "$1" | tr -d ' ')" = "$expected_size" ] || metadata_error } install_linux() { if [ "$(uname -m)" != x86_64 ] || ! command -v apt-get >/dev/null 2>&1; then echo 'Linux requires 64-bit Debian or Ubuntu with a desktop environment. Visit https://cryptomesh-vpn-prod.web.app/download.' >&2 exit 1 fi work_dir=$(mktemp -d) trap 'rm -rf "$work_dir"' EXIT trap 'exit 1' HUP INT TERM platform=linux load_release echo "Downloading CryptoMesh VPN $version..." curl --fail --show-error --location --proto '=https' --proto-redir '=https' \ --output "$work_dir/cryptomesh-vpn.deb" \ "$download_url" verify_size "$work_dir/cryptomesh-vpn.deb" printf '%s %s\n' "$expected_hash" \ "$work_dir/cryptomesh-vpn.deb" | sha256sum -c - # The downloaded package is public; allow apt's sandbox to read it. chmod 755 "$work_dir" chmod 644 "$work_dir/cryptomesh-vpn.deb" if [ "$(id -u)" = 0 ]; then apt-get install "$work_dir/cryptomesh-vpn.deb" else sudo apt-get install "$work_dir/cryptomesh-vpn.deb" fi echo 'Installed. Open CryptoMesh VPN from your applications menu and sign in.' } main() { case "$(uname -s)" in Linux) install_linux; return ;; Darwin) ;; *) echo 'For Windows, iOS, or Android, visit https://cryptomesh-vpn-prod.web.app/download.' >&2 exit 1 ;; esac if [ "$(id -u)" = 0 ]; then echo 'Run this command as your normal desktop user, without sudo.' >&2 exit 1 fi destination='/Applications/CryptoMesh VPN.app' if [ -e "$destination" ] || [ -L "$destination" ]; then echo 'CryptoMesh VPN is already installed. Quit the app and use the disk image at https://cryptomesh-vpn-prod.web.app/download to update it.' >&2 exit 1 fi work_dir=$(mktemp -d) cleanup() { hdiutil detach "$work_dir/mount" -quiet 2>/dev/null || true rm -rf "$work_dir" } trap cleanup EXIT trap 'exit 1' HUP INT TERM platform=macos load_release echo "Downloading CryptoMesh VPN $version..." curl --fail --show-error --location --proto '=https' --proto-redir '=https' \ --output "$work_dir/cryptomesh-vpn-macos.dmg" \ "$download_url" verify_size "$work_dir/cryptomesh-vpn-macos.dmg" printf '%s %s\n' "$expected_hash" \ "$work_dir/cryptomesh-vpn-macos.dmg" | shasum -a 256 -c - hdiutil attach "$work_dir/cryptomesh-vpn-macos.dmg" -readonly -nobrowse \ -mountpoint "$work_dir/mount" -quiet app="$work_dir/mount/CryptoMesh VPN.app" codesign --verify --deep --strict \ -R '=anchor apple generic and certificate leaf[subject.OU] = "NX8GQXV95J"' "$app" spctl --assess --type execute "$app" # Do not replace an existing installation or disable Gatekeeper/quarantine. # Applications is required by the app's system extension. if [ -w /Applications ]; then ditto "$app" "$destination" else echo 'Administrator approval is needed to install in Applications.' sudo ditto "$app" "$destination" fi echo 'Installed. Open CryptoMesh VPN, sign in, and approve VPN permissions.' open "$destination" } main "$@"