File size: 6,888 Bytes
95f8c4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/data/data/com.termux/files/usr/bin/bash
# Idempotent Termux prereq installer for aistudio-api.
#
# What it does:
#   1. Ensures pkg: proot-distro, ca-certificates, curl.
#   2. Installs proot-distro container ${AISTUDIO_PROOT_NAME} (default
#      aistudio-api) — Ubuntu 24.04 from termux/proot-distro. Skips if
#      already present so it never collides with the user's own
#      `ubuntu` (or any other) container.
#   3. Inside the container, apt-installs the glibc runtime deps
#      CloakBrowser actually needs (libnss3, libnspr4, libgbm1,
#      libasound2, libxkbcommon0, libxcomposite1, libxdamage1,
#      libxrandr2, libxkbcommon0, libatk-bridge2.0-0, libatk1.0-0,
#      libatspi2.0-0, libgtk-3-0, libnotify4, fonts-liberation).
#   4. Downloads CloakBrowser into
#      <project_root>/.cloakbrowser/chromium-<ver>/. Skips if already
#      cached. Extracts in place; copies the chrome tree into the
#      container at /opt/cloakbrowser/ so the wrapper can --bind it.
#
# Flags:
#   --project-root PATH      where to place .cloakbrowser (default: cwd)
#   --proot-name NAME        container name (default: aistudio-api)
#   --proot-distro IMAGE     OCI image to install (default: ubuntu:24.04)
#   --chromium-version VER   CloakBrowser chromium version
#                            (default: 146.0.7680.177.3)
#   --skip-proot-install     don't create/update proot container
#   --skip-browser-download  don't re-fetch CloakBrowser tarball
#
# Re-running is safe and fast: each step short-circuits when its
# precondition is already satisfied.

set -euo pipefail

PROJECT_ROOT="$(pwd)"
PROOT_NAME="aistudio-api"
PROOT_IMAGE="ubuntu:24.04"
CHROMIUM_VERSION="146.0.7680.177.3"
SKIP_PROOT=0
SKIP_BROWSER=0

while [[ $# -gt 0 ]]; do
    case "$1" in
        --project-root) PROJECT_ROOT="$2"; shift 2 ;;
        --proot-name) PROOT_NAME="$2"; shift 2 ;;
        --proot-distro) PROOT_IMAGE="$2"; shift 2 ;;
        --chromium-version) CHROMIUM_VERSION="$2"; shift 2 ;;
        --skip-proot-install) SKIP_PROOT=1; shift ;;
        --skip-browser-download) SKIP_BROWSER=1; shift ;;
        -h|--help) sed -n '2,40p' "$0"; exit 0 ;;
        *) echo "unknown flag: $1" >&2; exit 2 ;;
    esac
done

PROJECT_ROOT="$(cd "${PROJECT_ROOT}" && pwd)"
CLOAK_ROOT="${PROJECT_ROOT}/.cloakbrowser"
CHROME_DIR_HOST="${CLOAK_ROOT}/chromium-${CHROMIUM_VERSION}"

log() { printf '[install] %s\n' "$*" >&2; }

