diff --git a/app/lib/DeployHelper.php b/app/lib/DeployHelper.php index b06a550..2e5c804 100644 --- a/app/lib/DeployHelper.php +++ b/app/lib/DeployHelper.php @@ -489,6 +489,59 @@ class DeployHelper ], 'taskinputs' => [], ], + 'uusec' => [ + 'name' => '南墙WAF', + 'class' => 1, + 'icon' => 'waf.png', + 'desc' => '', + 'note' => null, + 'inputs' => [ + 'url' => [ + 'name' => '控制台地址', + 'type' => 'input', + 'placeholder' => '南墙WAF控制台地址', + 'note' => '填写规则如:http://192.168.1.100:4443 ,不要带其他后缀', + 'required' => true, + ], + 'username' => [ + 'name' => '用户名', + 'type' => 'input', + 'placeholder' => '', + 'required' => true, + ], + 'password' => [ + 'name' => '密码', + 'type' => 'input', + 'placeholder' => '', + 'required' => true, + ], + 'proxy' => [ + 'name' => '使用代理服务器', + 'type' => 'radio', + 'options' => [ + '0' => '否', + '1' => '是', + ], + 'value' => '0' + ], + ], + 'taskinputs' => [ + 'id' => [ + 'name' => '证书ID', + 'type' => 'input', + 'placeholder' => '', + 'note' => '在证书管理查看证书的ID,注意域名是否与证书匹配', + 'required' => true, + ], + 'name' => [ + 'name' => '证书名称', + 'type' => 'input', + 'placeholder' => '', + 'note' => '在证书管理查看证书的名称', + 'required' => true, + ], + ], + ], 'opanel' => [ 'name' => '1Panel', 'class' => 1, @@ -649,6 +702,47 @@ class DeployHelper ], ], ], + 'xp' => [ + 'name' => '小皮面板', + 'class' => 1, + 'icon' => 'xp.png', + 'desc' => '', + 'note' => null, + 'tasknote' => '', + 'inputs' => [ + 'url' => [ + 'name' => '面板地址', + 'type' => 'input', + 'placeholder' => '小皮面板地址', + 'note' => '填写规则如:http://192.168.1.100:8888 ,不要带其他后缀', + 'required' => true, + ], + 'apikey' => [ + 'name' => '接口密钥', + 'type' => 'input', + 'placeholder' => '设置->OpenAPI接口', + 'required' => true, + ], + 'proxy' => [ + 'name' => '使用代理服务器', + 'type' => 'radio', + 'options' => [ + '0' => '否', + '1' => '是', + ], + 'value' => '0' + ], + ], + 'taskinputs' => [ + 'sites' => [ + 'name' => '网站名称列表', + 'type' => 'textarea', + 'placeholder' => '填写要部署证书的网站名称,每行一个', + 'note' => '网站名称,即为网站创建时绑定的第一个域名', + 'required' => true, + ], + ], + ], 'synology' => [ 'name' => '群晖面板', 'class' => 1, diff --git a/app/lib/deploy/uusec.php b/app/lib/deploy/uusec.php new file mode 100644 index 0000000..f578643 --- /dev/null +++ b/app/lib/deploy/uusec.php @@ -0,0 +1,103 @@ +url = rtrim($config['url'], '/'); + $this->username = $config['username']; + $this->password = $config['password']; + $this->proxy = $config['proxy'] == 1; + } + + public function check() + { + if (empty($this->url) || empty($this->password) || empty($this->password)) throw new Exception('用户名和密码不能为空'); + $this->login(); + } + + public function deploy($fullchain, $privatekey, $config, &$info) + { + $id = $config['id']; + if (empty($id)) throw new Exception('证书ID不能为空'); + + $this->login(); + + $params = [ + 'id' => intval($id), + 'type' => 1, + 'name' => $config['name'], + 'crt' => $fullchain, + 'key' => $privatekey, + ]; + $result = $this->request('/api/v1/certs', $params, 'PUT'); + if (is_string($result) && $result == 'OK') { + $this->log('证书ID:' . $id . '更新成功!'); + } else { + throw new Exception('证书ID:' . $id . '更新失败,' . (isset($result['err']) ? $result['err'] : '未知错误')); + } + } + + private function login() + { + $path = '/api/v1/users/login'; + $params = [ + 'usr' => $this->username, + 'pwd' => $this->password, + 'otp' => '', + ]; + $result = $this->request($path, $params); + if (isset($result['token'])) { + $this->accessToken = $result['token']; + } else { + throw new Exception('登录失败,' . (isset($result['err']) ? $result['err'] : '未知错误')); + } + } + + private function request($path, $params = null, $method = null) + { + $url = $this->url . $path; + $headers = []; + $body = null; + if ($this->accessToken) { + $headers['Authorization'] = 'Bearer ' . $this->accessToken; + } + if ($params) { + $headers['Content-Type'] = 'application/json;charset=UTF-8'; + $body = json_encode($params); + } + $response = http_request($url, $body, null, null, $headers, $this->proxy, $method); + $result = json_decode($response['body'], true); + if ($response['code'] == 200) { + return $result; + } elseif (isset($result['message'])) { + throw new Exception($result['message']); + } else { + throw new Exception('请求失败,HTTP状态码:' . $response['code']); + } + } + + public function setLogger($func) + { + $this->logger = $func; + } + + private function log($txt) + { + if ($this->logger) { + call_user_func($this->logger, $txt); + } + } +} diff --git a/app/lib/deploy/xp.php b/app/lib/deploy/xp.php new file mode 100644 index 0000000..6d27201 --- /dev/null +++ b/app/lib/deploy/xp.php @@ -0,0 +1,113 @@ +url = rtrim($config['url'], '/'); + $this->apikey = $config['apikey']; + $this->proxy = $config['proxy'] == 1; + } + + public function check() + { + if (empty($this->url) || empty($this->apikey)) throw new Exception('请填写面板地址和接口密钥'); + + $path = '/openApi/siteList'; + $response = $this->request($path); + $result = json_decode($response, true); + if (isset($result['code']) && $result['code'] == 1000) { + return true; + } else { + throw new Exception(isset($result['message']) ? $result['message'] : '面板地址无法连接'); + } + } + + public function deploy($fullchain, $privatekey, $config, &$info) + { + $path = '/openApi/siteList'; + $response = $this->request($path); + $result = json_decode($response, true); + if (isset($result['code']) && $result['code'] == 1000) { + + $sites = explode("\n", $config['sites']); + $sites = array_map('trim', $sites); + $success = 0; + $errmsg = null; + + foreach ($result['data'] as $item) { + if (!in_array($item['name'], $sites)) { + continue; + } + try { + $this->deploySite($item['id'], $fullchain, $privatekey); + $this->log("网站 {$item['name']} 证书部署成功"); + $success++; + } catch (Exception $e) { + $errmsg = $e->getMessage(); + $this->log("网站 {$item['name']} 证书部署失败:" . $errmsg); + } + } + if ($success == 0) { + throw new Exception($errmsg ? $errmsg : '要部署的网站不存在'); + } + + } elseif (isset($result['message'])) { + throw new Exception($result['message']); + } else { + throw new Exception($response ? $response : '返回数据解析失败'); + } + } + + private function deploySite($id, $fullchain, $privatekey) + { + $path = '/openApi/setSSL'; + $data = [ + 'id' => $id, + 'key' => $privatekey, + 'pem' => $fullchain, + ]; + $response = $this->request($path, $data); + $result = json_decode($response, true); + if (isset($result['code']) && $result['code'] == 1000) { + return true; + } elseif (isset($result['message'])) { + throw new Exception($result['message']); + } else { + throw new Exception($response ? $response : '返回数据解析失败'); + } + } + + public function setLogger($func) + { + $this->logger = $func; + } + + private function log($txt) + { + if ($this->logger) { + call_user_func($this->logger, $txt); + } + } + + private function request($path, $params = null) + { + $url = $this->url . $path; + + $headers = [ + 'XP-API-KEY' => $this->apikey, + ]; + $response = http_request($url, $params ? json_encode($params) : null, null, null, $headers, $this->proxy); + return $response['body']; + } +} diff --git a/public/static/images/xp.png b/public/static/images/xp.png new file mode 100644 index 0000000..6894785 Binary files /dev/null and b/public/static/images/xp.png differ