diff --git a/apps/chatwoot/data.yml b/apps/chatwoot/data.yml index 5791796f5..ccba9b248 100644 --- a/apps/chatwoot/data.yml +++ b/apps/chatwoot/data.yml @@ -1,30 +1,34 @@ name: Chatwoot tags: - - CRM +- CRM title: 开源全渠道客户支持平台 description: 开源全渠道客户支持平台 additionalProperties: key: chatwoot name: Chatwoot tags: - - CRM + - CRM + type: website + website: https://www.chatwoot.com/ + document: https://developers.chatwoot.com/self-hosted/deployment/docker + github: https://github.com/chatwoot/chatwoot shortDescZh: 开源全渠道客户支持平台 shortDescEn: Open source omnichannel customer support platform + crossVersionUpdate: false + limit: 0 + architectures: + - amd64 + - arm64 description: - en: An open source omnichannel customer support platform for live chat, email, inboxes and helpdesk workflows. + en: An open source omnichannel customer support platform for live chat, email, + inboxes and helpdesk workflows. zh: 面向在线客服、邮件、收件箱和工单流程的开源全渠道客户支持平台。 zh-Hant: 面向線上客服、郵件、收件匣和工單流程的開源全通路客戶支援平台。 ja: ライブチャット、メール、受信トレイ、ヘルプデスク業務向けのオープンソース全チャネル顧客サポート平台です。 ko: 라이브 채팅, 이메일, 받은 편지함 및 헬프데스크 워크플로를 위한 오픈소스 옴니채널 고객 지원 플랫폼입니다. - ru: Открытая омниканальная платформа поддержки клиентов для онлайн-чата, почты, входящих обращений и helpdesk-процессов. - ms: Platform sokongan pelanggan omnichannel sumber terbuka untuk sembang langsung, e-mel, peti masuk dan aliran kerja meja bantuan. - pt-br: Plataforma omnichannel open source de suporte ao cliente para chat ao vivo, email, caixas de entrada e fluxos de helpdesk. - type: website - crossVersionUpdate: false - limit: 0 - website: https://www.chatwoot.com/ - github: https://github.com/chatwoot/chatwoot - document: https://developers.chatwoot.com/self-hosted/deployment/docker - architectures: - - amd64 - - arm64 + ru: Открытая омниканальная платформа поддержки клиентов для онлайн-чата, почты, + входящих обращений и helpdesk-процессов. + ms: Platform sokongan pelanggan omnichannel sumber terbuka untuk sembang langsung, + e-mel, peti masuk dan aliran kerja meja bantuan. + pt-br: Plataforma omnichannel open source de suporte ao cliente para chat ao vivo, + email, caixas de entrada e fluxos de helpdesk. diff --git a/apps/chatwoot/latest/.env.sample b/apps/chatwoot/latest/.env.sample index e65203fd7..2989ba565 100644 --- a/apps/chatwoot/latest/.env.sample +++ b/apps/chatwoot/latest/.env.sample @@ -1,3 +1,4 @@ +CONTAINER_NAME=chatwoot-compose-check PANEL_APP_PORT_HTTP=18086 TZ=Asia/Shanghai APP_DATA_DIR=./data @@ -6,4 +7,3 @@ SECRET_KEY_BASE=chatwoot_secret_key_base POSTGRES_PASSWORD=chatwoot_postgres_password REDIS_PASSWORD=chatwoot_redis_password ENABLE_ACCOUNT_SIGNUP=true -CONTAINER_NAME=chatwoot diff --git a/apps/chatwoot/latest/data.yml b/apps/chatwoot/latest/data.yml index 81b5c4363..9aae7449d 100644 --- a/apps/chatwoot/latest/data.yml +++ b/apps/chatwoot/latest/data.yml @@ -1,143 +1,143 @@ additionalProperties: formFields: - - default: 18086 - 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: Asia/Shanghai - edit: true - envKey: TZ - labelEn: Timezone - labelZh: 时区 - label: - en: Timezone - zh: 时区 - zh-Hant: 時區 - ja: タイムゾーン - ko: 시간대 - ru: Часовой пояс - ms: Zon waktu - pt-br: Fuso horario - 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: Diretorio de dados - required: true - type: text - - default: http://1.2.3.4:18086 - edit: true - envKey: FRONTEND_URL - labelEn: Public URL - labelZh: 公开访问地址 - label: - en: Public URL - zh: 公开访问地址 - zh-Hant: 公開存取位址 - ja: 公開アクセス URL - ko: 공개 접속 주소 - ru: Публичный URL - ms: URL awam - pt-br: URL publico - required: true - rule: paramExtUrl - type: text - - default: chatwoot_secret_key_base - edit: true - envKey: SECRET_KEY_BASE - labelEn: Secret Key Base - labelZh: Rails 签名密钥 - label: - en: Secret Key Base - zh: Rails 签名密钥 - zh-Hant: Rails 簽章金鑰 - ja: Rails 署名キー - ko: Rails 서명 키 - ru: Ключ подписи Rails - ms: Kunci tandatangan Rails - pt-br: Chave de assinatura Rails - random: true - required: true - rule: paramComplexity - type: password - - default: chatwoot_postgres_password - edit: true - envKey: POSTGRES_PASSWORD - labelEn: PostgreSQL Password - labelZh: PostgreSQL 密码 - label: - en: PostgreSQL Password - zh: PostgreSQL 密码 - zh-Hant: PostgreSQL 密碼 - ja: PostgreSQL パスワード - ko: PostgreSQL 비밀번호 - ru: Пароль PostgreSQL - ms: Kata laluan PostgreSQL - pt-br: Senha do PostgreSQL - random: true - required: true - rule: paramComplexity - type: password - - default: chatwoot_redis_password - edit: true - envKey: REDIS_PASSWORD - labelEn: Redis Password - labelZh: Redis 密码 - label: - en: Redis Password - zh: Redis 密码 - zh-Hant: Redis 密碼 - ja: Redis パスワード - ko: Redis 비밀번호 - ru: Пароль Redis - ms: Kata laluan Redis - pt-br: Senha do Redis - random: true - required: true - rule: paramComplexity - type: password - - default: "true" - edit: true - envKey: ENABLE_ACCOUNT_SIGNUP - labelEn: Enable Account Signup - labelZh: 允许账号注册 - label: - en: Enable Account Signup - zh: 允许账号注册 - zh-Hant: 允許帳號註冊 - ja: アカウント登録を許可 - ko: 계정 가입 허용 - ru: Разрешить регистрацию аккаунтов - ms: Benarkan pendaftaran akaun - pt-br: Permitir cadastro de contas - required: true - type: select - values: - - label: "true" - value: "true" - - label: "false" - value: "false" + - default: 18086 + 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: Asia/Shanghai + edit: true + envKey: TZ + labelEn: Timezone + labelZh: 时区 + label: + en: Timezone + zh: 时区 + zh-Hant: 時區 + ja: タイムゾーン + ko: 시간대 + ru: Часовой пояс + ms: Zon waktu + pt-br: Fuso horario + 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: Diretorio de dados + required: true + type: text + - default: http://1.2.3.4:18086 + edit: true + envKey: FRONTEND_URL + labelEn: Public URL + labelZh: 公开访问地址 + label: + en: Public URL + zh: 公开访问地址 + zh-Hant: 公開存取位址 + ja: 公開アクセス URL + ko: 공개 접속 주소 + ru: Публичный URL + ms: URL awam + pt-br: URL publico + required: true + rule: paramExtUrl + type: text + - default: chatwoot_secret_key_base + edit: true + envKey: SECRET_KEY_BASE + labelEn: Secret Key Base + labelZh: Rails 签名密钥 + label: + en: Secret Key Base + zh: Rails 签名密钥 + zh-Hant: Rails 簽章金鑰 + ja: Rails 署名キー + ko: Rails 서명 키 + ru: Ключ подписи Rails + ms: Kunci tandatangan Rails + pt-br: Chave de assinatura Rails + random: true + required: true + rule: paramComplexity + type: password + - default: chatwoot_postgres_password + edit: true + envKey: POSTGRES_PASSWORD + labelEn: PostgreSQL Password + labelZh: PostgreSQL 密码 + label: + en: PostgreSQL Password + zh: PostgreSQL 密码 + zh-Hant: PostgreSQL 密碼 + ja: PostgreSQL パスワード + ko: PostgreSQL 비밀번호 + ru: Пароль PostgreSQL + ms: Kata laluan PostgreSQL + pt-br: Senha do PostgreSQL + random: true + required: true + rule: paramComplexity + type: password + - default: chatwoot_redis_password + edit: true + envKey: REDIS_PASSWORD + labelEn: Redis Password + labelZh: Redis 密码 + label: + en: Redis Password + zh: Redis 密码 + zh-Hant: Redis 密碼 + ja: Redis パスワード + ko: Redis 비밀번호 + ru: Пароль Redis + ms: Kata laluan Redis + pt-br: Senha do Redis + random: true + required: true + rule: paramComplexity + type: password + - default: 'true' + edit: true + envKey: ENABLE_ACCOUNT_SIGNUP + labelEn: Enable Account Signup + labelZh: 允许账号注册 + label: + en: Enable Account Signup + zh: 允许账号注册 + zh-Hant: 允許帳號註冊 + ja: アカウント登録を許可 + ko: 계정 가입 허용 + ru: Разрешить регистрацию аккаунтов + ms: Benarkan pendaftaran akaun + pt-br: Permitir cadastro de contas + required: true + type: select + values: + - label: 'true' + value: 'true' + - label: 'false' + value: 'false' diff --git a/apps/chatwoot/latest/docker-compose.yml b/apps/chatwoot/latest/docker-compose.yml index 347e59e9c..0f93b104c 100644 --- a/apps/chatwoot/latest/docker-compose.yml +++ b/apps/chatwoot/latest/docker-compose.yml @@ -1,6 +1,6 @@ services: chatwoot: - image: "chatwoot/chatwoot:v4.17.0-ce" + image: "chatwoot/chatwoot:v4.17.1-ce" container_name: ${CONTAINER_NAME} restart: always depends_on: @@ -49,7 +49,7 @@ services: createdBy: "Apps" chatwoot-sidekiq: - image: "chatwoot/chatwoot:v4.17.0-ce" + image: "chatwoot/chatwoot:v4.17.1-ce" container_name: ${CONTAINER_NAME}-sidekiq restart: always depends_on: diff --git a/apps/chatwoot/latest/scripts/init.sh b/apps/chatwoot/latest/scripts/init.sh index 6062c6d34..253e8bd06 100755 --- a/apps/chatwoot/latest/scripts/init.sh +++ b/apps/chatwoot/latest/scripts/init.sh @@ -1,8 +1,105 @@ #!/usr/bin/env bash set -euo pipefail +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +export PATH -DATA_DIR="${APP_DATA_DIR:-./data}" -mkdir -p \ - "${DATA_DIR}/storage" \ - "${DATA_DIR}/postgres" \ - "${DATA_DIR}/redis" +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; } +} + +ensure_dir "APP_DATA_DIR" "./data" diff --git a/apps/chatwoot/logo.png b/apps/chatwoot/logo.png index d72c12398..4fc8a6488 100644 Binary files a/apps/chatwoot/logo.png and b/apps/chatwoot/logo.png differ