# ---------- 1. Termux host packages ----------
if command -v pkg >/dev/null 2>&1; then
    NEEDED_PKGS=()
    for p in proot-distro ca-certificates curl; do
        if ! command -v "${p%proot-distro*}" >/dev/null 2>&1 \
           && ! dpkg -s "${p}" >/dev/null 2>&1; then
            NEEDED_PKGS+=("${p}")
        fi
    done
    command -v proot-distro >/dev/null 2>&1 || NEEDED_PKGS+=("proot-distro")
    command -v curl >/dev/null 2>&1 || NEEDED_PKGS+=("curl")
    if [[ ${#NEEDED_PKGS[@]} -gt 0 ]]; then
        log "Installing Termux packages: ${NEEDED_PKGS[*]}"
        pkg update -y
        pkg install -y "${NEEDED_PKGS[@]}"
    else
        log "Termux packages already present"
    fi
else
    log "pkg not found; assuming non-Termux host (skip host deps)"
fi

command -v proot-distro >/dev/null 2>&1 || {
    echo "proot-distro is required. Install it via 'pkg install proot-distro'." >&2
    exit 1
}

# ---------- 2. proot container ----------
if { proot-distro list 2>&1 1>/dev/null || true; } | grep -qE "[[:space:]]\\*?[[:space:]]*${PROOT_NAME}([[:space:]]|$)"; then
    log "proot container '${PROOT_NAME}' already exists; skipping install"
elif [[ ${SKIP_PROOT} -eq 1 ]]; then
    log "--skip-proot-install set but container missing; aborting"
    exit 1
else
    log "Installing proot container '${PROOT_NAME}' from ${PROOT_IMAGE}"
    proot-distro install "${PROOT_IMAGE}" --name "${PROOT_NAME}"
fi

# ---------- 3. apt deps inside container ----------
install_apt_deps() {
    proot-distro login "${PROOT_NAME}" -- bash -c '
        set -euo pipefail
        export DEBIAN_FRONTEND=noninteractive
        export TZ=UTC
        dpkg --configure -a >/dev/null 2>&1 || true
        apt-get install -y --no-install-recommends \
            ca-certificates curl \
            libnss3 libnspr4 libgbm1 libasound2t64 \
            libxkbcommon0 libxcomposite1 libxdamage1 libxrandr2 \
            libxfixes3 libxext6 libxrender1 libx11-6 libxcb1 \
            libatk-bridge2.0-0 libatk1.0-0 libatspi2.0-0 \
            libgtk-3-0 libnotify4 fonts-liberation libpangocairo-1.0-0
        apt-get clean
        rm -rf /var/lib/apt/lists/*
    '
}
log "Ensuring runtime libs inside container '${PROOT_NAME}'"
install_apt_deps

# ---------- 4. CloakBrowser binary ----------
ARCHIVE_NAME="cloakbrowser-linux-arm64.tar.gz"
DOWNLOAD_URL="https://github.com/CloakHQ/cloakbrowser/releases/download/chromium-v${CHROMIUM_VERSION}/${ARCHIVE_NAME}"

mkdir -p "${CLOAK_ROOT}"

if [[ -x "${CHROME_DIR_HOST}/chrome" ]]; then
    log "CloakBrowser ${CHROMIUM_VERSION} already cached at ${CHROME_DIR_HOST}"
elif [[ ${SKIP_BROWSER} -eq 1 ]]; then
    log "--skip-browser-download set but no chrome binary; aborting"
    exit 1
else
    log "Downloading CloakBrowser ${CHROMIUM_VERSION} (~200MB)..."
    TMP="$(mktemp -d)"
    trap 'rm -rf "${TMP}"' EXIT
    if command -v curl >/dev/null 2>&1; then
        curl -fSL --retry 3 -o "${TMP}/${ARCHIVE_NAME}" "${DOWNLOAD_URL}"
    else
        proot-distro login "${PROOT_NAME}" -- curl -fSL --retry 3 \
        proot-distro copy "${PROOT_NAME}:/tmp/${ARCHIVE_NAME}" \
            "${TMP}/${ARCHIVE_NAME}"
    fi
    tar -xzf "${TMP}/${ARCHIVE_NAME}" -C "${CLOAK_ROOT}"
    # Tarball may nest: chromium-<ver>/... — flatten one level if so.
    INNER="$(find "${CLOAK_ROOT}" -mindepth 2 -maxdepth 2 -type d -name 'chromium-*' | head -1 || true)"
    if [[ -n "${INNER}" && "${INNER}" != "${CHROME_DIR_HOST}" ]]; then
        mv "${INNER}" "${CHROME_DIR_HOST}"
    fi
    if [[ ! -x "${CHROME_DIR_HOST}/chrome" ]]; then
        echo "extracted chrome binary not found at ${CHROME_DIR_HOST}/chrome" >&2
        exit 1
    fi
    log "CloakBrowser extracted to ${CHROME_DIR_HOST}"
fi

# ---------- 5. Stage chrome tree into the container ----------
PROOT_CHROME_DIR="/opt/cloakbrowser"
log "Staging chrome tree into container at ${PROOT_CHROME_DIR}"
# proot-distro copy -r copies the dir itself. We'll rename it inside.
proot-distro login "${PROOT_NAME}" -- bash -c "rm -rf '/opt/$(basename "${CHROME_DIR_HOST}")'"
proot-distro copy -r "${CHROME_DIR_HOST}" "${PROOT_NAME}:/opt/$(basename "${CHROME_DIR_HOST}")"
proot-distro login "${PROOT_NAME}" -- bash -c "
    rm -rf '${PROOT_CHROME_DIR}'
    mv '/opt/$(basename "${CHROME_DIR_HOST}")' '${PROOT_CHROME_DIR}'
"

cat <<EOF

[install] Done.

Quick smoke test:
    bash scripts/cloakbrowser_termux/run-chrome.sh --version

Then start the API:
    uv run python3 main.py server --port 8080
EOF