From a54e03b9242674ce8bf89521a7b15fb612ca16fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AC=A2?= <2711452309@qq.com> Date: Sun, 14 Jun 2026 03:15:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=B8=80=E9=94=AE=E5=AE=89?= =?UTF-8?q?=E8=A3=85certbot=E8=84=9A=E6=9C=AC+=E5=A2=9E=E5=8A=A0=E6=9B=B4?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E7=9A=84webssh=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mofang/clicd.php | 14 ++++++- Mofang/handlers/webssh.php | 19 ++++++++- install-certbot.sh | 80 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 install-certbot.sh diff --git a/Mofang/clicd.php b/Mofang/clicd.php index db09a36..353f912 100644 --- a/Mofang/clicd.php +++ b/Mofang/clicd.php @@ -40,7 +40,7 @@ function clicd_MetaData() 'DisplayName' => 'CLICD 对接模块 by 欢-Huan and ChatGPT 5.5 and DeepSeek V4', 'APIVersion' => '1.1', 'HelpDoc' => 'https://github.com/MengMengCode/CLICD', - 'version' => '1.0.10', + 'version' => '1.0.11', ]; } @@ -365,7 +365,10 @@ function clicd_webssh_url($params, $ticket, $containerName) $host = parse_url($baseUrl, PHP_URL_HOST); $port = parse_url($baseUrl, PHP_URL_PORT); $wsBase = $scheme . '://' . $host . ($port ? ':' . $port : ''); - $wsUrl = $wsBase . '/api/ssh?container=' . rawurlencode((string)$containerName); + $wsUrl = $wsBase + . '/api/ssh?container=' . rawurlencode((string)$containerName) + . '&container_name=' . rawurlencode((string)$containerName) + . '&ticket=' . rawurlencode((string)$ticket); $siteScheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $siteHost = $_SERVER['HTTP_HOST'] ?? ''; @@ -374,6 +377,7 @@ function clicd_webssh_url($params, $ticket, $containerName) return $handler . '?ws=' . rawurlencode($wsUrl) . '&protocol=' . rawurlencode('clicd-ticket.' . (string)$ticket) + . '&ticket=' . rawurlencode((string)$ticket) . '&container=' . rawurlencode((string)$containerName); } @@ -1419,7 +1423,13 @@ function clicd_ClientButton($params) function clicd_webssh($params) { + $container = []; $containerName = clicd_container_name($params); + clicd_container_api_id($params, $container); + if (!empty($container['name'])) { + $containerName = (string)$container['name']; + } + $res = clicd_request($params, '/api/v1/ssh-ticket', ['container_name' => $containerName], 'POST', 30); if (!clicd_success($res)) { return ['status' => 'error', 'msg' => clicd_message($res, 'WebSSH ticket create failed')]; diff --git a/Mofang/handlers/webssh.php b/Mofang/handlers/webssh.php index 3be35c7..510308a 100644 --- a/Mofang/handlers/webssh.php +++ b/Mofang/handlers/webssh.php @@ -2,8 +2,13 @@ $ws = isset($_GET['ws']) ? (string)$_GET['ws'] : (isset($_GET['amp;ws']) ? (string)$_GET['amp;ws'] : ''); $protocol = isset($_GET['protocol']) ? (string)$_GET['protocol'] : (isset($_GET['amp;protocol']) ? (string)$_GET['amp;protocol'] : ''); $container = isset($_GET['container']) ? (string)$_GET['container'] : (isset($_GET['amp;container']) ? (string)$_GET['amp;container'] : ''); +$ticket = isset($_GET['ticket']) ? (string)$_GET['ticket'] : (isset($_GET['amp;ticket']) ? (string)$_GET['amp;ticket'] : ''); -if ($ws === '' || $protocol === '') { +if ($protocol === '' && $ticket !== '') { + $protocol = 'clicd-ticket.' . $ticket; +} + +if ($ws === '') { http_response_code(400); header('Content-Type: text/plain; charset=utf-8'); echo "Missing WebSSH parameters\n"; @@ -64,6 +69,7 @@ if ($ws === '' || $protocol === '') { (function(){ var wsUrl = ; var protocol = ; + var ticket = ; var term = document.getElementById('term'); var state = document.getElementById('state'); var modeSelect = document.getElementById('send-mode'); @@ -189,8 +195,17 @@ if ($ws === '' || $protocol === '') { iostat.textContent = 'S' + sentCount + ' R' + recvCount + ' ' + stateText; } + function websocketProtocolValue(value) { + value = String(value || ''); + return /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(value) ? value : ''; + } + try { - socket = new WebSocket(wsUrl, protocol); + var protocolValue = websocketProtocolValue(protocol); + if (!protocolValue && ticket) { + append('[WebSSH] 票据已通过 URL 参数传递,当前浏览器不会发送子协议。\n'); + } + socket = protocolValue ? new WebSocket(wsUrl, protocolValue) : new WebSocket(wsUrl); socket.binaryType = 'arraybuffer'; } catch (e) { setState('err', '\nWebSocket 创建失败:' + e.message + '\n'); diff --git a/install-certbot.sh b/install-certbot.sh new file mode 100644 index 0000000..71c6a73 --- /dev/null +++ b/install-certbot.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -e + +echo "==============================" +echo " Certbot (Snap) Auto Installer" +echo "==============================" + +# 检测系统 +if [ -f /etc/os-release ]; then + . /etc/os-release + OS=$ID + VER=$VERSION_ID +else + echo "无法识别系统版本" + exit 1 +fi + +echo "检测到系统: $OS" + +install_snap_debian() { + apt update -y + apt install -y snapd + systemctl enable --now snapd.socket || true + + # 修复 snap 路径 + ln -sf /var/lib/snapd/snap /snap + + # 安装 certbot + snap install --classic certbot + + # 软链 + ln -sf /snap/bin/certbot /usr/bin/certbot +} + +install_snap_rhel() { + # 启用 EPEL(部分系统需要) + if command -v dnf >/dev/null 2>&1; then + dnf install -y epel-release || true + dnf install -y snapd + systemctl enable --now snapd.socket || true + else + yum install -y epel-release || true + yum install -y snapd + systemctl enable --now snapd.socket || true + fi + + # snap 经典路径 + ln -sf /var/lib/snapd/snap /snap + + # 安装 certbot + snap install --classic certbot + + # 软链 + ln -sf /snap/bin/certbot /usr/bin/certbot +} + +case "$OS" in + ubuntu|debian) + install_snap_debian + ;; + centos|rhel|almalinux|rocky) + install_snap_rhel + ;; + fedora) + dnf install -y snapd + systemctl enable --now snapd.socket || true + ln -sf /var/lib/snapd/snap /snap + snap install --classic certbot + ln -sf /snap/bin/certbot /usr/bin/certbot + ;; + *) + echo "不支持的系统: $OS" + exit 1 + ;; +esac + +echo "==============================" +echo "安装完成!验证版本:" +certbot --version || true +echo "==============================" \ No newline at end of file