diff --git a/apps/tinyauth/5.1.3/.env.sample b/apps/tinyauth/5.1.3/.env.sample new file mode 100644 index 000000000..48d328944 --- /dev/null +++ b/apps/tinyauth/5.1.3/.env.sample @@ -0,0 +1,6 @@ +CONTAINER_NAME=tinyauth +PANEL_APP_PORT_HTTP=3000 +TINYAUTH_APP_URL=http://tinyauth.localhost:3000 +TINYAUTH_ADMIN_USERNAME=admin +TINYAUTH_ADMIN_PASSWORD=Tinyauth_Admin_Change_Me_2026! +TINYAUTH_SECURE_COOKIE=false diff --git a/apps/tinyauth/5.1.3/data.yml b/apps/tinyauth/5.1.3/data.yml new file mode 100644 index 000000000..96949bffa --- /dev/null +++ b/apps/tinyauth/5.1.3/data.yml @@ -0,0 +1,92 @@ +additionalProperties: + formFields: + - default: 3000 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: HTTP Port + labelZh: HTTP 端口 + label: + en: HTTP Port + zh: HTTP 端口 + zh-Hant: HTTP 連接埠 + ja: HTTP ポート + ko: HTTP 포트 + ru: Порт HTTP + ms: Port HTTP + pt-br: Porta HTTP + required: true + rule: paramPort + type: number + - default: http://tinyauth.localhost:3000 + edit: true + envKey: TINYAUTH_APP_URL + labelEn: External URL + labelZh: 外部访问地址 + label: + en: External URL + zh: 外部访问地址 + zh-Hant: 外部存取網址 + ja: 外部 URL + ko: 외부 URL + ru: Внешний URL + ms: URL Luaran + pt-br: URL externo + required: true + rule: paramExtUrl + type: text + - default: admin + edit: true + envKey: TINYAUTH_ADMIN_USERNAME + labelEn: Admin Username + labelZh: 管理员用户名 + label: + en: Admin Username + zh: 管理员用户名 + zh-Hant: 管理員使用者名稱 + ja: 管理者ユーザー名 + ko: 관리자 사용자 이름 + ru: Имя администратора + ms: Nama Pengguna Pentadbir + pt-br: Usuario administrador + required: true + rule: paramCommon + type: text + - default: "" + edit: true + envKey: TINYAUTH_ADMIN_PASSWORD + labelEn: Admin Password + labelZh: 管理员密码 + label: + en: Admin Password + zh: 管理员密码 + zh-Hant: 管理員密碼 + ja: 管理者パスワード + ko: 관리자 비밀번호 + ru: Пароль администратора + ms: Kata Laluan Pentadbir + pt-br: Senha do administrador + random: true + required: true + rule: paramComplexity + type: password + - default: "false" + edit: true + envKey: TINYAUTH_SECURE_COOKIE + labelEn: Secure Cookies + labelZh: 安全 Cookie + label: + en: Secure Cookies + zh: 安全 Cookie + zh-Hant: 安全 Cookie + ja: Secure Cookie + ko: 보안 Cookie + ru: Secure Cookie + ms: Cookie Selamat + pt-br: Cookie seguro + required: true + type: select + values: + - label: "false" + value: "false" + - label: "true" + value: "true" diff --git a/apps/tinyauth/5.1.3/docker-compose.yml b/apps/tinyauth/5.1.3/docker-compose.yml new file mode 100644 index 000000000..74224fc12 --- /dev/null +++ b/apps/tinyauth/5.1.3/docker-compose.yml @@ -0,0 +1,42 @@ +services: + tinyauth: + image: "ghcr.io/tinyauthapp/tinyauth:v5.1.3@sha256:a1bde189951900f84a60f133c26a1ec7a3264073ec7875b548f4fbadb7f5f735" + container_name: ${CONTAINER_NAME} + restart: unless-stopped + user: "1000:1000" + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:3000" + environment: + - TINYAUTH_APPURL=${TINYAUTH_APP_URL} + - TINYAUTH_LABELPROVIDER=none + - TINYAUTH_AUTH_USERSFILE=/data/users + - TINYAUTH_AUTH_SECURECOOKIE=${TINYAUTH_SECURE_COOKIE} + - TINYAUTH_ANALYTICS_ENABLED=false + - TINYAUTH_SERVER_ADDRESS=0.0.0.0 + - TINYAUTH_SERVER_PORT=3000 + - TINYAUTH_DATABASE_DRIVER=sqlite + - TINYAUTH_DATABASE_PATH=/data/tinyauth.db + - TINYAUTH_RESOURCES_PATH=/data/resources + volumes: + - "./data:/data" + read_only: true + tmpfs: + - /tmp:nodev,noexec,nosuid,size=32M + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + healthcheck: + test: ["CMD", "tinyauth", "healthcheck"] + interval: 30s + timeout: 5s + start_period: 10s + retries: 5 + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/tinyauth/5.1.3/scripts/init.sh b/apps/tinyauth/5.1.3/scripts/init.sh new file mode 100755 index 000000000..95c45bbff --- /dev/null +++ b/apps/tinyauth/5.1.3/scripts/init.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}" +DOCKER_BIN="${DOCKER_BIN:-docker}" +IMAGE='ghcr.io/tinyauthapp/tinyauth:v5.1.3@sha256:a1bde189951900f84a60f133c26a1ec7a3264073ec7875b548f4fbadb7f5f735' + +fail() { + printf '%s\n' "$1" >&2 + exit 1 +} + +read_env_value() { + local key="$1" + 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" +} + +[[ -f "$ENV_FILE" && ! -L "$ENV_FILE" ]] || fail "$ENV_FILE must be a regular file" +command -v "$DOCKER_BIN" >/dev/null 2>&1 || fail 'Docker is required to generate the Tinyauth password hash' + +username="${TINYAUTH_ADMIN_USERNAME:-$(read_env_value TINYAUTH_ADMIN_USERNAME)}" +password="${TINYAUTH_ADMIN_PASSWORD:-$(read_env_value TINYAUTH_ADMIN_PASSWORD)}" +app_url="${TINYAUTH_APP_URL:-$(read_env_value TINYAUTH_APP_URL)}" +secure_cookie="${TINYAUTH_SECURE_COOKIE:-$(read_env_value TINYAUTH_SECURE_COOKIE)}" + +data_dir="$(realpath -m -- "$ROOT_DIR/data")" +case "$data_dir" in + "$ROOT_DIR"/*) ;; + *) fail 'Tinyauth data directory must remain inside the application version directory' ;; +esac +for path in "$data_dir" "$data_dir/resources" "$data_dir/oidc"; do + [[ ! -L "$path" ]] || fail "$path must not be a symbolic link" + [[ ! -e "$path" || -d "$path" ]] || fail "$path must be a directory" +done +users_file="$data_dir/users" +[[ ! -L "$users_file" ]] || fail 'Tinyauth users file must not be a symbolic link' +[[ ! -e "$users_file" || -f "$users_file" ]] || fail 'Tinyauth users path must be a regular file' + +[[ "$username" =~ ^[A-Za-z0-9._-]{1,64}$ ]] || fail 'TINYAUTH_ADMIN_USERNAME must contain only letters, digits, dot, underscore, or hyphen' +[[ ${#password} -ge 12 && ${#password} -le 256 ]] || fail 'TINYAUTH_ADMIN_PASSWORD must contain 12 to 256 characters' +[[ "$password" != *$'\n'* && "$password" != *$'\r'* ]] || fail 'TINYAUTH_ADMIN_PASSWORD must not contain line breaks' +[[ "$app_url" =~ ^https?://[^[:space:]]+$ ]] || fail 'TINYAUTH_APP_URL must be an absolute HTTP or HTTPS URL without whitespace' +app_host="${app_url#*://}" +app_host="${app_host%%/*}" +app_host="${app_host%%:*}" +[[ "$app_host" == *.* && "$app_host" =~ ^[A-Za-z0-9][A-Za-z0-9.-]*[A-Za-z0-9]$ ]] || fail 'TINYAUTH_APP_URL must use a domain name with at least two labels' +[[ ! "$app_host" =~ ^[0-9.]+$ ]] || fail 'TINYAUTH_APP_URL must not use an IP address' +[[ "$secure_cookie" == false || "$secure_cookie" == true ]] || fail 'TINYAUTH_SECURE_COOKIE must be true or false' + +install -d -m 0750 -o 1000 -g 1000 -- "$data_dir" "$data_dir/resources" "$data_dir/oidc" + +# Variables in this command are expanded by the shell inside the generator container. +# shellcheck disable=SC2016 +generator_command='IFS= read -r password; exec tinyauth user create --username "$1" --password "$password"' +generator_output="$( + printf '%s\n' "$password" | + "$DOCKER_BIN" run --rm -i --network none --read-only --user 1000:1000 \ + --cap-drop ALL --security-opt no-new-privileges --env NO_COLOR=1 \ + --entrypoint /bin/sh "$IMAGE" -ec \ + "$generator_command" \ + sh "$username" +)" +user_entry="$(printf '%s\n' "$generator_output" | sed -n 's/^TINYAUTH_AUTH_USERS=//p' | head -n 1)" +[[ "$user_entry" =~ ^[A-Za-z0-9._-]{1,64}:\$2[aby]\$[0-9]{2}\$[./A-Za-z0-9]{53}$ ]] || fail 'Failed to generate a valid bcrypt user entry' + +umask 077 +temporary="$(mktemp "$data_dir/.users.tmp.XXXXXX")" +trap 'rm -f -- "${temporary:-}"' EXIT +printf '%s\n' "$user_entry" >"$temporary" +chmod 0600 "$temporary" +chown 1000:1000 "$temporary" +mv -f -- "$temporary" "$users_file" +trap - EXIT + +chown 1000:1000 "$data_dir" "$data_dir/resources" "$data_dir/oidc" "$users_file" +chmod 0750 "$data_dir" "$data_dir/resources" "$data_dir/oidc" +chmod 0600 "$users_file" diff --git a/apps/tinyauth/5.1.3/scripts/uninstall.sh b/apps/tinyauth/5.1.3/scripts/uninstall.sh new file mode 100755 index 000000000..5a3f6bd6b --- /dev/null +++ b/apps/tinyauth/5.1.3/scripts/uninstall.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +if command -v docker-compose >/dev/null 2>&1; then + docker-compose down --volumes --remove-orphans +else + docker compose down --volumes --remove-orphans +fi diff --git a/apps/tinyauth/5.1.3/scripts/upgrade.sh b/apps/tinyauth/5.1.3/scripts/upgrade.sh new file mode 100755 index 000000000..9879df4c3 --- /dev/null +++ b/apps/tinyauth/5.1.3/scripts/upgrade.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exit 0 diff --git a/apps/tinyauth/README.md b/apps/tinyauth/README.md new file mode 100644 index 000000000..cc750f262 --- /dev/null +++ b/apps/tinyauth/README.md @@ -0,0 +1,68 @@ +# Tinyauth + +## 产品介绍 + +Tinyauth 是一个轻量级身份认证与授权服务,可作为 Traefik、Nginx、Caddy 等反向代理的 Forward Auth 后端,也可独立提供本地用户登录、OAuth、LDAP 和 OpenID Connect 服务。 + +本应用使用 Tinyauth 官方镜像和本地 SQLite 数据库。安装时输入的管理员密码会通过上游自带命令生成 bcrypt 哈希,运行容器只读取持久化的哈希用户文件,不接收管理员明文密码。 + +## 主要功能 + +- 本地用户登录与基于 Cookie 的认证会话 +- 适配 Traefik、Nginx 和 Caddy 的 Forward Auth 端点 +- OAuth、LDAP 和 Tailscale 身份源集成 +- 作为 OpenID Connect 身份提供方服务其他应用 +- 按用户、组、IP、域名和路径配置访问控制 + +## 访问说明 + +- Web 界面:安装表单中填写的外部访问地址 +- 初始管理员:安装表单中的管理员用户名和随机密码 +- 使用 HTTP 时保持“安全 Cookie”为 `false`;通过 HTTPS 域名访问时应将其设置为 `true` +- 外部访问地址必须使用至少两级的域名,并与浏览器实际使用的协议、域名和端口一致;Tinyauth 不接受 IP 地址或裸 `localhost` + +登录后可直接使用 Tinyauth 的独立认证界面。若要保护其他应用,需要在反向代理中把认证请求转发到 Tinyauth,并按上游文档配置对应的 Forward Auth 端点和请求头。本包不会自动发现或修改其他 1Panel 应用。 + +## 安全边界 + +本包明确设置 `TINYAUTH_LABELPROVIDER=none`,不挂载 `/var/run/docker.sock`,也不启用 Docker 或 Kubernetes label provider。容器以 UID/GID `1000:1000` 运行,根文件系统只读,删除全部 Linux capabilities,并启用 `no-new-privileges`。 + +镜像依赖扫描会报告 Docker client 库中的三个 High 漏洞,但这些代码只由已禁用的 Docker label provider 调用;默认包没有 Docker socket、Docker API 地址或 provider 自动探测路径。请勿自行把 label provider 改为 `auto` 或 `docker`,也不要向容器添加 Docker socket。 + +固定版本从 `5.1.3` 开始,因为 `5.1.2` 及更早版本受 `GHSA-r27r-rr9v-vv37` 的 Forward Auth ACL 认证绕过影响。不要降级到 `5.1.2` 或更早版本。 + +## 数据与升级 + +`./data` 挂载到容器 `/data`,保存 bcrypt 用户文件、SQLite 数据库、OIDC 密钥和资源文件。卸载只移除容器和 Compose 资源,不删除该目录。升级前应备份整个 `./data` 目录,并确认外部访问地址和反向代理配置保持一致。 + +`latest` 使用上游 `v5` 移动标签;需要可重复部署时请选择固定版本 `5.1.3`。 + +## Introduction + +Tinyauth is a lightweight authentication and authorization server for reverse proxies and standalone applications. It supports local users, OAuth, LDAP, OpenID Connect, and Forward Auth integrations for Traefik, Nginx, and Caddy. + +This package uses the official image and a local SQLite database. The install script passes the administrator password to Tinyauth's own bcrypt generator over standard input and persists only the resulting user hash for the runtime container. + +## Features + +- Local users and cookie-based authentication sessions +- Forward Auth endpoints for Traefik, Nginx, and Caddy +- OAuth, LDAP, and Tailscale identity integrations +- OpenID Connect provider support for downstream applications +- User, group, IP, domain, and path-based access controls + +The package explicitly disables label discovery with `TINYAUTH_LABELPROVIDER=none` and does not mount the Docker socket. The container runs as UID/GID `1000:1000` with a read-only root filesystem, all Linux capabilities dropped, and `no-new-privileges` enabled. Do not enable the Docker provider or add a Docker socket mount. + +Set the external URL to the exact browser-facing protocol, domain, and port. Tinyauth rejects IP addresses and bare `localhost`; use a domain with at least two labels. Use secure cookies only with HTTPS. To protect another application, configure its reverse proxy to call the appropriate Tinyauth Forward Auth endpoint; this package intentionally does not discover or modify other 1Panel applications. + +Version `5.1.3` is the oldest version packaged here because it fixes the Forward Auth ACL authentication bypass in `GHSA-r27r-rr9v-vv37`. Do not downgrade to `5.1.2` or earlier. + +Persistent users, SQLite state, OIDC keys, and resources live under `./data`. Uninstall preserves this directory. Back up the entire directory before upgrades. + +## References + +- Website: +- Documentation: +- Source: +- Security advisory: +- Official image: diff --git a/apps/tinyauth/data.yml b/apps/tinyauth/data.yml new file mode 100644 index 000000000..7f032783d --- /dev/null +++ b/apps/tinyauth/data.yml @@ -0,0 +1,31 @@ +name: Tinyauth +tags: + - Security +title: 轻量级身份认证与授权服务 +description: 轻量级身份认证与授权服务 +additionalProperties: + key: tinyauth + name: Tinyauth + tags: + - Security + shortDescZh: 轻量级身份认证与授权服务 + shortDescEn: Lightweight authentication and authorization server + description: + en: A lightweight authentication and authorization server for reverse proxies and standalone applications + zh: 为反向代理和独立应用提供身份认证、OAuth、LDAP、OIDC 与访问控制 + zh-Hant: 為反向代理和獨立應用提供身份驗證、OAuth、LDAP、OIDC 與存取控制 + ja: リバースプロキシとスタンドアロンアプリ向けの軽量な認証・認可サーバー + ko: 리버스 프록시와 독립 실행형 앱을 위한 경량 인증 및 권한 부여 서버 + ru: Легковесный сервер аутентификации и авторизации для обратных прокси и автономных приложений + ms: Pelayan pengesahan dan kebenaran ringan untuk proksi songsang dan aplikasi kendiri + pt-br: Servidor leve de autenticacao e autorizacao para proxies reversos e aplicativos independentes + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://tinyauth.app/ + github: https://github.com/tinyauthapp/tinyauth + document: https://tinyauth.app/docs/getting-started/ + architectures: + - amd64 + - arm64 diff --git a/apps/tinyauth/latest/.env.sample b/apps/tinyauth/latest/.env.sample new file mode 100644 index 000000000..48d328944 --- /dev/null +++ b/apps/tinyauth/latest/.env.sample @@ -0,0 +1,6 @@ +CONTAINER_NAME=tinyauth +PANEL_APP_PORT_HTTP=3000 +TINYAUTH_APP_URL=http://tinyauth.localhost:3000 +TINYAUTH_ADMIN_USERNAME=admin +TINYAUTH_ADMIN_PASSWORD=Tinyauth_Admin_Change_Me_2026! +TINYAUTH_SECURE_COOKIE=false diff --git a/apps/tinyauth/latest/data.yml b/apps/tinyauth/latest/data.yml new file mode 100644 index 000000000..96949bffa --- /dev/null +++ b/apps/tinyauth/latest/data.yml @@ -0,0 +1,92 @@ +additionalProperties: + formFields: + - default: 3000 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: HTTP Port + labelZh: HTTP 端口 + label: + en: HTTP Port + zh: HTTP 端口 + zh-Hant: HTTP 連接埠 + ja: HTTP ポート + ko: HTTP 포트 + ru: Порт HTTP + ms: Port HTTP + pt-br: Porta HTTP + required: true + rule: paramPort + type: number + - default: http://tinyauth.localhost:3000 + edit: true + envKey: TINYAUTH_APP_URL + labelEn: External URL + labelZh: 外部访问地址 + label: + en: External URL + zh: 外部访问地址 + zh-Hant: 外部存取網址 + ja: 外部 URL + ko: 외부 URL + ru: Внешний URL + ms: URL Luaran + pt-br: URL externo + required: true + rule: paramExtUrl + type: text + - default: admin + edit: true + envKey: TINYAUTH_ADMIN_USERNAME + labelEn: Admin Username + labelZh: 管理员用户名 + label: + en: Admin Username + zh: 管理员用户名 + zh-Hant: 管理員使用者名稱 + ja: 管理者ユーザー名 + ko: 관리자 사용자 이름 + ru: Имя администратора + ms: Nama Pengguna Pentadbir + pt-br: Usuario administrador + required: true + rule: paramCommon + type: text + - default: "" + edit: true + envKey: TINYAUTH_ADMIN_PASSWORD + labelEn: Admin Password + labelZh: 管理员密码 + label: + en: Admin Password + zh: 管理员密码 + zh-Hant: 管理員密碼 + ja: 管理者パスワード + ko: 관리자 비밀번호 + ru: Пароль администратора + ms: Kata Laluan Pentadbir + pt-br: Senha do administrador + random: true + required: true + rule: paramComplexity + type: password + - default: "false" + edit: true + envKey: TINYAUTH_SECURE_COOKIE + labelEn: Secure Cookies + labelZh: 安全 Cookie + label: + en: Secure Cookies + zh: 安全 Cookie + zh-Hant: 安全 Cookie + ja: Secure Cookie + ko: 보안 Cookie + ru: Secure Cookie + ms: Cookie Selamat + pt-br: Cookie seguro + required: true + type: select + values: + - label: "false" + value: "false" + - label: "true" + value: "true" diff --git a/apps/tinyauth/latest/docker-compose.yml b/apps/tinyauth/latest/docker-compose.yml new file mode 100644 index 000000000..6a9953ca1 --- /dev/null +++ b/apps/tinyauth/latest/docker-compose.yml @@ -0,0 +1,42 @@ +services: + tinyauth: + image: "ghcr.io/tinyauthapp/tinyauth:v5" + container_name: ${CONTAINER_NAME} + restart: unless-stopped + user: "1000:1000" + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:3000" + environment: + - TINYAUTH_APPURL=${TINYAUTH_APP_URL} + - TINYAUTH_LABELPROVIDER=none + - TINYAUTH_AUTH_USERSFILE=/data/users + - TINYAUTH_AUTH_SECURECOOKIE=${TINYAUTH_SECURE_COOKIE} + - TINYAUTH_ANALYTICS_ENABLED=false + - TINYAUTH_SERVER_ADDRESS=0.0.0.0 + - TINYAUTH_SERVER_PORT=3000 + - TINYAUTH_DATABASE_DRIVER=sqlite + - TINYAUTH_DATABASE_PATH=/data/tinyauth.db + - TINYAUTH_RESOURCES_PATH=/data/resources + volumes: + - "./data:/data" + read_only: true + tmpfs: + - /tmp:nodev,noexec,nosuid,size=32M + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + healthcheck: + test: ["CMD", "tinyauth", "healthcheck"] + interval: 30s + timeout: 5s + start_period: 10s + retries: 5 + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/tinyauth/latest/scripts/init.sh b/apps/tinyauth/latest/scripts/init.sh new file mode 100755 index 000000000..89b2ec7e8 --- /dev/null +++ b/apps/tinyauth/latest/scripts/init.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}" +DOCKER_BIN="${DOCKER_BIN:-docker}" +IMAGE='ghcr.io/tinyauthapp/tinyauth:v5' + +fail() { + printf '%s\n' "$1" >&2 + exit 1 +} + +read_env_value() { + local key="$1" + 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" +} + +[[ -f "$ENV_FILE" && ! -L "$ENV_FILE" ]] || fail "$ENV_FILE must be a regular file" +command -v "$DOCKER_BIN" >/dev/null 2>&1 || fail 'Docker is required to generate the Tinyauth password hash' + +username="${TINYAUTH_ADMIN_USERNAME:-$(read_env_value TINYAUTH_ADMIN_USERNAME)}" +password="${TINYAUTH_ADMIN_PASSWORD:-$(read_env_value TINYAUTH_ADMIN_PASSWORD)}" +app_url="${TINYAUTH_APP_URL:-$(read_env_value TINYAUTH_APP_URL)}" +secure_cookie="${TINYAUTH_SECURE_COOKIE:-$(read_env_value TINYAUTH_SECURE_COOKIE)}" + +data_dir="$(realpath -m -- "$ROOT_DIR/data")" +case "$data_dir" in + "$ROOT_DIR"/*) ;; + *) fail 'Tinyauth data directory must remain inside the application version directory' ;; +esac +for path in "$data_dir" "$data_dir/resources" "$data_dir/oidc"; do + [[ ! -L "$path" ]] || fail "$path must not be a symbolic link" + [[ ! -e "$path" || -d "$path" ]] || fail "$path must be a directory" +done +users_file="$data_dir/users" +[[ ! -L "$users_file" ]] || fail 'Tinyauth users file must not be a symbolic link' +[[ ! -e "$users_file" || -f "$users_file" ]] || fail 'Tinyauth users path must be a regular file' + +[[ "$username" =~ ^[A-Za-z0-9._-]{1,64}$ ]] || fail 'TINYAUTH_ADMIN_USERNAME must contain only letters, digits, dot, underscore, or hyphen' +[[ ${#password} -ge 12 && ${#password} -le 256 ]] || fail 'TINYAUTH_ADMIN_PASSWORD must contain 12 to 256 characters' +[[ "$password" != *$'\n'* && "$password" != *$'\r'* ]] || fail 'TINYAUTH_ADMIN_PASSWORD must not contain line breaks' +[[ "$app_url" =~ ^https?://[^[:space:]]+$ ]] || fail 'TINYAUTH_APP_URL must be an absolute HTTP or HTTPS URL without whitespace' +app_host="${app_url#*://}" +app_host="${app_host%%/*}" +app_host="${app_host%%:*}" +[[ "$app_host" == *.* && "$app_host" =~ ^[A-Za-z0-9][A-Za-z0-9.-]*[A-Za-z0-9]$ ]] || fail 'TINYAUTH_APP_URL must use a domain name with at least two labels' +[[ ! "$app_host" =~ ^[0-9.]+$ ]] || fail 'TINYAUTH_APP_URL must not use an IP address' +[[ "$secure_cookie" == false || "$secure_cookie" == true ]] || fail 'TINYAUTH_SECURE_COOKIE must be true or false' + +install -d -m 0750 -o 1000 -g 1000 -- "$data_dir" "$data_dir/resources" "$data_dir/oidc" + +# Variables in this command are expanded by the shell inside the generator container. +# shellcheck disable=SC2016 +generator_command='IFS= read -r password; exec tinyauth user create --username "$1" --password "$password"' +generator_output="$( + printf '%s\n' "$password" | + "$DOCKER_BIN" run --rm -i --network none --read-only --user 1000:1000 \ + --cap-drop ALL --security-opt no-new-privileges --env NO_COLOR=1 \ + --entrypoint /bin/sh "$IMAGE" -ec \ + "$generator_command" \ + sh "$username" +)" +user_entry="$(printf '%s\n' "$generator_output" | sed -n 's/^TINYAUTH_AUTH_USERS=//p' | head -n 1)" +[[ "$user_entry" =~ ^[A-Za-z0-9._-]{1,64}:\$2[aby]\$[0-9]{2}\$[./A-Za-z0-9]{53}$ ]] || fail 'Failed to generate a valid bcrypt user entry' + +umask 077 +temporary="$(mktemp "$data_dir/.users.tmp.XXXXXX")" +trap 'rm -f -- "${temporary:-}"' EXIT +printf '%s\n' "$user_entry" >"$temporary" +chmod 0600 "$temporary" +chown 1000:1000 "$temporary" +mv -f -- "$temporary" "$users_file" +trap - EXIT + +chown 1000:1000 "$data_dir" "$data_dir/resources" "$data_dir/oidc" "$users_file" +chmod 0750 "$data_dir" "$data_dir/resources" "$data_dir/oidc" +chmod 0600 "$users_file" diff --git a/apps/tinyauth/latest/scripts/uninstall.sh b/apps/tinyauth/latest/scripts/uninstall.sh new file mode 100755 index 000000000..5a3f6bd6b --- /dev/null +++ b/apps/tinyauth/latest/scripts/uninstall.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +if command -v docker-compose >/dev/null 2>&1; then + docker-compose down --volumes --remove-orphans +else + docker compose down --volumes --remove-orphans +fi diff --git a/apps/tinyauth/latest/scripts/upgrade.sh b/apps/tinyauth/latest/scripts/upgrade.sh new file mode 100755 index 000000000..9879df4c3 --- /dev/null +++ b/apps/tinyauth/latest/scripts/upgrade.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exit 0 diff --git a/apps/tinyauth/logo.png b/apps/tinyauth/logo.png new file mode 100644 index 000000000..bb4c431cd Binary files /dev/null and b/apps/tinyauth/logo.png differ