From 0c4ad939aab1b0ccc03869971320bcbc4c710f8a Mon Sep 17 00:00:00 2001 From: smail Date: Thu, 1 Oct 2026 11:24:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=85=A8=E6=96=B0=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E6=95=B0=E6=8D=AE=E4=BF=9D=E6=8A=A4=E4=B8=8E=E5=9F=9F?= =?UTF-8?q?=E5=90=8D=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充部署时的历史运行数据保护,移除前端旧域名兜底,并将 Nginx 模板改为用户确认域名占位符。 --- deploy/deploy-runtime.ps1 | 2 +- deploy/install-systemd.sh | 23 +++++++++++++++++++ deploy/install-windows.ps1 | 20 ++++++++++++++++ deploy/nginx/smail.conf | 14 ++++++----- .../ThirdPartyAuthorization.js | 1 + .../ThirdPartyAuthorization.vue | 15 +++++++----- 6 files changed, 62 insertions(+), 13 deletions(-) diff --git a/deploy/deploy-runtime.ps1 b/deploy/deploy-runtime.ps1 index ac763fcd..e6f5e37b 100644 --- a/deploy/deploy-runtime.ps1 +++ b/deploy/deploy-runtime.ps1 @@ -40,7 +40,7 @@ foreach ($item in $receipt.files) { } & node (Join-Path $PSScriptRoot 'build-state.mjs') verify --deployed if ($LASTEXITCODE -ne 0) { throw '部署校验失败,禁止启动;旧程序备份保留在 out/deployment-history' } -Write-Output '最新编译包已部署到 yunx-test;配置、证书、数据库未被构建过程覆盖。' +Write-Output '最新程序已部署到 yunx-test;正常升级不会覆盖配置、证书或数据库。全新部署必须使用独立的空运行目录。' } finally { if ($lock) { $lock.Dispose() } } diff --git a/deploy/install-systemd.sh b/deploy/install-systemd.sh index 96e4d381..bf776f8c 100644 --- a/deploy/install-systemd.sh +++ b/deploy/install-systemd.sh @@ -66,6 +66,29 @@ if [ -L /run/smail/admin-control.sock ] || { [ -e /run/smail/admin-control.sock exit 1 fi +# 全新安装不继承目标目录中的配置、证书或业务数据,也不自动清理它们。 +for directory in config data ssl log plugins; do + target="$runtime_dir/$directory" + if [ -d "$target" ] && [ -n "$(find "$target" -mindepth 1 -maxdepth 1 -print -quit)" ]; then + echo "全新部署已停止:$target 非空。请先确认并处理旧数据,再通过初始化页面重新配置。" >&2 + exit 1 + fi +done +for file in config.json config.dev.json smail.db smail-state.db; do + if [ -e "$runtime_dir/$file" ] || [ -L "$runtime_dir/$file" ]; then + echo "全新部署已停止:发现历史运行文件 $file,不会自动继承或删除。" >&2 + exit 1 + fi +done +if [ -e /etc/smail/smail.env ]; then + echo "全新部署已停止:请先确认并处理 /etc/smail/smail.env 中的旧部署环境配置。" >&2 + exit 1 +fi +if [ -d /etc/systemd/system/smail.service.d ] && [ -n "$(find /etc/systemd/system/smail.service.d -mindepth 1 -maxdepth 1 -print -quit)" ]; then + echo "全新部署已停止:请先确认并处理 Smail 的旧服务覆盖配置。" >&2 + exit 1 +fi + # 安装备份存放在系统备份目录,不在部署根目录遗留 .bak 文件。 backup_dir="$(mktemp -d /var/backups/smail-deploy-XXXXXXXX)" for name in smail smail-admin; do diff --git a/deploy/install-windows.ps1 b/deploy/install-windows.ps1 index c3d0a754..43b61c6a 100644 --- a/deploy/install-windows.ps1 +++ b/deploy/install-windows.ps1 @@ -115,6 +115,26 @@ $adminSource = Resolve-PackageFile -Candidates @( ) -Description "smail-admin.exe" $resolvedInstallRoot = [IO.Path]::GetFullPath($InstallRoot) +if (Test-Path -LiteralPath $resolvedInstallRoot) { + $rootInfo = Get-Item -LiteralPath $resolvedInstallRoot -Force + if (-not $rootInfo.PSIsContainer -or $rootInfo.Attributes -band [IO.FileAttributes]::ReparsePoint) { + throw "安装目录不能是文件或链接" + } +} +foreach ($name in @('config', 'data', 'ssl', 'log', 'plugins')) { + $existing = Join-Path $resolvedInstallRoot $name + if (-not (Test-Path -LiteralPath $existing)) { continue } + $info = Get-Item -LiteralPath $existing -Force + if (-not $info.PSIsContainer -or $info.Attributes -band [IO.FileAttributes]::ReparsePoint -or + (Get-ChildItem -LiteralPath $existing -Force | Select-Object -First 1)) { + throw "全新部署已停止:$existing 不是空目录。请先确认并处理旧数据,再通过初始化页面重新配置。" + } +} +foreach ($name in @('config.json', 'config.dev.json', 'smail.db', 'smail-state.db')) { + if (Test-Path -LiteralPath (Join-Path $resolvedInstallRoot $name)) { + throw "全新部署已停止:发现历史运行文件 $name,不会自动继承或删除。" + } +} New-Item -ItemType Directory -Path $resolvedInstallRoot -Force | Out-Null New-Item -ItemType Directory -Path (Join-Path $resolvedInstallRoot "config") -Force | Out-Null New-Item -ItemType Directory -Path (Join-Path $resolvedInstallRoot "data") -Force | Out-Null diff --git a/deploy/nginx/smail.conf b/deploy/nginx/smail.conf index 3af7164e..c246c4a3 100644 --- a/deploy/nginx/smail.conf +++ b/deploy/nginx/smail.conf @@ -1,3 +1,5 @@ +# 部署前必须将域名占位符替换为用户在初始化页面确认的邮件主域名和后台域名。 +# 此模板不包含测试域名;不要将未填写的模板直接安装到 Nginx。 server { listen 80 default_server; listen [::]:80 default_server; @@ -8,7 +10,7 @@ server { server { listen 80; listen [::]:80; - server_name solit.cn mail.solit.cn web.solit.cn smtp.solit.cn imap.solit.cn pop.solit.cn; + server_name __SMAIL_MAIL_DOMAIN__ __SMAIL_WEB_DOMAIN__; location ^~ /.well-known/acme-challenge/ { root /var/lib/smail-acme; @@ -17,7 +19,7 @@ server { } location / { - return 308 https://web.solit.cn$request_uri; + return 308 https://__SMAIL_WEB_DOMAIN__$request_uri; } } @@ -31,16 +33,16 @@ server { server { listen 443 ssl; listen [::]:443 ssl; - server_name solit.cn mail.solit.cn smtp.solit.cn imap.solit.cn pop.solit.cn; + server_name __SMAIL_MAIL_DOMAIN__; ssl_certificate /opt/smail/ssl/custom.crt; ssl_certificate_key /opt/smail/ssl/custom.key; - return 308 https://web.solit.cn$request_uri; + return 308 https://__SMAIL_WEB_DOMAIN__$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; - server_name web.solit.cn; + server_name __SMAIL_WEB_DOMAIN__; ssl_certificate /opt/smail/ssl/custom.crt; ssl_certificate_key /opt/smail/ssl/custom.key; @@ -54,7 +56,7 @@ server { proxy_set_header X-Forwarded-Proto https; proxy_set_header Connection ""; proxy_ssl_server_name on; - proxy_ssl_name web.solit.cn; + proxy_ssl_name __SMAIL_WEB_DOMAIN__; proxy_ssl_verify on; proxy_ssl_verify_depth 3; proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt; diff --git a/frontend/src/views/components/ThirdPartyAuthorization/ThirdPartyAuthorization.js b/frontend/src/views/components/ThirdPartyAuthorization/ThirdPartyAuthorization.js index 0da76676..779d1b2c 100644 --- a/frontend/src/views/components/ThirdPartyAuthorization/ThirdPartyAuthorization.js +++ b/frontend/src/views/components/ThirdPartyAuthorization/ThirdPartyAuthorization.js @@ -86,6 +86,7 @@ export function usePage() { } const loadBaseInfo = async () => { + currentDomain.value = '' try { const infoRes = await http.post('/api/v1/user/info', {}) const email = infoRes?.data?.email diff --git a/frontend/src/views/components/ThirdPartyAuthorization/ThirdPartyAuthorization.vue b/frontend/src/views/components/ThirdPartyAuthorization/ThirdPartyAuthorization.vue index 07d3c554..907252cd 100644 --- a/frontend/src/views/components/ThirdPartyAuthorization/ThirdPartyAuthorization.vue +++ b/frontend/src/views/components/ThirdPartyAuthorization/ThirdPartyAuthorization.vue @@ -156,7 +156,8 @@ link size="small" class="btn-card-copy" - @click="copyText(`imap.${currentDomain || 'solit.cn'}:993`, 'IMAP 参数')" + :disabled="!currentDomain" + @click="copyText(`imap.${currentDomain}:993`, 'IMAP 参数')" > 复制 @@ -165,7 +166,7 @@
服务器 - imap.{{ currentDomain || 'solit.cn' }} + {{ currentDomain ? `imap.${currentDomain}` : '未配置邮件域名' }}
端口 @@ -193,7 +194,8 @@ link size="small" class="btn-card-copy" - @click="copyText(`pop.${currentDomain || 'solit.cn'}:995`, 'POP3 参数')" + :disabled="!currentDomain" + @click="copyText(`pop.${currentDomain}:995`, 'POP3 参数')" > 复制 @@ -202,7 +204,7 @@
服务器 - pop.{{ currentDomain || 'solit.cn' }} + {{ currentDomain ? `pop.${currentDomain}` : '未配置邮件域名' }}
端口 @@ -230,7 +232,8 @@ link size="small" class="btn-card-copy" - @click="copyText(`smtp.${currentDomain || 'solit.cn'}:465`, 'SMTP 参数')" + :disabled="!currentDomain" + @click="copyText(`smtp.${currentDomain}:465`, 'SMTP 参数')" > 复制 @@ -239,7 +242,7 @@
服务器 - smtp.{{ currentDomain || 'solit.cn' }} + {{ currentDomain ? `smtp.${currentDomain}` : '未配置邮件域名' }}
端口