diff --git a/apps/autobrr/1.87.0/.env.sample b/apps/autobrr/1.87.0/.env.sample new file mode 100644 index 000000000..7146a71bb --- /dev/null +++ b/apps/autobrr/1.87.0/.env.sample @@ -0,0 +1,4 @@ +CONTAINER_NAME=autobrr-compose-check +PANEL_APP_PORT_HTTP=7474 +TZ=Asia/Shanghai +APP_DATA_DIR=./data diff --git a/apps/autobrr/1.87.0/data.yml b/apps/autobrr/1.87.0/data.yml new file mode 100644 index 000000000..f3afd6138 --- /dev/null +++ b/apps/autobrr/1.87.0/data.yml @@ -0,0 +1,51 @@ +additionalProperties: + formFields: + - default: 7474 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Web Port + labelZh: Web 端口 + label: + en: Web Port + zh: Web 端口 + zh-Hant: Web 連接埠 + ja: Web ポート + ko: 웹 포트 + ru: Веб-порт + ms: Port Web + pt-br: Porta Web + required: true + rule: paramPort + type: number + - default: Asia/Shanghai + edit: true + envKey: TZ + labelEn: Timezone + labelZh: 时区 + label: + en: Timezone + zh: 时区 + zh-Hant: 時區 + ja: タイムゾーン + ko: 시간대 + ru: Часовой пояс + ms: Zon Waktu + pt-br: Fuso Horário + required: true + type: text + - default: ./data + edit: true + envKey: APP_DATA_DIR + labelEn: Data Directory + labelZh: 数据目录 + label: + en: Data Directory + zh: 数据目录 + zh-Hant: 資料目錄 + ja: データディレクトリ + ko: 데이터 디렉터리 + ru: Каталог данных + ms: Direktori Data + pt-br: Diretório de Dados + required: true + type: text diff --git a/apps/autobrr/1.87.0/docker-compose.yml b/apps/autobrr/1.87.0/docker-compose.yml new file mode 100644 index 000000000..9647714d6 --- /dev/null +++ b/apps/autobrr/1.87.0/docker-compose.yml @@ -0,0 +1,20 @@ +services: + autobrr: + image: "ghcr.io/autobrr/autobrr:v1.87.0" + container_name: ${CONTAINER_NAME} + restart: unless-stopped + user: "1000:1000" + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:7474" + volumes: + - "${APP_DATA_DIR}:/config" + environment: + - TZ=${TZ} + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/autobrr/1.87.0/scripts/init.sh b/apps/autobrr/1.87.0/scripts/init.sh new file mode 100755 index 000000000..3b67e5956 --- /dev/null +++ b/apps/autobrr/1.87.0/scripts/init.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +set -euo pipefail +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +export PATH + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}" + +read_env_value() { + local key="$1" + [[ -f "$ENV_FILE" ]] || return 0 + local value + value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)" + case "$value" in + \"*\") value="${value#\"}"; value="${value%\"}" ;; + \'*\') value="${value#\'}"; value="${value%\'}" ;; + esac + printf '%s\n' "$value" +} + +configured_value() { + local key="$1" + local default_value="$2" + local value + value="${!key:-}" + if [[ -z "$value" ]]; then + value="$(read_env_value "$key")" + fi + printf '%s\n' "${value:-$default_value}" +} + +resolve_app_path() { + local key="$1" + local raw="$2" + local clean candidate resolved current part + local -a parts=() + case "$raw" in + ""|/*|.|..|../*|*/../*|*/..) echo "unsafe ${key} path" >&2; return 1 ;; + esac + if [[ "$raw" =~ [[:cntrl:]] ]]; then + echo "unsafe ${key} path" >&2 + return 1 + fi + clean="${raw#./}" + [[ -n "$clean" ]] || { echo "unsafe ${key} path" >&2; return 1; } + command -v realpath >/dev/null 2>&1 || { echo "realpath is required" >&2; return 1; } + candidate="$ROOT_DIR/$clean" + resolved="$(realpath -m -- "$candidate")" || { echo "unsafe ${key} path" >&2; return 1; } + case "$resolved" in + "$ROOT_DIR"/*) ;; + *) echo "unsafe ${key} path" >&2; return 1 ;; + esac + current="$ROOT_DIR" + IFS='/' read -r -a parts <<< "$clean" + for part in "${parts[@]}"; do + [[ -z "$part" || "$part" == "." ]] && continue + current="$current/$part" + if [[ -L "$current" ]]; then + echo "unsafe ${key} path" >&2 + return 1 + fi + done + printf '%s\n' "$resolved" +} + +resolve_direct_child() { + local key="$1" + local raw="$2" + local clean path + clean="${raw#./}" + if [[ -z "$clean" || "$clean" == */* ]]; then + echo "unsafe ${key} path: lifecycle directories must be direct children of the version root" >&2 + return 1 + fi + path="$(resolve_app_path "$key" "$raw")" + [[ "$path" == "$ROOT_DIR/$clean" ]] || { echo "unsafe ${key} path" >&2; return 1; } + printf '%s\n' "$path" +} + +verify_trusted_root_chain() { + local current owner mode + [[ "$(id -u)" == "0" ]] || { echo "directory ownership initialization must run as root" >&2; return 1; } + command -v stat >/dev/null 2>&1 || { echo "stat is required" >&2; return 1; } + current="$ROOT_DIR" + while [[ "$current" != "/" ]]; do + [[ -d "$current" && ! -L "$current" ]] || { echo "unsafe version root chain: $current" >&2; return 1; } + IFS=':' read -r owner mode < <(stat -c '%u:%a' -- "$current") + [[ "$owner" == "0" ]] || { echo "unsafe version root chain owner: $current" >&2; return 1; } + [[ "$mode" =~ ^[0-7]{3,4}$ ]] || { echo "unsafe version root chain mode: $current" >&2; return 1; } + (( (8#$mode & 0022) == 0 )) || { echo "unsafe version root chain permissions: $current" >&2; return 1; } + current="$(dirname -- "$current")" + done +} + +ensure_dir() { + local key="$1" + local raw + local path + raw="$(configured_value "$key" "$2")" + path="$(resolve_app_path "$key" "$raw")" + mkdir -p -- "$path" + [[ "$(resolve_app_path "$key" "$raw")" == "$path" ]] || { echo "unsafe ${key} path" >&2; return 1; } + chown -R 1000:1000 -- "$path" + chmod 755 -- "$path" +} + +ensure_dir "APP_DATA_DIR" "./data" diff --git a/apps/autobrr/1.87.0/scripts/uninstall.sh b/apps/autobrr/1.87.0/scripts/uninstall.sh new file mode 100755 index 000000000..ab8a8d674 --- /dev/null +++ b/apps/autobrr/1.87.0/scripts/uninstall.sh @@ -0,0 +1,2 @@ +#!/bin/bash +docker-compose down --volumes diff --git a/apps/autobrr/1.87.0/scripts/upgrade.sh b/apps/autobrr/1.87.0/scripts/upgrade.sh new file mode 100755 index 000000000..0056a4fe4 --- /dev/null +++ b/apps/autobrr/1.87.0/scripts/upgrade.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +exec bash "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/init.sh"