mirror of
https://github.com/netcccyun/dnsmgr.git
synced 2026-05-09 23:16:27 +02:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c00e426cc | ||
|
|
814781c1d1 | ||
|
|
af2117faf0 | ||
|
|
9275256e36 | ||
|
|
d368a0190a | ||
|
|
684a4e59ce | ||
|
|
1bab48ad93 | ||
|
|
02718e58a9 | ||
|
|
8e563a89ff | ||
|
|
7f370a095d | ||
|
|
5aab54c79e | ||
|
|
ce9ae51aeb | ||
|
|
8b06cc5400 | ||
|
|
a71fd35f6f | ||
|
|
0d20d8ad46 | ||
|
|
ff676b7be1 | ||
|
|
8c7c568e5c | ||
|
|
a4698d67c6 | ||
|
|
5f0e973770 | ||
|
|
a99d0320df | ||
|
|
bb35ee3378 | ||
|
|
8193ade02d | ||
|
|
904c3ceb5b | ||
|
|
5add791ef1 | ||
|
|
3587db2b53 | ||
|
|
4a4cdd059c | ||
|
|
1021deb60d | ||
|
|
848610ffe0 | ||
|
|
767aec5ebc | ||
|
|
30912fdf75 | ||
|
|
5050af2f73 | ||
|
|
6418c3a2ee | ||
|
|
efd18676f3 | ||
|
|
5ba7c324af | ||
|
|
236610d8fb | ||
|
|
0015015b7a | ||
|
|
f776b9f47f | ||
|
|
0860624bd5 | ||
|
|
e328dc6808 | ||
|
|
e58d8f4af1 | ||
|
|
9d4260062c | ||
|
|
17c50e4ba1 |
15
.github/dependabot.yml
vendored
Normal file
15
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Dependabot configuration.
|
||||
#
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/code-security/dependabot/working-with-dependabot/dependabot-options-reference
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "composer"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,4 +3,3 @@
|
||||
/vendor
|
||||
*.log
|
||||
.env
|
||||
/composer.lock
|
||||
|
||||
15
README.md
15
README.md
@@ -29,7 +29,7 @@
|
||||
|
||||
* 从[Release](https://github.com/netcccyun/dnsmgr/releases)页面下载安装包
|
||||
|
||||
* 运行环境要求PHP7.4+,MySQL5.6+
|
||||
* 运行环境要求PHP8.0+,MySQL5.6+
|
||||
|
||||
* 设置网站运行目录为`public`
|
||||
|
||||
@@ -52,10 +52,13 @@
|
||||
* Nginx
|
||||
|
||||
```
|
||||
location ~* (runtime|application)/ {
|
||||
return 403;
|
||||
}
|
||||
location / {
|
||||
if (!-e $request_filename){
|
||||
rewrite ^(.*)$ /index.php?s=$1 last; break;
|
||||
}
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?s=$1 last; break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -195,6 +198,10 @@ SSL证书自动部署功能
|
||||
|
||||
⭐ 如果您觉得本项目对您有帮助,欢迎给项目点个 Star
|
||||
|
||||
🤝 捐赠:
|
||||
|
||||
<img height="240" src="https://wkphoto.bj.bcebos.com/d8f9d72a6059252db065f556249b033b5bb5b976.jpg">
|
||||
|
||||
### 其他推荐
|
||||
|
||||
- [彩虹云主机 - 免备案CDN/虚拟主机](https://www.cccyun.net/)
|
||||
|
||||
324
app/common.php
324
app/common.php
@@ -1,50 +1,54 @@
|
||||
<?php
|
||||
// 应用公共文件
|
||||
use think\facade\Db;
|
||||
use think\facade\Config;
|
||||
use think\facade\Request;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
function get_curl($url, $post = 0, $referer = 0, $cookie = 0, $header = 0, $ua = 0, $nobody = 0, $addheader = 0)
|
||||
function get_curl($url, $post = 0, $referer = 0, $cookie = 0, $ua = 0, $nobody = 0, $addheader = [])
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: close";
|
||||
if ($addheader) {
|
||||
$httpheader = array_merge($httpheader, $addheader);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
if ($post) {
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||
}
|
||||
if ($header) {
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
$options = [
|
||||
'timeout' => 10,
|
||||
'verify' => false,
|
||||
'headers' => [
|
||||
'User-Agent' => $ua ?: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
|
||||
],
|
||||
'http_errors' => false // 不抛出异常
|
||||
];
|
||||
|
||||
$options['headers'] = array_merge($options['headers'], $addheader);
|
||||
if ($referer) {
|
||||
$options['headers']['Referer'] = $referer;
|
||||
}
|
||||
if ($cookie) {
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
|
||||
$options['headers']['Cookie'] = $cookie;
|
||||
}
|
||||
if ($referer) {
|
||||
curl_setopt($ch, CURLOPT_REFERER, $referer);
|
||||
|
||||
$method = 'GET';
|
||||
if ($post) {
|
||||
$method = 'POST';
|
||||
if (!isset($options['headers']['Content-Type'])) {
|
||||
$options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
if (is_array($post)) {
|
||||
$options['form_params'] = $post;
|
||||
} else {
|
||||
$options['body'] = $post;
|
||||
}
|
||||
}
|
||||
if ($ua) {
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $ua);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Linux; U; Android 4.0.4; es-mx; HTC_One_X Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0");
|
||||
|
||||
try {
|
||||
$client = new Client();
|
||||
$response = $client->request($method, $url, $options);
|
||||
|
||||
if ($nobody) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $response->getBody()->getContents();
|
||||
} catch (GuzzleException $e) {
|
||||
return '';
|
||||
}
|
||||
if ($nobody) {
|
||||
curl_setopt($ch, CURLOPT_NOBODY, 1);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$ret = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function real_ip($type = 0)
|
||||
@@ -319,45 +323,41 @@ function getMainDomain($host)
|
||||
|
||||
function check_proxy($url, $proxy_server, $proxy_port, $type, $proxy_user, $proxy_pwd)
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
if ($type == 'https') {
|
||||
$proxy_type = CURLPROXY_HTTPS;
|
||||
} elseif ($type == 'sock4') {
|
||||
$proxy_type = CURLPROXY_SOCKS4;
|
||||
} elseif ($type == 'sock5') {
|
||||
$proxy_type = CURLPROXY_SOCKS5;
|
||||
} else {
|
||||
$proxy_type = CURLPROXY_HTTP;
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
|
||||
curl_setopt($ch, CURLOPT_PROXY, $proxy_server);
|
||||
curl_setopt($ch, CURLOPT_PROXYPORT, intval($proxy_port));
|
||||
match ($type) {
|
||||
'https' => $proxy_string = 'https://',
|
||||
'sock4' => $proxy_string = 'socks4://',
|
||||
'sock5' => $proxy_string = 'socks5://',
|
||||
'sock5h' => $proxy_string = 'socks5h://',
|
||||
default => $proxy_string = 'http://',
|
||||
};
|
||||
|
||||
if (!empty($proxy_user) && !empty($proxy_pwd)) {
|
||||
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy_user . ':' . $proxy_pwd);
|
||||
$proxy_string .= $proxy_user . ':' . $proxy_pwd . '@';
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_PROXYTYPE, $proxy_type);
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: close";
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36');
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
|
||||
curl_exec($ch);
|
||||
$errno = curl_errno($ch);
|
||||
if ($errno) {
|
||||
$errmsg = curl_error($ch);
|
||||
curl_close($ch);
|
||||
throw new Exception($errmsg);
|
||||
}
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
if ($httpCode >= 200 && $httpCode < 400) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Exception('HTTP状态码异常:' . $httpCode);
|
||||
|
||||
$proxy_string .= $proxy_server . ':' . intval($proxy_port);
|
||||
$options = [
|
||||
'proxy' => $proxy_string,
|
||||
'timeout' => 3,
|
||||
'connect_timeout' => 3,
|
||||
'verify' => false,
|
||||
'headers' => [
|
||||
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
|
||||
]
|
||||
];
|
||||
|
||||
try {
|
||||
$client = new Client();
|
||||
$response = $client->request('GET', $url, $options);
|
||||
$httpCode = $response->getStatusCode();
|
||||
|
||||
if ($httpCode >= 200 && $httpCode < 400) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Exception('HTTP状态码异常:' . $httpCode);
|
||||
}
|
||||
} catch (GuzzleException $e) {
|
||||
throw new Exception(guzzle_error($e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,59 +392,151 @@ function clearDirectory($dir): bool
|
||||
return true;
|
||||
}
|
||||
|
||||
function curl_client($url, $data = null, $referer = null, $cookie = null, $headers = null, $proxy = false, $method = null, $timeout = 5, $default_headers = true)
|
||||
/**
|
||||
* 发送 HTTP 请求
|
||||
*
|
||||
* @param string $url 请求URL
|
||||
* @param mixed $data 请求数据,可以是字符串或数组,数组将自动根据请求方法及传入的 Content-Type 头序列化
|
||||
* @param string|null $referer 请求的 Referer 头
|
||||
* @param array|null $cookie 请求的 Cookie 头
|
||||
* @param array|null $headers 其他自定义请求头
|
||||
* @param bool $proxy 是否使用代理
|
||||
* @param string|null $method 请求方法,默认为 GET 或 POST(如果存在请求数据)
|
||||
* @param int $timeout 请求超时时间,默认为 10 秒
|
||||
* @return array 包含 HTTP 状态码、重定向 URL、响应头和响应体的数组
|
||||
* @throws Exception
|
||||
*/
|
||||
function http_request($url, $data = null, $referer = null, $cookie = null, $headers = null, $proxy = false, $method = null, $timeout = 10): array
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
if ($default_headers === true) {
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: close";
|
||||
if ($headers) {
|
||||
$httpheader = array_merge($headers, $httpheader);
|
||||
}
|
||||
} else {
|
||||
$httpheader = $headers;
|
||||
$options = [
|
||||
'timeout' => $timeout,
|
||||
'connect_timeout' => $timeout,
|
||||
'allow_redirects' => false,
|
||||
'verify' => false,
|
||||
'headers' => [
|
||||
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
|
||||
],
|
||||
'http_errors' => false // 不抛出异常
|
||||
];
|
||||
|
||||
// 默认请求方法
|
||||
if (!$method) {
|
||||
$method = $data ? 'POST' : 'GET';
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36");
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
if ($data) {
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||
// 处理头部
|
||||
if (is_array($headers)) {
|
||||
$options['headers'] = array_merge($options['headers'], $headers);
|
||||
}
|
||||
// 处理Cookie
|
||||
if ($cookie) {
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
|
||||
$options['headers']['Cookie'] = $cookie;
|
||||
}
|
||||
// 处理Referer
|
||||
if ($referer) {
|
||||
curl_setopt($ch, CURLOPT_REFERER, $referer);
|
||||
$options['headers']['Referer'] = $referer;
|
||||
}
|
||||
if ($method) {
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
// 处理数据
|
||||
if ($data) {
|
||||
if ($method !== 'GET') {
|
||||
if (is_string($data)) {
|
||||
$options['body'] = $data;
|
||||
if (!isset($options['headers']['Content-Type'])) {
|
||||
if (json_validate($data)) {
|
||||
// json
|
||||
$options['headers']['Content-Type'] = 'application/json';
|
||||
} elseif (str_contains($data, '=') || str_contains($data, '&')) {
|
||||
// 表单
|
||||
$options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
}
|
||||
} else if (is_array($data) || is_object($data)) {
|
||||
if (!isset($options['headers']['Content-Type'])) {
|
||||
// 默认为表单
|
||||
$options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
if ($options['headers']['Content-Type'] == 'application/x-www-form-urlencoded') {
|
||||
// 表单
|
||||
$options['form_params'] = $data;
|
||||
} else if ($options['headers']['Content-Type'] == 'application/json') {
|
||||
// json
|
||||
$options['json'] = $data;
|
||||
} else {
|
||||
// 其他
|
||||
$options['body'] = http_build_query($data);
|
||||
}
|
||||
} else {
|
||||
$options['body'] = $data;
|
||||
}
|
||||
} else {
|
||||
// 兼容已经存在查询字符串的情况
|
||||
if (!str_contains($url, '?')) {
|
||||
$options['query'] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理代理
|
||||
if ($proxy) {
|
||||
curl_set_proxy($ch);
|
||||
$proxy_server = config_get('proxy_server');
|
||||
$proxy_port = intval(config_get('proxy_port'));
|
||||
$proxy_userpwd = config_get('proxy_user').':'.config_get('proxy_pwd');
|
||||
$proxy_type = config_get('proxy_type');
|
||||
|
||||
if (empty($proxy_server) || empty($proxy_port)) {
|
||||
throw new Exception('代理服务器或端口未配置');
|
||||
}
|
||||
|
||||
match ($proxy_type) {
|
||||
'https' => $proxy_string = 'https://',
|
||||
'sock4' => $proxy_string = 'socks4://',
|
||||
'sock5' => $proxy_string = 'socks5://',
|
||||
'sock5h' => $proxy_string = 'socks5h://',
|
||||
default => $proxy_string = 'http://',
|
||||
};
|
||||
|
||||
if ($proxy_userpwd != ':') {
|
||||
$proxy_string .= $proxy_userpwd . '@';
|
||||
}
|
||||
|
||||
$proxy_string .= $proxy_server . ':' . $proxy_port;
|
||||
$options['proxy'] = $proxy_string;
|
||||
}
|
||||
|
||||
$ret = curl_exec($ch);
|
||||
$errno = curl_errno($ch);
|
||||
if ($errno) {
|
||||
$errmsg = curl_error($ch);
|
||||
curl_close($ch);
|
||||
throw new Exception('Curl error: ' . $errmsg);
|
||||
try {
|
||||
$client = new Client();
|
||||
$response = $client->request($method, $url, $options);
|
||||
$code = $response->getStatusCode();
|
||||
|
||||
// 取重定向URL
|
||||
$redirect_url = '';
|
||||
if ($code >= 300 && $code < 400) {
|
||||
$redirect_url = $response->getHeaderLine('Location');
|
||||
}
|
||||
|
||||
return [
|
||||
'code' => $code,
|
||||
'redirect_url' => $redirect_url,
|
||||
'headers' => $response->getHeaders(),
|
||||
'body' => $response->getBody()->getContents()
|
||||
];
|
||||
} catch (GuzzleException $e) {
|
||||
throw new Exception('请求失败: ' . guzzle_error($e));
|
||||
}
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$redirect_url = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
|
||||
curl_close($ch);
|
||||
$header = substr($ret, 0, $headerSize);
|
||||
$body = substr($ret, $headerSize);
|
||||
return ['code' => $httpCode, 'redirect_url' => $redirect_url, 'header' => $header, 'body' => $body];
|
||||
}
|
||||
|
||||
function guzzle_error($e)
|
||||
{
|
||||
$errmsg = $e->getMessage();
|
||||
if (preg_match('/^cURL error \d+: /', $errmsg)) {
|
||||
$errmsg = preg_replace('/^cURL error \d+: /', '', $errmsg);
|
||||
}
|
||||
$pos = strpos($errmsg, ' (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)');
|
||||
if ($pos !== false) {
|
||||
$errmsg = substr($errmsg, 0, $pos);
|
||||
}
|
||||
if (strlen($errmsg) > 100) {
|
||||
$errmsg = substr($errmsg, 0, 97) . '...';
|
||||
}
|
||||
return $errmsg;
|
||||
}
|
||||
|
||||
function curl_set_proxy(&$ch)
|
||||
@@ -462,6 +554,8 @@ function curl_set_proxy(&$ch)
|
||||
$proxy_type = CURLPROXY_SOCKS4;
|
||||
} elseif ($proxy_type == 'sock5') {
|
||||
$proxy_type = CURLPROXY_SOCKS5;
|
||||
} elseif ($proxy_type == 'sock5h') {
|
||||
$proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
|
||||
} else {
|
||||
$proxy_type = CURLPROXY_HTTP;
|
||||
}
|
||||
@@ -496,7 +590,7 @@ function getDomainDate($domain)
|
||||
$info = $whois->loadDomainInfo($domain);
|
||||
if ($info) {
|
||||
if ($info->expirationDate > 0) {
|
||||
return [date('Y-m-d H:i:s', $info->creationDate), date('Y-m-d H:i:s', $info->expirationDate)];
|
||||
return [$info->creationDate > 0 ? date('Y-m-d H:i:s', $info->creationDate) : null, date('Y-m-d H:i:s', $info->expirationDate)];
|
||||
} else {
|
||||
throw new Exception('域名到期时间未知');
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class Auth extends BaseController
|
||||
if (empty($username) || empty($password)) {
|
||||
return json(['code' => -1, 'msg' => '用户名或密码不能为空']);
|
||||
}
|
||||
if (!captcha_check($code)) {
|
||||
if (config_get('vcode', '1') == '1' && !captcha_check($code)) {
|
||||
return json(['code' => -1, 'msg' => '验证码错误', 'vcode' => 1]);
|
||||
}
|
||||
if (file_exists($login_limit_file)) {
|
||||
|
||||
@@ -43,8 +43,17 @@ class Cert extends BaseController
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $row) {
|
||||
$row['typename'] = $deploy == 1 ? DeployHelper::$deploy_config[$row['type']]['name'] : CertHelper::$cert_config[$row['type']]['name'];
|
||||
$row['icon'] = $deploy == 1 ? DeployHelper::$deploy_config[$row['type']]['icon'] : CertHelper::$cert_config[$row['type']]['icon'];
|
||||
if ($deploy == 1) {
|
||||
if (!empty($row['type']) && isset(DeployHelper::$deploy_config[$row['type']])) {
|
||||
$row['typename'] = DeployHelper::$deploy_config[$row['type']]['name'];
|
||||
$row['icon'] = DeployHelper::$deploy_config[$row['type']]['icon'];
|
||||
}
|
||||
} else {
|
||||
if (!empty($row['type']) && isset(CertHelper::$cert_config[$row['type']])) {
|
||||
$row['typename'] = CertHelper::$cert_config[$row['type']]['name'];
|
||||
$row['icon'] = CertHelper::$cert_config[$row['type']]['icon'];
|
||||
}
|
||||
}
|
||||
$list[] = $row;
|
||||
}
|
||||
|
||||
@@ -66,7 +75,7 @@ class Cert extends BaseController
|
||||
if ($type == 'local') $name = '复制到本机';
|
||||
if (empty($name) || empty($config)) return json(['code' => -1, 'msg' => '必填参数不能为空']);
|
||||
if (Db::name('cert_account')->where('type', $type)->where('config', $config)->find()) {
|
||||
return json(['code' => -1, 'msg' => $title.'已存在']);
|
||||
return json(['code' => -1, 'msg' => $title . '已存在']);
|
||||
}
|
||||
Db::startTrans();
|
||||
$id = Db::name('cert_account')->insertGetId([
|
||||
@@ -80,15 +89,15 @@ class Cert extends BaseController
|
||||
try {
|
||||
$this->checkAccount($id, $type, $deploy);
|
||||
Db::commit();
|
||||
return json(['code' => 0, 'msg' => '添加'.$title.'成功!']);
|
||||
} catch(Exception $e) {
|
||||
return json(['code' => 0, 'msg' => '添加' . $title . '成功!']);
|
||||
} catch (Exception $e) {
|
||||
Db::rollback();
|
||||
return json(['code' => -1, 'msg' => $e->getMessage()]);
|
||||
}
|
||||
} elseif ($action == 'edit') {
|
||||
$id = input('post.id/d');
|
||||
$row = Db::name('cert_account')->where('id', $id)->find();
|
||||
if (!$row) return json(['code' => -1, 'msg' => $title.'不存在']);
|
||||
if (!$row) return json(['code' => -1, 'msg' => $title . '不存在']);
|
||||
$type = input('post.type');
|
||||
$name = input('post.name', null, 'trim');
|
||||
$config = input('post.config', null, 'trim');
|
||||
@@ -96,7 +105,7 @@ class Cert extends BaseController
|
||||
if ($type == 'local') $name = '复制到本机';
|
||||
if (empty($name) || empty($config)) return json(['code' => -1, 'msg' => '必填参数不能为空']);
|
||||
if (Db::name('cert_account')->where('type', $type)->where('config', $config)->where('id', '<>', $id)->find()) {
|
||||
return json(['code' => -1, 'msg' => $title.'已存在']);
|
||||
return json(['code' => -1, 'msg' => $title . '已存在']);
|
||||
}
|
||||
Db::startTrans();
|
||||
Db::name('cert_account')->where('id', $id)->update([
|
||||
@@ -108,19 +117,19 @@ class Cert extends BaseController
|
||||
try {
|
||||
$this->checkAccount($id, $type, $deploy);
|
||||
Db::commit();
|
||||
return json(['code' => 0, 'msg' => '修改'.$title.'成功!']);
|
||||
} catch(Exception $e) {
|
||||
return json(['code' => 0, 'msg' => '修改' . $title . '成功!']);
|
||||
} catch (Exception $e) {
|
||||
Db::rollback();
|
||||
return json(['code' => -1, 'msg' => $e->getMessage()]);
|
||||
}
|
||||
} elseif ($action == 'del') {
|
||||
$id = input('post.id/d');
|
||||
if($deploy == 0){
|
||||
if ($deploy == 0) {
|
||||
$dcount = DB::name('cert_order')->where('aid', $id)->count();
|
||||
if ($dcount > 0) return json(['code' => -1, 'msg' => '该'.$title.'下存在证书订单,无法删除']);
|
||||
}else{
|
||||
if ($dcount > 0) return json(['code' => -1, 'msg' => '该' . $title . '下存在证书订单,无法删除']);
|
||||
} else {
|
||||
$dcount = DB::name('cert_deploy')->where('aid', $id)->count();
|
||||
if ($dcount > 0) return json(['code' => -1, 'msg' => '该'.$title.'下存在自动部署任务,无法删除']);
|
||||
if ($dcount > 0) return json(['code' => -1, 'msg' => '该' . $title . '下存在自动部署任务,无法删除']);
|
||||
}
|
||||
Db::name('cert_account')->where('id', $id)->delete();
|
||||
return json(['code' => 0]);
|
||||
@@ -139,7 +148,7 @@ class Cert extends BaseController
|
||||
if ($action == 'edit') {
|
||||
$id = input('get.id/d');
|
||||
$account = Db::name('cert_account')->where('id', $id)->find();
|
||||
if (empty($account)) return $this->alert('error', $title.'不存在');
|
||||
if (empty($account)) return $this->alert('error', $title . '不存在');
|
||||
}
|
||||
|
||||
$typeList = $deploy == 1 ? DeployHelper::getList() : CertHelper::getList();
|
||||
@@ -156,32 +165,32 @@ class Cert extends BaseController
|
||||
|
||||
private function checkAccount($id, $type, $deploy)
|
||||
{
|
||||
if($deploy == 0){
|
||||
if ($deploy == 0) {
|
||||
$mod = CertHelper::getModel($id);
|
||||
if($mod){
|
||||
try{
|
||||
if ($mod) {
|
||||
try {
|
||||
$ext = $mod->register();
|
||||
if(is_array($ext)){
|
||||
Db::name('cert_account')->where('id', $id)->update(['ext'=>json_encode($ext)]);
|
||||
if (is_array($ext)) {
|
||||
Db::name('cert_account')->where('id', $id)->update(['ext' => json_encode($ext)]);
|
||||
}
|
||||
return true;
|
||||
}catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('验证SSL证书账户失败,' . $e->getMessage());
|
||||
}
|
||||
}else{
|
||||
throw new Exception('SSL证书申请模块'.$type.'不存在');
|
||||
} else {
|
||||
throw new Exception('SSL证书申请模块' . $type . '不存在');
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
$mod = DeployHelper::getModel($id);
|
||||
if($mod){
|
||||
try{
|
||||
if ($mod) {
|
||||
try {
|
||||
$mod->check();
|
||||
return true;
|
||||
}catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('验证自动部署账户失败,' . $e->getMessage());
|
||||
}
|
||||
}else{
|
||||
throw new Exception('SSL证书申请模块'.$type.'不存在');
|
||||
} else {
|
||||
throw new Exception('SSL证书申请模块' . $type . '不存在');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,7 +199,7 @@ class Cert extends BaseController
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$types = [];
|
||||
foreach(CertHelper::$cert_config as $key=>$value){
|
||||
foreach (CertHelper::$cert_config as $key => $value) {
|
||||
$types[$key] = $value['name'];
|
||||
}
|
||||
View::assign('types', $types);
|
||||
@@ -202,18 +211,22 @@ class Cert extends BaseController
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$domain = $this->request->post('domain', null, 'trim');
|
||||
$id = input('post.id');
|
||||
$aid = input('post.aid', null, 'trim');
|
||||
$type = input('post.type', null, 'trim');
|
||||
$status = input('post.status', null, 'trim');
|
||||
$offset = input('post.offset/d');
|
||||
$limit = input('post.limit/d');
|
||||
|
||||
$select = Db::name('cert_order')->alias('A')->join('cert_account B', 'A.aid = B.id');
|
||||
$select = Db::name('cert_order')->alias('A')->leftJoin('cert_account B', 'A.aid = B.id');
|
||||
if (!empty($id)) {
|
||||
$select->where('A.id', $id);
|
||||
}elseif (!empty($domain)) {
|
||||
} elseif (!empty($domain)) {
|
||||
$oids = Db::name('cert_domain')->where('domain', 'like', '%' . $domain . '%')->column('oid');
|
||||
$select->whereIn('A.id', $oids);
|
||||
}
|
||||
if (!empty($aid)) {
|
||||
$select->where('A.aid', $aid);
|
||||
}
|
||||
if (!empty($type)) {
|
||||
$select->where('B.type', $type);
|
||||
}
|
||||
@@ -233,11 +246,15 @@ class Cert extends BaseController
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $row) {
|
||||
$row['typename'] = CertHelper::$cert_config[$row['type']]['name'];
|
||||
$row['icon'] = CertHelper::$cert_config[$row['type']]['icon'];
|
||||
$row['domains'] = Db::name('cert_domain')->where('oid', $row['id'])->order('sort','ASC')->column('domain');
|
||||
if (!empty($row['type']) && isset(CertHelper::$cert_config[$row['type']])) {
|
||||
$row['typename'] = CertHelper::$cert_config[$row['type']]['name'];
|
||||
$row['icon'] = CertHelper::$cert_config[$row['type']]['icon'];
|
||||
} else {
|
||||
$row['typename'] = null;
|
||||
}
|
||||
$row['domains'] = Db::name('cert_domain')->where('oid', $row['id'])->order('sort', 'ASC')->column('domain');
|
||||
$row['end_day'] = $row['expiretime'] ? ceil((strtotime($row['expiretime']) - time()) / 86400) : null;
|
||||
if($row['error']) $row['error'] = htmlspecialchars(str_replace("'", "\\'", $row['error']));
|
||||
if ($row['error']) $row['error'] = htmlspecialchars(str_replace("'", "\\'", $row['error']));
|
||||
$list[] = $row;
|
||||
}
|
||||
|
||||
@@ -252,7 +269,7 @@ class Cert extends BaseController
|
||||
if (!$row) return json(['code' => -1, 'msg' => '证书订单不存在']);
|
||||
$pfx = CertHelper::getPfx($row['fullchain'], $row['privatekey']);
|
||||
$row['pfx'] = base64_encode($pfx);
|
||||
return json(['code' => 0, 'data' => ['id' => $row['id'], 'crt' => $row['fullchain'], 'key' => $row['privatekey'], 'pfx' => $row['pfx'], 'issuetime' => $row['issuetime'], 'expiretime' => $row['expiretime'], 'domains' => Db::name('cert_domain')->where('oid', $row['id'])->order('sort','ASC')->column('domain')]]);
|
||||
return json(['code' => 0, 'data' => ['id' => $row['id'], 'crt' => $row['fullchain'], 'key' => $row['privatekey'], 'pfx' => $row['pfx'], 'issuetime' => $row['issuetime'], 'expiretime' => $row['expiretime'], 'domains' => Db::name('cert_domain')->where('oid', $row['id'])->order('sort', 'ASC')->column('domain')]]);
|
||||
}
|
||||
|
||||
public function order_op()
|
||||
@@ -268,32 +285,66 @@ class Cert extends BaseController
|
||||
$row['pfx'] = base64_encode($pfx);
|
||||
return json(['code' => 0, 'data' => $row]);
|
||||
} elseif ($action == 'add') {
|
||||
$domains = input('post.domains', [], 'trim');
|
||||
$order = [
|
||||
'aid' => input('post.aid/d'),
|
||||
'keytype' => input('post.keytype'),
|
||||
'keysize' => input('post.keysize'),
|
||||
'addtime' => date('Y-m-d H:i:s'),
|
||||
'issuer' => '',
|
||||
'status' => 0,
|
||||
'isauto' => 1,
|
||||
];
|
||||
$domains = array_map('trim', $domains);
|
||||
$domains = array_filter($domains, function ($v) {
|
||||
return !empty($v);
|
||||
});
|
||||
$domains = array_unique($domains);
|
||||
if (empty($domains)) return json(['code' => -1, 'msg' => '绑定域名不能为空']);
|
||||
if (empty($order['aid']) || empty($order['keytype']) || empty($order['keysize'])) return json(['code' => -1, 'msg' => '必填参数不能为空']);
|
||||
$aid = input('post.aid/d');
|
||||
|
||||
$res = $this->check_order($order, $domains);
|
||||
if (is_array($res)) return json($res);
|
||||
if ($aid == -1) {
|
||||
$fullchain = input('post.fullchain', null, 'trim');
|
||||
$privatekey = input('post.privatekey', null, 'trim');
|
||||
$certInfo = $this->parse_cert_key($fullchain, $privatekey);
|
||||
if ($certInfo['code'] == -1) return json($certInfo);
|
||||
$domains = $certInfo['domains'];
|
||||
|
||||
$order_ids = Db::name('cert_order')->where('issuetime', $certInfo['issuetime'])->column('id');
|
||||
if (!empty($order_ids)) {
|
||||
foreach ($order_ids as $order_id) {
|
||||
$domains2 = Db::name('cert_domain')->where('oid', $order_id)->column('domain');
|
||||
if (arrays_are_equal($domains2, $domains)) {
|
||||
return json(['code' => -1, 'msg' => '该证书已存在,无需重复添加']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$order = [
|
||||
'aid' => 0,
|
||||
'keytype' => $certInfo['keytype'],
|
||||
'keysize' => $certInfo['keysize'],
|
||||
'addtime' => date('Y-m-d H:i:s'),
|
||||
'updatetime' => date('Y-m-d H:i:s'),
|
||||
'issuetime' => $certInfo['issuetime'],
|
||||
'expiretime' => $certInfo['expiretime'],
|
||||
'issuer' => $certInfo['issuer'],
|
||||
'status' => 3,
|
||||
'isauto' => 1,
|
||||
'fullchain' => $fullchain,
|
||||
'privatekey' => $privatekey,
|
||||
];
|
||||
} else {
|
||||
$order = [
|
||||
'aid' => $aid,
|
||||
'keytype' => input('post.keytype'),
|
||||
'keysize' => input('post.keysize'),
|
||||
'addtime' => date('Y-m-d H:i:s'),
|
||||
'issuer' => '',
|
||||
'status' => 0,
|
||||
'isauto' => 1,
|
||||
];
|
||||
$domains = input('post.domains', [], 'trim');
|
||||
$domains = array_map('trim', $domains);
|
||||
$domains = array_filter($domains, function ($v) {
|
||||
return !empty($v);
|
||||
});
|
||||
$domains = array_unique($domains);
|
||||
if (empty($domains)) return json(['code' => -1, 'msg' => '绑定域名不能为空']);
|
||||
$res = $this->check_order($order, $domains);
|
||||
if (is_array($res)) return json($res);
|
||||
}
|
||||
if (empty($order['keytype']) || empty($order['keysize'])) return json(['code' => -1, 'msg' => '必填参数不能为空']);
|
||||
|
||||
Db::startTrans();
|
||||
$id = Db::name('cert_order')->insertGetId($order);
|
||||
$domainList = [];
|
||||
$i=1;
|
||||
foreach($domains as $domain){
|
||||
$i = 1;
|
||||
foreach ($domains as $domain) {
|
||||
$domainList[] = [
|
||||
'oid' => $id,
|
||||
'domain' => convertDomainToAscii($domain),
|
||||
@@ -307,31 +358,53 @@ class Cert extends BaseController
|
||||
$id = input('post.id/d');
|
||||
$row = Db::name('cert_order')->where('id', $id)->find();
|
||||
if (!$row) return json(['code' => -1, 'msg' => '证书订单不存在']);
|
||||
|
||||
$domains = input('post.domains', [], 'trim');
|
||||
$order = [
|
||||
'aid' => input('post.aid/d'),
|
||||
'keytype' => input('post.keytype'),
|
||||
'keysize' => input('post.keysize'),
|
||||
'updatetime' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
$domains = array_map('trim', $domains);
|
||||
$domains = array_filter($domains, function ($v) {
|
||||
return !empty($v);
|
||||
});
|
||||
$domains = array_unique($domains);
|
||||
if (empty($domains)) return json(['code' => -1, 'msg' => '绑定域名不能为空']);
|
||||
if (empty($order['aid']) || empty($order['keytype']) || empty($order['keysize'])) return json(['code' => -1, 'msg' => '必填参数不能为空']);
|
||||
|
||||
$res = $this->check_order($order, $domains);
|
||||
if (is_array($res)) return json($res);
|
||||
$aid = input('post.aid/d');
|
||||
if ($aid == -1) {
|
||||
$fullchain = input('post.fullchain', null, 'trim');
|
||||
$privatekey = input('post.privatekey', null, 'trim');
|
||||
$certInfo = $this->parse_cert_key($fullchain, $privatekey);
|
||||
if ($certInfo['code'] == -1) return json($certInfo);
|
||||
$domains = $certInfo['domains'];
|
||||
|
||||
$order = [
|
||||
'aid' => 0,
|
||||
'keytype' => $certInfo['keytype'],
|
||||
'keysize' => $certInfo['keysize'],
|
||||
'updatetime' => date('Y-m-d H:i:s'),
|
||||
'issuetime' => $certInfo['issuetime'],
|
||||
'expiretime' => $certInfo['expiretime'],
|
||||
'issuer' => $certInfo['issuer'],
|
||||
'status' => 3,
|
||||
'issend' => 0,
|
||||
'fullchain' => $fullchain,
|
||||
'privatekey' => $privatekey,
|
||||
];
|
||||
} else {
|
||||
$domains = input('post.domains', [], 'trim');
|
||||
$order = [
|
||||
'aid' => $aid,
|
||||
'keytype' => input('post.keytype'),
|
||||
'keysize' => input('post.keysize'),
|
||||
'updatetime' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
$domains = array_map('trim', $domains);
|
||||
$domains = array_filter($domains, function ($v) {
|
||||
return !empty($v);
|
||||
});
|
||||
$domains = array_unique($domains);
|
||||
if (empty($domains)) return json(['code' => -1, 'msg' => '绑定域名不能为空']);
|
||||
$res = $this->check_order($order, $domains);
|
||||
if (is_array($res)) return json($res);
|
||||
}
|
||||
if (empty($order['keytype']) || empty($order['keysize'])) return json(['code' => -1, 'msg' => '必填参数不能为空']);
|
||||
|
||||
Db::startTrans();
|
||||
Db::name('cert_order')->where('id', $id)->update($order);
|
||||
Db::name('cert_domain')->where('oid', $id)->delete();
|
||||
$domainList = [];
|
||||
$i=1;
|
||||
foreach($domains as $domain){
|
||||
$i = 1;
|
||||
foreach ($domains as $domain) {
|
||||
$domainList[] = [
|
||||
'oid' => $id,
|
||||
'domain' => convertDomainToAscii($domain),
|
||||
@@ -341,79 +414,13 @@ class Cert extends BaseController
|
||||
Db::name('cert_domain')->insertAll($domainList);
|
||||
Db::commit();
|
||||
return json(['code' => 0, 'msg' => '修改证书订单成功!']);
|
||||
} elseif ($action == 'import') {
|
||||
$fullchain = input('post.fullchain', null, 'trim');
|
||||
$privatekey = input('post.privatekey', null, 'trim');
|
||||
if (!openssl_x509_read($fullchain)) return json(['code' => -1, 'msg' => '证书内容填写错误']);
|
||||
if (!openssl_get_privatekey($privatekey)) return json(['code' => -1, 'msg' => '私钥内容填写错误']);
|
||||
if (!openssl_x509_check_private_key($fullchain, $privatekey)) return json(['code' => -1, 'msg' => 'SSL证书与私钥不匹配']);
|
||||
$certInfo = openssl_x509_parse($fullchain, true);
|
||||
if (!$certInfo || !isset($certInfo['extensions']['subjectAltName'])) return json(['code' => -1, 'msg' => '证书内容解析失败']);
|
||||
|
||||
$domains = [];
|
||||
$subjectAltName = explode(',', $certInfo['extensions']['subjectAltName']);
|
||||
foreach ($subjectAltName as $domain) {
|
||||
$domain = trim($domain);
|
||||
if (strpos($domain, 'DNS:') === 0) $domain = substr($domain, 4);
|
||||
if (!empty($domain)) {
|
||||
$domains[] = $domain;
|
||||
}
|
||||
}
|
||||
$domains = array_unique($domains);
|
||||
if (empty($domains)) return json(['code' => -1, 'msg' => '证书绑定域名不能为空']);
|
||||
$issuetime = date('Y-m-d H:i:s', $certInfo['validFrom_time_t']);
|
||||
$expiretime = date('Y-m-d H:i:s', $certInfo['validTo_time_t']);
|
||||
$issuer = $certInfo['issuer']['CN'];
|
||||
|
||||
$order_ids = Db::name('cert_order')->where('issuetime', $issuetime)->column('id');
|
||||
if (!empty($order_ids)) {
|
||||
foreach ($order_ids as $order_id) {
|
||||
$domains2 = Db::name('cert_domain')->where('oid', $order_id)->column('domain');
|
||||
if (arrays_are_equal($domains2, $domains)) {
|
||||
return json(['code' => -1, 'msg' => '该证书已存在,无需重复添加']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$order = [
|
||||
'aid' => input('post.aid/d'),
|
||||
'keytype' => input('post.keytype'),
|
||||
'keysize' => input('post.keysize'),
|
||||
'addtime' => date('Y-m-d H:i:s'),
|
||||
'updatetime' => date('Y-m-d H:i:s'),
|
||||
'issuetime' => $issuetime,
|
||||
'expiretime' => $expiretime,
|
||||
'issuer' => $issuer,
|
||||
'status' => 3,
|
||||
'fullchain' => $fullchain,
|
||||
'privatekey' => $privatekey,
|
||||
];
|
||||
if (empty($order['aid']) || empty($order['keytype']) || empty($order['keysize'])) return json(['code' => -1, 'msg' => '必填参数不能为空']);
|
||||
|
||||
$res = $this->check_order($order, $domains);
|
||||
if (is_array($res)) return json($res);
|
||||
|
||||
Db::startTrans();
|
||||
$id = Db::name('cert_order')->insertGetId($order);
|
||||
$domainList = [];
|
||||
$i = 1;
|
||||
foreach ($domains as $domain) {
|
||||
$domainList[] = [
|
||||
'oid' => $id,
|
||||
'domain' => $domain,
|
||||
'sort' => $i++,
|
||||
];
|
||||
}
|
||||
Db::name('cert_domain')->insertAll($domainList);
|
||||
Db::commit();
|
||||
return json(['code' => 0, 'msg' => '导入证书成功!']);
|
||||
} elseif ($action == 'del') {
|
||||
$id = input('post.id/d');
|
||||
$dcount = DB::name('cert_deploy')->where('oid', $id)->count();
|
||||
if ($dcount > 0) return json(['code' => -1, 'msg' => '该证书关联了自动部署任务,无法删除']);
|
||||
try{
|
||||
try {
|
||||
(new CertOrderService($id))->cancel();
|
||||
}catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
Db::name('cert_order')->where('id', $id)->delete();
|
||||
Db::name('cert_domain')->where('oid', $id)->delete();
|
||||
@@ -425,28 +432,28 @@ class Cert extends BaseController
|
||||
return json(['code' => 0]);
|
||||
} elseif ($action == 'reset') {
|
||||
$id = input('post.id/d');
|
||||
try{
|
||||
try {
|
||||
$service = new CertOrderService($id);
|
||||
$service->cancel();
|
||||
$service->reset();
|
||||
return json(['code' => 0]);
|
||||
}catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
return json(['code' => -1, 'msg' => $e->getMessage()]);
|
||||
}
|
||||
} elseif ($action == 'revoke') {
|
||||
$id = input('post.id/d');
|
||||
try{
|
||||
try {
|
||||
$service = new CertOrderService($id);
|
||||
$service->revoke();
|
||||
return json(['code' => 0]);
|
||||
}catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
return json(['code' => -1, 'msg' => $e->getMessage()]);
|
||||
}
|
||||
} elseif ($action == 'show_log') {
|
||||
$processid = input('post.processid');
|
||||
$file = app()->getRuntimePath().'log/'.$processid.'.log';
|
||||
if(!file_exists($file)) return json(['code' => -1, 'msg' => '日志文件不存在']);
|
||||
return json(['code' => 0, 'data' => file_get_contents($file), 'time'=>filemtime($file)]);
|
||||
$file = app()->getRuntimePath() . 'log/' . $processid . '.log';
|
||||
if (!file_exists($file)) return json(['code' => -1, 'msg' => '日志文件不存在']);
|
||||
return json(['code' => 0, 'data' => file_get_contents($file), 'time' => filemtime($file)]);
|
||||
} elseif ($action == 'operation') {
|
||||
$ids = input('post.ids');
|
||||
$success = 0;
|
||||
@@ -489,24 +496,79 @@ class Cert extends BaseController
|
||||
$cname = CertHelper::$cert_config[$account['type']]['cname'];
|
||||
if (count($domains) > $max_domains) {
|
||||
if (!(count($domains) == 2 && $max_domains == 1 && ltrim($domains[0], 'www.') == ltrim($domains[1], 'www.'))) {
|
||||
return ['code' => -1, 'msg' => '域名数量不能超过'.$max_domains.'个'];
|
||||
return ['code' => -1, 'msg' => '域名数量不能超过' . $max_domains . '个'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach($domains as $domain){
|
||||
foreach ($domains as $domain) {
|
||||
if (!$wildcard && strpos($domain, '*') !== false) return ['code' => -1, 'msg' => '该证书账户类型不支持泛域名'];
|
||||
$mainDomain = getMainDomain($domain);
|
||||
$drow = Db::name('domain')->where('name', $mainDomain)->find();
|
||||
if (!$drow) {
|
||||
if (substr($domain, 0, 2) == '*.') $domain = substr($domain, 2);
|
||||
if (!$cname || !Db::name('cert_cname')->where('domain', $domain)->where('status', 1)->find()) {
|
||||
return ['code' => -1, 'msg' => '域名'.$domain.'未在本系统添加'];
|
||||
return ['code' => -1, 'msg' => '域名' . $domain . '未在本系统添加'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function parse_cert_key($fullchain, $privatekey)
|
||||
{
|
||||
if (!openssl_x509_read($fullchain)) return ['code' => -1, 'msg' => '证书内容填写错误'];
|
||||
if (!openssl_get_privatekey($privatekey)) return ['code' => -1, 'msg' => '私钥内容填写错误'];
|
||||
if (!openssl_x509_check_private_key($fullchain, $privatekey)) return ['code' => -1, 'msg' => 'SSL证书与私钥不匹配'];
|
||||
$certInfo = openssl_x509_parse($fullchain, true);
|
||||
if (!$certInfo || !isset($certInfo['extensions']['subjectAltName'])) return ['code' => -1, 'msg' => '证书内容解析失败'];
|
||||
|
||||
$pubKey = openssl_pkey_get_public($fullchain);
|
||||
if (!$pubKey) return ['code' => -1, 'msg' => '证书公钥解析失败'];
|
||||
$keyDetails = openssl_pkey_get_details($pubKey);
|
||||
$keytype = null;
|
||||
$keysize = 0;
|
||||
switch ($keyDetails['type']) {
|
||||
case OPENSSL_KEYTYPE_RSA:
|
||||
$keytype = 'RSA';
|
||||
$keysize = $keyDetails['bits'];
|
||||
break;
|
||||
case OPENSSL_KEYTYPE_EC:
|
||||
$keytype = 'ECC';
|
||||
$keysize = $keyDetails['bits'];
|
||||
break;
|
||||
case OPENSSL_KEYTYPE_DSA:
|
||||
$keytype = 'DSA';
|
||||
$keysize = $keyDetails['bits'];
|
||||
break;
|
||||
default:
|
||||
$keytype = 'Unknown';
|
||||
}
|
||||
|
||||
$domains = [];
|
||||
$subjectAltName = explode(',', $certInfo['extensions']['subjectAltName']);
|
||||
foreach ($subjectAltName as $domain) {
|
||||
$domain = trim($domain);
|
||||
if (strpos($domain, 'DNS:') === 0) $domain = substr($domain, 4);
|
||||
if (!empty($domain)) {
|
||||
$domains[] = $domain;
|
||||
}
|
||||
}
|
||||
$domains = array_unique($domains);
|
||||
if (empty($domains)) return ['code' => -1, 'msg' => '证书绑定域名不能为空'];
|
||||
$issuetime = date('Y-m-d H:i:s', $certInfo['validFrom_time_t']);
|
||||
$expiretime = date('Y-m-d H:i:s', $certInfo['validTo_time_t']);
|
||||
$issuer = $certInfo['issuer']['CN'];
|
||||
return [
|
||||
'code' => 0,
|
||||
'keytype' => $keytype,
|
||||
'keysize' => $keysize,
|
||||
'issuetime' => $issuetime,
|
||||
'expiretime' => $expiretime,
|
||||
'issuer' => $issuer,
|
||||
'domains' => $domains,
|
||||
];
|
||||
}
|
||||
|
||||
public function order_process()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
@@ -518,18 +580,18 @@ class Cert extends BaseController
|
||||
}
|
||||
$id = input('post.id/d');
|
||||
$reset = input('post.reset/d', 0);
|
||||
try{
|
||||
try {
|
||||
$service = new CertOrderService($id);
|
||||
if($reset == 1){
|
||||
if ($reset == 1) {
|
||||
$service->reset();
|
||||
}
|
||||
$retcode = $service->process(true);
|
||||
if($retcode == 3){
|
||||
if ($retcode == 3) {
|
||||
return json(['code' => 0, 'msg' => '证书已签发成功!']);
|
||||
}elseif($retcode == 1){
|
||||
} elseif ($retcode == 1) {
|
||||
return json(['code' => 0, 'msg' => '添加DNS记录成功!请等待DNS生效后点击验证']);
|
||||
}
|
||||
}catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
return json(['code' => -1, 'msg' => $e->getMessage(), 'trace' => $e->getTrace()]);
|
||||
}
|
||||
}
|
||||
@@ -542,14 +604,16 @@ class Cert extends BaseController
|
||||
$order = null;
|
||||
if ($action == 'edit') {
|
||||
$id = input('get.id/d');
|
||||
$order = Db::name('cert_order')->where('id', $id)->fieldRaw('id,aid,keytype,keysize,status')->find();
|
||||
$order = Db::name('cert_order')->where('id', $id)->fieldRaw('id,aid,keytype,keysize,status,fullchain,privatekey')->find();
|
||||
if (empty($order)) return $this->alert('error', '证书订单不存在');
|
||||
$order['domains'] = Db::name('cert_domain')->where('oid', $order['id'])->order('sort','ASC')->column('domain');
|
||||
$order['domains'] = Db::name('cert_domain')->where('oid', $order['id'])->order('sort', 'ASC')->column('domain');
|
||||
if ($order['aid'] == 0) $order['aid'] = -1;
|
||||
}
|
||||
|
||||
$accounts = [];
|
||||
foreach (Db::name('cert_account')->where('deploy', 0)->select() as $row) {
|
||||
$accounts[$row['id']] = ['name'=>$row['id'].'_'.CertHelper::$cert_config[$row['type']]['name'], 'type'=>$row['type']];
|
||||
if (empty($row['type']) || !isset(CertHelper::$cert_config[$row['type']])) continue;
|
||||
$accounts[$row['id']] = ['name' => $row['id'] . '_' . CertHelper::$cert_config[$row['type']]['name'], 'type' => $row['type']];
|
||||
if (!empty($row['remark'])) {
|
||||
$accounts[$row['id']]['name'] .= '(' . $row['remark'] . ')';
|
||||
}
|
||||
@@ -561,26 +625,11 @@ class Cert extends BaseController
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
public function order_import()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$accounts = [];
|
||||
foreach (Db::name('cert_account')->where('deploy', 0)->select() as $row) {
|
||||
$accounts[$row['id']] = ['name'=>$row['id'].'_'.CertHelper::$cert_config[$row['type']]['name'], 'type'=>$row['type']];
|
||||
if (!empty($row['remark'])) {
|
||||
$accounts[$row['id']]['name'] .= '(' . $row['remark'] . ')';
|
||||
}
|
||||
}
|
||||
View::assign('accounts', $accounts);
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
|
||||
public function deploytask()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$types = [];
|
||||
foreach(DeployHelper::$deploy_config as $key=>$value){
|
||||
foreach (DeployHelper::$deploy_config as $key => $value) {
|
||||
$types[$key] = $value['name'];
|
||||
}
|
||||
View::assign('types', $types);
|
||||
@@ -592,19 +641,23 @@ class Cert extends BaseController
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$domain = $this->request->post('domain', null, 'trim');
|
||||
$oid = input('post.oid');
|
||||
$aid = input('post.aid', null, 'trim');
|
||||
$type = input('post.type', null, 'trim');
|
||||
$status = input('post.status', null, 'trim');
|
||||
$remark = input('post.remark', null, 'trim');
|
||||
$offset = input('post.offset/d');
|
||||
$limit = input('post.limit/d');
|
||||
|
||||
$select = Db::name('cert_deploy')->alias('A')->join('cert_account B', 'A.aid = B.id')->join('cert_order C', 'A.oid = C.id')->join('cert_account D', 'C.aid = D.id');
|
||||
$select = Db::name('cert_deploy')->alias('A')->leftJoin('cert_account B', 'A.aid = B.id')->leftJoin('cert_order C', 'A.oid = C.id')->leftJoin('cert_account D', 'C.aid = D.id');
|
||||
if (!empty($oid)) {
|
||||
$select->where('A.oid', $oid);
|
||||
} elseif (!empty($domain)) {
|
||||
$oids = Db::name('cert_domain')->where('domain', 'like', '%' . $domain . '%')->column('oid');
|
||||
$select->whereIn('oid', $oids);
|
||||
}
|
||||
if (!empty($aid)) {
|
||||
$select->where('A.aid', $aid);
|
||||
}
|
||||
if (!empty($type)) {
|
||||
$select->where('B.type', $type);
|
||||
}
|
||||
@@ -619,11 +672,17 @@ class Cert extends BaseController
|
||||
|
||||
$list = [];
|
||||
foreach ($rows as $row) {
|
||||
$row['typename'] = DeployHelper::$deploy_config[$row['type']]['name'];
|
||||
$row['icon'] = DeployHelper::$deploy_config[$row['type']]['icon'];
|
||||
$row['certtypename'] = CertHelper::$cert_config[$row['certtype']]['name'];
|
||||
$row['domains'] = Db::name('cert_domain')->where('oid', $row['oid'])->order('sort','ASC')->column('domain');
|
||||
if($row['error']) $row['error'] = htmlspecialchars(str_replace("'", "\\'", $row['error']));
|
||||
if (!empty($row['type']) && isset(DeployHelper::$deploy_config[$row['type']])) {
|
||||
$row['typename'] = DeployHelper::$deploy_config[$row['type']]['name'];
|
||||
$row['icon'] = DeployHelper::$deploy_config[$row['type']]['icon'];
|
||||
}
|
||||
if (!empty($row['certtype']) && isset(CertHelper::$cert_config[$row['certtype']])) {
|
||||
$row['certtypename'] = CertHelper::$cert_config[$row['certtype']]['name'];
|
||||
} else {
|
||||
$row['certtypename'] = '手动续期';
|
||||
}
|
||||
$row['domains'] = Db::name('cert_domain')->where('oid', $row['oid'])->order('sort', 'ASC')->column('domain');
|
||||
if ($row['error']) $row['error'] = htmlspecialchars(str_replace("'", "\\'", $row['error']));
|
||||
$list[] = $row;
|
||||
}
|
||||
|
||||
@@ -652,7 +711,7 @@ class Cert extends BaseController
|
||||
$id = input('post.id/d');
|
||||
$row = Db::name('cert_deploy')->where('id', $id)->find();
|
||||
if (!$row) return json(['code' => -1, 'msg' => '自动部署任务不存在']);
|
||||
|
||||
|
||||
$task = [
|
||||
'aid' => input('post.aid/d'),
|
||||
'oid' => input('post.oid/d'),
|
||||
@@ -673,21 +732,27 @@ class Cert extends BaseController
|
||||
return json(['code' => 0]);
|
||||
} elseif ($action == 'reset') {
|
||||
$id = input('post.id/d');
|
||||
try{
|
||||
try {
|
||||
$service = new CertDeployService($id);
|
||||
$service->reset();
|
||||
return json(['code' => 0]);
|
||||
}catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
return json(['code' => -1, 'msg' => $e->getMessage()]);
|
||||
}
|
||||
} elseif ($action == 'show_log') {
|
||||
$processid = input('post.processid');
|
||||
$file = app()->getRuntimePath().'log/'.$processid.'.log';
|
||||
if(!file_exists($file)) return json(['code' => -1, 'msg' => '日志文件不存在']);
|
||||
return json(['code' => 0, 'data' => file_get_contents($file), 'time'=>filemtime($file)]);
|
||||
$file = app()->getRuntimePath() . 'log/' . $processid . '.log';
|
||||
if (!file_exists($file)) return json(['code' => -1, 'msg' => '日志文件不存在']);
|
||||
return json(['code' => 0, 'data' => file_get_contents($file), 'time' => filemtime($file)]);
|
||||
} elseif ($action == 'operation') {
|
||||
$ids = input('post.ids');
|
||||
$success = 0;
|
||||
$certid = 0;
|
||||
if (input('post.action') == 'cert') {
|
||||
$certid = input('post.certid/d');
|
||||
$cert = Db::name('cert_order')->where('id', $certid)->find();
|
||||
if (!$cert) return json(['code' => -1, 'msg' => '证书订单不存在']);
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
if (input('post.action') == 'delete') {
|
||||
Db::name('cert_deploy')->where('id', $id)->delete();
|
||||
@@ -703,6 +768,9 @@ class Cert extends BaseController
|
||||
$active = input('post.action') == 'open' ? 1 : 0;
|
||||
Db::name('cert_deploy')->where('id', $id)->update(['active' => $active]);
|
||||
$success++;
|
||||
} elseif (input('post.action') == 'cert') {
|
||||
Db::name('cert_deploy')->where('id', $id)->update(['oid' => $certid]);
|
||||
$success++;
|
||||
}
|
||||
}
|
||||
return json(['code' => 0, 'msg' => '成功操作' . $success . '个任务']);
|
||||
@@ -721,14 +789,14 @@ class Cert extends BaseController
|
||||
}
|
||||
$id = input('post.id/d');
|
||||
$reset = input('post.reset/d', 0);
|
||||
try{
|
||||
try {
|
||||
$service = new CertDeployService($id);
|
||||
if($reset == 1){
|
||||
if ($reset == 1) {
|
||||
$service->reset();
|
||||
}
|
||||
$service->process(true);
|
||||
return json(['code' => 0, 'msg' => 'SSL证书部署任务执行成功!']);
|
||||
}catch(Exception $e){
|
||||
} catch (Exception $e) {
|
||||
return json(['code' => -1, 'msg' => $e->getMessage(), 'trace' => $e->getTrace()]);
|
||||
}
|
||||
}
|
||||
@@ -747,7 +815,8 @@ class Cert extends BaseController
|
||||
|
||||
$accounts = [];
|
||||
foreach (Db::name('cert_account')->where('deploy', 1)->select() as $row) {
|
||||
$accounts[$row['id']] = ['name'=>$row['id'].'_'.DeployHelper::$deploy_config[$row['type']]['name'], 'type'=>$row['type']];
|
||||
if (empty($row['type']) || !isset(DeployHelper::$deploy_config[$row['type']])) continue;
|
||||
$accounts[$row['id']] = ['name' => $row['id'] . '_' . DeployHelper::$deploy_config[$row['type']]['name'], 'type' => $row['type']];
|
||||
if (!empty($row['remark'])) {
|
||||
$accounts[$row['id']]['name'] .= '(' . $row['remark'] . ')';
|
||||
}
|
||||
@@ -755,10 +824,15 @@ class Cert extends BaseController
|
||||
View::assign('accounts', $accounts);
|
||||
|
||||
$orders = [];
|
||||
foreach (Db::name('cert_order')->alias('A')->join('cert_account B', 'A.aid = B.id')->where('status', '<>', 4)->fieldRaw('A.id,A.aid,B.type,B.remark aremark')->order('id', 'desc')->select() as $row) {
|
||||
$domains = Db::name('cert_domain')->where('oid', $row['id'])->order('sort','ASC')->column('domain');
|
||||
$domainstr = count($domains) > 2 ? implode('、',array_slice($domains, 0, 2)).'等'.count($domains).'个域名' : implode('、',$domains);
|
||||
$orders[$row['id']] = ['name'=>$row['id'].'_'.$domainstr.'('.CertHelper::$cert_config[$row['type']]['name'].')'];
|
||||
foreach (Db::name('cert_order')->alias('A')->leftJoin('cert_account B', 'A.aid = B.id')->where('status', '<>', 4)->fieldRaw('A.id,A.aid,B.type,B.remark aremark')->order('id', 'desc')->select() as $row) {
|
||||
$domains = Db::name('cert_domain')->where('oid', $row['id'])->order('sort', 'ASC')->column('domain');
|
||||
$domainstr = count($domains) > 2 ? implode('、', array_slice($domains, 0, 2)) . '等' . count($domains) . '个域名' : implode('、', $domains);
|
||||
if ($row['aid'] == 0) {
|
||||
$name = $row['id'] . '_' . $domainstr . '(手动续期)';
|
||||
} else {
|
||||
$name = $row['id'] . '_' . $domainstr . '(' . CertHelper::$cert_config[$row['type']]['name'] . ')';
|
||||
}
|
||||
$orders[$row['id']] = ['name' => $name];
|
||||
}
|
||||
View::assign('orders', $orders);
|
||||
|
||||
@@ -786,7 +860,7 @@ class Cert extends BaseController
|
||||
$offset = input('post.offset/d');
|
||||
$limit = input('post.limit/d');
|
||||
|
||||
$select = Db::name('cert_cname')->alias('A')->join('domain B', 'A.did = B.id');
|
||||
$select = Db::name('cert_cname')->alias('A')->leftJoin('domain B', 'A.did = B.id');
|
||||
if (!empty($kw)) {
|
||||
$select->whereLike('A.domain', '%' . $kw . '%');
|
||||
}
|
||||
@@ -829,7 +903,7 @@ class Cert extends BaseController
|
||||
if (empty($data['domain']) || empty($data['rr']) || empty($data['did'])) return json(['code' => -1, 'msg' => '必填参数不能为空']);
|
||||
if (!checkDomain($data['domain'])) return json(['code' => -1, 'msg' => '域名格式不正确']);
|
||||
if (Db::name('cert_cname')->where('domain', $data['domain'])->find()) {
|
||||
return json(['code' => -1, 'msg' => '域名'.$data['domain'].'已存在']);
|
||||
return json(['code' => -1, 'msg' => '域名' . $data['domain'] . '已存在']);
|
||||
}
|
||||
if (Db::name('cert_cname')->where('rr', $data['rr'])->where('did', $data['did'])->find()) {
|
||||
return json(['code' => -1, 'msg' => '已存在相同CNAME记录值']);
|
||||
@@ -840,7 +914,7 @@ class Cert extends BaseController
|
||||
$id = input('post.id/d');
|
||||
$row = Db::name('cert_cname')->where('id', $id)->find();
|
||||
if (!$row) return json(['code' => -1, 'msg' => 'CMAME代理不存在']);
|
||||
|
||||
|
||||
$data = [
|
||||
'rr' => input('post.rr', null, 'trim'),
|
||||
'did' => input('post.did/d'),
|
||||
@@ -867,13 +941,13 @@ class Cert extends BaseController
|
||||
$domain = '_acme-challenge.' . $row['domain'];
|
||||
$record = $row['rr'] . '.' . $row['cnamedomain'];
|
||||
$result = \app\utils\DnsQueryUtils::get_dns_records($domain, 'CNAME');
|
||||
if(!$result || !in_array($record, $result)){
|
||||
if (!$result || !in_array($record, $result)) {
|
||||
$result = \app\utils\DnsQueryUtils::query_dns_doh($domain, 'CNAME');
|
||||
if(!$result || !in_array($record, $result)){
|
||||
if (!$result || !in_array($record, $result)) {
|
||||
$status = 0;
|
||||
}
|
||||
}
|
||||
if($status != $row['status']){
|
||||
if ($status != $row['status']) {
|
||||
Db::name('cert_cname')->where('id', $id)->update(['status' => $status]);
|
||||
}
|
||||
return json(['code' => 0, 'status' => $status]);
|
||||
@@ -883,17 +957,6 @@ class Cert extends BaseController
|
||||
public function certset()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
if ($this->request->isPost()) {
|
||||
$params = input('post.');
|
||||
foreach ($params as $key => $value) {
|
||||
if (empty($key)) {
|
||||
continue;
|
||||
}
|
||||
config_set($key, $value);
|
||||
Cache::delete('configs');
|
||||
}
|
||||
return json(['code' => 0, 'msg' => 'succ']);
|
||||
}
|
||||
return View::fetch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,20 +222,6 @@ class Dmonitor extends BaseController
|
||||
return json(['total' => $total, 'rows' => $list]);
|
||||
}
|
||||
|
||||
public function noticeset()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$params = input('post.');
|
||||
foreach ($params as $key => $value) {
|
||||
if (empty($key)) {
|
||||
continue;
|
||||
}
|
||||
config_set($key, $value);
|
||||
Cache::delete('configs');
|
||||
}
|
||||
return json(['code' => 0, 'msg' => 'succ']);
|
||||
}
|
||||
|
||||
public function clean()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
|
||||
@@ -142,13 +142,14 @@ class Domain extends BaseController
|
||||
$accounts = [];
|
||||
$types = [];
|
||||
foreach ($list as $row) {
|
||||
$accounts[$row['id']] = $row['id'] . '_' . DnsHelper::$dns_config[$row['type']]['name'];
|
||||
$name = $row['id'] . '_' . DnsHelper::$dns_config[$row['type']]['name'];
|
||||
if (!array_key_exists($row['type'], $types)) {
|
||||
$types[$row['type']] = DnsHelper::$dns_config[$row['type']]['name'];
|
||||
}
|
||||
if (!empty($row['remark'])) {
|
||||
$accounts[$row['id']] .= '(' . $row['remark'] . ')';
|
||||
$name .= '(' . $row['remark'] . ')';
|
||||
}
|
||||
$accounts[] = ['id' => $row['id'], 'name' => $name, 'type' => DnsHelper::$dns_config[$row['type']]['name'], 'add' => DnsHelper::$dns_config[$row['type']]['add']];
|
||||
}
|
||||
View::assign('accounts', $accounts);
|
||||
View::assign('types', $types);
|
||||
@@ -225,13 +226,21 @@ class Domain extends BaseController
|
||||
} elseif ($act == 'add') {
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$aid = input('post.aid/d');
|
||||
$method = input('post.method/d', 0);
|
||||
$name = input('post.name', null, 'trim');
|
||||
$thirdid = input('post.thirdid', null, 'trim');
|
||||
$recordcount = input('post.recordcount/d', 0);
|
||||
if (empty($name) || empty($thirdid)) return json(['code' => -1, 'msg' => '参数不能为空']);
|
||||
if ($method == 1 && empty($name) || $method == 0 && (empty($name) || empty($thirdid))) return json(['code' => -1, 'msg' => '参数不能为空']);
|
||||
if (Db::name('domain')->where('aid', $aid)->where('name', $name)->find()) {
|
||||
return json(['code' => -1, 'msg' => '域名已存在']);
|
||||
}
|
||||
if ($method == 1) {
|
||||
$dns = DnsHelper::getModel($aid);
|
||||
$result = $dns->addDomain($name);
|
||||
if (!$result) return json(['code' => -1, 'msg' => '添加域名失败,' . $dns->getError()]);
|
||||
$name = $result['name'];
|
||||
$thirdid = $result['id'];
|
||||
}
|
||||
Db::name('domain')->insert([
|
||||
'aid' => $aid,
|
||||
'name' => $name,
|
||||
@@ -536,7 +545,6 @@ class Domain extends BaseController
|
||||
$remark = input('post.remark', null, 'trim');
|
||||
|
||||
$recordinfo = input('post.recordinfo', null, 'trim');
|
||||
$recordinfo = json_decode($recordinfo, true);
|
||||
|
||||
if (empty($recordid) || empty($name) || empty($type) || empty($value)) {
|
||||
return json(['code' => -1, 'msg' => '参数不能为空']);
|
||||
@@ -546,6 +554,7 @@ class Domain extends BaseController
|
||||
$recordid = $dns->updateDomainRecord($recordid, $name, $type, $value, $line, $ttl, $mx, $weight, $remark);
|
||||
if ($recordid) {
|
||||
if ($recordinfo) {
|
||||
$recordinfo = json_decode($recordinfo, true);
|
||||
if (is_array($recordinfo['Value'])) $recordinfo['Value'] = implode(',', $recordinfo['Value']);
|
||||
if ($recordinfo['Name'] != $name || $recordinfo['Type'] != $type || $recordinfo['Value'] != $value) {
|
||||
$this->add_log($drow['name'], '修改解析', $recordinfo['Name'].' ['.$recordinfo['Type'].'] '.$recordinfo['Value'].' → '.$name.' ['.$type.'] '.$value.' (线路:'.$line.' TTL:'.$ttl.')');
|
||||
@@ -572,7 +581,6 @@ class Domain extends BaseController
|
||||
|
||||
$recordid = input('post.recordid', null, 'trim');
|
||||
$recordinfo = input('post.recordinfo', null, 'trim');
|
||||
$recordinfo = json_decode($recordinfo, true);
|
||||
|
||||
if (empty($recordid)) {
|
||||
return json(['code' => -1, 'msg' => '参数不能为空']);
|
||||
@@ -581,6 +589,7 @@ class Domain extends BaseController
|
||||
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
|
||||
if ($dns->deleteDomainRecord($recordid)) {
|
||||
if ($recordinfo) {
|
||||
$recordinfo = json_decode($recordinfo, true);
|
||||
if (is_array($recordinfo['Value'])) $recordinfo['Value'] = implode(',', $recordinfo['Value']);
|
||||
$this->add_log($drow['name'], '删除解析', $recordinfo['Name'].' ['.$recordinfo['Type'].'] '.$recordinfo['Value'].' (线路:'.$recordinfo['Line'].' TTL:'.$recordinfo['TTL'].')');
|
||||
} else {
|
||||
@@ -604,7 +613,6 @@ class Domain extends BaseController
|
||||
$recordid = input('post.recordid', null, 'trim');
|
||||
$status = input('post.status', null, 'trim');
|
||||
$recordinfo = input('post.recordinfo', null, 'trim');
|
||||
$recordinfo = json_decode($recordinfo, true);
|
||||
|
||||
if (empty($recordid)) {
|
||||
return json(['code' => -1, 'msg' => '参数不能为空']);
|
||||
@@ -614,6 +622,7 @@ class Domain extends BaseController
|
||||
if ($dns->setDomainRecordStatus($recordid, $status)) {
|
||||
$action = $status == '1' ? '启用解析' : '暂停解析';
|
||||
if ($recordinfo) {
|
||||
$recordinfo = json_decode($recordinfo, true);
|
||||
if (is_array($recordinfo['Value'])) $recordinfo['Value'] = implode(',', $recordinfo['Value']);
|
||||
$this->add_log($drow['name'], $action, $recordinfo['Name'].' ['.$recordinfo['Type'].'] '.$recordinfo['Value'].' (线路:'.$recordinfo['Line'].' TTL:'.$recordinfo['TTL'].')');
|
||||
} else {
|
||||
@@ -990,7 +999,7 @@ class Domain extends BaseController
|
||||
return json(['code' => -1, 'msg' => '参数不能为空']);
|
||||
}
|
||||
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
|
||||
if ($dns->setWeightStatus($subdomain, $status, $type, $line)) {
|
||||
if ($type == 'CNAME' || $dns->setWeightStatus($subdomain, $status, $type, $line)) {
|
||||
if ($status == '1') {
|
||||
$success = 0;
|
||||
foreach($weight as $recordid => $weight) {
|
||||
|
||||
@@ -7,8 +7,6 @@ use Exception;
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use think\facade\Cache;
|
||||
use app\lib\DnsHelper;
|
||||
use app\utils\MsgNotice;
|
||||
|
||||
class Index extends BaseController
|
||||
{
|
||||
@@ -28,7 +26,7 @@ class Index extends BaseController
|
||||
$stat['tasks'] = Db::name('dmtask')->count();
|
||||
$stat['certs'] = Db::name('cert_order')->count();
|
||||
$stat['deploys'] = Db::name('cert_deploy')->count();
|
||||
|
||||
|
||||
$run_time = config_get('run_time', null, true);
|
||||
$run_state = $run_time ? (time() - strtotime($run_time) > 10 ? 0 : 1) : 0;
|
||||
$stat['dmonitor_state'] = $run_state;
|
||||
@@ -44,7 +42,7 @@ class Index extends BaseController
|
||||
$stat['certorder_status_5'] = Db::name('cert_order')->where('status', '<', 0)->count();
|
||||
$stat['certorder_status_6'] = Db::name('cert_order')->where('expiretime', '<', date('Y-m-d H:i:s', time() + 86400 * 7))->where('expiretime', '>=', date('Y-m-d H:i:s'))->count();
|
||||
$stat['certorder_status_7'] = Db::name('cert_order')->where('expiretime', '<', date('Y-m-d H:i:s'))->count();
|
||||
|
||||
|
||||
$stat['certdeploy_status_0'] = Db::name('cert_deploy')->where('status', 0)->count();
|
||||
$stat['certdeploy_status_1'] = Db::name('cert_deploy')->where('status', 1)->count();
|
||||
$stat['certdeploy_status_2'] = Db::name('cert_deploy')->where('status', -1)->count();
|
||||
@@ -63,7 +61,7 @@ class Index extends BaseController
|
||||
$tmp = 'version()';
|
||||
$mysqlVersion = Db::query("select version()")[0][$tmp];
|
||||
$info = [
|
||||
'framework_version' => app()::VERSION,
|
||||
'framework_version' => app()->version(),
|
||||
'php_version' => PHP_VERSION,
|
||||
'mysql_version' => $mysqlVersion,
|
||||
'software' => $_SERVER['SERVER_SOFTWARE'],
|
||||
|
||||
@@ -10,41 +10,39 @@ use think\facade\Cache;
|
||||
|
||||
class System extends BaseController
|
||||
{
|
||||
public function set()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
$params = input('post.');
|
||||
if (isset($params['mail_type']) && isset($params['mail_name2']) && $params['mail_type'] > 0) {
|
||||
$params['mail_name'] = $params['mail_name2'];
|
||||
unset($params['mail_name2']);
|
||||
}
|
||||
foreach ($params as $key => $value) {
|
||||
if (empty($key)) {
|
||||
continue;
|
||||
}
|
||||
config_set($key, $value);
|
||||
}
|
||||
Cache::delete('configs');
|
||||
return json(['code' => 0, 'msg' => 'succ']);
|
||||
}
|
||||
|
||||
public function loginset()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
public function noticeset()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
if ($this->request->isPost()) {
|
||||
$params = input('post.');
|
||||
if (isset($params['mail_type']) && isset($params['mail_name2']) && $params['mail_type'] > 0) {
|
||||
$params['mail_name'] = $params['mail_name2'];
|
||||
unset($params['mail_name2']);
|
||||
}
|
||||
foreach ($params as $key => $value) {
|
||||
if (empty($key)) {
|
||||
continue;
|
||||
}
|
||||
config_set($key, $value);
|
||||
Cache::delete('configs');
|
||||
}
|
||||
return json(['code' => 0, 'msg' => 'succ']);
|
||||
}
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
public function proxyset()
|
||||
{
|
||||
if (!checkPermission(2)) return $this->alert('error', '无权限');
|
||||
if ($this->request->isPost()) {
|
||||
$params = input('post.');
|
||||
foreach ($params as $key => $value) {
|
||||
if (empty($key)) {
|
||||
continue;
|
||||
}
|
||||
config_set($key, $value);
|
||||
Cache::delete('configs');
|
||||
}
|
||||
return json(['code' => 0, 'msg' => 'succ']);
|
||||
}
|
||||
return View::fetch();
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ location / {
|
||||
'tencent' => [
|
||||
'name' => '腾讯云免费SSL',
|
||||
'class' => 2,
|
||||
'icon' => 'tencent.ico',
|
||||
'icon' => 'tencent.png',
|
||||
'wildcard' => false,
|
||||
'max_domains' => 1,
|
||||
'cname' => false,
|
||||
@@ -215,7 +215,7 @@ location / {
|
||||
'aliyun' => [
|
||||
'name' => '阿里云免费SSL',
|
||||
'class' => 2,
|
||||
'icon' => 'aliyun.ico',
|
||||
'icon' => 'aliyun.png',
|
||||
'wildcard' => false,
|
||||
'max_domains' => 1,
|
||||
'cname' => false,
|
||||
|
||||
@@ -10,7 +10,8 @@ class DeployHelper
|
||||
'btpanel' => [
|
||||
'name' => '宝塔面板',
|
||||
'class' => 1,
|
||||
'icon' => 'bt.ico',
|
||||
'icon' => 'bt.png',
|
||||
'desc' => '支持部署到宝塔面板搭建的站点、Docker、邮局与面板本身',
|
||||
'note' => null,
|
||||
'inputs' => [
|
||||
'url' => [
|
||||
@@ -41,9 +42,10 @@ class DeployHelper
|
||||
'name' => '部署类型',
|
||||
'type' => 'radio',
|
||||
'options' => [
|
||||
'0' => '宝塔面板站点的证书',
|
||||
'1' => '宝塔面板本身的证书',
|
||||
'2' => '宝塔邮局域名的证书',
|
||||
'0' => '网站的证书',
|
||||
'3' => 'Docker网站的证书',
|
||||
'2' => '邮局域名的证书',
|
||||
'1' => '面板本身的证书',
|
||||
],
|
||||
'value' => '0',
|
||||
'required' => true,
|
||||
@@ -53,7 +55,7 @@ class DeployHelper
|
||||
'type' => 'textarea',
|
||||
'placeholder' => '填写要部署证书的网站名称,每行一个',
|
||||
'note' => 'PHP项目和反代项目填写创建时绑定的第一个域名,Java/Node/Go等其他项目填写项目名称,邮局填写域名',
|
||||
'show' => 'type==0||type==2',
|
||||
'show' => 'type==0||type==2||type==3',
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
@@ -62,6 +64,7 @@ class DeployHelper
|
||||
'name' => 'Kangle用户',
|
||||
'class' => 1,
|
||||
'icon' => 'host.png',
|
||||
'desc' => '支持虚拟主机与CDN站点',
|
||||
'note' => '以上登录信息为Easypanel用户面板的,非管理员面板。如选网站密码认证类型,则用户面板登录不能开启验证码。',
|
||||
'inputs' => [
|
||||
'url' => [
|
||||
@@ -135,6 +138,7 @@ class DeployHelper
|
||||
'name' => 'Kangle管理员',
|
||||
'class' => 1,
|
||||
'icon' => 'host.png',
|
||||
'desc' => '支持虚拟主机与CDN站点',
|
||||
'note' => '以上登录地址需填写Easypanel管理员面板地址,非用户面板。',
|
||||
'inputs' => [
|
||||
'url' => [
|
||||
@@ -201,6 +205,7 @@ class DeployHelper
|
||||
'name' => '雷池WAF',
|
||||
'class' => 1,
|
||||
'icon' => 'safeline.png',
|
||||
'desc' => '',
|
||||
'note' => null,
|
||||
'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书',
|
||||
'inputs' => [
|
||||
@@ -232,7 +237,8 @@ class DeployHelper
|
||||
'btwaf' => [
|
||||
'name' => '堡塔云WAF',
|
||||
'class' => 1,
|
||||
'icon' => 'bt.ico',
|
||||
'icon' => 'bt.png',
|
||||
'desc' => '',
|
||||
'note' => null,
|
||||
'tasknote' => '',
|
||||
'inputs' => [
|
||||
@@ -272,6 +278,7 @@ class DeployHelper
|
||||
'name' => 'Cdnfly',
|
||||
'class' => 1,
|
||||
'icon' => 'waf.png',
|
||||
'desc' => '',
|
||||
'note' => '登录Cdnfly控制台->账户中心->API密钥,点击开启后获取',
|
||||
'inputs' => [
|
||||
'url' => [
|
||||
@@ -317,6 +324,7 @@ class DeployHelper
|
||||
'name' => 'LeCDN',
|
||||
'class' => 1,
|
||||
'icon' => 'waf.png',
|
||||
'desc' => '',
|
||||
'note' => null,
|
||||
'inputs' => [
|
||||
'url' => [
|
||||
@@ -362,6 +370,7 @@ class DeployHelper
|
||||
'name' => 'GoEdge',
|
||||
'class' => 1,
|
||||
'icon' => 'waf.png',
|
||||
'desc' => '支持GoEdge与FlexCDN',
|
||||
'note' => '需要先<a href="https://goedge.cloud/docs/API/Settings.md" target="_blank" rel="noreferrer">开启HTTP API端口</a>',
|
||||
'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书',
|
||||
'inputs' => [
|
||||
@@ -420,6 +429,7 @@ class DeployHelper
|
||||
'name' => '1Panel',
|
||||
'class' => 1,
|
||||
'icon' => 'opanel.png',
|
||||
'desc' => '更新面板证书管理内的SSL证书',
|
||||
'note' => null,
|
||||
'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书',
|
||||
'inputs' => [
|
||||
@@ -462,6 +472,7 @@ class DeployHelper
|
||||
'name' => 'MW面板',
|
||||
'class' => 1,
|
||||
'icon' => 'mwpanel.ico',
|
||||
'desc' => '',
|
||||
'note' => null,
|
||||
'tasknote' => '',
|
||||
'inputs' => [
|
||||
@@ -519,6 +530,7 @@ class DeployHelper
|
||||
'name' => '耗子面板',
|
||||
'class' => 1,
|
||||
'icon' => 'ratpanel.ico',
|
||||
'desc' => '支持耗子面板 v2.5+ 版本使用',
|
||||
'note' => '支持耗子面板 v2.5+ 版本使用',
|
||||
'inputs' => [
|
||||
'url' => [
|
||||
@@ -577,6 +589,7 @@ class DeployHelper
|
||||
'name' => '群晖面板',
|
||||
'class' => 1,
|
||||
'icon' => 'synology.png',
|
||||
'desc' => '支持群晖DSM 6.x/7.x版本',
|
||||
'note' => null,
|
||||
'tasknote' => '',
|
||||
'inputs' => [
|
||||
@@ -628,10 +641,49 @@ class DeployHelper
|
||||
],
|
||||
],
|
||||
],
|
||||
'lucky' => [
|
||||
'name' => 'Lucky',
|
||||
'class' => 1,
|
||||
'icon' => 'lucky.png',
|
||||
'desc' => '更新Lucky证书',
|
||||
'note' => '在“设置->开发者设置”打开OpenToken开关',
|
||||
'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书',
|
||||
'inputs' => [
|
||||
'url' => [
|
||||
'name' => '面板地址',
|
||||
'type' => 'input',
|
||||
'placeholder' => 'Lucky 面板地址',
|
||||
'note' => '填写规则如:https://192.168.1.100:16601 ,不要带其他后缀',
|
||||
'required' => true,
|
||||
],
|
||||
'path' => [
|
||||
'name' => '安全入口',
|
||||
'type' => 'input',
|
||||
'note' => '未设置请留空,参考Lucky设置中的安全入口设置'
|
||||
],
|
||||
'opentoken' => [
|
||||
'name' => 'OpenToken',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'required' => true,
|
||||
],
|
||||
'proxy' => [
|
||||
'name' => '使用代理服务器',
|
||||
'type' => 'radio',
|
||||
'options' => [
|
||||
'0' => '否',
|
||||
'1' => '是',
|
||||
],
|
||||
'value' => '0'
|
||||
],
|
||||
],
|
||||
'taskinputs' => [],
|
||||
],
|
||||
'proxmox' => [
|
||||
'name' => 'Proxmox VE',
|
||||
'class' => 1,
|
||||
'icon' => 'proxmox.ico',
|
||||
'desc' => '部署到PVE节点',
|
||||
'note' => '在“权限->API令牌”添加令牌,不要选特权分离',
|
||||
'tasknote' => '',
|
||||
'inputs' => [
|
||||
@@ -676,8 +728,9 @@ class DeployHelper
|
||||
'aliyun' => [
|
||||
'name' => '阿里云',
|
||||
'class' => 2,
|
||||
'icon' => 'aliyun.ico',
|
||||
'note' => '支持部署到阿里云CDN、ESA、SLB、OSS、WAF等服务',
|
||||
'icon' => 'aliyun.png',
|
||||
'desc' => '支持部署到阿里云CDN、ESA、SLB、OSS、WAF、FC等服务',
|
||||
'note' => '支持部署到阿里云CDN、ESA、SLB、OSS、WAF、FC等服务',
|
||||
'tasknote' => '',
|
||||
'inputs' => [
|
||||
'AccessKeyId' => [
|
||||
@@ -755,7 +808,7 @@ class DeployHelper
|
||||
['value'=>'ap-southeast-1', 'label'=>'非中国内地'],
|
||||
],
|
||||
'value' => 'cn-hangzhou',
|
||||
'show' => 'product==\'waf\'||product==\'waf2\'||product==\'ddoscoo\'',
|
||||
'show' => 'product==\'waf\'||product==\'waf2\'||product==\'ddoscoo\'||product==\'esa\'',
|
||||
'required' => true,
|
||||
],
|
||||
'regionid' => [
|
||||
@@ -823,7 +876,8 @@ class DeployHelper
|
||||
'tencent' => [
|
||||
'name' => '腾讯云',
|
||||
'class' => 2,
|
||||
'icon' => 'tencent.ico',
|
||||
'icon' => 'tencent.png',
|
||||
'desc' => '支持部署到腾讯云CDN、EO、CLB、COS、TKE、SCF等服务',
|
||||
'note' => '支持部署到腾讯云CDN、EO、CLB、COS、TKE、SCF等服务',
|
||||
'tasknote' => '',
|
||||
'inputs' => [
|
||||
@@ -958,6 +1012,7 @@ class DeployHelper
|
||||
'name' => '华为云',
|
||||
'class' => 2,
|
||||
'icon' => 'huawei.ico',
|
||||
'desc' => '支持部署到华为云CDN、ELB、WAF等服务',
|
||||
'note' => '支持部署到华为云CDN、ELB、WAF等服务',
|
||||
'inputs' => [
|
||||
'AccessKeyId' => [
|
||||
@@ -1030,6 +1085,7 @@ class DeployHelper
|
||||
'name' => 'UCloud',
|
||||
'class' => 2,
|
||||
'icon' => 'ucloud.ico',
|
||||
'desc' => '支持部署到UCDN',
|
||||
'note' => '支持部署到UCDN',
|
||||
'inputs' => [
|
||||
'PublicKey' => [
|
||||
@@ -1059,6 +1115,7 @@ class DeployHelper
|
||||
'name' => '七牛云',
|
||||
'class' => 2,
|
||||
'icon' => 'qiniu.ico',
|
||||
'desc' => '支持部署到七牛云CDN、OSS',
|
||||
'note' => '支持部署到七牛云CDN、OSS',
|
||||
'inputs' => [
|
||||
'AccessKey' => [
|
||||
@@ -1113,7 +1170,8 @@ class DeployHelper
|
||||
'doge' => [
|
||||
'name' => '多吉云',
|
||||
'class' => 2,
|
||||
'icon' => 'cloud.png',
|
||||
'icon' => 'doge.png',
|
||||
'desc' => '支持部署到多吉云融合CDN',
|
||||
'note' => '支持部署到多吉云融合CDN',
|
||||
'inputs' => [
|
||||
'AccessKey' => [
|
||||
@@ -1151,6 +1209,8 @@ class DeployHelper
|
||||
'name' => '又拍云',
|
||||
'class' => 2,
|
||||
'icon' => 'upyun.ico',
|
||||
'desc' => '支持部署到又拍云CDN',
|
||||
'note' => '支持部署到又拍云CDN',
|
||||
'tasknote' => '系统会根据关联SSL证书的域名,进行证书的迁移操作',
|
||||
'inputs' => [
|
||||
'username' => [
|
||||
@@ -1180,6 +1240,7 @@ class DeployHelper
|
||||
'name' => '百度云',
|
||||
'class' => 2,
|
||||
'icon' => 'baidu.ico',
|
||||
'desc' => '支持部署到百度云CDN',
|
||||
'note' => '支持部署到百度云CDN',
|
||||
'inputs' => [
|
||||
'AccessKeyId' => [
|
||||
@@ -1217,6 +1278,7 @@ class DeployHelper
|
||||
'name' => '火山引擎',
|
||||
'class' => 2,
|
||||
'icon' => 'huoshan.ico',
|
||||
'desc' => '支持部署到火山引擎CDN',
|
||||
'note' => '支持部署到火山引擎CDN',
|
||||
'inputs' => [
|
||||
'AccessKeyId' => [
|
||||
@@ -1284,6 +1346,7 @@ class DeployHelper
|
||||
'name' => '西部数码',
|
||||
'class' => 2,
|
||||
'icon' => 'west.ico',
|
||||
'desc' => '支持部署到西部数码虚拟主机',
|
||||
'note' => '支持部署到西部数码虚拟主机',
|
||||
'inputs' => [
|
||||
'username' => [
|
||||
@@ -1321,6 +1384,7 @@ class DeployHelper
|
||||
'name' => '网宿科技',
|
||||
'class' => 2,
|
||||
'icon' => 'wangsu.ico',
|
||||
'desc' => '支持部署到网宿CDN',
|
||||
'note' => '适用产品:网页加速、下载分发、全站加速、点播分发、直播分发、上传加速、移动加速、上网加速、S-P2P、PCDN、应用性能管理、WEB应用防火墙、BotGuard爬虫管理、WSS、DMS、DDoS云清洗、应用加速、应用安全加速解决方案、IPv6一体化解决方案、电商安全加速解决方案、金融安全加速解决方案、政企安全加速解决方案、DDoS云清洗(非网站业务)、区块链安全加速解决方案、IPv6安全加速解决方案、CDN Pro。暂不支持AKSK鉴权。',
|
||||
'inputs' => [
|
||||
'username' => [
|
||||
@@ -1389,6 +1453,7 @@ class DeployHelper
|
||||
'name' => '白山云',
|
||||
'class' => 2,
|
||||
'icon' => 'waf.png',
|
||||
'desc' => '替换白山云证书管理内的证书',
|
||||
'note' => null,
|
||||
'inputs' => [
|
||||
'account' => [
|
||||
@@ -1428,7 +1493,8 @@ class DeployHelper
|
||||
'name' => '天翼云',
|
||||
'class' => 2,
|
||||
'icon' => 'ctyun.ico',
|
||||
'note' => '支持部署到天翼云CDN',
|
||||
'desc' => '支持部署到天翼云CDN、边缘加速',
|
||||
'note' => '支持部署到天翼云CDN、边缘加速',
|
||||
'inputs' => [
|
||||
'AccessKeyId' => [
|
||||
'name' => 'AccessKeyId',
|
||||
@@ -1476,6 +1542,7 @@ class DeployHelper
|
||||
'name' => '括彩云',
|
||||
'class' => 2,
|
||||
'icon' => 'kuocai.jpg',
|
||||
'desc' => '替换括彩云证书管理内的证书',
|
||||
'note' => '支持括彩云及其代理商,填写控制台登录账号及密码',
|
||||
'inputs' => [
|
||||
'username' => [
|
||||
@@ -1511,23 +1578,24 @@ class DeployHelper
|
||||
],
|
||||
],
|
||||
],
|
||||
'allwaf' => [
|
||||
'name' => 'AllWAF',
|
||||
'rainyun' => [
|
||||
'name' => '雨云',
|
||||
'class' => 2,
|
||||
'icon' => 'waf.png',
|
||||
'note' => '在<a href="https://user.allwaf.cn/" target="_blank" rel="noreferrer">ALLWAF</a>访问控制页面创建AccessKey',
|
||||
'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书',
|
||||
'desc' => '替换雨云证书管理内的证书',
|
||||
'note' => null,
|
||||
'inputs' => [
|
||||
'accessKeyId' => [
|
||||
'name' => 'AccessKey ID',
|
||||
'account' => [
|
||||
'name' => '账号',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'placeholder' => '仅用作标记',
|
||||
'required' => true,
|
||||
],
|
||||
'accessKey' => [
|
||||
'name' => 'AccessKey密钥',
|
||||
'apikey' => [
|
||||
'name' => 'ApiKey',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'note' => '在 账户设置->API密钥 页面查看',
|
||||
'required' => true,
|
||||
],
|
||||
'proxy' => [
|
||||
@@ -1540,12 +1608,21 @@ class DeployHelper
|
||||
'value' => '0'
|
||||
],
|
||||
],
|
||||
'taskinputs' => [],
|
||||
'taskinputs' => [
|
||||
'id' => [
|
||||
'name' => '证书ID',
|
||||
'type' => 'input',
|
||||
'placeholder' => '',
|
||||
'note' => '在SSL证书->我的证书页面查看,注意域名是否与证书匹配',
|
||||
'required' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
'aws' => [
|
||||
'name' => 'AWS',
|
||||
'class' => 2,
|
||||
'icon' => 'aws.ico',
|
||||
'icon' => 'aws.png',
|
||||
'desc' => '支持部署到Amazon CloudFront、AWS Certificate Manager',
|
||||
'note' => '支持部署到Amazon CloudFront、AWS Certificate Manager',
|
||||
'inputs' => [
|
||||
'AccessKeyId' => [
|
||||
@@ -1602,6 +1679,7 @@ class DeployHelper
|
||||
'name' => 'Gcore',
|
||||
'class' => 2,
|
||||
'icon' => 'gcore.ico',
|
||||
'desc' => '替换Gcore CDN证书',
|
||||
'note' => '在 个人资料->API令牌 页面创建API令牌',
|
||||
'inputs' => [
|
||||
'account' => [
|
||||
@@ -1646,6 +1724,7 @@ class DeployHelper
|
||||
'name' => 'Cachefly',
|
||||
'class' => 2,
|
||||
'icon' => 'cloud.png',
|
||||
'desc' => '替换Cachefly CDN证书',
|
||||
'note' => '在 API Tokens 页面生成 API Token',
|
||||
'inputs' => [
|
||||
'account' => [
|
||||
@@ -1678,6 +1757,7 @@ class DeployHelper
|
||||
'name' => 'SSH服务器',
|
||||
'class' => 3,
|
||||
'icon' => 'server.png',
|
||||
'desc' => '可通过SSH连接到Linux/Windows服务器并部署证书',
|
||||
'note' => '可通过SSH连接到Linux/Windows服务器并部署证书,php需要安装ssh2扩展',
|
||||
'tasknote' => '请确保路径存在且有写入权限,路径一定要以/开头(Windows路径请使用/代替\,且需要在最开头加/)',
|
||||
'inputs' => [
|
||||
@@ -1804,6 +1884,7 @@ class DeployHelper
|
||||
'name' => 'FTP服务器',
|
||||
'class' => 3,
|
||||
'icon' => 'server.png',
|
||||
'desc' => '可将证书上传到FTP服务器',
|
||||
'note' => '可将证书上传到FTP服务器,php需要安装ftp扩展',
|
||||
'tasknote' => '请确保路径存在且有写入权限',
|
||||
'inputs' => [
|
||||
@@ -1887,6 +1968,7 @@ class DeployHelper
|
||||
'name' => '复制到本机',
|
||||
'class' => 3,
|
||||
'icon' => 'server2.png',
|
||||
'desc' => '将证书复制到本机指定路径',
|
||||
'note' => '将证书复制到本机指定路径',
|
||||
'tasknote' => '请确保php进程有对证书保存路径的写入权限,宝塔面板需关闭防跨站攻击,如果当前是Docker运行的,则需要做目录映射到宿主机。',
|
||||
'inputs' => [],
|
||||
|
||||
@@ -19,6 +19,7 @@ class DnsHelper
|
||||
'log' => true, //是否支持查看日志
|
||||
'weight' => false, //是否支持权重
|
||||
'page' => false, //是否客户端分页
|
||||
'add' => true, //是否支持添加域名
|
||||
],
|
||||
'dnspod' => [
|
||||
'name' => '腾讯云',
|
||||
@@ -32,6 +33,7 @@ class DnsHelper
|
||||
'log' => true,
|
||||
'weight' => true,
|
||||
'page' => false,
|
||||
'add' => true,
|
||||
],
|
||||
'huawei' => [
|
||||
'name' => '华为云',
|
||||
@@ -45,6 +47,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => true,
|
||||
'page' => false,
|
||||
'add' => true,
|
||||
],
|
||||
'baidu' => [
|
||||
'name' => '百度云',
|
||||
@@ -58,6 +61,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => false,
|
||||
'page' => true,
|
||||
'add' => true,
|
||||
],
|
||||
'west' => [
|
||||
'name' => '西部数码',
|
||||
@@ -71,6 +75,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => false,
|
||||
'page' => false,
|
||||
'add' => false,
|
||||
],
|
||||
'huoshan' => [
|
||||
'name' => '火山引擎',
|
||||
@@ -84,6 +89,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => true,
|
||||
'page' => false,
|
||||
'add' => true,
|
||||
],
|
||||
'jdcloud' => [
|
||||
'name' => '京东云',
|
||||
@@ -97,6 +103,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => true,
|
||||
'page' => false,
|
||||
'add' => true,
|
||||
],
|
||||
'dnsla' => [
|
||||
'name' => 'DNSLA',
|
||||
@@ -110,6 +117,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => true,
|
||||
'page' => false,
|
||||
'add' => true,
|
||||
],
|
||||
'cloudflare' => [
|
||||
'name' => 'Cloudflare',
|
||||
@@ -123,6 +131,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => false,
|
||||
'page' => false,
|
||||
'add' => true,
|
||||
],
|
||||
'namesilo' => [
|
||||
'name' => 'NameSilo',
|
||||
@@ -136,6 +145,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => false,
|
||||
'page' => true,
|
||||
'add' => false,
|
||||
],
|
||||
'powerdns' => [
|
||||
'name' => 'PowerDNS',
|
||||
@@ -150,6 +160,7 @@ class DnsHelper
|
||||
'log' => false,
|
||||
'weight' => false,
|
||||
'page' => true,
|
||||
'add' => true,
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
@@ -31,4 +31,6 @@ interface DnsInterface
|
||||
function getRecordLine();
|
||||
|
||||
function getMinTTL();
|
||||
|
||||
function addDomain($Domain);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ class NewDbManager extends \think\Db
|
||||
/**
|
||||
* 创建数据库连接实例
|
||||
* @access protected
|
||||
* @param string|null $name 连接标识
|
||||
* @param string|array|null $name 连接标识
|
||||
* @param bool $force 强制重新连接
|
||||
* @return ConnectionInterface
|
||||
*/
|
||||
protected function instance(string $name = null, bool $force = false): ConnectionInterface
|
||||
protected function instance(string|array $name = null, bool $force = false): ConnectionInterface
|
||||
{
|
||||
if (empty($name)) {
|
||||
$name = $this->getConfig('default', 'mysql');
|
||||
|
||||
@@ -321,7 +321,7 @@ class ACMEv2
|
||||
}
|
||||
));
|
||||
|
||||
if ($this->proxy) {
|
||||
if ($this->proxy == 1) {
|
||||
curl_set_proxy($this->ch);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class aliyun implements CertInterface
|
||||
$dnsList = [];
|
||||
if ($data['Type'] == 'domain_verify') {
|
||||
$mainDomain = getMainDomain($domain);
|
||||
$name = str_replace('.' . $mainDomain, '', $data['RecordDomain']);
|
||||
$name = substr($data['RecordDomain'], 0, -(strlen($mainDomain) + 1));
|
||||
$dnsList[$mainDomain][] = ['name' => $name, 'type' => $data['RecordType'], 'value' => $data['RecordValue']];
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class customacme implements CertInterface
|
||||
if (!empty($order['challenges'])) {
|
||||
foreach ($order['challenges'] as $opts) {
|
||||
$mainDomain = getMainDomain($opts['domain']);
|
||||
$name = str_replace('.' . $mainDomain, '', $opts['key']);
|
||||
$name = substr($opts['key'], 0, -(strlen($mainDomain) + 1));
|
||||
$dnsList[$mainDomain][] = ['name' => $name, 'type' => 'TXT', 'value' => $opts['value']];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class google implements CertInterface
|
||||
if (!empty($order['challenges'])) {
|
||||
foreach ($order['challenges'] as $opts) {
|
||||
$mainDomain = getMainDomain($opts['domain']);
|
||||
$name = str_replace('.' . $mainDomain, '', $opts['key']);
|
||||
$name = substr($opts['key'], 0, -(strlen($mainDomain) + 1));
|
||||
/*if (!array_key_exists($mainDomain, $dnsList)) {
|
||||
$dnsList[$mainDomain][] = ['name' => '@', 'type' => 'CAA', 'value' => '0 issue "pki.goog"'];
|
||||
}*/
|
||||
@@ -128,7 +128,7 @@ class google implements CertInterface
|
||||
private function getEAB()
|
||||
{
|
||||
$api = "https://gts.rat.dev/eab";
|
||||
$response = curl_client($api, null, null, null, null, $this->config['proxy'] == 1, 'GET', 10);
|
||||
$response = http_request($api, null, null, null, null, $this->config['proxy'] == 1, 'GET', 10);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (!isset($result['msg'])) {
|
||||
throw new Exception('解析返回数据失败:' . $response['body']);
|
||||
|
||||
@@ -66,7 +66,7 @@ class huoshan implements CertInterface
|
||||
$type = $data['validation_type'] == 'dns_cname' ? 'CNAME' : 'TXT';
|
||||
foreach ($data['domains_to_be_validated'] as $opts) {
|
||||
$mainDomain = getMainDomain($domain);
|
||||
$name = str_replace('.' . $mainDomain, '', $opts['validation_domain']);
|
||||
$name = substr($opts['validation_domain'], 0, -(strlen($mainDomain) + 1));
|
||||
$dnsList[$mainDomain][] = ['name' => $name, 'type' => $type, 'value' => $opts['value']];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class letsencrypt implements CertInterface
|
||||
if (!empty($order['challenges'])) {
|
||||
foreach ($order['challenges'] as $opts) {
|
||||
$mainDomain = getMainDomain($opts['domain']);
|
||||
$name = str_replace('.' . $mainDomain, '', $opts['key']);
|
||||
$name = substr($opts['key'], 0, -(strlen($mainDomain) + 1));
|
||||
/*if (!array_key_exists($mainDomain, $dnsList)) {
|
||||
$dnsList[$mainDomain][] = ['name' => '@', 'type' => 'CAA', 'value' => '0 issue "letsencrypt.org"'];
|
||||
}*/
|
||||
|
||||
@@ -60,8 +60,9 @@ class tencent implements CertInterface
|
||||
$dnsList = [];
|
||||
if (!empty($data['DvAuthDetail']['DvAuths'])) {
|
||||
foreach ($data['DvAuthDetail']['DvAuths'] as $opts) {
|
||||
$mainDomain = $opts['DvAuthDomain'];
|
||||
$dnsList[$mainDomain][] = ['name' => $opts['DvAuthSubDomain'], 'type' => $opts['DvAuthVerifyType'] ?? 'CNAME', 'value' => $opts['DvAuthValue']];
|
||||
$mainDomain = getMainDomain($opts['DvAuthKey']);
|
||||
$name = substr($opts['DvAuthKey'], 0, -(strlen($mainDomain) + 1));
|
||||
$dnsList[$mainDomain][] = ['name' => $name, 'type' => $opts['DvAuthVerifyType'] ?? 'CNAME', 'value' => $opts['DvAuthValue']];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,13 +98,19 @@ class tencent implements CertInterface
|
||||
|
||||
public function finalizeOrder($domainList, $order, $keytype, $keysize)
|
||||
{
|
||||
$param = [
|
||||
'CertificateIds' => [$order['CertificateId']],
|
||||
'SwitchStatus' => 1,
|
||||
];
|
||||
$this->request('ModifyCertificatesExpiringNotificationSwitch', $param);
|
||||
|
||||
if (!is_dir(app()->getRuntimePath() . 'cert')) mkdir(app()->getRuntimePath() . 'cert');
|
||||
$param = [
|
||||
'CertificateId' => $order['CertificateId'],
|
||||
'ServiceType' => 'nginx',
|
||||
];
|
||||
$data = $this->request('DescribeDownloadCertificateUrl', $param);
|
||||
$file_data = curl_client($data['DownloadCertificateUrl'], null, null, null, null, $this->proxy);
|
||||
$file_data = http_request($data['DownloadCertificateUrl'], null, null, null, null, $this->proxy);
|
||||
$file_data = $file_data['body'] ?? null;
|
||||
if (empty($file_data)) throw new Exception('下载证书失败');
|
||||
$file_path = app()->getRuntimePath() . 'cert/' . $data['DownloadFilename'];
|
||||
|
||||
@@ -80,7 +80,8 @@ class ucloud implements CertInterface
|
||||
if (!empty($data['Auths'])) {
|
||||
foreach ($data['Auths'] as $auth) {
|
||||
$mainDomain = getMainDomain($auth['Domain']);
|
||||
$dnsList[$mainDomain][] = ['name' => $auth['AuthRecord'], 'type' => $auth['AuthType'] == 'DNS_TXT' ? 'TXT' : 'CNAME', 'value' => $auth['AuthValue']];
|
||||
$name = substr($auth['AuthKey'], 0, -(strlen($mainDomain) + 1));
|
||||
$dnsList[$mainDomain][] = ['name' => $name, 'type' => $auth['AuthType'] == 'DNS_TXT' ? 'TXT' : 'CNAME', 'value' => $auth['AuthValue']];
|
||||
}
|
||||
}
|
||||
return $dnsList;
|
||||
|
||||
@@ -64,7 +64,7 @@ class zerossl implements CertInterface
|
||||
if (!empty($order['challenges'])) {
|
||||
foreach ($order['challenges'] as $opts) {
|
||||
$mainDomain = getMainDomain($opts['domain']);
|
||||
$name = str_replace('.' . $mainDomain, '', $opts['key']);
|
||||
$name = substr($opts['key'], 0, -(strlen($mainDomain) + 1));
|
||||
/*if (!array_key_exists($mainDomain, $dnsList)) {
|
||||
$dnsList[$mainDomain][] = ['name' => '@', 'type' => 'CAA', 'value' => '0 issue "sectigo.com"'];
|
||||
}*/
|
||||
@@ -120,7 +120,7 @@ class zerossl implements CertInterface
|
||||
private function getEAB($email)
|
||||
{
|
||||
$api = "https://api.zerossl.com/acme/eab-credentials-email";
|
||||
$response = curl_client($api, http_build_query(['email' => $email]), null, null, null, $this->config['proxy'] == 1);
|
||||
$response = http_request($api, http_build_query(['email' => $email]), null, null, null, $this->config['proxy'] == 1);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (!isset($result['success'])) {
|
||||
throw new Exception('获取EAB失败:' . $response['body']);
|
||||
|
||||
@@ -27,7 +27,7 @@ class Ucloud
|
||||
$param = array_merge($param, $params);
|
||||
$param['Signature'] = $this->ucloudSignature($param);
|
||||
$ua = sprintf("PHP/%s PHP-SDK/%s", phpversion(), self::VERSION);
|
||||
$response = get_curl($this->ApiUrl, json_encode($param), 0, 0, 0, $ua, 0, ['Content-Type: application/json']);
|
||||
$response = get_curl($this->ApiUrl, json_encode($param), 0, 0, $ua, 0, ['Content-Type' => 'application/json']);
|
||||
$result = json_decode($response, true);
|
||||
if (isset($result['RetCode']) && $result['RetCode'] == 0) {
|
||||
return $result;
|
||||
|
||||
@@ -42,14 +42,14 @@ class aliyun implements DeployInterface
|
||||
} elseif ($config['product'] == 'fc2') {
|
||||
$this->deploy_fc2($fullchain, $privatekey, $config);
|
||||
} else {
|
||||
[$cert_id, $cert_name] = $this->get_cert_id($fullchain, $privatekey);
|
||||
[$cert_id, $cert_name] = $this->get_cert_id($fullchain, $privatekey, $config);
|
||||
if (!$cert_id) throw new Exception('证书ID获取失败');
|
||||
if ($config['product'] == 'cdn') {
|
||||
$this->deploy_cdn($cert_id, $cert_name, $config);
|
||||
} elseif ($config['product'] == 'dcdn') {
|
||||
$this->deploy_dcdn($cert_id, $cert_name, $config);
|
||||
} elseif ($config['product'] == 'esa') {
|
||||
$this->deploy_esa($cert_id, $config);
|
||||
$this->deploy_esa($cert_id, $cert_name, $config);
|
||||
} elseif ($config['product'] == 'oss') {
|
||||
$this->deploy_oss($cert_id, $config);
|
||||
} elseif ($config['product'] == 'waf') {
|
||||
@@ -74,14 +74,20 @@ class aliyun implements DeployInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function get_cert_id($fullchain, $privatekey)
|
||||
private function get_cert_id($fullchain, $privatekey, $config)
|
||||
{
|
||||
$certInfo = openssl_x509_parse($fullchain, true);
|
||||
if (!$certInfo) throw new Exception('证书解析失败');
|
||||
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
|
||||
$serial_no = strtolower($certInfo['serialNumberHex']);
|
||||
|
||||
$client = new AliyunClient($this->AccessKeyId, $this->AccessKeySecret, 'cas.aliyuncs.com', '2020-04-07', $this->proxy);
|
||||
if ($config['region'] == 'ap-southeast-1') {
|
||||
$endpoint = 'cas.ap-southeast-1.aliyuncs.com';
|
||||
} else {
|
||||
$endpoint = 'cas.aliyuncs.com';
|
||||
}
|
||||
|
||||
$client = new AliyunClient($this->AccessKeyId, $this->AccessKeySecret, $endpoint, '2020-04-07', $this->proxy);
|
||||
$param = [
|
||||
'Action' => 'ListUserCertificateOrder',
|
||||
'Keyword' => $certInfo['subject']['CN'],
|
||||
@@ -157,12 +163,18 @@ class aliyun implements DeployInterface
|
||||
$this->log('DCDN域名 ' . $domain . ' 部署证书成功!');
|
||||
}
|
||||
|
||||
private function deploy_esa($cas_id, $config)
|
||||
private function deploy_esa($cas_id, $cert_name, $config)
|
||||
{
|
||||
$sitename = $config['esa_sitename'];
|
||||
if (empty($sitename)) throw new Exception('ESA站点名称不能为空');
|
||||
|
||||
$client = new AliyunClient($this->AccessKeyId, $this->AccessKeySecret, 'esa.cn-hangzhou.aliyuncs.com', '2024-09-10');
|
||||
if ($config['region'] == 'ap-southeast-1') {
|
||||
$endpoint = 'esa.ap-southeast-1.aliyuncs.com';
|
||||
} else {
|
||||
$endpoint = 'esa.cn-hangzhou.aliyuncs.com';
|
||||
}
|
||||
|
||||
$client = new AliyunClient($this->AccessKeyId, $this->AccessKeySecret, $endpoint, '2024-09-10');
|
||||
$param = [
|
||||
'Action' => 'ListSites',
|
||||
'SiteName' => $sitename,
|
||||
@@ -188,24 +200,26 @@ class aliyun implements DeployInterface
|
||||
}
|
||||
$this->log('ESA站点 ' . $sitename . ' 查询到' . $data['TotalCount'] . '个SSL证书');
|
||||
|
||||
$cert_id = null;
|
||||
$cert_name = null;
|
||||
$casid = null;
|
||||
foreach ($data['Result'] as $cert) {
|
||||
$domains = explode(',', $cert['SAN']);
|
||||
$flag = true;
|
||||
foreach ($domains as $domain) {
|
||||
if (!in_array($domain, $config['domainList'])) {
|
||||
$flag = false;
|
||||
$exist_cert_id = null;
|
||||
$exist_cert_name = null;
|
||||
$exist_cert_casid = null;
|
||||
if ($data['TotalCount'] > 0) {
|
||||
foreach ($data['Result'] as $cert) {
|
||||
$domains = explode(',', $cert['SAN']);
|
||||
$flag = true;
|
||||
foreach ($domains as $domain) {
|
||||
if (!in_array($domain, $config['domainList'])) {
|
||||
$flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($flag) {
|
||||
$exist_cert_id = $cert['Id'];
|
||||
$exist_cert_name = $cert['Name'];
|
||||
$exist_cert_casid = $cert['CasId'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($flag) {
|
||||
$cert_id = $cert['Id'];
|
||||
$cert_name = $cert['CommonName'];
|
||||
$casid = $cert['CasId'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$param = [
|
||||
@@ -213,20 +227,25 @@ class aliyun implements DeployInterface
|
||||
'SiteId' => $site_id,
|
||||
'Type' => 'cas',
|
||||
'CasId' => $cas_id,
|
||||
'Name' => $cert_name,
|
||||
'Region' => $config['region'],
|
||||
];
|
||||
if ($cert_id) {
|
||||
$param['Update'] = 'true';
|
||||
$param['Id'] = $cert_id;
|
||||
if ($casid == $cas_id) {
|
||||
|
||||
if ($exist_cert_id) {
|
||||
$param['Id'] = $exist_cert_id;
|
||||
|
||||
if ($exist_cert_casid == $cas_id) {
|
||||
$this->log('ESA站点 ' . $sitename . ' 证书已配置,无需重复操作');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$client->request($param);
|
||||
if ($cert_id) {
|
||||
$this->log('ESA站点 ' . $sitename . ' 域名 ' . $cert_name . ' 更新证书成功!');
|
||||
|
||||
if ($exist_cert_name) {
|
||||
$this->log('ESA站点 ' . $sitename . ' 证书 ' . $exist_cert_name . ' 更新成功');
|
||||
} else {
|
||||
$this->log('ESA站点 ' . $sitename . ' 添加证书成功!');
|
||||
$this->log('ESA站点 ' . $sitename . ' 证书添加成功!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace app\lib\deploy;
|
||||
|
||||
use app\lib\DeployInterface;
|
||||
use Exception;
|
||||
|
||||
class allwaf implements DeployInterface
|
||||
{
|
||||
private $logger;
|
||||
private $url = 'https://api.allwaf.cn';
|
||||
private $accessKeyId;
|
||||
private $accessKey;
|
||||
private $usertype = 'user';
|
||||
private $proxy;
|
||||
private $accessToken;
|
||||
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->accessKeyId = $config['accessKeyId'];
|
||||
$this->accessKey = $config['accessKey'];
|
||||
$this->proxy = $config['proxy'] == 1;
|
||||
}
|
||||
|
||||
public function check()
|
||||
{
|
||||
if (empty($this->url) || empty($this->accessKeyId) || empty($this->accessKey)) throw new Exception('必填参数不能为空');
|
||||
$this->getAccessToken();
|
||||
}
|
||||
|
||||
public function deploy($fullchain, $privatekey, $config, &$info)
|
||||
{
|
||||
$domains = $config['domainList'];
|
||||
if (empty($domains)) throw new Exception('没有设置要部署的域名');
|
||||
|
||||
$this->getAccessToken();
|
||||
|
||||
$params = [
|
||||
'domains' => $domains,
|
||||
'offset' => 0,
|
||||
'size' => 10,
|
||||
];
|
||||
try {
|
||||
$data = $this->request('/SSLCertService/listSSLCerts', $params);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('获取证书列表失败:' . $e->getMessage());
|
||||
}
|
||||
$list = json_decode(base64_decode($data['sslCertsJSON']), true);
|
||||
if (!$list || empty($list)) {
|
||||
throw new Exception('证书列表为空');
|
||||
}
|
||||
$this->log('获取证书列表成功(total=' . count($list) . ')');
|
||||
|
||||
$certInfo = openssl_x509_parse($fullchain, true);
|
||||
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
|
||||
|
||||
if (!empty($list)) {
|
||||
foreach ($list as $row) {
|
||||
$params = [
|
||||
'sslCertId' => $row['id'],
|
||||
'isOn' => true,
|
||||
'name' => $row['name'],
|
||||
'description' => $row['description'],
|
||||
'serverName' => $row['serverName'],
|
||||
'isCA' => false,
|
||||
'certData' => base64_encode($fullchain),
|
||||
'keyData' => base64_encode($privatekey),
|
||||
'timeBeginAt' => $certInfo['validFrom_time_t'],
|
||||
'timeEndAt' => $certInfo['validTo_time_t'],
|
||||
'dnsNames' => $domains,
|
||||
'commonNames' => [$certInfo['issuer']['CN']],
|
||||
];
|
||||
$this->request('/SSLCertService/updateSSLCert', $params);
|
||||
$this->log('证书ID:' . $row['id'] . '更新成功!');
|
||||
}
|
||||
} else {
|
||||
$params = [
|
||||
'isOn' => true,
|
||||
'name' => $cert_name,
|
||||
'description' => $cert_name,
|
||||
'serverName' => $certInfo['subject']['CN'],
|
||||
'isCA' => false,
|
||||
'certData' => base64_encode($fullchain),
|
||||
'keyData' => base64_encode($privatekey),
|
||||
'timeBeginAt' => $certInfo['validFrom_time_t'],
|
||||
'timeEndAt' => $certInfo['validTo_time_t'],
|
||||
'dnsNames' => $domains,
|
||||
'commonNames' => [$certInfo['issuer']['CN']],
|
||||
];
|
||||
$result = $this->request('/SSLCertService/createSSLCert', $params);
|
||||
$this->log('证书ID:' . $result['sslCertId'] . '添加成功!');
|
||||
}
|
||||
}
|
||||
|
||||
private function getAccessToken()
|
||||
{
|
||||
$path = '/APIAccessTokenService/getAPIAccessToken';
|
||||
$params = [
|
||||
'type' => $this->usertype,
|
||||
'accessKeyId' => $this->accessKeyId,
|
||||
'accessKey' => $this->accessKey,
|
||||
];
|
||||
$result = $this->request($path, $params);
|
||||
if (isset($result['token'])) {
|
||||
$this->accessToken = $result['token'];
|
||||
} else {
|
||||
throw new Exception('登录成功,获取AccessToken失败');
|
||||
}
|
||||
}
|
||||
|
||||
private function request($path, $params = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
$headers = [];
|
||||
$body = null;
|
||||
if ($this->accessToken) {
|
||||
$headers[] = 'X-Cloud-Access-Token: ' . $this->accessToken;
|
||||
}
|
||||
if ($params) {
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 200) {
|
||||
return isset($result['data']) ? $result['data'] : null;
|
||||
} elseif (isset($result['message'])) {
|
||||
throw new Exception($result['message']);
|
||||
} else {
|
||||
if (!empty($response['body'])) $this->log('Response:' . $response['body']);
|
||||
throw new Exception('返回数据解析失败');
|
||||
}
|
||||
}
|
||||
|
||||
public function setLogger($func)
|
||||
{
|
||||
$this->logger = $func;
|
||||
}
|
||||
|
||||
private function log($txt)
|
||||
{
|
||||
if ($this->logger) {
|
||||
call_user_func($this->logger, $txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,10 +56,10 @@ class baishan implements DeployInterface
|
||||
$headers = [];
|
||||
$body = null;
|
||||
if ($params) {
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 0) {
|
||||
return $result;
|
||||
|
||||
@@ -46,7 +46,16 @@ class btpanel implements DeployInterface
|
||||
foreach ($sites as $site) {
|
||||
$siteName = trim($site);
|
||||
if (empty($siteName)) continue;
|
||||
if ($config['type'] == '2') {
|
||||
if ($config['type'] == '3') {
|
||||
try {
|
||||
$this->deployDocker($siteName, $fullchain, $privatekey);
|
||||
$this->log("Docker域名 {$siteName} 证书部署成功");
|
||||
$success++;
|
||||
} catch (Exception $e) {
|
||||
$errmsg = $e->getMessage();
|
||||
$this->log("Docker域名 {$siteName} 证书部署失败:" . $errmsg);
|
||||
}
|
||||
} elseif ($config['type'] == '2') {
|
||||
try {
|
||||
$this->deployMailSys($siteName, $fullchain, $privatekey);
|
||||
$this->log("邮局域名 {$siteName} 证书部署成功");
|
||||
@@ -129,6 +138,25 @@ class btpanel implements DeployInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function deployDocker($domain, $fullchain, $privatekey)
|
||||
{
|
||||
$path = '/mod/docker/com/set_ssl';
|
||||
$data = [
|
||||
'site_name' => $domain,
|
||||
'key' => $privatekey,
|
||||
'csr' => $fullchain,
|
||||
];
|
||||
$response = $this->request($path, $data);
|
||||
$result = json_decode($response, true);
|
||||
if (isset($result['status']) && $result['status']) {
|
||||
return true;
|
||||
} elseif (isset($result['msg'])) {
|
||||
throw new Exception($result['msg']);
|
||||
} else {
|
||||
throw new Exception($response ? $response : '返回数据解析失败');
|
||||
}
|
||||
}
|
||||
|
||||
public function setLogger($func)
|
||||
{
|
||||
$this->logger = $func;
|
||||
@@ -151,7 +179,7 @@ class btpanel implements DeployInterface
|
||||
'request_time' => $now_time
|
||||
];
|
||||
$post_data = array_merge($post_data, $params);
|
||||
$response = curl_client($url, $post_data, null, null, null, $this->proxy);
|
||||
$response = http_request($url, $post_data, null, null, null, $this->proxy);
|
||||
return $response['body'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +123,12 @@ class btwaf implements DeployInterface
|
||||
|
||||
$now_time = time();
|
||||
$headers = [
|
||||
'waf_request_time: ' . $now_time,
|
||||
'waf_request_token: ' . md5($now_time . md5($this->key)),
|
||||
'Content-Type: application/json',
|
||||
'waf_request_time' => $now_time,
|
||||
'waf_request_token' => md5($now_time . md5($this->key)),
|
||||
'Content-Type' => 'application/json',
|
||||
];
|
||||
$post = $params ? json_encode($params) : null;
|
||||
$response = curl_client($url, $post, null, null, $headers, $this->proxy, 'POST');
|
||||
$response = http_request($url, $post, null, null, $headers, $this->proxy, 'POST');
|
||||
return $response['body'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@ class cachefly implements DeployInterface
|
||||
private function request($path, $params = null, $method = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
$headers = ['x-cf-authorization: Bearer ' . $this->apikey];
|
||||
$headers = ['x-cf-authorization' => 'Bearer ' . $this->apikey];
|
||||
$body = null;
|
||||
if ($params) {
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$result = json_decode($response['body'], true);
|
||||
if ($response['code'] >= 200 && $response['code'] < 300) {
|
||||
return $result;
|
||||
|
||||
@@ -44,13 +44,13 @@ class cdnfly implements DeployInterface
|
||||
private function request($path, $params = null, $method = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
$headers = ['api-key: ' . $this->api_key, 'api-secret: ' . $this->api_secret];
|
||||
$headers = ['api-key' => $this->api_key, 'api-secret' => $this->api_secret];
|
||||
$body = null;
|
||||
if ($params) {
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 0) {
|
||||
return isset($result['data']) ? $result['data'] : null;
|
||||
|
||||
@@ -95,13 +95,13 @@ class doge implements DeployInterface
|
||||
$signStr = $path . "\n" . $body;
|
||||
$sign = hash_hmac('sha1', $signStr, $this->SecretKey);
|
||||
$authorization = "TOKEN " . $this->AccessKey . ":" . $sign;
|
||||
$headers = ['Authorization: ' . $authorization];
|
||||
if($body && $json) $headers[] = 'Content-Type: application/json';
|
||||
$headers = ['Authorization' => $authorization];
|
||||
if($body && $json) $headers['Content-Type'] = 'application/json';
|
||||
$url = 'https://api.dogecloud.com'.$path;
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if(isset($result['code']) && $result['code'] == 200){
|
||||
return isset($result['data']) ? $result['data'] : true;
|
||||
return $result['data'] ?? true;
|
||||
}elseif(isset($result['msg'])){
|
||||
throw new Exception($result['msg']);
|
||||
}else{
|
||||
|
||||
@@ -42,13 +42,13 @@ class gcore implements DeployInterface
|
||||
private function request($path, $params = null, $method = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
$headers = ['Authorization: APIKey ' . $this->apikey];
|
||||
$headers = ['Authorization' => 'APIKey ' . $this->apikey];
|
||||
$body = null;
|
||||
if ($params) {
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$result = json_decode($response['body'], true);
|
||||
if ($response['code'] >= 200 && $response['code'] < 300) {
|
||||
return $result;
|
||||
|
||||
@@ -119,19 +119,19 @@ class goedge implements DeployInterface
|
||||
$body = null;
|
||||
if ($this->accessToken) {
|
||||
if ($this->systype == '1') {
|
||||
$headers[] = 'X-Cloud-Access-Token: ' . $this->accessToken;
|
||||
$headers['X-Cloud-Access-Token'] = $this->accessToken;
|
||||
} else {
|
||||
$headers[] = 'X-Edge-Access-Token: ' . $this->accessToken;
|
||||
$headers['X-Edge-Access-Token'] = $this->accessToken;
|
||||
}
|
||||
}
|
||||
if ($params) {
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 200) {
|
||||
return isset($result['data']) ? $result['data'] : null;
|
||||
return $result['data'] ?? null;
|
||||
} elseif (isset($result['message'])) {
|
||||
throw new Exception($result['message']);
|
||||
} else {
|
||||
|
||||
@@ -71,7 +71,7 @@ class kangle implements DeployInterface
|
||||
'certificate' => $fullchain,
|
||||
'certificate_key' => $privatekey,
|
||||
];
|
||||
$response = curl_client($this->url . $path, http_build_query($post), null, $this->cookie, null, $this->proxy);
|
||||
$response = http_request($this->url . $path, http_build_query($post), null, $this->cookie, null, $this->proxy);
|
||||
if (strpos($response['body'], '成功')) {
|
||||
return true;
|
||||
} elseif (preg_match('/alert\(\'(.*?)\'\)/i', $response['body'], $match)) {
|
||||
@@ -90,7 +90,7 @@ class kangle implements DeployInterface
|
||||
'certificate' => $fullchain,
|
||||
'certificate_key' => $privatekey,
|
||||
];
|
||||
$response = curl_client($this->url . $path, http_build_query($post), null, $this->cookie, null, $this->proxy);
|
||||
$response = http_request($this->url . $path, http_build_query($post), null, $this->cookie, null, $this->proxy);
|
||||
if (strpos($response['body'], '成功')) {
|
||||
return true;
|
||||
} elseif (preg_match('/alert\(\'(.*?)\'\)/i', $response['body'], $match)) {
|
||||
@@ -114,11 +114,11 @@ class kangle implements DeployInterface
|
||||
private function loginBySkey()
|
||||
{
|
||||
$url = $this->url . '/vhost/index.php?c=sso&a=hello&url=' . urlencode($this->url . '/index.php?');
|
||||
$response = curl_client($url, null, null, null, null, $this->proxy);
|
||||
$response = http_request($url, null, null, null, null, $this->proxy);
|
||||
if ($response['code'] == 302 && !empty($response['redirect_url'])) {
|
||||
$cookie = '';
|
||||
if (preg_match_all('/Set-Cookie: (.*);/iU', $response['header'], $matchs)) {
|
||||
foreach ($matchs[1] as $val) {
|
||||
if (isset($response['headers']['Set-Cookie'])) {
|
||||
foreach ($response['headers']['Set-Cookie'] as $val) {
|
||||
$arr = explode('=', $val);
|
||||
if ($arr[1] == '' || $arr[1] == 'deleted') continue;
|
||||
$cookie .= $val . '; ';
|
||||
@@ -147,7 +147,7 @@ class kangle implements DeployInterface
|
||||
{
|
||||
$s = md5($sess_key . $this->username . $sess_key . $this->skey);
|
||||
$url = $this->url . '/vhost/index.php?c=sso&a=login&name=' . $this->username . '&r=' . $sess_key . '&s=' . $s;
|
||||
$response = curl_client($url, null, null, $cookie, null, $this->proxy);
|
||||
$response = http_request($url, null, null, $cookie, null, $this->proxy);
|
||||
if ($response['code'] == 302) {
|
||||
return true;
|
||||
} elseif (strlen($response['body']) > 3 && strlen($response['body']) < 50) {
|
||||
@@ -165,11 +165,11 @@ class kangle implements DeployInterface
|
||||
'username' => $this->username,
|
||||
'passwd' => $this->password,
|
||||
];
|
||||
$response = curl_client($url, http_build_query($post), $referer, null, null, $this->proxy);
|
||||
$response = http_request($url, http_build_query($post), $referer, null, null, $this->proxy);
|
||||
if ($response['code'] == 302) {
|
||||
$cookie = '';
|
||||
if (preg_match_all('/Set-Cookie: (.*);/iU', $response['header'], $matchs)) {
|
||||
foreach ($matchs[1] as $val) {
|
||||
if (isset($response['headers']['Set-Cookie'])) {
|
||||
foreach ($response['headers']['Set-Cookie'] as $val) {
|
||||
$arr = explode('=', $val);
|
||||
if ($arr[1] == '' || $arr[1] == 'deleted') continue;
|
||||
$cookie .= $val . '; ';
|
||||
@@ -191,7 +191,7 @@ class kangle implements DeployInterface
|
||||
private function getMain()
|
||||
{
|
||||
$path = '/vhost/';
|
||||
curl_client($this->url . $path, null, null, $this->cookie, null, $this->proxy);
|
||||
http_request($this->url . $path, null, null, $this->cookie, null, $this->proxy);
|
||||
}
|
||||
|
||||
public function setLogger($func)
|
||||
|
||||
@@ -71,7 +71,7 @@ class kangleadmin implements DeployInterface
|
||||
'certificate' => $fullchain,
|
||||
'certificate_key' => $privatekey,
|
||||
];
|
||||
$response = curl_client($this->url . $path, http_build_query($post), null, $this->cookie, null, $this->proxy);
|
||||
$response = http_request($this->url . $path, http_build_query($post), null, $this->cookie, null, $this->proxy);
|
||||
if (strpos($response['body'], '成功')) {
|
||||
return true;
|
||||
} elseif (preg_match('/alert\(\'(.*?)\'\)/i', $response['body'], $match)) {
|
||||
@@ -90,7 +90,7 @@ class kangleadmin implements DeployInterface
|
||||
'certificate' => $fullchain,
|
||||
'certificate_key' => $privatekey,
|
||||
];
|
||||
$response = curl_client($this->url . $path, http_build_query($post), null, $this->cookie, null, $this->proxy);
|
||||
$response = http_request($this->url . $path, http_build_query($post), null, $this->cookie, null, $this->proxy);
|
||||
if (strpos($response['body'], '成功')) {
|
||||
return true;
|
||||
} elseif (preg_match('/alert\(\'(.*?)\'\)/i', $response['body'], $match)) {
|
||||
@@ -105,11 +105,11 @@ class kangleadmin implements DeployInterface
|
||||
private function login()
|
||||
{
|
||||
$url = $this->url . $this->path . '/index.php?c=sso&a=hello&url=' . urlencode($this->url . $this->path . '/index.php?');
|
||||
$response = curl_client($url, null, null, null, null, $this->proxy);
|
||||
$response = http_request($url, null, null, null, null, $this->proxy);
|
||||
if ($response['code'] == 302 && !empty($response['redirect_url'])) {
|
||||
$cookie = '';
|
||||
if (preg_match_all('/Set-Cookie: (.*);/iU', $response['header'], $matchs)) {
|
||||
foreach ($matchs[1] as $val) {
|
||||
if (isset($response['headers']['Set-Cookie'])) {
|
||||
foreach ($response['headers']['Set-Cookie'] as $val) {
|
||||
$arr = explode('=', $val);
|
||||
if ($arr[1] == '' || $arr[1] == 'deleted') continue;
|
||||
$cookie .= $val . '; ';
|
||||
@@ -138,7 +138,7 @@ class kangleadmin implements DeployInterface
|
||||
{
|
||||
$s = md5($sess_key . $this->username . $sess_key . $this->skey);
|
||||
$url = $this->url . $this->path . '/index.php?c=sso&a=login&name=' . $this->username . '&r=' . $sess_key . '&s=' . $s;
|
||||
$response = curl_client($url, null, null, $cookie, null, $this->proxy);
|
||||
$response = http_request($url, null, null, $cookie, null, $this->proxy);
|
||||
if ($response['code'] == 302) {
|
||||
return true;
|
||||
} elseif (strlen($response['body']) > 3 && strlen($response['body']) < 50) {
|
||||
@@ -151,9 +151,9 @@ class kangleadmin implements DeployInterface
|
||||
private function loginVhost($name)
|
||||
{
|
||||
$url = $this->url . $this->path . '/index.php?c=vhost&a=impLogin&name=' . $name;
|
||||
$response = curl_client($url, null, null, $this->cookie, null, $this->proxy);
|
||||
$response = http_request($url, null, null, $this->cookie, null, $this->proxy);
|
||||
if ($response['code'] == 302) {
|
||||
curl_client($this->url . '/vhost/', null, null, $this->cookie, null, $this->proxy);
|
||||
http_request($this->url . '/vhost/', null, null, $this->cookie, null, $this->proxy);
|
||||
} else {
|
||||
throw new Exception('用户面板登录失败 (httpCode=' . $response['code'] . ')');
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ class kuocai implements DeployInterface
|
||||
$url = 'https://kuocai.cn' . $path;
|
||||
$body = $json ? json_encode($params) : $params;
|
||||
$headers = [];
|
||||
if ($json) $headers[] = 'Content-Type: application/json';
|
||||
$response = curl_client(
|
||||
if ($json) $headers['Content-Type'] = 'application/json';
|
||||
$response = http_request(
|
||||
$url,
|
||||
$body,
|
||||
null,
|
||||
|
||||
@@ -59,6 +59,7 @@ class lecdn implements DeployInterface
|
||||
$path = '/prod-api/login';
|
||||
$params = [
|
||||
'email' => $this->email,
|
||||
'username' => $this->email,
|
||||
'password' => $this->password,
|
||||
];
|
||||
$result = $this->request($path, $params);
|
||||
@@ -75,16 +76,16 @@ class lecdn implements DeployInterface
|
||||
$headers = [];
|
||||
$body = null;
|
||||
if ($this->accessToken) {
|
||||
$headers[] = 'Authorization: Bearer ' . $this->accessToken;
|
||||
$headers['Authorization'] = 'Bearer ' . $this->accessToken;
|
||||
}
|
||||
if ($params) {
|
||||
$headers[] = 'Content-Type: application/json;charset=UTF-8';
|
||||
$headers['Content-Type'] = 'application/json;charset=UTF-8';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 200) {
|
||||
return isset($result['data']) ? $result['data'] : null;
|
||||
return $result['data'] ?? null;
|
||||
} elseif (isset($result['message'])) {
|
||||
throw new Exception($result['message']);
|
||||
} else {
|
||||
|
||||
114
app/lib/deploy/lucky.php
Normal file
114
app/lib/deploy/lucky.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace app\lib\deploy;
|
||||
|
||||
use app\lib\DeployInterface;
|
||||
use Exception;
|
||||
|
||||
class lucky implements DeployInterface
|
||||
{
|
||||
private $logger;
|
||||
private $url;
|
||||
private $opentoken;
|
||||
private $proxy;
|
||||
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->url = rtrim($config['url'], '/') . (!empty($config['path']) ? $config['path'] : '');
|
||||
$this->opentoken = $config['opentoken'];
|
||||
$this->proxy = $config['proxy'] == 1;
|
||||
}
|
||||
|
||||
public function check()
|
||||
{
|
||||
if (empty($this->url) || empty($this->opentoken)) throw new Exception('请填写面板地址和OpenToken');
|
||||
$this->request("/api/modules/list");
|
||||
}
|
||||
|
||||
public function deploy($fullchain, $privatekey, $config, &$info)
|
||||
{
|
||||
$domains = $config['domainList'];
|
||||
if (empty($domains)) throw new Exception('没有设置要部署的域名');
|
||||
|
||||
try {
|
||||
$data = $this->request("/api/ssl");
|
||||
$this->log('获取证书列表成功');
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('获取证书列表失败:' . $e->getMessage());
|
||||
}
|
||||
|
||||
$success = 0;
|
||||
$errmsg = null;
|
||||
if (!empty($data['list'])) {
|
||||
foreach ($data['list'] as $row) {
|
||||
if (empty($row['CertsInfo']['Domains'])) continue;
|
||||
$cert_domains = $row['CertsInfo']['Domains'];
|
||||
$flag = false;
|
||||
foreach ($cert_domains as $domain) {
|
||||
if (in_array($domain, $domains)) {
|
||||
$flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($flag) {
|
||||
$params = [
|
||||
'Key' => $row['Key'],
|
||||
'CertBase64' => base64_encode($fullchain),
|
||||
'KeyBase64' => base64_encode($privatekey),
|
||||
'AddFrom' => 'file',
|
||||
'Enable' => true,
|
||||
'MappingToPath' => false,
|
||||
'Remark' => $row['Remark'] ?: '',
|
||||
'AllSyncClient' => false,
|
||||
];
|
||||
try {
|
||||
$this->request('/api/ssl', $params, 'PUT');
|
||||
$this->log("证书ID:{$row['Key']}更新成功!");
|
||||
$success++;
|
||||
} catch (Exception $e) {
|
||||
$errmsg = $e->getMessage();
|
||||
$this->log("证书ID:{$row['Key']}更新失败:" . $errmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($success == 0) {
|
||||
throw new Exception($errmsg ? $errmsg : '没有要更新的证书');
|
||||
}
|
||||
}
|
||||
|
||||
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, $method = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
|
||||
$headers = [
|
||||
'openToken' => $this->opentoken,
|
||||
];
|
||||
$body = null;
|
||||
if ($params) {
|
||||
$body = json_encode($params);
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['ret']) && $result['ret'] == 0) {
|
||||
return $result;
|
||||
} elseif (isset($result['msg'])) {
|
||||
throw new Exception($result['msg']);
|
||||
} else {
|
||||
throw new Exception('请求失败(httpCode=' . $response['code'] . ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,10 +118,10 @@ class mwpanel implements DeployInterface
|
||||
$url = $this->url . $path;
|
||||
|
||||
$headers = [
|
||||
'app-id: '.$this->appid,
|
||||
'app-secret: '.$this->appsecret,
|
||||
'app-id' => $this->appid,
|
||||
'app-secret' => $this->appsecret,
|
||||
];
|
||||
$response = curl_client($url, $params ? http_build_query($params) : null, null, null, $headers, $this->proxy);
|
||||
$response = http_request($url, $params ? http_build_query($params) : null, null, null, $headers, $this->proxy);
|
||||
return $response['body'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,15 +96,15 @@ class opanel implements DeployInterface
|
||||
$timestamp = time() . '';
|
||||
$token = md5('1panel' . $this->key . $timestamp);
|
||||
$headers = [
|
||||
'1Panel-Token: ' . $token,
|
||||
'1Panel-Timestamp: ' . $timestamp
|
||||
'1Panel-Token' => $token,
|
||||
'1Panel-Timestamp' => $timestamp
|
||||
];
|
||||
$body = $params ? json_encode($params) : '{}';
|
||||
if ($body) $headers[] = 'Content-Type: application/json';
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy);
|
||||
if ($body) $headers['Content-Type'] = 'application/json';
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 200) {
|
||||
return isset($result['data']) ? $result['data'] : null;
|
||||
return $result['data'] ?? null;
|
||||
} elseif (isset($result['message'])) {
|
||||
throw new Exception($result['message']);
|
||||
} else {
|
||||
|
||||
@@ -59,9 +59,9 @@ class proxmox implements DeployInterface
|
||||
private function send_request($path, $params = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
$headers = ['Authorization: PVEAPIToken=' . $this->api_user . '=' . $this->api_key];
|
||||
$headers = ['Authorization' => 'PVEAPIToken=' . $this->api_user . '=' . $this->api_key];
|
||||
$post = $params ? http_build_query($params) : null;
|
||||
$response = curl_client($url, $post, null, null, $headers, $this->proxy);
|
||||
$response = http_request($url, $post, null, null, $headers, $this->proxy);
|
||||
if ($response['code'] == 200) {
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['data'])) {
|
||||
@@ -75,12 +75,7 @@ class proxmox implements DeployInterface
|
||||
throw new Exception('返回数据解析失败');
|
||||
}
|
||||
} else {
|
||||
$header = getSubstr($response['header'], ' ', "\r\n");
|
||||
if ($header) {
|
||||
throw new Exception($header);
|
||||
} else {
|
||||
throw new Exception('请求失败(httpCode=' . $response['code'] . ')');
|
||||
}
|
||||
throw new Exception('请求失败(httpCode=' . $response['code'] . ', body=' . $response['body'] . ')');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
78
app/lib/deploy/rainyun.php
Normal file
78
app/lib/deploy/rainyun.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace app\lib\deploy;
|
||||
|
||||
use app\lib\DeployInterface;
|
||||
use Exception;
|
||||
|
||||
class rainyun implements DeployInterface
|
||||
{
|
||||
private $logger;
|
||||
private $url = 'https://api.v2.rainyun.com';
|
||||
private $apikey;
|
||||
private $proxy;
|
||||
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->apikey = $config['apikey'];
|
||||
$this->proxy = $config['proxy'] == 1;
|
||||
}
|
||||
|
||||
public function check()
|
||||
{
|
||||
if (empty($this->apikey)) throw new Exception('ApiKey不能为空');
|
||||
$this->request('/product/');
|
||||
}
|
||||
|
||||
public function deploy($fullchain, $privatekey, $config, &$info)
|
||||
{
|
||||
if (empty($config['id'])) throw new Exception('证书ID不能为空');
|
||||
|
||||
$params = [
|
||||
'cert' => $fullchain,
|
||||
'key' => $privatekey,
|
||||
];
|
||||
try {
|
||||
$this->request('/product/sslcenter/' . $config['id'], $params, 'PUT');
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
|
||||
$this->log('证书ID:' . $config['id'] . '更新成功!');
|
||||
}
|
||||
|
||||
private function request($path, $params = null, $method = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
$headers = [
|
||||
'x-api-key' => $this->apikey,
|
||||
];
|
||||
$body = null;
|
||||
if ($params) {
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['code']) && $result['code'] == 200) {
|
||||
return $result;
|
||||
} elseif (isset($result['message'])) {
|
||||
throw new Exception($result['message']);
|
||||
} else {
|
||||
if (!empty($response['body'])) $this->log('Response:' . $response['body']);
|
||||
throw new Exception('请求失败(httpCode=' . $response['code'] . ')');
|
||||
}
|
||||
}
|
||||
|
||||
public function setLogger($func)
|
||||
{
|
||||
$this->logger = $func;
|
||||
}
|
||||
|
||||
private function log($txt)
|
||||
{
|
||||
if ($this->logger) {
|
||||
call_user_func($this->logger, $txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,10 +113,10 @@ class ratpanel implements DeployInterface
|
||||
$url = $this->url . '/api' . $path;
|
||||
$body = $method == 'GET' ? null : json_encode($params);
|
||||
$sign = $this->signRequest($method, $url, $body, $this->id, $this->token);
|
||||
$response = curl_client($url, $body, null, null, [
|
||||
'Content-Type: application/json',
|
||||
'X-Timestamp: ' . $sign['timestamp'],
|
||||
'Authorization: HMAC-SHA256 Credential=' . $sign['id'] . ', Signature=' . $sign['signature']
|
||||
$response = http_request($url, $body, null, null, [
|
||||
'Content-Type' => 'application/json',
|
||||
'X-Timestamp' => $sign['timestamp'],
|
||||
'Authorization' => 'HMAC-SHA256 Credential=' . $sign['id'] . ', Signature=' . $sign['signature']
|
||||
], $this->proxy, $method);
|
||||
return $response['body'];
|
||||
}
|
||||
@@ -130,7 +130,7 @@ class ratpanel implements DeployInterface
|
||||
|
||||
// 规范化路径
|
||||
$canonicalPath = $path;
|
||||
if (strpos($path, '/api') !== 0) {
|
||||
if (!str_starts_with($path, '/api')) {
|
||||
$apiPos = strpos($path, '/api');
|
||||
if ($apiPos !== false) {
|
||||
$canonicalPath = substr($path, $apiPos);
|
||||
|
||||
@@ -83,16 +83,16 @@ class safeline implements DeployInterface
|
||||
private function request($path, $params = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
$headers = ['X-SLCE-API-TOKEN: ' . $this->token];
|
||||
$headers = ['X-SLCE-API-TOKEN' => $this->token];
|
||||
$body = null;
|
||||
if ($params) {
|
||||
$heders[] = 'Content-Type: application/json';
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
$body = json_encode($params);
|
||||
}
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if ($response['code'] == 200 && $result) {
|
||||
return isset($result['data']) ? $result['data'] : null;
|
||||
return $result['data'] ?? null;
|
||||
} else {
|
||||
throw new Exception(!empty($result['msg']) ? $result['msg'] : '请求失败(httpCode=' . $response['code'] . ')');
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class synology implements DeployInterface
|
||||
'format' => 'sid',
|
||||
'enable_syno_token' => 'yes',
|
||||
];
|
||||
$response = curl_client($url, http_build_query($params), null, null, null, $this->proxy);
|
||||
$response = http_request($url, http_build_query($params), null, null, null, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['success']) && $result['success']) {
|
||||
$this->token = $result['data'];
|
||||
@@ -69,7 +69,7 @@ class synology implements DeployInterface
|
||||
'_sid' => $this->token['sid'],
|
||||
'SynoToken' => $this->token['synotoken'],
|
||||
];
|
||||
$response = curl_client($url . '?' . http_build_query($params), null, null, $this->proxy);
|
||||
$response = http_request($url . '?' . http_build_query($params), null, null, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['success']) && $result['success']) {
|
||||
$this->log('获取证书列表成功');
|
||||
@@ -119,7 +119,7 @@ class synology implements DeployInterface
|
||||
'id' => $id,
|
||||
'desc' => $config['desc'],
|
||||
];
|
||||
$response = curl_client($url . '?' . http_build_query($params), $post, null, null, null, $this->proxy, null, 15);
|
||||
$response = http_request($url . '?' . http_build_query($params), $post, null, null, null, $this->proxy, null, 15);
|
||||
unlink($privatekey_file);
|
||||
unlink($fullchain_file);
|
||||
$result = json_decode($response['body'], true);
|
||||
|
||||
@@ -105,6 +105,13 @@ class tencent implements DeployInterface
|
||||
}
|
||||
$this->log('上传证书成功 CertificateId=' . $data['CertificateId']);
|
||||
usleep(300000);
|
||||
|
||||
$param = [
|
||||
'CertificateIds' => [$data['CertificateId']],
|
||||
'SwitchStatus' => 1,
|
||||
];
|
||||
$this->client->request('ModifyCertificatesExpiringNotificationSwitch', $param);
|
||||
|
||||
return $data['CertificateId'];
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class upyun implements DeployInterface
|
||||
'certificate' => $fullchain,
|
||||
'private_key' => $privatekey,
|
||||
];
|
||||
$response = curl_client($url, http_build_query($params), null, $this->cookie, null, $this->proxy);
|
||||
$response = http_request($url, http_build_query($params), null, $this->cookie, null, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if ($result['data']['status'] === 0) {
|
||||
$common_name = $result['data']['result']['commonName'];
|
||||
@@ -52,7 +52,7 @@ class upyun implements DeployInterface
|
||||
'limit' => 100,
|
||||
'domain' => $common_name,
|
||||
];
|
||||
$response = curl_client($url . '?' . http_build_query($params), null, null, $this->cookie, null, $this->proxy);
|
||||
$response = http_request($url . '?' . http_build_query($params), null, null, $this->cookie, null, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['data']['result']) && is_array($result['data']['result'])) {
|
||||
$cert_list = $result['data']['result'];
|
||||
@@ -73,7 +73,7 @@ class upyun implements DeployInterface
|
||||
'new_crt_id' => $certificate_id,
|
||||
'old_crt_id' => $crt_id,
|
||||
];
|
||||
$response = curl_client($url, http_build_query($params), null, $this->cookie, null, $this->proxy);
|
||||
$response = http_request($url, http_build_query($params), null, $this->cookie, null, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['data']['result']) && $result['data']['result'] == true) {
|
||||
$i++;
|
||||
@@ -97,12 +97,12 @@ class upyun implements DeployInterface
|
||||
'username' => $this->username,
|
||||
'password' => $this->password,
|
||||
];
|
||||
$response = curl_client($url, http_build_query($params), null, null, null, $this->proxy);
|
||||
$response = http_request($url, http_build_query($params), null, null, null, $this->proxy);
|
||||
$result = json_decode($response['body'], true);
|
||||
if (isset($result['data']['result']) && $result['data']['result'] == true) {
|
||||
$cookie = '';
|
||||
if (preg_match_all('/Set-Cookie: (.*);/iU', $response['header'], $matchs)) {
|
||||
foreach ($matchs[1] as $val) {
|
||||
if (isset($response['headers']['Set-Cookie'])) {
|
||||
foreach ($response['headers']['Set-Cookie'] as $val) {
|
||||
$arr = explode('=', $val);
|
||||
if ($arr[1] == '' || $arr[1] == 'deleted') continue;
|
||||
$cookie .= $val . '; ';
|
||||
|
||||
@@ -24,7 +24,7 @@ class wangsu implements DeployInterface
|
||||
public function check()
|
||||
{
|
||||
if (empty($this->username) || empty($this->apiKey)) throw new Exception('必填参数不能为空');
|
||||
$this->request('/cdn/certificates');
|
||||
$this->request('/api/ssl/certificate');
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ class wangsu implements DeployInterface
|
||||
} elseif ($cert_name == $cert['name']) {
|
||||
$this->log('证书' . $cert_name . '已存在,但序列号(' . $cert['certificate-id'] . ')不匹配,准备重新上传');
|
||||
try {
|
||||
$this->request('/api/certificate/' . $cert['certificate-id'], [['name'] => $cert_name . '-bak'], true, null, 'PUT');
|
||||
$this->request('/api/certificate/' . $cert['certificate-id'], ['name' => $cert_name . '-bak'], true, null, 'PUT');
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('证书更名失败:' . $e->getMessage());
|
||||
}
|
||||
@@ -416,29 +416,29 @@ class wangsu implements DeployInterface
|
||||
|
||||
if (empty($headers)) {
|
||||
$headers = [
|
||||
'Authorization: ' . $authorization,
|
||||
'Date: ' . $date,
|
||||
'Accept: application/json',
|
||||
'Connection: close',
|
||||
'Authorization' => $authorization,
|
||||
'Date' => $date,
|
||||
'Accept' => 'application/json',
|
||||
'Connection' => 'close',
|
||||
];
|
||||
} else {
|
||||
$headers[] = 'Authorization: ' . $authorization;
|
||||
$headers[] = 'Date: ' . $date;
|
||||
$headers[] = 'Accept: application/json';
|
||||
$headers[] = 'Connection: close';
|
||||
$headers['Authorization'] = $authorization;
|
||||
$headers['Date'] = $date;
|
||||
$headers['Accept'] = 'application/json';
|
||||
$headers['Connection'] = 'close';
|
||||
}
|
||||
|
||||
if ($body && $json) {
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
$url = 'https://open.chinanetcenter.com' . $path;
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy, $method, 30, false);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method, 30);
|
||||
$result = json_decode($response['body'], true);
|
||||
|
||||
if ((isset($response['code']) && $response['code'] == 201) || (isset($response['code']) && $response['code'] == 200 && $getLocation === true)) {
|
||||
if (preg_match('/Location:\s*(.*)/i', $response['header'], $matches)) {
|
||||
$location = trim($matches[1]); // 提取 Location 头部的值并去除多余空格
|
||||
if (isset($response['headers']['Location'])) {
|
||||
$location = trim(array_shift($response['headers']['Location'])); // 提取 Location 头部的值并去除多余空格
|
||||
if (!empty($location)) {
|
||||
return $location;
|
||||
}
|
||||
@@ -452,6 +452,9 @@ class wangsu implements DeployInterface
|
||||
} elseif (isset($result['message'])) {
|
||||
throw new Exception($result['message']);
|
||||
|
||||
} elseif (isset($result['result'])) {
|
||||
throw new Exception($result['result']);
|
||||
|
||||
} else {
|
||||
throw new Exception('请求失败');
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ class west implements DeployInterface
|
||||
$params['username'] = $this->username;
|
||||
$params['time'] = getMillisecond();
|
||||
$params['token'] = md5($this->username . $this->api_password . $params['time']);
|
||||
$response = curl_client($this->baseUrl . $path, str_replace('+', '%20', http_build_query($params)), null, null, null, $this->proxy);
|
||||
$response = http_request($this->baseUrl . $path, str_replace('+', '%20', http_build_query($params)), null, null, null, $this->proxy);
|
||||
$response = mb_convert_encoding($response['body'], 'UTF-8', 'GBK');
|
||||
$arr = json_decode($response, true);
|
||||
if ($arr) {
|
||||
|
||||
@@ -293,6 +293,16 @@ class aliyun implements DnsInterface
|
||||
return $this->request($param);
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
$param = ['Action' => 'AddDomain', 'DomainName' => $Domain];
|
||||
$result = $this->request($param, true);
|
||||
if ($result) {
|
||||
return ['id' => $result['DomainId'], 'name' => $result['DomainName']];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertLineCode($line)
|
||||
{
|
||||
$convert_dict = ['0' => 'default', '10=1' => 'unicom', '10=0' => 'telecom', '10=3' => 'mobile', '10=2' => 'edu', '3=0' => 'oversea', '10=22' => 'btvn', '80=0' => 'search', '7=0' => 'internal'];
|
||||
|
||||
@@ -222,6 +222,19 @@ class baidu implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
$query = ['clientToken' => getSid(), 'name' => $Domain];
|
||||
$res = $this->send_reuqest('POST', '/v1/dns/zone', null, $query);
|
||||
if ($res) {
|
||||
$data = $this->getDomainInfo($Domain);
|
||||
if ($data) {
|
||||
return ['id' => $data['DomainId'], 'name' => $data['Domain']];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertType($type)
|
||||
{
|
||||
return $type;
|
||||
|
||||
@@ -205,6 +205,16 @@ class cloudflare implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
$param = ['name' => $Domain];
|
||||
$data = $this->send_reuqest('POST', '/zones', $param);
|
||||
if ($data) {
|
||||
return ['id' => $data['result']['id'], 'name' => $data['result']['name']];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertType($type)
|
||||
{
|
||||
$convert_dict = ['REDIRECT_URL' => 'URI', 'FORWARD_URL' => 'URI'];
|
||||
|
||||
@@ -210,6 +210,16 @@ class dnsla implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
$param = ['domain' => $Domain];
|
||||
$data = $this->execute('POST', '/api/domain', $param);
|
||||
if ($data) {
|
||||
return ['id' => $data['id'], 'name' => $Domain];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertType($type)
|
||||
{
|
||||
$typeList = array_flip($this->typeList);
|
||||
|
||||
@@ -314,6 +314,19 @@ class dnspod implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
$action = 'CreateDomain';
|
||||
$param = [
|
||||
'Domain' => $Domain,
|
||||
];
|
||||
$data = $this->send_request($action, $param);
|
||||
if ($data) {
|
||||
return ['id' => $data['DomainInfo']['Id'], 'name' => $data['DomainInfo']['Domain']];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertLineCode($line)
|
||||
{
|
||||
$convert_dict = ['default' => '0', 'unicom' => '10=1', 'telecom' => '10=0', 'mobile' => '10=3', 'edu' => '10=2', 'oversea' => '3=0', 'btvn' => '10=22', 'search' => '80=0', 'internal' => '7=0'];
|
||||
|
||||
@@ -229,6 +229,18 @@ class huawei implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
$params = [
|
||||
'name' => $Domain,
|
||||
];
|
||||
$data = $this->send_request('POST', '/v2/zones', null, $params);
|
||||
if ($data) {
|
||||
return ['id' => $data['id'], 'name' => rtrim($data['name'], '.')];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertType($type)
|
||||
{
|
||||
return $type;
|
||||
|
||||
@@ -237,6 +237,16 @@ class huoshan implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
$params = ['ZoneName' => $Domain];
|
||||
$data = $this->send_request('POST', 'CreateZone', $params);
|
||||
if ($data) {
|
||||
return ['id' => $data['ZID'], 'name' => $data['ZoneName']];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertType($type)
|
||||
{
|
||||
return $type;
|
||||
|
||||
@@ -225,6 +225,16 @@ class jdcloud implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
$params = ['packId' => 0, 'domainName' => $Domain];
|
||||
$data = $this->send_request('POST', '/domain', $params);
|
||||
if ($data) {
|
||||
return ['id' => $data['data']['id'], 'name' => $data['data']['domainName']];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertType($type)
|
||||
{
|
||||
$convert_dict = ['REDIRECT_URL' => 'EXPLICIT_URL', 'FORWARD_URL' => 'IMPLICIT_URL'];
|
||||
|
||||
@@ -181,6 +181,11 @@ class namesilo implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function send_reuqest($operation, $param = null)
|
||||
{
|
||||
$url = $this->baseUrl . $operation;
|
||||
@@ -197,7 +202,7 @@ class namesilo implements DnsInterface
|
||||
$url .= '?' . http_build_query($params);
|
||||
|
||||
try{
|
||||
$response = curl_client($url, null, null, null, null, $this->proxy);
|
||||
$response = http_request($url, null, null, null, null, $this->proxy);
|
||||
}catch(Exception $e){
|
||||
$this->setError($e->getMessage());
|
||||
return false;
|
||||
|
||||
@@ -327,6 +327,23 @@ class powerdns implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
if (substr($Domain, -1) != '.') {
|
||||
$Domain .= '.';
|
||||
}
|
||||
$param = [
|
||||
'name' => $Domain,
|
||||
'kind' => 'Native',
|
||||
'soa_edit_api' => 'INCREASE',
|
||||
];
|
||||
$result = $this->send_reuqest('POST', '/servers/' . $this->server_id . '/zones', $param);
|
||||
if ($result) {
|
||||
return ['id' => $result['id'], 'name' => rtrim($result['name'], '.')];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function rrset_replace($host, $type, $ttl, $records, $remark = null)
|
||||
{
|
||||
$name = $host == '@' ? $this->domainid : $host . '.' . $this->domainid;
|
||||
@@ -369,7 +386,7 @@ class powerdns implements DnsInterface
|
||||
private function send_reuqest($method, $path, $params = null)
|
||||
{
|
||||
$url = $this->url . $path;
|
||||
$headers[] = 'X-API-Key: ' . $this->apikey;
|
||||
$headers['X-API-Key'] = $this->apikey;
|
||||
$body = null;
|
||||
if ($method == 'GET' || $method == 'DELETE') {
|
||||
if ($params) {
|
||||
@@ -377,10 +394,10 @@ class powerdns implements DnsInterface
|
||||
}
|
||||
} else {
|
||||
$body = json_encode($params);
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
try {
|
||||
$response = curl_client($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
$response = http_request($url, $body, null, null, $headers, $this->proxy, $method);
|
||||
} catch (Exception $e) {
|
||||
$this->setError($e->getMessage());
|
||||
return false;
|
||||
@@ -404,6 +421,5 @@ class powerdns implements DnsInterface
|
||||
private function setError($message)
|
||||
{
|
||||
$this->error = $message;
|
||||
//file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +171,11 @@ class west implements DnsInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addDomain($Domain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function convertType($type)
|
||||
{
|
||||
return $type;
|
||||
@@ -182,7 +187,7 @@ class west implements DnsInterface
|
||||
$params['time'] = getMillisecond();
|
||||
$params['token'] = md5($this->username.$this->api_password.$params['time']);
|
||||
try{
|
||||
$response = curl_client($this->baseUrl . $path, http_build_query($params), null, null, null, $this->proxy);
|
||||
$response = http_request($this->baseUrl . $path, http_build_query($params), null, null, null, $this->proxy);
|
||||
}catch(\Exception $e){
|
||||
$this->setError($e->getMessage());
|
||||
return false;
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
<?php
|
||||
namespace app\lib\mail\PHPMailer; class Exception extends \Exception { public function errorMessage() { return '<strong>' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "</strong><br />\n"; } }
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -89,6 +89,9 @@ class CertDeployService
|
||||
private function saveResult($status, $error = null, $retrytime = null)
|
||||
{
|
||||
$this->task['status'] = $status;
|
||||
if (!empty($error) && strlen($error) > 300) {
|
||||
$error = mb_strcut($error, 0, 300);
|
||||
}
|
||||
$update = ['status' => $status, 'error' => $error, 'retrytime' => $retrytime];
|
||||
if ($status == 1){
|
||||
$update['retry'] = 0;
|
||||
|
||||
@@ -178,6 +178,9 @@ class CertOrderService
|
||||
private function saveResult($status, $error = null, $retrytime = null)
|
||||
{
|
||||
$this->order['status'] = $status;
|
||||
if (!empty($error) && strlen($error) > 300) {
|
||||
$error = mb_strcut($error, 0, 300);
|
||||
}
|
||||
$update = ['status' => $status, 'error' => $error, 'updatetime' => date('Y-m-d H:i:s'), 'retrytime' => $retrytime];
|
||||
$res = Db::name('cert_order')->where('id', $this->order['id'])->data($update);
|
||||
if ($status < 0 || $retrytime) {
|
||||
|
||||
@@ -21,10 +21,14 @@ class CertTaskService
|
||||
private function execute_order()
|
||||
{
|
||||
$days = config_get('cert_renewdays', 7);
|
||||
$list = Db::name('cert_order')->field('id,status,issend')->whereRaw('status NOT IN (3,4) AND (retrytime IS NULL OR retrytime<NOW()) OR status=3 AND isauto=1 AND expiretime<:expiretime', ['expiretime' => date('Y-m-d H:i:s', time() + $days * 86400)])->select();
|
||||
$list = Db::name('cert_order')->field('id,aid,status,issend')->whereRaw('status NOT IN (3,4) AND (retrytime IS NULL OR retrytime<NOW()) OR status=3 AND isauto=1 AND expiretime<:expiretime', ['expiretime' => date('Y-m-d H:i:s', time() + $days * 86400)])->select();
|
||||
//print_r($list);exit;
|
||||
$failcount = 0;
|
||||
foreach ($list as $row) {
|
||||
if ($row['aid'] == 0) {
|
||||
if($row['issend'] == 0) MsgNotice::cert_order_send($row['id'], true);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$service = new CertOrderService($row['id']);
|
||||
if ($row['status'] == 3) {
|
||||
|
||||
@@ -57,7 +57,7 @@ class OptimizeService
|
||||
'key' => config_get('optimize_ip_key', 'o1zrmHAF'),
|
||||
'type' => $ip_type,
|
||||
];
|
||||
$response = get_curl($url, json_encode($params), 0, 0, 0, 0, 0, ['Content-Type: application/json; charset=UTF-8']);
|
||||
$response = get_curl($url, json_encode($params), 0, 0, 0, 0, ['Content-Type' => 'application/json; charset=UTF-8']);
|
||||
$arr = json_decode($response, true);
|
||||
if (isset($arr['code']) && $arr['code'] == 200) {
|
||||
return $arr['info'];
|
||||
|
||||
@@ -28,7 +28,7 @@ DROP TABLE IF EXISTS `dnsmgr_domain`;
|
||||
CREATE TABLE `dnsmgr_domain` (
|
||||
`id` int(11) unsigned NOT NULL auto_increment,
|
||||
`aid` int(11) unsigned NOT NULL,
|
||||
`name` varchar(128) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`thirdid` varchar(60) DEFAULT NULL,
|
||||
`addtime` datetime DEFAULT NULL,
|
||||
`is_hide` tinyint(1) NOT NULL DEFAULT '0',
|
||||
@@ -66,7 +66,7 @@ DROP TABLE IF EXISTS `dnsmgr_permission`;
|
||||
CREATE TABLE `dnsmgr_permission` (
|
||||
`id` int(11) unsigned NOT NULL auto_increment,
|
||||
`uid` int(11) unsigned NOT NULL,
|
||||
`domain` varchar(128) NOT NULL,
|
||||
`domain` varchar(255) NOT NULL,
|
||||
`sub` varchar(80) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `uid` (`uid`)
|
||||
@@ -77,7 +77,7 @@ CREATE TABLE `dnsmgr_log` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`uid` int(11) unsigned NOT NULL,
|
||||
`action` varchar(40) NOT NULL,
|
||||
`domain` varchar(128) NOT NULL DEFAULT '',
|
||||
`domain` varchar(255) NOT NULL DEFAULT '',
|
||||
`data` varchar(500) DEFAULT NULL,
|
||||
`addtime` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
|
||||
@@ -2,85 +2,102 @@
|
||||
|
||||
namespace app\utils;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
class CheckUtils
|
||||
{
|
||||
public static function curl($url, $timeout, $ip = null, $proxy = false)
|
||||
{
|
||||
$status = true;
|
||||
$errmsg = null;
|
||||
$start = microtime(true);
|
||||
|
||||
$urlarr = parse_url($url);
|
||||
if (!$urlarr) {
|
||||
return ['status' => false, 'errmsg' => 'Invalid URL', 'usetime' => 0];
|
||||
}
|
||||
if (str_starts_with($urlarr['host'], '[') && str_ends_with($urlarr['host'], ']')) {
|
||||
$urlarr['host'] = substr($urlarr['host'], 1, -1);
|
||||
}
|
||||
if (!empty($ip) && !filter_var($urlarr['host'], FILTER_VALIDATE_IP)) {
|
||||
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
$ip = gethostbyname($ip);
|
||||
}
|
||||
if (!empty($ip) && filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
$port = isset($urlarr['port']) ? $urlarr['port'] : ($urlarr['scheme'] == 'https' ? 443 : 80);
|
||||
$port = $urlarr['port'] ?? ($urlarr['scheme'] == 'https' ? 443 : 80);
|
||||
$resolve = $urlarr['host'] . ':' . $port . ':' . $ip;
|
||||
}
|
||||
}
|
||||
$ch = curl_init();
|
||||
|
||||
$options = [
|
||||
'timeout' => $timeout,
|
||||
'connect_timeout' => $timeout,
|
||||
'verify' => false,
|
||||
'headers' => [
|
||||
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'
|
||||
],
|
||||
'http_errors' => false // 不抛出异常
|
||||
];
|
||||
// 处理解析
|
||||
if (!empty($resolve)) {
|
||||
$options['curl'] = [
|
||||
CURLOPT_DNS_USE_GLOBAL_CACHE => false,
|
||||
CURLOPT_RESOLVE => [$resolve]
|
||||
];
|
||||
}
|
||||
// 处理代理
|
||||
if ($proxy) {
|
||||
$proxy_server = config_get('proxy_server');
|
||||
$proxy_port = intval(config_get('proxy_port'));
|
||||
$proxy_userpwd = config_get('proxy_user').':'.config_get('proxy_pwd');
|
||||
$proxy_type = config_get('proxy_type');
|
||||
if ($proxy_type == 'https') {
|
||||
$proxy_type = CURLPROXY_HTTPS;
|
||||
} elseif ($proxy_type == 'sock4') {
|
||||
$proxy_type = CURLPROXY_SOCKS4;
|
||||
} elseif ($proxy_type == 'sock5') {
|
||||
$proxy_type = CURLPROXY_SOCKS5;
|
||||
} else {
|
||||
$proxy_type = CURLPROXY_HTTP;
|
||||
|
||||
if (!empty($proxy_server) && !empty($proxy_port)) {
|
||||
match ($proxy_type) {
|
||||
'https' => $proxy_string = 'https://',
|
||||
'sock4' => $proxy_string = 'socks4://',
|
||||
'sock5' => $proxy_string = 'socks5://',
|
||||
'sock5h' => $proxy_string = 'socks5h://',
|
||||
default => $proxy_string = 'http://',
|
||||
};
|
||||
|
||||
if ($proxy_userpwd != ':') {
|
||||
$proxy_string .= $proxy_userpwd . '@';
|
||||
}
|
||||
|
||||
$proxy_string .= $proxy_server . ':' . $proxy_port;
|
||||
$options['proxy'] = $proxy_string;
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
|
||||
curl_setopt($ch, CURLOPT_PROXY, $proxy_server);
|
||||
curl_setopt($ch, CURLOPT_PROXYPORT, $proxy_port);
|
||||
if ($proxy_userpwd != ':') {
|
||||
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy_userpwd);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = new Client();
|
||||
$response = $client->request('GET', $url, $options);
|
||||
$httpcode = $response->getStatusCode();
|
||||
|
||||
if ($httpcode < 200 || $httpcode >= 400) {
|
||||
$status = false;
|
||||
$errmsg = 'http_code=' . $httpcode;
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_PROXYTYPE, $proxy_type);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: close";
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
if (!empty($resolve)) {
|
||||
curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false);
|
||||
curl_setopt($ch, CURLOPT_RESOLVE, [$resolve]);
|
||||
}
|
||||
curl_exec($ch);
|
||||
$errno = curl_errno($ch);
|
||||
if ($errno) {
|
||||
} catch (GuzzleException $e) {
|
||||
$status = false;
|
||||
$errmsg = curl_error($ch);
|
||||
$errmsg = guzzle_error($e);
|
||||
}
|
||||
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
if ($status && ($httpcode < 200 || $httpcode >= 400)) {
|
||||
$status = false;
|
||||
$errmsg = 'http_code='.$httpcode;
|
||||
}
|
||||
$usetime = round(curl_getinfo($ch, CURLINFO_TOTAL_TIME) * 1000);
|
||||
curl_close($ch);
|
||||
|
||||
$usetime = round((microtime(true) - $start) * 1000);
|
||||
return ['status' => $status, 'errmsg' => $errmsg, 'usetime' => $usetime];
|
||||
}
|
||||
|
||||
public static function tcp($target, $ip, $port, $timeout)
|
||||
{
|
||||
if (!empty($ip) && filter_var($ip, FILTER_VALIDATE_IP)) $target = $ip;
|
||||
if (substr($target, -1) == '.') $target = substr($target, 0, -1);
|
||||
if (str_ends_with($target, '.')) $target = substr($target, 0, -1);
|
||||
if (!filter_var($target, FILTER_VALIDATE_IP) && checkDomain($target)) {
|
||||
$target = gethostbyname($target);
|
||||
if (!$target) return ['status' => false, 'errmsg' => 'DNS resolve failed', 'usetime' => 0];
|
||||
}
|
||||
if (filter_var($target, FILTER_VALIDATE_IP) && strpos($target, ':') !== false) {
|
||||
if (filter_var($target, FILTER_VALIDATE_IP) && str_contains($target, ':')) {
|
||||
$target = '['.$target.']';
|
||||
}
|
||||
$starttime = getMillisecond();
|
||||
@@ -100,7 +117,7 @@ class CheckUtils
|
||||
{
|
||||
if (!function_exists('exec')) return ['status' => false, 'errmsg' => 'exec函数不可用', 'usetime' => 0];
|
||||
if (!empty($ip) && filter_var($ip, FILTER_VALIDATE_IP)) $target = $ip;
|
||||
if (substr($target, -1) == '.') $target = substr($target, 0, -1);
|
||||
if (str_ends_with($target, '.')) $target = substr($target, 0, -1);
|
||||
if (!filter_var($target, FILTER_VALIDATE_IP) && checkDomain($target)) {
|
||||
$target = gethostbyname($target);
|
||||
if (!$target) return ['status' => false, 'errmsg' => 'DNS resolve failed', 'usetime' => 0];
|
||||
@@ -109,8 +126,15 @@ class CheckUtils
|
||||
return ['status' => false, 'errmsg' => 'Invalid IP address', 'usetime' => 0];
|
||||
}
|
||||
$timeout = 1;
|
||||
exec('ping -c 1 -w '.$timeout.' '.$target.'', $output, $return_var);
|
||||
$usetime = !empty($output[1]) ? round(getSubstr($output[1], 'time=', ' ms')) : 0;
|
||||
exec('ping -c 1 -w '.$timeout.' '.$target, $output, $return_var);
|
||||
if (!empty($output[1])) {
|
||||
if (strpos($output[1], '毫秒') !== false) {
|
||||
$usetime = getSubstr($output[1], '时间=', ' 毫秒');
|
||||
} else {
|
||||
$usetime = getSubstr($output[1], 'time=', ' ms');
|
||||
}
|
||||
}
|
||||
$usetime = !empty($usetime) ? round(trim($usetime)) : 0;
|
||||
$errmsg = null;
|
||||
if ($return_var !== 0) {
|
||||
$usetime = $usetime == 0 ? $timeout * 1000 : $usetime;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace app\utils;
|
||||
|
||||
use Exception;
|
||||
|
||||
class DnsQueryUtils
|
||||
{
|
||||
private static $doh_servers = ['https://dns.alidns.com/resolve', 'https://doh.pub/resolve', 'https://doh.360.cn/resolve'];
|
||||
@@ -10,7 +12,11 @@ class DnsQueryUtils
|
||||
{
|
||||
$dns_type = ['A' => DNS_A, 'AAAA' => DNS_AAAA, 'CNAME' => DNS_CNAME, 'MX' => DNS_MX, 'TXT' => DNS_TXT];
|
||||
if (!array_key_exists($type, $dns_type)) return false;
|
||||
$list = dns_get_record($domain, $dns_type[$type]);
|
||||
try{
|
||||
$list = dns_get_record($domain, $dns_type[$type]);
|
||||
}catch(Exception $e){
|
||||
return false;
|
||||
}
|
||||
if (!$list || empty($list)) return false;
|
||||
$result = [];
|
||||
foreach ($list as $row) {
|
||||
@@ -38,7 +44,7 @@ class DnsQueryUtils
|
||||
$data = get_curl($url);
|
||||
$arr = json_decode($data, true);
|
||||
if (!$arr) {
|
||||
unset($doh_servers[$id]);
|
||||
unset(self::$doh_servers[$id]);
|
||||
$id = array_rand(self::$doh_servers);
|
||||
$url = self::$doh_servers[$id].'?name='.urlencode($domain).'&type='.$dns_type[$type];
|
||||
$data = get_curl($url);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace app\utils;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use think\facade\Db;
|
||||
use app\lib\CertHelper;
|
||||
use app\lib\DeployHelper;
|
||||
@@ -66,24 +67,33 @@ class MsgNotice
|
||||
{
|
||||
$row = Db::name('cert_order')->field('id,aid,issuetime,expiretime,issuer,status,error')->where('id', $id)->find();
|
||||
if (!$row) return;
|
||||
$type = Db::name('cert_account')->where('id', $row['aid'])->value('type');
|
||||
$domainList = Db::name('cert_domain')->where('oid', $id)->column('domain');
|
||||
if (empty($domainList)) return;
|
||||
if ($result) {
|
||||
if ($row['aid'] == 0) {
|
||||
if (count($domainList) > 1) {
|
||||
$mail_title = $domainList[0] . '等' . count($domainList) . '个域名SSL证书签发成功通知';
|
||||
$mail_title = $domainList[0] . '等' . count($domainList) . '个域名SSL证书即将到期提醒';
|
||||
} else {
|
||||
$mail_title = $domainList[0] . '域名SSL证书签发成功通知';
|
||||
$mail_title = $domainList[0] . '域名SSL证书即将到期提醒';
|
||||
}
|
||||
$mail_content = '尊敬的用户,您好:您的SSL证书已签发成功!<br/><b>证书账户:</b> '.CertHelper::$cert_config[$type]['name'].'('.$row['aid'].')<br/><b>证书域名:</b> '.implode('、', $domainList).'<br/><b>签发时间:</b> '.$row['issuetime'].'<br/><b>到期时间:</b> '.$row['expiretime'].'<br/><b>颁发机构:</b> '.$row['issuer'];
|
||||
$mail_content = '尊敬的用户,您好:您有一张SSL证书将在'.config_get('cert_renewdays', 7).'天后到期,该证书为手动续期证书,请及时续期!<br/><b>证书域名:</b> '.implode('、', $domainList).'<br/><b>签发时间:</b> '.$row['issuetime'].'<br/><b>到期时间:</b> '.$row['expiretime'].'<br/><b>颁发机构:</b> '.$row['issuer'];
|
||||
} else {
|
||||
$status_arr = [0 => '失败', -1 => '购买证书失败', -2 => '创建订单失败', -3 => '添加DNS失败', -4 => '验证DNS失败', -5 => '验证订单失败', -6 => '订单验证未通过', -7 => '签发证书失败'];
|
||||
if(count($domainList) > 1){
|
||||
$mail_title = $domainList[0].'等'.count($domainList).'个域名SSL证书'.$status_arr[$row['status']].'通知';
|
||||
}else{
|
||||
$mail_title = $domainList[0].'域名SSL证书'.$status_arr[$row['status']].'通知';
|
||||
$type = Db::name('cert_account')->where('id', $row['aid'])->value('type');
|
||||
if ($result) {
|
||||
if (count($domainList) > 1) {
|
||||
$mail_title = $domainList[0] . '等' . count($domainList) . '个域名SSL证书签发成功通知';
|
||||
} else {
|
||||
$mail_title = $domainList[0] . '域名SSL证书签发成功通知';
|
||||
}
|
||||
$mail_content = '尊敬的用户,您好:您的SSL证书已签发成功!<br/><b>证书账户:</b> '.CertHelper::$cert_config[$type]['name'].'('.$row['aid'].')<br/><b>证书域名:</b> '.implode('、', $domainList).'<br/><b>签发时间:</b> '.$row['issuetime'].'<br/><b>到期时间:</b> '.$row['expiretime'].'<br/><b>颁发机构:</b> '.$row['issuer'];
|
||||
} else {
|
||||
$status_arr = [0 => '失败', -1 => '购买证书失败', -2 => '创建订单失败', -3 => '添加DNS失败', -4 => '验证DNS失败', -5 => '验证订单失败', -6 => '订单验证未通过', -7 => '签发证书失败'];
|
||||
if(count($domainList) > 1){
|
||||
$mail_title = $domainList[0].'等'.count($domainList).'个域名SSL证书'.$status_arr[$row['status']].'通知';
|
||||
}else{
|
||||
$mail_title = $domainList[0].'域名SSL证书'.$status_arr[$row['status']].'通知';
|
||||
}
|
||||
$mail_content = '尊敬的用户,您好:您的SSL证书'.$status_arr[$row['status']].'!<br/><b>证书账户:</b> '.CertHelper::$cert_config[$type]['name'].'('.$row['aid'].')<br/><b>证书域名:</b> '.implode('、', $domainList).'<br/><b>失败时间:</b> '.date('Y-m-d H:i:s').'<br/><b>失败原因:</b> <font color="warning">'.$row['error'].'</font>';
|
||||
}
|
||||
$mail_content = '尊敬的用户,您好:您的SSL证书'.$status_arr[$row['status']].'!<br/><b>证书账户:</b> '.CertHelper::$cert_config[$type]['name'].'('.$row['aid'].')<br/><b>证书域名:</b> '.implode('、', $domainList).'<br/><b>失败时间:</b> '.date('Y-m-d H:i:s').'<br/><b>失败原因:</b> <font color="warning">'.$row['error'].'</font>';
|
||||
}
|
||||
$mail_content .= '<br/><font color="grey">'.self::$sitename.'</font><br/><font color="grey">'.date('Y-m-d H:i:s').'</font>';
|
||||
|
||||
@@ -176,7 +186,8 @@ class MsgNotice
|
||||
$mail_smtp = config_get('mail_smtp');
|
||||
$mail_pwd = config_get('mail_pwd');
|
||||
if (!$mail_name || !$mail_port || !$mail_smtp || !$mail_pwd) return false;
|
||||
$mail = new \app\lib\mail\PHPMailer\PHPMailer(true);
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->setLanguage('zh_cn');
|
||||
try {
|
||||
$mail->SMTPDebug = 0;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
@@ -211,12 +222,12 @@ class MsgNotice
|
||||
if (!$wechat_apptoken || !$wechat_appuid) return false;
|
||||
$url = 'https://wxpusher.zjiecode.com/api/send/message';
|
||||
$post = ['appToken' => $wechat_apptoken, 'content' => $content, 'summary' => $title, 'contentType' => 3, 'uids' => [$wechat_appuid]];
|
||||
$result = get_curl($url, json_encode($post), 0, 0, 0, 0, 0, ['Content-Type: application/json; charset=UTF-8']);
|
||||
$result = get_curl($url, json_encode($post), 0, 0, 0, 0, ['Content-Type' => 'application/json; charset=UTF-8']);
|
||||
$arr = json_decode($result, true);
|
||||
if (isset($arr['success']) && $arr['success'] == true) {
|
||||
return true;
|
||||
} else {
|
||||
return isset($arr['msg']) ? $arr['msg'] : '请求失败';
|
||||
return $arr['msg'] ?? '请求失败';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +250,7 @@ class MsgNotice
|
||||
if (isset($arr['ok']) && $arr['ok'] == true) {
|
||||
return true;
|
||||
} else {
|
||||
return isset($arr['description']) ? $arr['description'] : '请求失败';
|
||||
return $arr['description'] ?? '请求失败';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,12 +286,12 @@ class MsgNotice
|
||||
} else {
|
||||
return '不支持的Webhook地址';
|
||||
}
|
||||
$result = get_curl($url, json_encode($post), 0, 0, 0, 0, 0, ['Content-Type: application/json; charset=UTF-8']);
|
||||
$result = get_curl($url, json_encode($post), 0, 0, 0, 0, ['Content-Type' => 'application/json; charset=UTF-8']);
|
||||
$arr = json_decode($result, true);
|
||||
if (isset($arr['errcode']) && $arr['errcode'] == 0 || isset($arr['code']) && $arr['code'] == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return isset($arr['errmsg']) ? $arr['errmsg'] : (isset($arr['msg']) ? $arr['msg'] : '请求失败');
|
||||
return $arr['errmsg'] ?? (isset($arr['msg']) ? $arr['msg'] : '请求失败');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,13 +55,13 @@ a{color:#444}
|
||||
<div class="input-group-addon"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></div>
|
||||
<input type="password" class="form-control" placeholder="密码" name="password" required="required"/>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
{if config_get('vcode', '1')=='1'}<div class="input-group">
|
||||
<div class="input-group-addon"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></div>
|
||||
<input type="text" class="form-control input-lg" placeholder="验证码" name="code" autocomplete="off" required="required"/>
|
||||
<span class="input-group-addon" style="padding: 0">
|
||||
<img id="verifycode" src="/verifycode" height="45" onclick="this.src='/verifycode?r='+Math.random();" title="点击更换验证码">
|
||||
</span>
|
||||
</div>
|
||||
</div>{/if}
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-success btn-lg btn-block" id="submit" style="background:#708eea;">登 录</button>
|
||||
</div>
|
||||
|
||||
@@ -9,19 +9,108 @@
|
||||
color: #f56c6c;
|
||||
margin-right: 4px;
|
||||
}
|
||||
/* 账户类型卡片样式 */
|
||||
.account-type-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.account-type-category {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.account-type-card {
|
||||
width: calc(25% - 15px);
|
||||
min-width: 200px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
background: #fff;
|
||||
height: 100px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.account-type-card:hover {
|
||||
border-color: #409EFF;
|
||||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
.account-type-card .icon {
|
||||
width: 30px;
|
||||
margin: 11px 8px;
|
||||
float: left;
|
||||
}
|
||||
.account-type-card .content {
|
||||
margin-left: 38px;
|
||||
}
|
||||
.account-type-card .title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 3px;
|
||||
color: #333;
|
||||
}
|
||||
.account-type-card .desc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.account-type-card {
|
||||
width: calc(50% - 15px);
|
||||
}
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.account-type-card {
|
||||
width: 100%;
|
||||
height: 78px;
|
||||
}
|
||||
.account-type-card .desc {
|
||||
-webkit-line-clamp: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="row" id="app">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><h3 class="panel-title"><a href="javascript:window.history.back()" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}{$title}</h3></div>
|
||||
<div class="panel-body">
|
||||
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="accountform">
|
||||
<!-- 账户类型选择视图 -->
|
||||
<div id="account-type-view" v-if="!selectedType">
|
||||
<div v-for="(category, classId) in groupedTypes" :key="classId">
|
||||
<div class="account-type-category">{{ category.label }}</div>
|
||||
<div class="account-type-container">
|
||||
<div class="account-type-card" v-for="type in category.types" :key="type.value" @click="selectType(type.value)">
|
||||
<img class="icon" :src="'/static/images/' + typeList[type.value].icon" :alt="type.label">
|
||||
<div class="content">
|
||||
<div class="title">{{ type.label }}</div>
|
||||
<div class="desc">{{ typeList[type.value].desc || ''}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表单视图 -->
|
||||
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="accountform" v-if="selectedType">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>账户类型</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="type" v-model="set.type" class="form-control" required :disabled="action=='edit'">
|
||||
<optgroup v-for="item in typeOption" :label="item.label"><option v-for="item2 in item.children" :value="item2.value">{{item2.label}}</option></optgroup>
|
||||
</select>
|
||||
<div class="form-control-static">
|
||||
{{ typeList[set.type].name }}
|
||||
<a href="javascript:;" @click="selectedType = false" class="pull-right btn btn-default" v-if="action=='add'">重新选择</a>
|
||||
</div>
|
||||
<input type="hidden" name="type" v-model="set.type">
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(item,name) in inputs" v-show="isShow(item.show)">
|
||||
@@ -104,6 +193,7 @@ new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
action: '{$action}',
|
||||
selectedType: false,
|
||||
set: {
|
||||
deploy: '{$deploy}',
|
||||
id: '',
|
||||
@@ -140,16 +230,24 @@ new Vue({
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.typeOption = Object.keys(classList).map((key) => {
|
||||
var tempList = [];
|
||||
Object.keys(typeList).forEach((key2) => {
|
||||
if(typeList[key2].class == key){
|
||||
tempList.push({label: typeList[key2].name, value: key2})
|
||||
}
|
||||
computed: {
|
||||
groupedTypes() {
|
||||
return Object.keys(classList).map((key) => {
|
||||
var tempList = [];
|
||||
Object.keys(typeList).forEach((key2) => {
|
||||
if(typeList[key2].class == key){
|
||||
tempList.push({label: typeList[key2].name, value: key2})
|
||||
}
|
||||
})
|
||||
return {label: classList[key], types: tempList}
|
||||
})
|
||||
return {label: classList[key], children: tempList}
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.typeOption = this.groupedTypes;
|
||||
if(this.action == 'edit') {
|
||||
this.selectedType = true;
|
||||
}
|
||||
if(this.action == 'edit'){
|
||||
Object.keys(info).forEach((key) => {
|
||||
this.set[key] = info[key]
|
||||
@@ -181,6 +279,10 @@ new Vue({
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
selectType(type) {
|
||||
this.set.type = type;
|
||||
this.selectedType = true;
|
||||
},
|
||||
submit(){
|
||||
var that=this;
|
||||
Object.keys(this.config).forEach((key) => {
|
||||
@@ -235,4 +337,4 @@ new Vue({
|
||||
},
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
{/block}
|
||||
|
||||
@@ -65,10 +65,10 @@ $(document).ready(function(){
|
||||
title: '添加时间'
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="/cert/account/edit?deploy=0&id='+row.id+'" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
|
||||
var html = '<a href="/cert/account/edit?deploy=0&id='+row.id+'" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a> <a href="/cert/certorder?aid='+row.id+'" class="btn btn-default btn-xs">订单</a>';
|
||||
return html;
|
||||
}
|
||||
},
|
||||
@@ -79,12 +79,12 @@ function delItem(id){
|
||||
layer.confirm('确定要删除此账户吗?', {
|
||||
btn: ['确定','取消']
|
||||
}, function(){
|
||||
$.post('/cert/account/del?deploy=0', {id: id}, function(data){
|
||||
$.post('/cert/account/del', {id: id, deploy: 0}, function(data){
|
||||
if(data.code == 0) {
|
||||
layer.msg('删除成功', {icon: 1, time:800});
|
||||
$('#listTable').bootstrapTable('refresh');
|
||||
} else {
|
||||
layer.msg(data.msg, {icon: 2});
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
|
||||
|
||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
|
||||
<input type="hidden" name="id" value="">
|
||||
<input type="hidden" name="aid" value="">
|
||||
<div class="form-group">
|
||||
<label>搜索</label>
|
||||
<div class="form-group">
|
||||
@@ -34,12 +35,6 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
|
||||
<a href="javascript:searchClear()" class="btn btn-default" title="刷新订单列表"><i class="fa fa-refresh"></i> 刷新</a>
|
||||
<div class="btn-group">
|
||||
<a href="/cert/order/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/cert/order/import">导入已有证书</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">批量操作 <span class="caret"></span></button>
|
||||
@@ -87,7 +82,10 @@ $(document).ready(function(){
|
||||
field: 'typename',
|
||||
title: '证书账户',
|
||||
formatter: function(value, row, index) {
|
||||
return '<span title="'+row.aremark+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+value+'('+row.aid+')</span>';
|
||||
if(value){
|
||||
return '<span title="'+row.aremark+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+value+'('+row.aid+')</span>';
|
||||
}
|
||||
return '手动续期';
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -197,7 +195,7 @@ $(document).ready(function(){
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '';
|
||||
@@ -208,7 +206,10 @@ $(document).ready(function(){
|
||||
}else if(row.status == 2) {
|
||||
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-check-circle"></i> 继续验证</a> ';
|
||||
}else if(row.status == 3) {
|
||||
html += '<a href="javascript:download(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-download"></i> 下载</a> <a href="javascript:renewOrder(\''+row.id+'\')" class="btn btn-warning btn-xs"><i class="fa fa-refresh"></i> 续签</a> ';
|
||||
html += '<a href="javascript:download(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-download"></i> 下载</a> ';
|
||||
if(row.aid > 0){
|
||||
html += '<a href="javascript:renewOrder(\''+row.id+'\')" class="btn btn-warning btn-xs"><i class="fa fa-refresh"></i> 续签</a> ';
|
||||
}
|
||||
}else if(row.status == 4) {
|
||||
html += '<a href="javascript:renewOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 重新申请</a> ';
|
||||
}else{
|
||||
@@ -219,7 +220,9 @@ $(document).ready(function(){
|
||||
html += '<li><a href="javascript:showLog(\''+row.processid+'\')">查看日志</a></li>';
|
||||
if(row.status == 3){
|
||||
html += '<li><a href="/cert/deploytask?oid='+row.id+'">部署任务</a></li>';
|
||||
html += '<li><a href="javascript:revokeOrder(\''+row.id+'\')">吊销证书</a></li>';
|
||||
if(row.aid > 0){
|
||||
html += '<li><a href="javascript:revokeOrder(\''+row.id+'\')">吊销证书</a></li>';
|
||||
}
|
||||
}else if(row.status < 0){
|
||||
html += '<li><a href="javascript:resetOrder(\''+row.id+'\')">重置订单</a></li>';
|
||||
}else if(row.status == 1 || row.status == 2){
|
||||
|
||||
@@ -93,7 +93,7 @@ function saveSetting(obj){
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '',
|
||||
url : '/system/set',
|
||||
data : $(obj).serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
|
||||
@@ -130,7 +130,7 @@ $(document).ready(function(){
|
||||
title: '添加时间'
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="javascript:editframe('+row.id+')" class="btn btn-primary btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
|
||||
|
||||
@@ -65,10 +65,10 @@ $(document).ready(function(){
|
||||
title: '添加时间'
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="/cert/account/edit?deploy=1&id='+row.id+'" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
|
||||
var html = '<a href="/cert/account/edit?deploy=1&id='+row.id+'" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a> <a href="/cert/deploytask?aid='+row.id+'" class="btn btn-default btn-xs">任务</a>';
|
||||
return html;
|
||||
}
|
||||
},
|
||||
@@ -79,12 +79,12 @@ function delItem(id){
|
||||
layer.confirm('确定要删除此账户吗?', {
|
||||
btn: ['确定','取消']
|
||||
}, function(){
|
||||
$.post('/cert/account/del?deploy=1', {id: id}, function(data){
|
||||
$.post('/cert/account/del', {id: id, deploy: 1}, function(data){
|
||||
if(data.code == 0) {
|
||||
layer.msg('删除成功', {icon: 1, time:800});
|
||||
$('#listTable').bootstrapTable('refresh');
|
||||
} else {
|
||||
layer.msg(data.msg, {icon: 2});
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
|
||||
<div class="panel-body">
|
||||
|
||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
|
||||
<input type="hidden" name="aid" value="">
|
||||
<input type="hidden" name="oid" value="">
|
||||
<div class="form-group">
|
||||
<label>搜索</label>
|
||||
@@ -37,7 +38,7 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
|
||||
<a href="/cert/deploy/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">批量操作 <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu"><li><a href="javascript:operation('delete')">删除</a></li><li><a href="javascript:operation('reset')">重置任务</a></li><li><a href="javascript:operation('open')">开启任务</a></li><li><a href="javascript:operation('close')">停止任务</a></li></ul>
|
||||
<ul class="dropdown-menu"><li><a href="javascript:operation('delete')">删除</a></li><li><a href="javascript:operation('reset')">重置任务</a></li><li><a href="javascript:operation('open')">开启任务</a></li><li><a href="javascript:operation('close')">停止任务</a></li><li><a href="javascript:operation('cert')">修改关联证书</a></li></ul>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -80,6 +81,7 @@ $(document).ready(function(){
|
||||
field: 'typename',
|
||||
title: '自动部署账户',
|
||||
formatter: function(value, row, index) {
|
||||
if(!value) return '已被删除'
|
||||
return '<span title="'+row.aname+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+(row.aremark?row.aremark:value+'('+row.aid+')')+'</span>';
|
||||
}
|
||||
},
|
||||
@@ -130,7 +132,7 @@ $(document).ready(function(){
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '';
|
||||
@@ -307,6 +309,8 @@ function operation(action){
|
||||
if(!confirm('确定要删除所选自动部署任务吗?')) return;
|
||||
}else if(action == 'reset'){
|
||||
if(!confirm('重置任务后,任务将变成待处理状态,是否确定重置?')) return;
|
||||
}else if(action == 'cert'){
|
||||
return batch_set_cert(ids);
|
||||
}
|
||||
|
||||
var ii = layer.load(2);
|
||||
@@ -327,5 +331,26 @@ function operation(action){
|
||||
}
|
||||
});
|
||||
}
|
||||
function batch_set_cert(ids){
|
||||
layer.prompt({title: '填写证书ID', value: '', formType: 0}, function(text, index){
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/cert/deploy/operation',
|
||||
data : {action: 'cert', ids: ids, certid: text},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.closeAll();
|
||||
layer.alert(data.msg, {icon: 1});
|
||||
searchRefresh();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{/block}
|
||||
@@ -22,9 +22,28 @@
|
||||
{foreach $accounts as $k=>$v}
|
||||
<option value="{$k}" data-type="{$v.type}">{$v.name}</option>
|
||||
{/foreach}
|
||||
<option value="-1" data-type="">手动续期</option>
|
||||
</select></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" v-show="set.aid==-1">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>证书内容</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<textarea name="fullchain" v-model="set.fullchain" class="form-control" rows="5" placeholder="输入PEM格式证书链" required></textarea>
|
||||
<a class="btn btn-default input-group-addon" @click="upload('fullchain')" title="上传证书文件"><i class="fa fa-upload"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.aid==-1">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>私钥内容</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<textarea name="privatekey" v-model="set.privatekey" class="form-control" rows="5" placeholder="输入PEM格式私钥" required></textarea>
|
||||
<a class="btn btn-default input-group-addon" @click="upload('privatekey')" title="上传私钥文件"><i class="fa fa-upload"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.aid!=-1">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>签名算法</label>
|
||||
<div class="col-sm-6">
|
||||
<label class="radio-inline" v-for="item in keytypeList">
|
||||
@@ -32,7 +51,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" v-show="set.aid!=-1">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>密钥长度</label>
|
||||
<div class="col-sm-6">
|
||||
<label class="radio-inline" v-for="item in keysizeList">
|
||||
@@ -41,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group" v-show="set.aid!=-1">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>绑定域名</label>
|
||||
<div class="col-sm-6">
|
||||
<textarea name="domains" v-model="domains" class="form-control" rows="5" placeholder="请输入域名,一行一个" required></textarea>
|
||||
@@ -51,7 +70,8 @@
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
|
||||
</div>
|
||||
<div class="panel panel-default"><div class="panel-body"><p><b style="color:#39b603;"><i class="fa fa-info-circle fa-fw"></i></b>提示:添加或修改订单信息,点击提交后,不会立即执行签发,只能通过计划任务或列表手动点击来执行</p><p>证书签发之前确保该主域名下没有CAA类型记录,避免证书验证失败。</p></div></div>
|
||||
<div class="panel panel-default" v-show="set.aid!=-1"><div class="panel-body"><p><b style="color:#39b603;"><i class="fa fa-info-circle fa-fw"></i></b>提示:添加或修改订单信息,点击提交后,不会立即执行签发,只能通过计划任务或列表手动点击来执行</p><p>证书签发之前确保该主域名下没有CAA类型记录,避免证书验证失败。</p></div></div>
|
||||
<div class="panel panel-default" v-show="set.aid==-1"><div class="panel-body"><p><b style="color:#39b603;"><i class="fa fa-info-circle fa-fw"></i></b>提示:选择手动续期,到达设置的续期天数,只会发送消息通知。</p></div></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -72,6 +92,8 @@ new Vue({
|
||||
set: {
|
||||
id: '',
|
||||
aid: '',
|
||||
fullchain: '',
|
||||
privatekey: '',
|
||||
keytype: '',
|
||||
keysize: '',
|
||||
domains: [],
|
||||
@@ -150,6 +172,22 @@ new Vue({
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
},
|
||||
upload(name){
|
||||
//读取上传文件并填充到表单
|
||||
var file = document.createElement('input');
|
||||
file.type = 'file';
|
||||
file.accept = '.pem,.crt,.key';
|
||||
file.style.display = 'none';
|
||||
file.onchange = function(){
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e){
|
||||
this.set[name] = e.target.result;
|
||||
}.bind(this);
|
||||
reader.readAsText(file.files[0]);
|
||||
}.bind(this);
|
||||
document.body.appendChild(file);
|
||||
file.click();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
{extend name="common/layout" /}
|
||||
{block name="title"}导入已有证书{/block}
|
||||
{block name="main"}
|
||||
<style>
|
||||
.tips{color: #f6a838; padding-left: 5px;}
|
||||
.control-label[is-required]:before {
|
||||
content: "*";
|
||||
color: #f56c6c;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.input-group-addon{padding: 6px 6px;}
|
||||
</style>
|
||||
<div class="row" id="app">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><h3 class="panel-title"><a href="/cert/certorder" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>导入已有证书</h3></div>
|
||||
<div class="panel-body">
|
||||
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="taskform">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>证书内容</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<textarea name="fullchain" v-model="set.fullchain" class="form-control" rows="5" placeholder="输入PEM格式证书链" required></textarea>
|
||||
<a class="btn btn-default input-group-addon" @click="upload('fullchain')" title="上传证书文件"><i class="fa fa-upload"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>私钥内容</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<textarea name="privatekey" v-model="set.privatekey" class="form-control" rows="5" placeholder="输入PEM格式私钥" required></textarea>
|
||||
<a class="btn btn-default input-group-addon" @click="upload('privatekey')" title="上传私钥文件"><i class="fa fa-upload"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 col-xs-12 control-label no-padding-right" is-required>证书续期账户</label>
|
||||
<div class="col-sm-6"><select name="aid" v-model="set.aid" class="form-control" required>
|
||||
<option value="">--选择证书账户--</option>
|
||||
{foreach $accounts as $k=>$v}
|
||||
<option value="{$k}" data-type="{$v.type}">{$v.name}</option>
|
||||
{/foreach}
|
||||
</select></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>签名算法</label>
|
||||
<div class="col-sm-6">
|
||||
<label class="radio-inline" v-for="item in keytypeList">
|
||||
<input type="radio" name="keytype" :value="item" v-model="set.keytype"> {{item}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right" is-required>密钥长度</label>
|
||||
<div class="col-sm-6">
|
||||
<label class="radio-inline" v-for="item in keysizeList">
|
||||
<input type="radio" name="keysize" :value="item.value" v-model="set.keysize"> {{item.label}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="/static/js/bootstrapValidator.min.js"></script>
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
type: '',
|
||||
set: {
|
||||
fullchain: '',
|
||||
privatekey: '',
|
||||
aid: '',
|
||||
keytype: '',
|
||||
keysize: '',
|
||||
},
|
||||
keytypeList: [
|
||||
'RSA',
|
||||
'ECC'
|
||||
],
|
||||
keysizeMap: [
|
||||
{label:'2048 bit',value:'2048',type:'RSA'},
|
||||
{label:'3072 bit',value:'3072',type:'RSA'},
|
||||
{label:'P-256',value:'256',type:'ECC'},
|
||||
{label:'P-384',value:'384',type:'ECC'},
|
||||
],
|
||||
keysizeList: [],
|
||||
},
|
||||
watch: {
|
||||
'set.aid': function(val){
|
||||
this.type = $('option:selected', 'select[name=aid]').data('type');
|
||||
},
|
||||
'set.keytype': function(val){
|
||||
this.keysizeList = this.keysizeMap.filter((item) => {
|
||||
return item.type == val;
|
||||
})
|
||||
if(!this.keysizeList.filter((item) => {return item.value == this.set.keysize}).length)
|
||||
this.set.keysize = this.keysizeList[0].value;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.set.keytype = 'RSA';
|
||||
$("#taskform").bootstrapValidator({
|
||||
live: 'submitted',
|
||||
});
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
},
|
||||
methods: {
|
||||
submit(){
|
||||
var that=this;
|
||||
$("#taskform").data("bootstrapValidator").validate();
|
||||
if(!$("#taskform").data("bootstrapValidator").isValid()){
|
||||
return false;
|
||||
}
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "",
|
||||
data: this.set,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert(data.msg, {icon: 1}, function(){
|
||||
if(document.referrer.indexOf('/cert/certorder?') > 0)
|
||||
window.location.href = document.referrer;
|
||||
else
|
||||
window.location.href = '/cert/certorder';
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
},
|
||||
error: function(data){
|
||||
layer.close(ii);
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
},
|
||||
upload(name){
|
||||
//读取上传文件并填充到表单
|
||||
var file = document.createElement('input');
|
||||
file.type = 'file';
|
||||
file.accept = '.pem,.crt,.key';
|
||||
file.style.display = 'none';
|
||||
file.onchange = function(){
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e){
|
||||
this.set[name] = e.target.result;
|
||||
}.bind(this);
|
||||
reader.readAsText(file.files[0]);
|
||||
}.bind(this);
|
||||
document.body.appendChild(file);
|
||||
file.click();
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -153,7 +153,7 @@
|
||||
<li class="{:checkIfActive('certset')}"><a href="/cert/certset"><i class="fa fa-circle-o"></i> 计划任务设置</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="treeview {:checkIfActive('noticeset,proxyset')}">
|
||||
<li class="treeview {:checkIfActive('loginset,noticeset,proxyset')}">
|
||||
<a href="javascript:;">
|
||||
<i class="fa fa-cogs fa-fw"></i>
|
||||
<span>系统设置</span>
|
||||
@@ -162,6 +162,7 @@
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li class="{:checkIfActive('loginset')}"><a href="/system/loginset"><i class="fa fa-circle-o"></i> 登录设置</a></li>
|
||||
<li class="{:checkIfActive('noticeset')}"><a href="/system/noticeset"><i class="fa fa-circle-o"></i> 通知设置</a></li>
|
||||
<li class="{:checkIfActive('proxyset')}"><a href="/system/proxyset"><i class="fa fa-circle-o"></i> 代理设置</a></li>
|
||||
<li><a href="https://www.showdoc.com.cn/dnsmgr/11058996709621562" target="_blank" rel="noreferrer"><i class="fa fa-circle-o"></i> <span>接口文档</span></a></li>
|
||||
|
||||
@@ -195,7 +195,7 @@ function submitClean(){
|
||||
});
|
||||
}
|
||||
function submitNotice(){
|
||||
$.post('/dmonitor/noticeset', $("#form-notice").serialize(), function(res){
|
||||
$.post('/system/set', $("#form-notice").serialize(), function(res){
|
||||
if(res.code == 0){
|
||||
layer.alert('设置保存成功!<br/>重启检测进程或容器后生效', {
|
||||
icon: 1,
|
||||
|
||||
@@ -134,7 +134,7 @@ $(document).ready(function(){
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="/dmonitor/task/info/'+row.id+'" class="btn btn-info btn-xs">切换日志</a> ';
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
<div class="form-group" v-show="set.type<=2&&set.checktype<2">
|
||||
<label class="col-sm-3 control-label no-padding-right">指定检测IP</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="checkurl" v-model="set.checkurl" placeholder="留空默认为解析记录值IP" class="form-control" data-bv-uri="true" required>
|
||||
<input type="text" name="checkip" v-model="set.checkurl" placeholder="留空默认为解析记录值IP" class="form-control" data-bv-ip="true">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" v-show="set.type<=2&&set.checktype==1">
|
||||
|
||||
@@ -130,7 +130,7 @@ $(document).ready(function(){
|
||||
title: '添加时间'
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="javascript:editframe('+row.id+')" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
|
||||
|
||||
@@ -17,18 +17,31 @@
|
||||
<label class="col-sm-3 control-label">域名账户</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="aid" class="form-control">
|
||||
{foreach $accounts as $k=>$v}
|
||||
<option value="{$k}">{$v}</option>
|
||||
{foreach $accounts as $item}
|
||||
<option value="{$item.id}" data-type="{$item.type}" data-add="{$item.add}">{$item.name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" id="methodSelect" style="display: none;">
|
||||
<label class="col-sm-3 control-label"></label>
|
||||
<div class="col-sm-9">
|
||||
<label class="radio-inline"><input type="radio" name="method" value="0" checked> 已有域名</label>
|
||||
<label class="radio-inline"><input type="radio" name="method" value="1"> 新域名</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="domainSelect">
|
||||
<label class="col-sm-3 control-label">选择域名</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="domain" id="domainList" class="form-control"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="domainInput" style="display: none;">
|
||||
<label class="col-sm-3 control-label">输入域名</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="adddomain" placeholder="输入要新增的域名" value="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
@@ -271,7 +284,7 @@ $(document).ready(function(){
|
||||
title: '备注'
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="/record/'+row.id+'" class="btn btn-success btn-xs" onclick="loading()">解析</a>';
|
||||
@@ -289,7 +302,30 @@ $(document).ready(function(){
|
||||
})
|
||||
|
||||
$("#form-store select[name=aid]").change(function(){
|
||||
getDomainList()
|
||||
if($(this).val() != ''){
|
||||
$("#form-store input[name=method][value=0]").prop('checked', true);
|
||||
$("#domainSelect").show();
|
||||
$("#domainInput").hide();
|
||||
var add = $(this).find('option:selected').data('add');
|
||||
if(add == '1'){
|
||||
$("#methodSelect").show();
|
||||
}else{
|
||||
$("#methodSelect").hide();
|
||||
}
|
||||
getDomainList();
|
||||
}
|
||||
})
|
||||
$("#form-store input[name=method]").change(function(){
|
||||
var value = $("#form-store input[name=method]:checked").val();
|
||||
if(value == '0'){
|
||||
$("#domainSelect").show();
|
||||
$("#domainInput").hide();
|
||||
getDomainList();
|
||||
}else{
|
||||
$("#domainSelect").hide();
|
||||
$("#domainInput").show();
|
||||
$('#domainList').empty();
|
||||
}
|
||||
})
|
||||
|
||||
$('[data-toggle="popover"]').popover()
|
||||
@@ -298,26 +334,37 @@ function addframe(){
|
||||
$("#modal-store").modal('show');
|
||||
var aid = $("#form-store select[name=aid]").val();
|
||||
if(aid != ''){
|
||||
getDomainList()
|
||||
$("#form-store select[name=aid]").change();
|
||||
}
|
||||
}
|
||||
function saveAdd(){
|
||||
var aid = $("#form-store select[name=aid]").val();
|
||||
var select = $('#domainList').select2('data');
|
||||
if(select.length == 0){
|
||||
layer.alert('请选择域名!');return false;
|
||||
if(aid == ''){
|
||||
layer.alert('请选择域名账户!');return false;
|
||||
}
|
||||
var name = select[0].text;
|
||||
var thirdid = select[0].id;
|
||||
var recordcount = select[0].recordcount;
|
||||
if(aid=='' || thirdid==''){
|
||||
layer.alert('请确保各项不能为空!');return false;
|
||||
var method = $("#form-store input[name=method]:checked").val();
|
||||
if(method == '1'){
|
||||
var name = $("#form-store input[name=adddomain]").val();
|
||||
if(name == ''){
|
||||
layer.alert('域名不能为空!');return false;
|
||||
}
|
||||
}else{
|
||||
var select = $('#domainList').select2('data');
|
||||
if(select.length == 0){
|
||||
layer.alert('请选择域名!');return false;
|
||||
}
|
||||
var name = select[0].text;
|
||||
var thirdid = select[0].id;
|
||||
var recordcount = select[0].recordcount;
|
||||
if(aid=='' || thirdid==''){
|
||||
layer.alert('请确保各项不能为空!');return false;
|
||||
}
|
||||
}
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/domain/op/act/add',
|
||||
data : {aid: aid, thirdid: thirdid, name: name, recordcount: recordcount},
|
||||
data : {aid: aid, method: method, thirdid: thirdid, name: name, recordcount: recordcount},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
|
||||
@@ -38,6 +38,9 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;
|
||||
<option value="CAA">CAA</option>
|
||||
{if $dnsconfig.redirect}<option value="REDIRECT_URL">显性URL</option>
|
||||
<option value="FORWARD_URL">隐性URL</option>{/if}
|
||||
{if $dnsconfig.type=='powerdns'}<option value="LOC">LOC</option>
|
||||
<option value="PTR">PTR</option>
|
||||
<option value="LUA">LUA</option>{/if}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,6 +115,9 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;
|
||||
<option value="CAA">CAA</option>
|
||||
{if $dnsconfig.redirect}<option value="REDIRECT_URL">显性URL</option>
|
||||
<option value="FORWARD_URL">隐性URL</option>{/if}
|
||||
{if $dnsconfig.type=='powerdns'}<option value="LOC">LOC</option>
|
||||
<option value="PTR">PTR</option>
|
||||
<option value="LUA">LUA</option>{/if}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -201,6 +207,9 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;
|
||||
<option value="CAA">CAA</option>
|
||||
{if $dnsconfig.redirect}<option value="REDIRECT_URL">显性URL</option>
|
||||
<option value="FORWARD_URL">隐性URL</option>{/if}
|
||||
{if $dnsconfig.type=='powerdns'}<option value="LOC">LOC</option>
|
||||
<option value="PTR">PTR</option>
|
||||
<option value="LUA">LUA</option>{/if}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -316,7 +325,7 @@ $(document).ready(function(){
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
if((row.Type == 'NS' || row.Type == 'SOA') && row.Name == '@') return '-';
|
||||
|
||||
@@ -156,6 +156,8 @@ function editframe(id){
|
||||
$("#form-store input[name=id]").val(id);
|
||||
$("#form-store input[name=subdomain]").val(row.SubDomain);
|
||||
$("#form-store input[name=type]").val(row.Type);
|
||||
if(row.Type == 'CNAME') $("#weight-switch").prop("disabled", true);
|
||||
else $("#weight-switch").prop("disabled", false);
|
||||
|
||||
lineList = [];
|
||||
$.each(recordLine, function(i, item){
|
||||
|
||||
@@ -71,9 +71,9 @@
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="browser-notice"></div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div id="browser-notice"></div>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-12">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
@@ -129,14 +129,22 @@
|
||||
</div>
|
||||
<table class="table table-bordered">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="query-title">框架版本</td>
|
||||
<td class="query-result">{$info.framework_version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">PHP版本</td>
|
||||
<td class="query-result">{$info.php_version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">MySQL版本</td>
|
||||
<td class="query-title">数据库版本</td>
|
||||
<td class="query-result">{$info.mysql_version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">Web服务器</td>
|
||||
<td class="query-result">{$info.software}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">服务器时间</td>
|
||||
<td class="query-result">{$info.date}</td>
|
||||
@@ -218,15 +226,14 @@ function cleancache(){
|
||||
</script>
|
||||
<script>
|
||||
function speedModeNotice(){
|
||||
var ua = window.navigator.userAgent;
|
||||
if(ua.indexOf('Windows NT')>-1 && ua.indexOf('Trident/')>-1){
|
||||
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\">当前浏览器是兼容模式,为确保后台功能正常使用,请切换到<b style='color:#51b72f'>极速模式</b>!<br>操作方法:点击浏览器地址栏右侧的IE符号<b style='color:#51b72f;'><i class='fa fa-internet-explorer fa-fw'></i></b>→选择“<b style='color:#51b72f;'><i class='fa fa-flash fa-fw'></i></b><b style='color:#51b72f;'>极速模式</b>”</div></div>";
|
||||
$("#browser-notice").html(html)
|
||||
}
|
||||
else if(window.location.protocol.indexOf("https")==-1){
|
||||
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\"><b style='color:#CC3022;'><i class='fa fa-info-circle fa-fw'></i></b>当前正在使用HTTP访问,可能存在被窃取敏感信息风险,请使用HTTPS访问!</div></div>";
|
||||
$("#browser-notice").html(html)
|
||||
}
|
||||
var ua = window.navigator.userAgent;
|
||||
if(ua.indexOf('Windows NT')>-1 && ua.indexOf('Trident/')>-1){
|
||||
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\">当前浏览器是兼容模式,为确保后台功能正常使用,请切换到<b style='color:#51b72f'>极速模式</b>!<br>操作方法:点击浏览器地址栏右侧的IE符号<b style='color:#51b72f;'><i class='fa fa-internet-explorer fa-fw'></i></b>→选择“<b style='color:#51b72f;'><i class='fa fa-flash fa-fw'></i></b><b style='color:#51b72f;'>极速模式</b>”</div></div>";
|
||||
$("#browser-notice").html(html)
|
||||
}else if(window.location.protocol.indexOf("https")==-1){
|
||||
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\"><b style='color:#CC3022;'><i class='fa fa-info-circle fa-fw'></i></b>当前正在使用HTTP访问,可能存在被窃取敏感信息风险,请使用HTTPS访问!</div></div>";
|
||||
$("#browser-notice").html(html)
|
||||
}
|
||||
}
|
||||
speedModeNotice();
|
||||
</script>
|
||||
|
||||
@@ -131,7 +131,7 @@ $(document).ready(function(){
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="javascript:runTask(\''+row.id+'\')" class="btn btn-success btn-xs">手动更新</a> ';
|
||||
|
||||
39
app/view/system/loginset.html
Normal file
39
app/view/system/loginset.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{extend name="common/layout" /}
|
||||
{block name="title"}登录设置{/block}
|
||||
{block name="main"}
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-8 col-lg-6 center-block" style="float: none;">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading"><h3 class="panel-title">登录验证码设置</h3></div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">开启图形验证码</label>
|
||||
<div class="col-sm-9"><div class="material-switch"><input id="vocde_switch" type="checkbox" {if config_get('vcode', '1')=='1'}checked{/if} onchange="setvcode()"><label for="vocde_switch" class="label-primary"></label></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script>
|
||||
var items = $("select[default]");
|
||||
for (i = 0; i < items.length; i++) {
|
||||
$(items[i]).val($(items[i]).attr("default")||0);
|
||||
}
|
||||
function setvcode(){
|
||||
var status = $("#vocde_switch").is(':checked') ? '1' : '2';
|
||||
$.post('/system/set', {vcode: status}, function(res){
|
||||
if(res.code == 0){
|
||||
layer.msg(status == '1' ? '图形验证码已开启' : '图形验证码已关闭', {icon: 1, time: 1000});
|
||||
}else{
|
||||
layer.alert(res.msg, {icon: 2});
|
||||
$("#vocde_switch").prop('checked', !status);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{/block}
|
||||
@@ -165,7 +165,7 @@ function saveSetting(obj){
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '',
|
||||
url : '/system/set',
|
||||
data : $(obj).serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<option value="https">HTTPS</option>
|
||||
<option value="sock4">SOCK4</option>
|
||||
<option value="sock5">SOCK5</option>
|
||||
<option value="sock5h">SOCK5H</option>
|
||||
</select></div>
|
||||
</div><br/>
|
||||
<div class="form-group">
|
||||
@@ -56,7 +57,7 @@ function saveSetting(obj){
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '',
|
||||
url : '/system/set',
|
||||
data : $(obj).serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
|
||||
@@ -174,7 +174,7 @@ $(document).ready(function(){
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
field: 'action',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="javascript:editframe('+row.id+')" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "netcccyun/dnsmgr",
|
||||
"description": "聚合DNS管理系统",
|
||||
"type": "project",
|
||||
@@ -31,40 +32,50 @@
|
||||
"email": "admin@kuxi.tech",
|
||||
"homepage": "https://www.kuxi.tech",
|
||||
"role": "Project Developer"
|
||||
},
|
||||
{
|
||||
"name": "耗子",
|
||||
"email": "haozi@loli.email",
|
||||
"homepage": "https://hzbk.net",
|
||||
"role": "Project Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-pdo": "*",
|
||||
"ext-gd": "*",
|
||||
"php": ">=8.2.0",
|
||||
"ext-curl": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-sockets": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-ssh2": "*",
|
||||
"ext-ftp": "*",
|
||||
"topthink/framework": "^6.0.0",
|
||||
"topthink/think-orm": "^2.0",
|
||||
"topthink/think-view": "^1.0",
|
||||
"ext-gd": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-pdo": "*",
|
||||
"ext-sockets": "*",
|
||||
"ext-ssh2": "*",
|
||||
"cccyun/php-whois": "^1.0",
|
||||
"cccyun/think-captcha": "^3.0",
|
||||
"symfony/polyfill-intl-idn": "^1.31",
|
||||
"symfony/polyfill-php80": "^1.31",
|
||||
"cccyun/php-whois": "^1.0"
|
||||
"guzzlehttp/guzzle": "^7.0",
|
||||
"phpmailer/phpmailer": "^6.10",
|
||||
"symfony/polyfill-intl-idn": "^1.32",
|
||||
"symfony/polyfill-mbstring": "^1.32",
|
||||
"symfony/polyfill-php81": "^1.32",
|
||||
"symfony/polyfill-php82": "^1.32",
|
||||
"topthink/framework": "^8.1.0",
|
||||
"topthink/think-orm": "^4.0",
|
||||
"topthink/think-view": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/var-dumper": "^4.2",
|
||||
"symfony/var-dumper": "^7.3",
|
||||
"topthink/think-trace":"^1.0",
|
||||
"swoole/ide-helper": "^5.1"
|
||||
"swoole/ide-helper": "^6.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"app\\": "app"
|
||||
},
|
||||
"psr-0": {
|
||||
"": "extend/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"sort-packages": true,
|
||||
"platform-check": false,
|
||||
"preferred-install": "dist"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -72,5 +83,7 @@
|
||||
"@php think service:discover",
|
||||
"@php think vendor:publish"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
||||
1882
composer.lock
generated
Normal file
1882
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ return [
|
||||
'show_error_msg' => true,
|
||||
'exception_tmpl' => \think\facade\App::getAppPath() . 'view/exception.tpl',
|
||||
|
||||
'version' => '1035',
|
||||
'version' => '1037',
|
||||
|
||||
'dbversion' => '1033'
|
||||
];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user