#!/bin/sh # PlusPanel CLI installer (Linux, macOS): https://get.pluspanel.net/cli.sh # # curl -fsSL https://get.pluspanel.net/cli.sh | sh # curl -fsSL https://get.pluspanel.net/cli.sh | sh -s -- --prefix /usr/local/bin # curl -fsSL https://get.pluspanel.net/cli.sh | PLUSPANEL_CLI_VERSION=0.1.0 sh # # Downloads a release from https://github.com/112tech/pluspanel-cli/releases, ALWAYS checks the # archive's SHA-256 against SHA256SUMS, and checks the cosign signature of SHA256SUMS against the # PlusPanel release key below when cosign is installed. Installs into ~/.local/bin (root: # /usr/local/bin) or --prefix; it never calls sudo. Windows: cli.ps1. # # Options: --prefix DIR, --version X.Y.Z (env PLUSPANEL_CLI_PREFIX, PLUSPANEL_CLI_VERSION). set -eu REPO="112tech/pluspanel-cli" VERSION="${PLUSPANEL_CLI_VERSION:-latest}" PREFIX="${PLUSPANEL_CLI_PREFIX:-}" # PlusPanel release signing key (keys/cosign.pub of the platform repository). PUBKEY='-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEN+KOMqi8UoEffVXLTqcwl2MqxB6v EfiETaipooX6zI70JTW+dteB5XQhVtjvP8Rq31mmmR0lFJAkkvbUuOdXIw== -----END PUBLIC KEY-----' say() { printf 'pluspanel-install: %s\n' "$*"; } die() { printf 'pluspanel-install: ERROR: %s\n' "$*" >&2; exit 1; } while [ $# -gt 0 ]; do case "$1" in --prefix) [ $# -ge 2 ] || die "--prefix needs a directory"; PREFIX="$2"; shift 2 ;; --prefix=*) PREFIX="${1#--prefix=}"; shift ;; --version) [ $# -ge 2 ] || die "--version needs a value"; VERSION="$2"; shift 2 ;; --version=*) VERSION="${1#--version=}"; shift ;; -h|--help) sed -n '2,14p' "$0" 2>/dev/null || true; exit 0 ;; *) die "unknown option: $1" ;; esac done case "$(uname -s)" in Linux) OS=linux ;; Darwin) OS=darwin ;; *) die "unsupported system $(uname -s); on Windows use: irm https://get.pluspanel.net/cli.ps1 | iex" ;; esac case "$(uname -m)" in x86_64|amd64) ARCH=amd64 ;; aarch64|arm64) ARCH=arm64 ;; *) die "unsupported architecture $(uname -m)" ;; esac if command -v curl >/dev/null 2>&1; then fetch() { curl -fsSL --proto '=https' --tlsv1.2 -o "$2" "$1"; } elif command -v wget >/dev/null 2>&1; then fetch() { wget -q --https-only -O "$2" "$1"; } else die "curl or wget is required" fi if command -v sha256sum >/dev/null 2>&1; then sha256() { sha256sum "$1" | cut -d' ' -f1; } elif command -v shasum >/dev/null 2>&1; then sha256() { shasum -a 256 "$1" | cut -d' ' -f1; } else die "sha256sum or shasum is required" fi TMP="$(mktemp -d 2>/dev/null || mktemp -d -t pluspanel)" trap 'rm -rf "$TMP"' EXIT INT TERM VERSION="${VERSION#v}" if [ "$VERSION" = latest ]; then fetch "https://api.github.com/repos/$REPO/releases/latest" "$TMP/latest.json" VERSION="$(sed -n 's/.*"tag_name": *"v\{0,1\}\([^"]*\)".*/\1/p' "$TMP/latest.json" | head -n 1)" [ -n "$VERSION" ] || die "could not find the latest release of $REPO" fi case "$VERSION" in *[!0-9A-Za-z.-]*|'') die "invalid version: $VERSION" ;; esac ARCHIVE="pluspanel_${VERSION}_${OS}_${ARCH}.tar.gz" BASE="https://github.com/$REPO/releases/download/v$VERSION" say "downloading pluspanel $VERSION ($OS/$ARCH)" fetch "$BASE/$ARCHIVE" "$TMP/$ARCHIVE" fetch "$BASE/SHA256SUMS" "$TMP/SHA256SUMS" if command -v cosign >/dev/null 2>&1; then fetch "$BASE/SHA256SUMS.sig" "$TMP/SHA256SUMS.sig" printf '%s\n' "$PUBKEY" >"$TMP/cosign.pub" cosign verify-blob --key "$TMP/cosign.pub" --signature "$TMP/SHA256SUMS.sig" \ --insecure-ignore-tlog=true "$TMP/SHA256SUMS" >/dev/null 2>&1 || die "the signature of SHA256SUMS does not verify against the PlusPanel release key" say "signature verified (cosign)" else say "cosign not found: signature not checked (install cosign to verify it); checking SHA-256 only" fi WANT="$(awk -v f="$ARCHIVE" '$2 == f || $2 == "*" f {print $1}' "$TMP/SHA256SUMS")" [ -n "$WANT" ] || die "$ARCHIVE is not listed in SHA256SUMS" GOT="$(sha256 "$TMP/$ARCHIVE")" [ "$WANT" = "$GOT" ] || die "SHA-256 mismatch for $ARCHIVE (expected $WANT, got $GOT)" say "checksum verified" tar -xzf "$TMP/$ARCHIVE" -C "$TMP" pluspanel if [ -z "$PREFIX" ]; then if [ "$(id -u)" = 0 ]; then PREFIX=/usr/local/bin; else PREFIX="$HOME/.local/bin"; fi fi mkdir -p "$PREFIX" 2>/dev/null || true if [ ! -w "$PREFIX" ]; then die "$PREFIX is not writable; choose another --prefix, or run the installer as root yourself (it never uses sudo)" fi cp "$TMP/pluspanel" "$PREFIX/pluspanel.tmp" chmod 0755 "$PREFIX/pluspanel.tmp" mv -f "$PREFIX/pluspanel.tmp" "$PREFIX/pluspanel" say "installed $PREFIX/pluspanel" case ":$PATH:" in *":$PREFIX:"*) ;; *) say "note: $PREFIX is not on your PATH; add it, e.g. export PATH=\"$PREFIX:\$PATH\"" ;; esac "$PREFIX/pluspanel" version || true say "next: pluspanel login --api-url https://"