Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions astrbot/dashboard/routes/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,58 @@ def validate(data: dict, metadata: dict = schema, path="") -> None:
return errors, data


def validate_ssl_config(post_config: dict) -> list[str]:
"""验证 SSL 配置的有效性。

当 dashboard.ssl.enable 为 true 时,必须配置 cert_file 和 key_file,
并且文件必须存在。

Returns:
错误信息列表,为空表示验证通过。
"""
from astrbot.core.utils.astrbot_path import get_astrbot_data_path

errors = []
dashboard_config = post_config.get("dashboard", {})
if not isinstance(dashboard_config, dict):
return errors

ssl_config = dashboard_config.get("ssl", {})
if not isinstance(ssl_config, dict):
return errors

ssl_enable = ssl_config.get("enable", False)
if not ssl_enable:
return errors

cert_file = ssl_config.get("cert_file", "")
key_file = ssl_config.get("key_file", "")

if not cert_file or not cert_file.strip():
errors.append(
"启用 HTTPS 时必须配置 SSL 证书文件路径 (dashboard.ssl.cert_file)"
)
elif not os.path.isabs(cert_file):
# 相对路径,基于 data 目录解析
cert_path = os.path.join(get_astrbot_data_path(), cert_file)
if not os.path.isfile(cert_path):
errors.append(f"SSL 证书文件不存在: {cert_file}")
elif not os.path.isfile(cert_file):
errors.append(f"SSL 证书文件不存在: {cert_file}")

if not key_file or not key_file.strip():
errors.append("启用 HTTPS 时必须配置 SSL 私钥文件路径 (dashboard.ssl.key_file)")
elif not os.path.isabs(key_file):
# 相对路径,基于 data 目录解析
key_path = os.path.join(get_astrbot_data_path(), key_file)
if not os.path.isfile(key_path):
errors.append(f"SSL 私钥文件不存在: {key_file}")
elif not os.path.isfile(key_file):
errors.append(f"SSL 私钥文件不存在: {key_file}")

return errors


def save_config(
post_config: dict, config: AstrBotConfig, is_core: bool = False
) -> None:
Expand All @@ -230,6 +282,11 @@ def save_config(
if errors:
raise ValueError(f"格式校验未通过: {errors}")

# 验证 SSL 配置
ssl_errors = validate_ssl_config(post_config)
if ssl_errors:
raise ValueError(f"SSL 配置校验未通过: {'; '.join(ssl_errors)}")

config.save_config(post_config)


Expand Down
3 changes: 3 additions & 0 deletions dashboard/src/i18n/locales/en-US/features/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,8 @@
"confirm": "confirm",
"cancel": "cancel"
}
},
"sslValidation": {
"required": "When WebUI HTTPS is enabled, SSL certificate file path and private key file path must be configured"
}
}
3 changes: 3 additions & 0 deletions dashboard/src/i18n/locales/zh-CN/features/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,8 @@
"confirm": "确定",
"cancel": "取消"
}
},
"sslValidation": {
"required": "启用 WebUI HTTPS 时,必须配置 SSL 证书文件路径和私钥文件路径"
}
}
24 changes: 24 additions & 0 deletions dashboard/src/views/ConfigPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -500,9 +500,33 @@ export default {
this.save_message_success = "error";
});
},
validateSslConfig() {
const dashboard = this.config_data?.dashboard;
if (!dashboard || !dashboard.ssl) return true;

const ssl = dashboard.ssl;
if (!ssl.enable) return true;

const certFile = (ssl.cert_file || '').trim();
const keyFile = (ssl.key_file || '').trim();

if (!certFile || !keyFile) {
return this.tm('sslValidation.required');
}
return true;
},
updateConfig() {
if (!this.fetched) return;

// 前端验证 SSL 配置
const sslValidation = this.validateSslConfig();
if (sslValidation !== true) {
this.save_message = sslValidation;
this.save_message_snack = true;
this.save_message_success = "error";
return Promise.resolve({ success: false });
}

const postData = {
config: JSON.parse(JSON.stringify(this.config_data)),
};
Expand Down