#!/bin/sh # CertifiedCopy agent installer. # # curl -fsSL https://certified.sh/install.sh | sh # # The agent is optional and always will be. Everything CertifiedCopy does with a file you already # have — reading a chat.db, finding sms.db inside a backup, searching, exporting a PDF — happens in # the browser and needs none of this. The agent exists for the one thing a browser cannot do: talk # to a plugged-in iPhone. On macOS, usbmuxd opens the Apple Mobile Device interface the moment a # cable goes in and holds it, and WebUSB has to claim an interface to speak to a device. # # Two notes on how this is written, both deliberate. # # Everything is inside main(), which is called on the very last line. A `curl | sh` that is cut off # mid-transfer — a dropped connection, a proxy timeout — otherwise executes whatever fraction # arrived, which for an installer means a half-finished install with no error. Truncated here, the # shell reaches the end of the file without ever calling main(), and does nothing at all. # # The download is checksummed. Not because the transport is untrusted — it is HTTPS — but because # a truncated or corrupted binary is the failure that actually happens, and it fails later, in a # place that looks like a bug in the program. set -eu BASE="${CERTIFIEDCOPY_BASE:-https://certified.sh}" PREFIX="${CERTIFIEDCOPY_PREFIX:-$HOME/.certifiedcopy}" BIN_DIR="${CERTIFIEDCOPY_BIN_DIR:-$HOME/.local/bin}" red() { printf '\033[31m%s\033[0m\n' "$*" >&2; } bold() { printf '\033[1m%s\033[0m\n' "$*"; } die() { red "$*"; exit 1; } main() { [ "$(uname -s)" = "Darwin" ] || die \ "The agent is macOS only for now. It exists to talk to a plugged-in iPhone, and it does that through usbmuxd, which ships with macOS. Everything else CertifiedCopy does works in your browser on any system, with no install: https://certified.sh/app/" need curl need shasum need tar bold "Downloading the CertifiedCopy agent…" tmp=$(mktemp -d) # Cleared on any exit, including a failure part-way through: a half-extracted archive left in # /tmp is the kind of thing that gets found months later and puzzled over. trap 'rm -rf "$tmp"' EXIT INT TERM # One small file names the current build and carries its digest. The archive's own name # contains that digest, so the two can never be cached out of step with each other -- which is # the failure a fixed filename invites: a stale archive, a fresh checksum, and an installer # refusing a release that is perfectly good. fetch "${BASE}/download/latest.txt" "$tmp/latest" name=$(cut -d' ' -f1 < "$tmp/latest") expected=$(cut -d' ' -f2 < "$tmp/latest") case "$name" in certifiedcopy-macos-*.tar.gz) ;; *) die "The download index names something unexpected: ${name:-}" ;; esac archive="$tmp/agent.tar.gz" fetch "${BASE}/download/${name}" "$archive" actual=$(shasum -a 256 "$archive" | cut -d' ' -f1) [ "$expected" = "$actual" ] || die \ "The download does not match its checksum. expected $expected got $actual This usually means the transfer was cut short. Try again; if it persists, say so at https://certified.sh and do not run what was downloaded." bold "Installing to ${PREFIX}…" rm -rf "$PREFIX" mkdir -p "$PREFIX" tar -xzf "$archive" -C "$PREFIX" [ -x "$PREFIX/certifiedcopy" ] || die "The archive did not contain the agent." mkdir -p "$BIN_DIR" ln -sf "$PREFIX/certifiedcopy" "$BIN_DIR/certifiedcopy" # Fetched by curl, so it never receives com.apple.quarantine and Gatekeeper does not block it. # A binary downloaded through a browser would be quarantined and refuse to run, which is worth # knowing before anyone tries to be helpful by offering a download button. printf '\n' bold "Installed." printf ' agent %s\n' "$PREFIX/certifiedcopy" printf ' link %s\n\n' "$BIN_DIR/certifiedcopy" case ":${PATH}:" in *":${BIN_DIR}:"*) printf 'Run it with:\n\n certifiedcopy\n\n' ;; *) printf '%s is not on your PATH. Either run it directly:\n\n %s\n\nor add it:\n\n echo '"'"'export PATH="%s:$PATH"'"'"' >> ~/.zshrc\n\n' \ "$BIN_DIR" "$BIN_DIR/certifiedcopy" "$BIN_DIR" ;; esac printf 'It serves the app at http://127.0.0.1:4823 and reads nothing until you ask it to.\n' printf 'To remove it: rm -rf %s %s\n\n' "$PREFIX" "$BIN_DIR/certifiedcopy" } need() { command -v "$1" >/dev/null 2>&1 || die "This installer needs $1, which is not on your PATH." } fetch() { # --fail so an HTML error page is never written to disk and then run. -L because the download # may be served from a redirect. curl -fsSL --proto '=https' --tlsv1.2 -o "$2" "$1" || die "Could not download $1" } # Called last, on purpose. See the note at the top: a truncated download of this file runs nothing. main "$@"