diff --git a/README.md b/README.md index 07b18f9..16fd3d1 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Harbor помогает пользоваться одной VPN-подписко ## Что понадобится - ссылка на подписку от VPN-провайдера; -- Git; - Docker с командой `docker compose`; +- для ручной установки Gateway — Git; - для Gateway — Linux-машина в одной локальной сети с устройствами; - для Connect — Mac с запущенным Docker Desktop. @@ -78,14 +78,12 @@ http://АДРЕС-GATEWAY:3456 ### 1. Запустите Docker Desktop -Установщик проверит наличие Git, Docker, Docker Compose и `curl`. Если Docker Desktop не запущен, установка остановится с понятным сообщением. +Установщик проверит наличие Docker, Docker Compose, `curl` и `tar`. Если Docker Desktop не запущен, установка остановится с понятным сообщением. -### 2. Скачайте проект и запустите установщик +### 2. Запустите установщик ```bash -git clone https://git.dokops.ru/dokril/vpn-proxy.git -cd vpn-proxy -./scripts/install-macos-client.sh +curl -fsSL https://git.dokops.ru/dokril/vpn-proxy/raw/branch/master/install.sh | sh ``` Установщик: @@ -114,9 +112,10 @@ cd vpn-proxy Передайте нужные значения при повторном запуске установщика: ```bash -VPN_PROXY_CLIENT_PORT=9080 \ -VPN_PROXY_CLIENT_UI_PORT=3457 \ -./scripts/install-macos-client.sh +curl -fsSL https://git.dokops.ru/dokril/vpn-proxy/raw/branch/master/install.sh | \ + VPN_PROXY_CLIENT_PORT=9080 \ + VPN_PROXY_CLIENT_UI_PORT=3457 \ + sh ``` Допустимы порты от `1024` до `65535`. Установщик не позволит выбрать занятый порт или один порт одновременно для интерфейса и прокси. @@ -212,11 +211,10 @@ docker compose -f docker-compose.gateway.yml up -d --build ### Connect -Повторно запустите установщик. Он обновит рабочую копию, снова спросит порт прокси и пересоберёт Connect: +Повторно запустите однострочный установщик. Он обновит рабочую копию, снова спросит порт прокси и пересоберёт Connect: ```bash -cd ~/.vpn-proxy-client -./scripts/install-macos-client.sh +curl -fsSL https://git.dokops.ru/dokril/vpn-proxy/raw/branch/master/install.sh | sh ``` Если раньше использовался нестандартный порт, укажите его снова через `VPN_PROXY_CLIENT_PORT`. diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..abeb817 --- /dev/null +++ b/install.sh @@ -0,0 +1,27 @@ +#!/bin/sh +set -eu + +need() { + command -v "$1" >/dev/null 2>&1 || { + printf '[harbor-connect] error: %s is required\n' "$1" >&2 + exit 1 + } +} + +need curl +need tar +[ -x /bin/bash ] || { printf '[harbor-connect] error: /bin/bash is required\n' >&2; exit 1; } + +branch="${VPN_PROXY_BRANCH:-master}" +archive_url="${VPN_PROXY_ARCHIVE_URL:-https://git.dokops.ru/dokril/vpn-proxy/archive/${branch}.tar.gz}" +tmp="$(mktemp -d "${TMPDIR:-/tmp}/harbor-connect.XXXXXX")" +trap 'rm -rf "$tmp"' 0 1 2 3 15 + +mkdir -p "$tmp/source" +curl -fsSL "$archive_url" | tar -xzf - -C "$tmp/source" --strip-components=1 +[ -f "$tmp/source/scripts/install-macos-client.sh" ] || { + printf '[harbor-connect] error: installer is missing from archive\n' >&2 + exit 1 +} + +VPN_PROXY_SOURCE_DIR="$tmp/source" /bin/bash "$tmp/source/scripts/install-macos-client.sh" diff --git a/scripts/harbor-version.mjs b/scripts/harbor-version.mjs index 34ef0c2..f5eb3ed 100644 --- a/scripts/harbor-version.mjs +++ b/scripts/harbor-version.mjs @@ -34,7 +34,7 @@ export function affectedComponents(files) { else if (/^(src\/web\/|public\/|index\.html$|vite\.config\.js$)/.test(file)) { add('macClient', 'gatewayClient'); } else if (/^src\/server\//.test(file)) add('macClient', 'gatewayBackend'); - else if (/^(Dockerfile\.client|docker-compose\.client(\.local)?\.yml|entrypoint\.client\.sh|scripts\/(install-macos-client|harbor-network-monitor)\.sh)$/.test(file)) { + else if (/^(install\.sh|Dockerfile\.client|docker-compose\.client(\.local)?\.yml|entrypoint\.client\.sh|scripts\/(install-macos-client|harbor-network-monitor)\.sh)$/.test(file)) { add('macClient'); } else if (/^(Dockerfile|Dockerfile\.runtime-base|docker-compose\.gateway\.yml|entrypoint\.sh|scripts\/(deploy-gateway|build-runtime-base|build-on-107-deploy-111)\.sh)$/.test(file)) { add('gatewayBackend'); diff --git a/scripts/install-macos-client.sh b/scripts/install-macos-client.sh index fcdab37..40a4988 100755 --- a/scripts/install-macos-client.sh +++ b/scripts/install-macos-client.sh @@ -2,8 +2,9 @@ set -euo pipefail INSTALL_DIR="${VPN_PROXY_INSTALL_DIR:-$HOME/.vpn-proxy-client}" -REPO_URL="${VPN_PROXY_REPO_URL:-https://git.dokops.ru/dokril/vpn-proxy.git}" BRANCH="${VPN_PROXY_BRANCH:-master}" +ARCHIVE_URL="${VPN_PROXY_ARCHIVE_URL:-https://git.dokops.ru/dokril/vpn-proxy/archive/${BRANCH}.tar.gz}" +SOURCE_DIR="${VPN_PROXY_SOURCE_DIR:-}" COMPOSE_FILE="docker-compose.client.yml" DEFAULT_PROXY_PORT="8082" REQUESTED_PROXY_PORT="${VPN_PROXY_CLIENT_PORT:-}" @@ -254,26 +255,49 @@ get_env_value() { ' .env } +copy_source() { + local source_dir="$1" + [ -f "$source_dir/docker-compose.client.yml" ] || die "invalid Harbor source archive" + log "installing files to $INSTALL_DIR" + mkdir -p "$INSTALL_DIR" + cp -R "$source_dir/." "$INSTALL_DIR/" +} + +download_source() { + local tmp_dir + tmp_dir="$(mktemp -d)" + mkdir -p "$tmp_dir/source" + log "downloading $ARCHIVE_URL" + if ! curl -fsSL "$ARCHIVE_URL" | tar -xzf - -C "$tmp_dir/source" --strip-components=1; then + rm -rf "$tmp_dir" + die "failed to download Harbor source" + fi + copy_source "$tmp_dir/source" + rm -rf "$tmp_dir" +} + if [[ "$(uname -s)" != "Darwin" ]]; then die "this installer is intended for macOS" fi -need git need docker need curl +need tar docker compose version >/dev/null 2>&1 || die "Docker Compose plugin is required" docker info >/dev/null 2>&1 || die "Docker Desktop is not running" -if [[ -d "$INSTALL_DIR/.git" ]]; then +if [[ -n "$SOURCE_DIR" ]]; then + copy_source "$SOURCE_DIR" +elif [[ -d "$INSTALL_DIR/.git" ]]; then + need git log "updating $INSTALL_DIR" git -C "$INSTALL_DIR" fetch origin "$BRANCH" git -C "$INSTALL_DIR" checkout "$BRANCH" git -C "$INSTALL_DIR" pull --ff-only origin "$BRANCH" else - log "cloning $REPO_URL#$BRANCH to $INSTALL_DIR" mkdir -p "$(dirname "$INSTALL_DIR")" - git clone --branch "$BRANCH" "$REPO_URL" "$INSTALL_DIR" + download_source fi cd "$INSTALL_DIR" diff --git a/src/shared/versions.js b/src/shared/versions.js index 80c7b81..593f07c 100644 --- a/src/shared/versions.js +++ b/src/shared/versions.js @@ -1,5 +1,5 @@ export const HARBOR_VERSIONS = Object.freeze({ - macClient: '0.8.9', + macClient: '0.8.10', gatewayClient: '0.8.9', gatewayBackend: '0.8.0', }); diff --git a/test/install-script.test.js b/test/install-script.test.js new file mode 100644 index 0000000..dfaae01 --- /dev/null +++ b/test/install-script.test.js @@ -0,0 +1,42 @@ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; + +const root = path.resolve(import.meta.dirname, '..'); + +test('one-line installer extracts the archive and hands it to the macOS installer', () => { + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'harbor-install-')); + try { + const source = path.join(tmp, 'fixture', 'harbor-net'); + fs.mkdirSync(path.join(source, 'scripts'), { recursive: true }); + fs.writeFileSync(path.join(source, 'marker'), 'ok'); + fs.writeFileSync(path.join(source, 'scripts', 'install-macos-client.sh'), [ + '#!/bin/bash', + 'set -eu', + 'test "$(cat "$VPN_PROXY_SOURCE_DIR/marker")" = ok', + 'printf bootstrap-ok', + ].join('\n')); + + const archive = path.join(tmp, 'source.tar.gz'); + execFileSync('tar', ['-czf', archive, '-C', path.dirname(source), path.basename(source)]); + const bin = path.join(tmp, 'bin'); + fs.mkdirSync(bin); + fs.writeFileSync(path.join(bin, 'curl'), '#!/bin/sh\ncat "$FIXTURE_ARCHIVE"\n', { mode: 0o755 }); + + const output = execFileSync('sh', [path.join(root, 'install.sh')], { + encoding: 'utf8', + env: { + ...process.env, + FIXTURE_ARCHIVE: archive, + PATH: `${bin}:/usr/bin:/bin`, + VPN_PROXY_ARCHIVE_URL: 'https://example.invalid/source.tar.gz', + }, + }); + assert.equal(output, 'bootstrap-ok'); + } finally { + fs.rmSync(tmp, { recursive: true, force: true }); + } +}); diff --git a/test/version-script.test.js b/test/version-script.test.js index e4e7bac..06dfc6e 100644 --- a/test/version-script.test.js +++ b/test/version-script.test.js @@ -13,6 +13,7 @@ test('version paths map to the components actually shipped by this repository', assert.deepEqual(affectedComponents(['src/web/App.jsx']), ['macClient', 'gatewayClient']); assert.deepEqual(affectedComponents(['src/server/index.js']), ['macClient', 'gatewayBackend']); assert.deepEqual(affectedComponents(['docker-compose.client.local.yml']), ['macClient']); + assert.deepEqual(affectedComponents(['install.sh']), ['macClient']); assert.deepEqual(affectedComponents(['package-lock.json']), [ 'macClient', 'gatewayClient',