From 51edee71ded597c297d01e54c35c18cbcd483237 Mon Sep 17 00:00:00 2001 From: okxlin <61420215+okxlin@users.noreply.github.com> Date: Sat, 19 Sep 2026 11:26:00 +0800 Subject: [PATCH] Update whodb app Rebuilt-from-PR: #7025 Source-PR: https://github.com/okxlin/appstore/pull/7025 Maintainer-workflow: appstore-pr-maintainer --- apps/whodb/0.127.0/data.yml | 88 ---------- apps/whodb/0.127.0/db-data/.gitkeep | 0 apps/whodb/0.127.0/docker-compose.yml | 22 --- apps/whodb/{0.127.0 => 0.129.0}/.env.sample | 2 +- apps/whodb/0.129.0/data.yml | 128 ++++++++++++++ apps/whodb/{0.127.0 => 0.129.0}/data/.gitkeep | 0 .../{latest => 0.129.0}/docker-compose.yml | 2 +- .../{0.127.0 => 0.129.0}/scripts/init.sh | 68 ++++---- .../{0.127.0 => 0.129.0}/scripts/uninstall.sh | 0 .../{0.127.0 => 0.129.0}/scripts/upgrade.sh | 0 apps/whodb/README_en.md | 35 ++++ apps/whodb/data.yml | 6 +- apps/whodb/latest/.env.sample | 6 - apps/whodb/latest/data.yml | 88 ---------- apps/whodb/latest/data/.gitkeep | 0 apps/whodb/latest/db-data/.gitkeep | 0 apps/whodb/latest/scripts/init.sh | 165 ------------------ apps/whodb/latest/scripts/uninstall.sh | 2 - apps/whodb/latest/scripts/upgrade.sh | 5 - apps/whodb/logo.png | Bin 3673 -> 3634 bytes 20 files changed, 208 insertions(+), 409 deletions(-) delete mode 100644 apps/whodb/0.127.0/data.yml delete mode 100644 apps/whodb/0.127.0/db-data/.gitkeep delete mode 100644 apps/whodb/0.127.0/docker-compose.yml rename apps/whodb/{0.127.0 => 0.129.0}/.env.sample (76%) create mode 100644 apps/whodb/0.129.0/data.yml rename apps/whodb/{0.127.0 => 0.129.0}/data/.gitkeep (100%) rename apps/whodb/{latest => 0.129.0}/docker-compose.yml (93%) rename apps/whodb/{0.127.0 => 0.129.0}/scripts/init.sh (76%) rename apps/whodb/{0.127.0 => 0.129.0}/scripts/uninstall.sh (100%) rename apps/whodb/{0.127.0 => 0.129.0}/scripts/upgrade.sh (100%) create mode 100644 apps/whodb/README_en.md delete mode 100644 apps/whodb/latest/.env.sample delete mode 100644 apps/whodb/latest/data.yml delete mode 100644 apps/whodb/latest/data/.gitkeep delete mode 100644 apps/whodb/latest/db-data/.gitkeep delete mode 100755 apps/whodb/latest/scripts/init.sh delete mode 100755 apps/whodb/latest/scripts/uninstall.sh delete mode 100755 apps/whodb/latest/scripts/upgrade.sh diff --git a/apps/whodb/0.127.0/data.yml b/apps/whodb/0.127.0/data.yml deleted file mode 100644 index acb80a61d..000000000 --- a/apps/whodb/0.127.0/data.yml +++ /dev/null @@ -1,88 +0,0 @@ -additionalProperties: - formFields: - - default: 8080 - 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: ./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: Diretorio de dados - required: true - type: text - - default: ./db-data - edit: true - envKey: DB_DATA_DIR - labelEn: Local Database Directory - labelZh: 本地数据库目录 - label: - en: Local Database Directory - zh: 本地数据库目录 - zh-Hant: 本機資料庫目錄 - ja: ローカルデータベースディレクトリ - ko: 로컬 데이터베이스 디렉터리 - ru: Каталог локальных баз данных - ms: Direktori pangkalan data setempat - pt-br: Diretorio de bancos de dados locais - required: true - type: text - - default: generate - edit: true - envKey: WHODB_ENCRYPTION_KEY - labelEn: Session Encryption Key - labelZh: 会话加密密钥 - label: - en: Session Encryption Key - zh: 会话加密密钥 - zh-Hant: 工作階段加密金鑰 - ja: セッション暗号化キー - ko: 세션 암호화 키 - ru: Ключ шифрования сеансов - ms: Kunci penyulitan sesi - pt-br: Chave de criptografia da sessao - required: true - type: password - - default: "false" - edit: true - envKey: WHODB_SECURE - labelEn: HTTPS Secure Cookie - labelZh: HTTPS 安全 Cookie - label: - en: HTTPS Secure Cookie - zh: HTTPS 安全 Cookie - zh-Hant: HTTPS 安全 Cookie - ja: HTTPS セキュア Cookie - ko: HTTPS 보안 쿠키 - ru: Защищенные Cookie для HTTPS - ms: Cookie selamat HTTPS - pt-br: Cookie seguro HTTPS - required: true - type: select - values: - - label: "false" - value: "false" - - label: "true" - value: "true" diff --git a/apps/whodb/0.127.0/db-data/.gitkeep b/apps/whodb/0.127.0/db-data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/whodb/0.127.0/docker-compose.yml b/apps/whodb/0.127.0/docker-compose.yml deleted file mode 100644 index 8c9300576..000000000 --- a/apps/whodb/0.127.0/docker-compose.yml +++ /dev/null @@ -1,22 +0,0 @@ -services: - whodb: - image: clidey/whodb:0.127.0 - container_name: ${CONTAINER_NAME} - restart: always - networks: - - 1panel-network - ports: - - "${PANEL_APP_PORT_HTTP}:8080" - environment: - - WHODB_ENCRYPTION_KEY=${WHODB_ENCRYPTION_KEY} - - WHODB_SECURE=${WHODB_SECURE} - - WHODB_DATA_DIR=/data - volumes: - - "${APP_DATA_DIR}:/data" - - "${DB_DATA_DIR}:/db" - labels: - createdBy: "Apps" - -networks: - 1panel-network: - external: true diff --git a/apps/whodb/0.127.0/.env.sample b/apps/whodb/0.129.0/.env.sample similarity index 76% rename from apps/whodb/0.127.0/.env.sample rename to apps/whodb/0.129.0/.env.sample index e2cbd2b46..c79500421 100644 --- a/apps/whodb/0.127.0/.env.sample +++ b/apps/whodb/0.129.0/.env.sample @@ -1,6 +1,6 @@ +CONTAINER_NAME=whodb-compose-check PANEL_APP_PORT_HTTP=8080 APP_DATA_DIR=./data DB_DATA_DIR=./db-data WHODB_ENCRYPTION_KEY=generate WHODB_SECURE=false -CONTAINER_NAME=whodb diff --git a/apps/whodb/0.129.0/data.yml b/apps/whodb/0.129.0/data.yml new file mode 100644 index 000000000..51f8f6ff6 --- /dev/null +++ b/apps/whodb/0.129.0/data.yml @@ -0,0 +1,128 @@ +additionalProperties: + formFields: + - default: 8080 + 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 + tr: HTTP Bağlantı Noktası + es-es: Puerto HTTP + fa: درگاه HTTP + lo: ພອດ HTTP + required: true + rule: paramPort + type: number + - 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: Diretorio de dados + tr: Veri Dizini + es-es: Directorio de datos + fa: فهرست داده‌ها + lo: ໂຟນເດີຂໍ້ມູນ + required: true + type: text + - default: ./db-data + edit: true + envKey: DB_DATA_DIR + labelEn: Local Database Directory + labelZh: 本地数据库目录 + label: + en: Local Database Directory + zh: 本地数据库目录 + zh-hant: 本機資料庫目錄 + ja: ローカルデータベースディレクトリ + ko: 로컬 데이터베이스 디렉터리 + ru: Каталог локальных баз данных + ms: Direktori pangkalan data setempat + pt-br: Diretorio de bancos de dados locais + tr: Yerel Veritabanı Dizini + es-es: Directorio de base de datos local + fa: فهرست پایگاه داده محلی + lo: ໂຟນເດີຖານຂໍ້ມູນທ້ອງຖິ່ນ + required: true + type: text + - default: generate + edit: true + envKey: WHODB_ENCRYPTION_KEY + labelEn: Session Encryption Key + labelZh: 会话加密密钥 + label: + en: Session Encryption Key + zh: 会话加密密钥 + zh-hant: 工作階段加密金鑰 + ja: セッション暗号化キー + ko: 세션 암호화 키 + ru: Ключ шифрования сеансов + ms: Kunci penyulitan sesi + pt-br: Chave de criptografia da sessao + tr: Oturum Şifreleme Anahtarı + es-es: Clave de cifrado de sesión + fa: کلید رمزنگاری نشست + lo: ຄີເຂົ້າລະຫັດເຊດຊັນ + required: true + type: password + - default: 'false' + edit: true + envKey: WHODB_SECURE + labelEn: HTTPS Secure Cookie + labelZh: HTTPS 安全 Cookie + label: + en: HTTPS Secure Cookie + zh: HTTPS 安全 Cookie + zh-hant: HTTPS 安全 Cookie + ja: HTTPS セキュア Cookie + ko: HTTPS 보안 쿠키 + ru: Защищенные Cookie для HTTPS + ms: Cookie selamat HTTPS + pt-br: Cookie seguro HTTPS + tr: HTTPS Güvenli Çerezi + es-es: Cookie segura HTTPS + fa: کوکی امن HTTPS + lo: ຄຸກກີປອດໄພ HTTPS + required: true + type: select + values: + - label: 'false' + value: 'false' + - label: 'true' + value: 'true' + - 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 + tr: Saat Dilimi + es-es: Zona horaria + fa: منطقه زمانی + lo: ເຂດເວລາ + required: true + type: text diff --git a/apps/whodb/0.127.0/data/.gitkeep b/apps/whodb/0.129.0/data/.gitkeep similarity index 100% rename from apps/whodb/0.127.0/data/.gitkeep rename to apps/whodb/0.129.0/data/.gitkeep diff --git a/apps/whodb/latest/docker-compose.yml b/apps/whodb/0.129.0/docker-compose.yml similarity index 93% rename from apps/whodb/latest/docker-compose.yml rename to apps/whodb/0.129.0/docker-compose.yml index 5ad5196d9..f9f74639d 100644 --- a/apps/whodb/latest/docker-compose.yml +++ b/apps/whodb/0.129.0/docker-compose.yml @@ -1,6 +1,6 @@ services: whodb: - image: clidey/whodb:latest + image: "clidey/whodb:0.129.0" container_name: ${CONTAINER_NAME} restart: always networks: diff --git a/apps/whodb/0.127.0/scripts/init.sh b/apps/whodb/0.129.0/scripts/init.sh similarity index 76% rename from apps/whodb/0.127.0/scripts/init.sh rename to apps/whodb/0.129.0/scripts/init.sh index 5888bf7bc..c741a165a 100755 --- a/apps/whodb/0.127.0/scripts/init.sh +++ b/apps/whodb/0.129.0/scripts/init.sh @@ -62,6 +62,40 @@ set_env_value() { mv -f -- "$temp_file" "$ENV_FILE" } +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" +} + generate_key() { local value="" if command -v openssl >/dev/null 2>&1; then @@ -89,20 +123,7 @@ write_key_cache() { data_dir_raw="$(read_effective_value APP_DATA_DIR)" [[ -n "$data_dir_raw" ]] || data_dir_raw="./data" -case "$data_dir_raw" in - *$'\n'* | *$'\r'* | *\\* | *'$'* | *'#'* | *'"'* | *"'") fail "APP_DATA_DIR contains unsupported dotenv characters" ;; -esac - -case "$data_dir_raw" in - /*) data_dir_abs="$(realpath -m -- "$data_dir_raw")" ;; - *) - data_dir_abs="$(realpath -m -- "${ROOT_DIR}/${data_dir_raw#./}")" - case "$data_dir_abs" in - "${ROOT_DIR}" | "${ROOT_DIR}"/*) ;; - *) fail "Relative APP_DATA_DIR must stay inside the application directory" ;; - esac - ;; -esac +data_dir_abs="$(resolve_app_path "APP_DATA_DIR" "$data_dir_raw")" [[ "$data_dir_abs" != "/" ]] || fail "APP_DATA_DIR must not be the filesystem root" if [[ -e "$data_dir_abs" && ! -d "$data_dir_abs" ]]; then @@ -112,20 +133,7 @@ mkdir -p -- "$data_dir_abs" db_data_dir_raw="$(read_effective_value DB_DATA_DIR)" [[ -n "$db_data_dir_raw" ]] || db_data_dir_raw="./db-data" -case "$db_data_dir_raw" in - *$'\n'* | *$'\r'* | *\\* | *'$'* | *'#'* | *'"'* | *"'") fail "DB_DATA_DIR contains unsupported dotenv characters" ;; -esac - -case "$db_data_dir_raw" in - /*) db_data_dir_abs="$(realpath -m -- "$db_data_dir_raw")" ;; - *) - db_data_dir_abs="$(realpath -m -- "${ROOT_DIR}/${db_data_dir_raw#./}")" - case "$db_data_dir_abs" in - "${ROOT_DIR}" | "${ROOT_DIR}"/*) ;; - *) fail "Relative DB_DATA_DIR must stay inside the application directory" ;; - esac - ;; -esac +db_data_dir_abs="$(resolve_app_path "DB_DATA_DIR" "$db_data_dir_raw")" [[ "$db_data_dir_abs" != "/" ]] || fail "DB_DATA_DIR must not be the filesystem root" [[ "$db_data_dir_abs" != "$data_dir_abs" ]] || fail "DB_DATA_DIR must differ from APP_DATA_DIR" @@ -159,7 +167,7 @@ secure_cookie="$(read_effective_value WHODB_SECURE)" [[ "$secure_cookie" == "true" || "$secure_cookie" == "false" ]] || fail "WHODB_SECURE must be true or false" write_key_cache "$cache_file" "$encryption_key" -set_env_value APP_DATA_DIR "$data_dir_raw" -set_env_value DB_DATA_DIR "$db_data_dir_raw" +set_env_value APP_DATA_DIR "$data_dir_abs" +set_env_value DB_DATA_DIR "$db_data_dir_abs" set_env_value WHODB_ENCRYPTION_KEY "$encryption_key" set_env_value WHODB_SECURE "$secure_cookie" diff --git a/apps/whodb/0.127.0/scripts/uninstall.sh b/apps/whodb/0.129.0/scripts/uninstall.sh similarity index 100% rename from apps/whodb/0.127.0/scripts/uninstall.sh rename to apps/whodb/0.129.0/scripts/uninstall.sh diff --git a/apps/whodb/0.127.0/scripts/upgrade.sh b/apps/whodb/0.129.0/scripts/upgrade.sh similarity index 100% rename from apps/whodb/0.127.0/scripts/upgrade.sh rename to apps/whodb/0.129.0/scripts/upgrade.sh diff --git a/apps/whodb/README_en.md b/apps/whodb/README_en.md new file mode 100644 index 000000000..9170b7be2 --- /dev/null +++ b/apps/whodb/README_en.md @@ -0,0 +1,35 @@ +# WhoDB + +## Introduction + +WhoDB is a lightweight browser workspace for exploring, querying, and editing multiple database systems. + +## Features + +- Browse schemas and edit data across multiple database engines. +- Run queries, inspect relationships, and import or export data. +- Optionally connect local or hosted AI providers. +- Persist encrypted database login sessions. +- Persist and connect local SQLite or DuckDB files through a separate directory. + +## Access and configuration + +After installation, open `http://:8080`; the actual published port is the value of `PANEL_APP_PORT_HTTP` in the installation form. + +- `APP_DATA_DIR` is mounted at `/data` for encrypted sessions and the key cache. +- `DB_DATA_DIR` is mounted at `/db` for local SQLite and DuckDB files. Enter a path relative to `/db`, such as `example.db`, in WhoDB. +- Leave `WHODB_ENCRYPTION_KEY` as `generate` to create and persist a 64-character hexadecimal key. Do not replace the key while existing sessions are in use. +- Set `WHODB_SECURE` to `true` when WhoDB is behind an HTTPS reverse proxy. + +## Security and data handling + +WhoDB stores database credentials in encrypted browser sessions. Protect the application `.env`, `APP_DATA_DIR`, `DB_DATA_DIR`, and backups. The Community image does not provide a separate global access login, so do not expose the port to an untrusted network; use a VPN, IP allowlist, or an authenticated 1Panel reverse proxy. Optional AI providers may receive user requests and database context, so review the selected provider's data and credential policy. + +Back up both persistent directories before upgrades, migrations, or uninstalling. + +## References + +- Website: +- Source: +- Documentation: +- Docker persistence: diff --git a/apps/whodb/data.yml b/apps/whodb/data.yml index 8d82e0775..38cfedc74 100644 --- a/apps/whodb/data.yml +++ b/apps/whodb/data.yml @@ -13,12 +13,16 @@ additionalProperties: description: en: A lightweight workspace for multiple databases zh: 轻量级多数据库管理工作台 - zh-Hant: 輕量級多資料庫管理工作台 + zh-hant: 輕量級多資料庫管理工作台 ja: 複数データベース向けの軽量管理ワークスペース ko: 여러 데이터베이스를 위한 가벼운 관리 작업 공간 ru: Легковесная рабочая среда для управления разными базами данных ms: Ruang kerja ringan untuk mengurus pelbagai pangkalan data pt-br: Espaco de trabalho leve para gerenciar varios bancos de dados + tr: Birden fazla veritabanı için hafif bir çalışma alanı + es-es: Espacio de trabajo ligero para múltiples bases de datos + fa: محیط کاری سبک برای چندین پایگاه داده + lo: ພື້ນທີ່ເຮັດວຽກຂະໜາດເບົາສຳລັບຫຼາຍຖານຂໍ້ມູນ type: tool crossVersionUpdate: true limit: 1 diff --git a/apps/whodb/latest/.env.sample b/apps/whodb/latest/.env.sample deleted file mode 100644 index e2cbd2b46..000000000 --- a/apps/whodb/latest/.env.sample +++ /dev/null @@ -1,6 +0,0 @@ -PANEL_APP_PORT_HTTP=8080 -APP_DATA_DIR=./data -DB_DATA_DIR=./db-data -WHODB_ENCRYPTION_KEY=generate -WHODB_SECURE=false -CONTAINER_NAME=whodb diff --git a/apps/whodb/latest/data.yml b/apps/whodb/latest/data.yml deleted file mode 100644 index acb80a61d..000000000 --- a/apps/whodb/latest/data.yml +++ /dev/null @@ -1,88 +0,0 @@ -additionalProperties: - formFields: - - default: 8080 - 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: ./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: Diretorio de dados - required: true - type: text - - default: ./db-data - edit: true - envKey: DB_DATA_DIR - labelEn: Local Database Directory - labelZh: 本地数据库目录 - label: - en: Local Database Directory - zh: 本地数据库目录 - zh-Hant: 本機資料庫目錄 - ja: ローカルデータベースディレクトリ - ko: 로컬 데이터베이스 디렉터리 - ru: Каталог локальных баз данных - ms: Direktori pangkalan data setempat - pt-br: Diretorio de bancos de dados locais - required: true - type: text - - default: generate - edit: true - envKey: WHODB_ENCRYPTION_KEY - labelEn: Session Encryption Key - labelZh: 会话加密密钥 - label: - en: Session Encryption Key - zh: 会话加密密钥 - zh-Hant: 工作階段加密金鑰 - ja: セッション暗号化キー - ko: 세션 암호화 키 - ru: Ключ шифрования сеансов - ms: Kunci penyulitan sesi - pt-br: Chave de criptografia da sessao - required: true - type: password - - default: "false" - edit: true - envKey: WHODB_SECURE - labelEn: HTTPS Secure Cookie - labelZh: HTTPS 安全 Cookie - label: - en: HTTPS Secure Cookie - zh: HTTPS 安全 Cookie - zh-Hant: HTTPS 安全 Cookie - ja: HTTPS セキュア Cookie - ko: HTTPS 보안 쿠키 - ru: Защищенные Cookie для HTTPS - ms: Cookie selamat HTTPS - pt-br: Cookie seguro HTTPS - required: true - type: select - values: - - label: "false" - value: "false" - - label: "true" - value: "true" diff --git a/apps/whodb/latest/data/.gitkeep b/apps/whodb/latest/data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/whodb/latest/db-data/.gitkeep b/apps/whodb/latest/db-data/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/whodb/latest/scripts/init.sh b/apps/whodb/latest/scripts/init.sh deleted file mode 100755 index 5888bf7bc..000000000 --- a/apps/whodb/latest/scripts/init.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" -ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}" - -fail() { - printf '%s\n' "$1" >&2 - exit 1 -} - -strip_matching_quotes() { - local value="$1" - if [[ ${#value} -ge 2 ]]; then - if [[ "${value:0:1}" == '"' && "${value: -1}" == '"' ]]; then - value="${value:1:${#value}-2}" - elif [[ "${value:0:1}" == "'" && "${value: -1}" == "'" ]]; then - value="${value:1:${#value}-2}" - fi - fi - printf '%s\n' "$value" -} - -read_env_value() { - local key="$1" - local value="" - if [[ -f "$ENV_FILE" ]]; then - value="$(grep -E "^${key}=" "$ENV_FILE" | tail -n 1 | cut -d '=' -f 2- || true)" - fi - strip_matching_quotes "$value" -} - -read_effective_value() { - local key="$1" - if [[ -v "$key" ]]; then - strip_matching_quotes "${!key}" - else - read_env_value "$key" - fi -} - -set_env_value() { - local key="$1" - local value="$2" - local temp_file - temp_file="$(mktemp "${ROOT_DIR}/.whodb-env.tmp.XXXXXX")" - awk -v key="$key" -v value="$value" ' - BEGIN { written = 0 } - $0 ~ "^" key "=" { - if (!written) { - print key "=" value - written = 1 - } - next - } - { print } - END { - if (!written) print key "=" value - } - ' "$ENV_FILE" > "$temp_file" - chmod --reference="$ENV_FILE" "$temp_file" - mv -f -- "$temp_file" "$ENV_FILE" -} - -generate_key() { - local value="" - if command -v openssl >/dev/null 2>&1; then - value="$(openssl rand -hex 32)" - elif [[ -r /dev/urandom ]] && command -v od >/dev/null 2>&1; then - value="$(od -An -N32 -tx1 /dev/urandom | tr -d ' \n')" - fi - [[ "$value" =~ ^[0-9a-f]{64}$ ]] || fail "Unable to generate a secure WhoDB encryption key" - printf '%s\n' "$value" -} - -write_key_cache() { - local cache_file="$1" - local value="$2" - local temp_file - umask 077 - temp_file="$(mktemp "${cache_file}.tmp.XXXXXX")" - printf '%s\n' "$value" > "$temp_file" - chmod 600 "$temp_file" - mv -f -- "$temp_file" "$cache_file" -} - -[[ -f "$ENV_FILE" ]] || fail "$ENV_FILE not found" -[[ ! -L "$ENV_FILE" ]] || fail "$ENV_FILE must not be a symbolic link" - -data_dir_raw="$(read_effective_value APP_DATA_DIR)" -[[ -n "$data_dir_raw" ]] || data_dir_raw="./data" -case "$data_dir_raw" in - *$'\n'* | *$'\r'* | *\\* | *'$'* | *'#'* | *'"'* | *"'") fail "APP_DATA_DIR contains unsupported dotenv characters" ;; -esac - -case "$data_dir_raw" in - /*) data_dir_abs="$(realpath -m -- "$data_dir_raw")" ;; - *) - data_dir_abs="$(realpath -m -- "${ROOT_DIR}/${data_dir_raw#./}")" - case "$data_dir_abs" in - "${ROOT_DIR}" | "${ROOT_DIR}"/*) ;; - *) fail "Relative APP_DATA_DIR must stay inside the application directory" ;; - esac - ;; -esac - -[[ "$data_dir_abs" != "/" ]] || fail "APP_DATA_DIR must not be the filesystem root" -if [[ -e "$data_dir_abs" && ! -d "$data_dir_abs" ]]; then - fail "APP_DATA_DIR must be a directory" -fi -mkdir -p -- "$data_dir_abs" - -db_data_dir_raw="$(read_effective_value DB_DATA_DIR)" -[[ -n "$db_data_dir_raw" ]] || db_data_dir_raw="./db-data" -case "$db_data_dir_raw" in - *$'\n'* | *$'\r'* | *\\* | *'$'* | *'#'* | *'"'* | *"'") fail "DB_DATA_DIR contains unsupported dotenv characters" ;; -esac - -case "$db_data_dir_raw" in - /*) db_data_dir_abs="$(realpath -m -- "$db_data_dir_raw")" ;; - *) - db_data_dir_abs="$(realpath -m -- "${ROOT_DIR}/${db_data_dir_raw#./}")" - case "$db_data_dir_abs" in - "${ROOT_DIR}" | "${ROOT_DIR}"/*) ;; - *) fail "Relative DB_DATA_DIR must stay inside the application directory" ;; - esac - ;; -esac - -[[ "$db_data_dir_abs" != "/" ]] || fail "DB_DATA_DIR must not be the filesystem root" -[[ "$db_data_dir_abs" != "$data_dir_abs" ]] || fail "DB_DATA_DIR must differ from APP_DATA_DIR" -if [[ -e "$db_data_dir_abs" && ! -d "$db_data_dir_abs" ]]; then - fail "DB_DATA_DIR must be a directory" -fi -mkdir -p -- "$db_data_dir_abs" - -cache_file="${data_dir_abs}/.whodb_encryption_key" -[[ ! -L "$cache_file" ]] || fail "WhoDB encryption key cache must not be a symbolic link" -if [[ -e "$cache_file" && ! -f "$cache_file" ]]; then - fail "WhoDB encryption key cache must be a regular file" -fi - -cached_key="" -if [[ -s "$cache_file" ]]; then - cached_key="$(sed -n '1p' "$cache_file")" - [[ "$cached_key" =~ ^[0-9a-f]{64}$ ]] || fail "Persisted WhoDB encryption key is invalid" -fi - -requested_key="$(read_effective_value WHODB_ENCRYPTION_KEY)" -if [[ -z "$requested_key" || "$requested_key" == "generate" ]]; then - encryption_key="${cached_key:-$(generate_key)}" -else - [[ "$requested_key" =~ ^[0-9a-fA-F]{64}$ ]] || fail "WHODB_ENCRYPTION_KEY must be generate or exactly 64 hexadecimal characters" - encryption_key="${requested_key,,}" -fi - -secure_cookie="$(read_effective_value WHODB_SECURE)" -[[ -n "$secure_cookie" ]] || secure_cookie=false -[[ "$secure_cookie" == "true" || "$secure_cookie" == "false" ]] || fail "WHODB_SECURE must be true or false" - -write_key_cache "$cache_file" "$encryption_key" -set_env_value APP_DATA_DIR "$data_dir_raw" -set_env_value DB_DATA_DIR "$db_data_dir_raw" -set_env_value WHODB_ENCRYPTION_KEY "$encryption_key" -set_env_value WHODB_SECURE "$secure_cookie" diff --git a/apps/whodb/latest/scripts/uninstall.sh b/apps/whodb/latest/scripts/uninstall.sh deleted file mode 100755 index ab8a8d674..000000000 --- a/apps/whodb/latest/scripts/uninstall.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -docker-compose down --volumes diff --git a/apps/whodb/latest/scripts/upgrade.sh b/apps/whodb/latest/scripts/upgrade.sh deleted file mode 100755 index e73ce2436..000000000 --- a/apps/whodb/latest/scripts/upgrade.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" -exec "${SCRIPT_DIR}/init.sh" diff --git a/apps/whodb/logo.png b/apps/whodb/logo.png index fb247bc6242078cb26c803bf6def2302aeeffa32..074d5dc70c0ee91ca7bd10117dd26b193139c097 100644 GIT binary patch delta 3190 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 c>;Fvu26>R+FP2V!urlwe& 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