feat: add preset scripts for synologydsm and fnos on deployment to ssh

This commit is contained in:
Fu Diwei 2025-05-15 20:52:43 +08:00
parent 564ed8f0d3
commit a3a56f3346
5 changed files with 175 additions and 25 deletions

View File

@ -52,6 +52,8 @@ export const initPresetScript = (
key: "sh_backup_files" | "ps_backup_files" | "sh_reload_nginx" | "ps_binding_iis" | "ps_binding_netsh" | "ps_binding_rdp",
params?: {
certPath?: string;
certPathForServerOnly?: string;
certPathForIntermediaOnly?: string;
keyPath?: string;
pfxPassword?: string;
jksAlias?: string;
@ -77,19 +79,22 @@ if (Test-Path -Path "${params?.keyPath || "<your-key-path>"}" -PathType Leaf) {
`.trim();
case "sh_reload_nginx":
return `sudo service nginx reload`;
return `# *** 需要 root 权限 ***
sudo service nginx reload
`.trim();
case "ps_binding_iis":
return `# 需要管理员权限
return `# *** 需要管理员权限 ***
#
$pfxPath = "${params?.certPath || "<your-cert-path>"}" # PFX
$pfxPassword = "${params?.pfxPassword || "<your-pfx-password>"}" # PFX
$pfxPath = "${params?.certPath || "<your-cert-path>"}" # PFX
$pfxPassword = "${params?.pfxPassword || "<your-pfx-password>"}" # PFX
$siteName = "<your-site-name>" # IIS
$domain = "<your-domain-name>" #
$ipaddr = "<your-binding-ip>" # IP* IP
$port = "<your-binding-port>" #
#
$cert = Import-PfxCertificate -FilePath "$pfxPath" -CertStoreLocation Cert:\\LocalMachine\\My -Password (ConvertTo-SecureString -String "$pfxPassword" -AsPlainText -Force) -Exportable
# Thumbprint
@ -111,16 +116,16 @@ Remove-Item -Path "$pfxPath" -Force
`.trim();
case "ps_binding_netsh":
return `# 需要管理员权限
return `# *** 需要管理员权限 ***
#
$pfxPath = "${params?.certPath || "<your-cert-path>"}" # PFX
$pfxPassword = "${params?.pfxPassword || "<your-pfx-password>"}" # PFX
$ipaddr = "<your-binding-ip>" # IP0.0.0.0 IP
$pfxPath = "${params?.certPath || "<your-cert-path>"}" # PFX
$pfxPassword = "${params?.pfxPassword || "<your-pfx-password>"}" # PFX
$ipaddr = "<your-binding-ip>" # IP0.0.0.0 IP
$port = "<your-binding-port>" #
$addr = $ipaddr + ":" + $port
#
$addr = $ipaddr + ":" + $port
$cert = Import-PfxCertificate -FilePath "$pfxPath" -CertStoreLocation Cert:\\LocalMachine\\My -Password (ConvertTo-SecureString -String "$pfxPassword" -AsPlainText -Force) -Exportable
# Thumbprint
$thumbprint = $cert.Thumbprint
@ -134,10 +139,11 @@ Remove-Item -Path "$pfxPath" -Force
`.trim();
case "ps_binding_rdp":
return `# 需要管理员权限
return `# *** 需要管理员权限 ***
#
$pfxPath = "${params?.certPath || "<your-cert-path>"}" # PFX
$pfxPassword = "${params?.pfxPassword || "<your-pfx-password>"}" # PFX
$pfxPath = "${params?.certPath || "<your-cert-path>"}" # PFX
$pfxPassword = "${params?.pfxPassword || "<your-pfx-password>"}" # PFX
#
$cert = Import-PfxCertificate -FilePath "$pfxPath" -CertStoreLocation Cert:\\LocalMachine\\My -Password (ConvertTo-SecureString -String "$pfxPassword" -AsPlainText -Force) -Exportable

View File

@ -8,7 +8,7 @@ import CodeInput from "@/components/CodeInput";
import Show from "@/components/Show";
import { CERTIFICATE_FORMATS } from "@/domain/certificate";
import { initPresetScript } from "./DeployNodeConfigFormLocalConfig";
import { initPresetScript as _initPresetScript } from "./DeployNodeConfigFormLocalConfig";
type DeployNodeConfigFormSSHConfigFieldValues = Nullish<{
format: string;
@ -45,6 +45,126 @@ const initFormModel = (): DeployNodeConfigFormSSHConfigFieldValues => {
};
};
const initPresetScript = (
key: Parameters<typeof _initPresetScript>[0] | "sh_replace_synologydsm_ssl" | "sh_replace_fnos_ssl",
params?: Parameters<typeof _initPresetScript>[1]
) => {
switch (key) {
case "sh_replace_synologydsm_ssl":
return `# *** 需要 root 权限 ***
# https://github.com/catchdave/ssl-certs/blob/main/replace_synology_ssl_certs.sh
#
$tmpFullchainPath = "${params?.certPath || "<your-fullchain-cert-path>"}" #
$tmpCertPath = "${params?.certPathForServerOnly || "<your-server-cert-path>"}" #
$tmpKeyPath = "${params?.keyPath || "<your-key-path>"}" #
DEBUG=1
error_exit() { echo "[ERROR] $1"; exit 1; }
warn() { echo "[WARN] $1"; }
info() { echo "[INFO] $1"; }
debug() { [[ "\${DEBUG}" ]] && echo "[DEBUG] $1"; }
certs_src_dir="/usr/syno/etc/certificate/system/default"
target_cert_dirs=(
"/usr/syno/etc/certificate/system/FQDN"
"/usr/local/etc/certificate/ScsiTarget/pkg-scsi-plugin-server/"
"/usr/local/etc/certificate/SynologyDrive/SynologyDrive/"
"/usr/local/etc/certificate/WebDAVServer/webdav/"
"/usr/local/etc/certificate/ActiveBackup/ActiveBackup/"
"/usr/syno/etc/certificate/smbftpd/ftpd/")
#
default_dir_name=$(</usr/syno/etc/certificate/_archive/DEFAULT)
if [[ -n "$default_dir_name" ]]; then
target_cert_dirs+=("/usr/syno/etc/certificate/_archive/\${default_dir_name}")
debug "Default cert directory found: '/usr/syno/etc/certificate/_archive/\${default_dir_name}'"
else
warn "No default directory found. Probably unusual? Check: 'cat /usr/syno/etc/certificate/_archive/DEFAULT'"
fi
#
for proxy in /usr/syno/etc/certificate/ReverseProxy/*/; do
debug "Found proxy dir: \${proxy}"
target_cert_dirs+=("\${proxy}")
done
[[ "\${DEBUG}" ]] && set -x
#
cp -rf "$tmpFullchainPath" "\${certs_src_dir}/fullchain.pem" || error_exit "Halting because of error moving fullchain file"
cp -rf "$tmpCertPath" "\${certs_src_dir}/cert.pem" || error_exit "Halting because of error moving cert file"
cp -rf "$tmpKeyPath" "\${certs_src_dir}/privkey.pem" || error_exit "Halting because of error moving privkey file"
chown root:root "\${certs_src_dir}/"{privkey,fullchain,cert}.pem || error_exit "Halting because of error chowning files"
info "Certs moved from /tmp & chowned."
#
for target_dir in "\${target_cert_dirs[@]}"; do
if [[ ! -d "$target_dir" ]]; then
debug "Target cert directory '$target_dir' not found, skipping..."
continue
fi
info "Copying certificates to '$target_dir'"
if ! (cp "\${certs_src_dir}/"{privkey,fullchain,cert}.pem "$target_dir/" && \
chown root:root "$target_dir/"{privkey,fullchain,cert}.pem); then
warn "Error copying or chowning certs to \${target_dir}"
fi
done
#
info "Rebooting all the things..."
/usr/syno/bin/synosystemctl restart nmbd
/usr/syno/bin/synosystemctl restart avahi
/usr/syno/bin/synosystemctl restart ldap-server
/usr/syno/bin/synopkg is_onoff ScsiTarget 1>/dev/null && /usr/syno/bin/synopkg restart ScsiTarget
/usr/syno/bin/synopkg is_onoff SynologyDrive 1>/dev/null && /usr/syno/bin/synopkg restart SynologyDrive
/usr/syno/bin/synopkg is_onoff WebDAVServer 1>/dev/null && /usr/syno/bin/synopkg restart WebDAVServer
/usr/syno/bin/synopkg is_onoff ActiveBackup 1>/dev/null && /usr/syno/bin/synopkg restart ActiveBackup
if ! /usr/syno/bin/synow3tool --gen-all && sudo /usr/syno/bin/synosystemctl restart nginx; then
warn "nginx failed to restart"
fi
info "Completed"
`.trim();
case "sh_replace_fnos_ssl":
return `# *** 需要 root 权限 ***
# https://github.com/lfgyx/fnos_certificate_update/blob/main/src/update_cert.sh
#
# \`/usr/trim/etc/network_cert_all.conf\` 中查看,注意不要修改文件名
$tmpFullchainPath = "${params?.certPath || "<your-fullchain-cert-path>"}" #
$tmpCertPath = "${params?.certPathForServerOnly || "<your-server-cert-path>"}" #
$tmpKeyPath = "${params?.keyPath || "<your-key-path>"}" #
$fnFullchainPath = "/usr/trim/var/trim_connect/ssls/example.com/1234567890/fullchain.crt" #
$fnCertPath = "/usr/trim/var/trim_connect/ssls/example.com/1234567890/example.com.crt" #
$fnKeyPath = "/usr/trim/var/trim_connect/ssls/example.com/1234567890/example.com.key" #
$domain = "<your-domain-name>" #
#
cp -rf "$tmpFullchainPath" "$fnFullchainPath"
cp -rf "$tmpCertPath" "$fnCertPath"
cp -rf "$tmpKeyPath" "$fnKeyPath"
chmod 755 "$fnCertPath"
chmod 755 "$fnKeyPath"
chmod 755 "$fnFullchainPath"
#
NEW_EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$fnCertPath" | sed "s/^.*=\\(.*\\)$/\\1/")
NEW_EXPIRY_TIMESTAMP=$(date -d "$NEW_EXPIRY_DATE" +%s%3N)
psql -U postgres -d trim_connect -c "UPDATE cert SET valid_to=$NEW_EXPIRY_TIMESTAMP WHERE domain='$domain'"
#
systemctl restart webdav.service
systemctl restart smbftpd.service
systemctl restart trim_nginx.service
`.trim();
}
return _initPresetScript(key as Parameters<typeof _initPresetScript>[0], params);
};
const DeployNodeConfigFormSSHConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormSSHConfigProps) => {
const { t } = useTranslation();
@ -160,6 +280,24 @@ const DeployNodeConfigFormSSHConfig = ({ form: formInst, formName, disabled, ini
const handlePresetPostScriptClick = (key: string) => {
switch (key) {
case "sh_reload_nginx":
{
formInst.setFieldValue("postCommand", initPresetScript(key));
}
break;
case "sh_replace_synologydsm_ssl":
case "sh_replace_fnos_ssl":
{
const presetScriptParams = {
certPath: formInst.getFieldValue("certPath"),
certPathForServerOnly: formInst.getFieldValue("certPathForServerOnly"),
certPathForIntermediaOnly: formInst.getFieldValue("certPathForIntermediaOnly"),
keyPath: formInst.getFieldValue("keyPath"),
};
formInst.setFieldValue("postCommand", initPresetScript(key, presetScriptParams));
}
break;
case "ps_binding_iis":
case "ps_binding_netsh":
case "ps_binding_rdp":
@ -324,11 +462,13 @@ const DeployNodeConfigFormSSHConfig = ({ form: formInst, formName, disabled, ini
<div className="text-right">
<Dropdown
menu={{
items: ["sh_reload_nginx", "ps_binding_iis", "ps_binding_netsh", "ps_binding_rdp"].map((key) => ({
key,
label: t(`workflow_node.deploy.form.ssh_preset_scripts.option.${key}.label`),
onClick: () => handlePresetPostScriptClick(key),
})),
items: ["sh_reload_nginx", "sh_replace_synologydsm_ssl", "sh_replace_fnos_ssl", "ps_binding_iis", "ps_binding_netsh", "ps_binding_rdp"].map(
(key) => ({
key,
label: t(`workflow_node.deploy.form.ssh_preset_scripts.option.${key}.label`),
onClick: () => handlePresetPostScriptClick(key),
})
),
}}
trigger={["click"]}
>

View File

@ -377,7 +377,7 @@
"access.form.webhook_default_data.errmsg.json_invalid": "Please enter a valiod JSON string",
"access.form.webhook_default_data_for_deployment.label": "Webhook data for deployment (Optional)",
"access.form.webhook_default_data_for_deployment.placeholder": "Please enter Webhook data",
"access.form.webhook_default_data_for_deployment.guide": "Tips: The Webhook data should be in JSON format. <br><br>The values in JSON support template variables, which will be replaced by actual values when sent to the Webhook URL. Supported variables: <br><ol style=\"margin-left: 1.25em; list-style: disc;\"><li><strong>${DOMAIN}</strong>: The primary domain of the certificate (<i>CommonName</i>).</li><li><strong>${DOMAINS}</strong>: The domain list of the certificate (<i>SubjectAltNames</i>).</li><li><strong>${CERTIFICATE}</strong>: The PEM format content of the certificate file.</li><li><strong>${SERVER_CERTIFICATE}</strong>: The PEM format content of the server certificate file.</li><li><strong>${INTERMEDIA_CERTIFICATE}</strong>: The PEM format content of the intermedia certificate file.</li><li><strong>${PRIVATE_KEY}</strong>: The PEM format content of the private key file.</li></ol><br>When the request method is GET, the data will be passed as query string. Otherwise, the data will be encoded in the format indicated by the Content-Type in the request headers. Supported formats: <br><ol style=\"margin-left: 1.25em; list-style: disc;\"><li>application/json (default).</li><li>application/x-www-form-urlencoded: Nested data is not supported.</li><li>multipart/form-data: Nested data is not supported.</li>",
"access.form.webhook_default_data_for_deployment.guide": "Tips: The Webhook data should be in JSON format. <br><br>The values in JSON support template variables, which will be replaced by actual values when sent to the Webhook URL. Supported variables: <br><ol style=\"margin-left: 1.25em; list-style: disc;\"><li><strong>${DOMAIN}</strong>: The primary domain of the certificate (<i>CommonName</i>).</li><li><strong>${DOMAINS}</strong>: The domain list of the certificate (<i>SubjectAltNames</i>).</li><li><strong>${CERTIFICATE}</strong>: The PEM format content of the certificate file.</li><li><strong>${SERVER_CERTIFICATE}</strong>: The PEM format content of the server certificate file.</li><li><strong>${INTERMEDIA_CERTIFICATE}</strong>: The PEM format content of the intermediate CA certificate file.</li><li><strong>${PRIVATE_KEY}</strong>: The PEM format content of the private key file.</li></ol><br>When the request method is GET, the data will be passed as query string. Otherwise, the data will be encoded in the format indicated by the Content-Type in the request headers. Supported formats: <br><ol style=\"margin-left: 1.25em; list-style: disc;\"><li>application/json (default).</li><li>application/x-www-form-urlencoded: Nested data is not supported.</li><li>multipart/form-data: Nested data is not supported.</li>",
"access.form.webhook_default_data_for_notification.label": "Webhook data for notification (Optional)",
"access.form.webhook_default_data_for_notification.placeholder": "Please enter Webhook data",
"access.form.webhook_default_data_for_notification.guide": "Tips: The Webhook data should be in JSON format. <br><br>The values in JSON support template variables, which will be replaced by actual values when sent to the Webhook URL. Supported variables: <br><ol style=\"margin-left: 1.25em; list-style: disc;\"><li><strong>${SUBJECT}</strong>: The subject of notification.</li><li><strong>${MESSAGE}</strong>: The message of notification.</li></ol><br>When the request method is GET, the data will be passed as query string. Otherwise, the data will be encoded in the format indicated by the Content-Type in the request headers. Supported formats: <br><ol style=\"margin-left: 1.25em; list-style: disc;\"><li>application/json (default).</li><li>application/x-www-form-urlencoded: Nested data is not supported.</li><li>multipart/form-data: Nested data is not supported.</li>",

View File

@ -455,8 +455,8 @@
"workflow_node.deploy.form.local_servercert_path.label": "Server certificate file saving path (Optional)",
"workflow_node.deploy.form.local_servercert_path.placeholder": "Please enter saving path for server certificate file",
"workflow_node.deploy.form.local_servercert_path.tooltip": "Note that the path should include the complete file name, not just the directory.",
"workflow_node.deploy.form.local_intermediacert_path.label": "Intermedia certificate file saving path (Optional)",
"workflow_node.deploy.form.local_intermediacert_path.placeholder": "Please enter saving path for intermedia certificate file",
"workflow_node.deploy.form.local_intermediacert_path.label": "Intermediate CA certificate file saving path (Optional)",
"workflow_node.deploy.form.local_intermediacert_path.placeholder": "Please enter saving path for intermediate CA certificate file",
"workflow_node.deploy.form.local_intermediacert_path.tooltip": "Note that the path should include the complete file name, not just the directory.",
"workflow_node.deploy.form.local_pfx_password.label": "PFX password",
"workflow_node.deploy.form.local_pfx_password.placeholder": "Please enter PFX password",
@ -526,8 +526,8 @@
"workflow_node.deploy.form.ssh_servercert_path.label": "Server certificate file uploading path (Optional)",
"workflow_node.deploy.form.ssh_servercert_path.placeholder": "Please enter uploading path for server certificate file",
"workflow_node.deploy.form.ssh_servercert_path.tooltip": "Note that the path should include the complete file name, not just the directory.",
"workflow_node.deploy.form.ssh_intermediacert_path.label": "Intermedia certificate file uploading path (Optional)",
"workflow_node.deploy.form.ssh_intermediacert_path.placeholder": "Please enter uploading path for intermedia certificate file",
"workflow_node.deploy.form.ssh_intermediacert_path.label": "Intermediate CA certificate file uploading path (Optional)",
"workflow_node.deploy.form.ssh_intermediacert_path.placeholder": "Please enter uploading path for intermediate CA certificate file",
"workflow_node.deploy.form.ssh_intermediacert_path.tooltip": "Note that the path should include the complete file name, not just the directory.",
"workflow_node.deploy.form.ssh_pfx_password.label": "PFX password",
"workflow_node.deploy.form.ssh_pfx_password.placeholder": "Please enter PFX password",
@ -549,6 +549,8 @@
"workflow_node.deploy.form.ssh_preset_scripts.option.sh_backup_files.label": "POSIX Bash - Backup certificate files",
"workflow_node.deploy.form.ssh_preset_scripts.option.ps_backup_files.label": "PowerShell - Backup certificate files",
"workflow_node.deploy.form.ssh_preset_scripts.option.sh_reload_nginx.label": "POSIX Bash - Reload nginx",
"workflow_node.deploy.form.ssh_preset_scripts.option.sh_replace_synologydsm_ssl.label": "POSIX Bash - Replace SynologyDSM SSL certificate",
"workflow_node.deploy.form.ssh_preset_scripts.option.sh_replace_fnos_ssl.label": "POSIX Bash - Replace fnOS SSL certificate",
"workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_iis.label": "PowerShell - Binding IIS",
"workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_netsh.label": "PowerShell - Binding netsh",
"workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_rdp.label": "PowerShell - Binding RDP",

View File

@ -548,6 +548,8 @@
"workflow_node.deploy.form.ssh_preset_scripts.option.sh_backup_files.label": "POSIX Bash - 备份原证书文件",
"workflow_node.deploy.form.ssh_preset_scripts.option.ps_backup_files.label": "PowerShell - 备份原证书文件",
"workflow_node.deploy.form.ssh_preset_scripts.option.sh_reload_nginx.label": "POSIX Bash - 重启 nginx 进程",
"workflow_node.deploy.form.ssh_preset_scripts.option.sh_replace_synologydsm_ssl.label": "POSIX Bash - 替换群晖 DSM 证书",
"workflow_node.deploy.form.ssh_preset_scripts.option.sh_replace_fnos_ssl.label": "POSIX Bash - 替换飞牛 OS 证书",
"workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_iis.label": "PowerShell - 导入并绑定到 IIS",
"workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_netsh.label": "PowerShell - 导入并绑定到 netsh",
"workflow_node.deploy.form.ssh_preset_scripts.option.ps_binding_rdp.label": "PowerShell - 导入并绑定到 RDP",