diff --git a/app/lib/DeployHelper.php b/app/lib/DeployHelper.php index d559f88..a6fff72 100644 --- a/app/lib/DeployHelper.php +++ b/app/lib/DeployHelper.php @@ -139,12 +139,12 @@ class DeployHelper 'class' => 1, 'icon' => 'host.png', 'desc' => '支持虚拟主机与CDN站点', - 'note' => '以上登录地址需填写Easypanel管理员面板地址,非用户面板。', + 'note' => '以上登录信息为Easypanel管理员面板的,非用户面板。', 'inputs' => [ 'url' => [ 'name' => '面板地址', 'type' => 'input', - 'placeholder' => 'Easypanel管理员面板地址', + 'placeholder' => 'Easypanel面板地址', 'note' => '填写规则如:http://192.168.1.100:3312 ,不要带其他后缀', 'required' => true, ], @@ -288,17 +288,43 @@ class DeployHelper 'note' => '填写示例:http://demo.cdnfly.cn', 'required' => true, ], + 'auth' => [ + 'name' => '认证方式', + 'type' => 'radio', + 'options' => [ + '0' => '接口密钥', + '1' => '模拟登录', + ], + 'value' => '0', + 'required' => true, + ], 'api_key' => [ 'name' => 'api_key', 'type' => 'input', 'placeholder' => '', 'required' => true, + 'show' => 'auth==0', ], 'api_secret' => [ 'name' => 'api_secret', 'type' => 'input', 'placeholder' => '', 'required' => true, + 'show' => 'auth==0', + ], + 'username' => [ + 'name' => '登录账号', + 'type' => 'input', + 'placeholder' => '', + 'required' => true, + 'show' => 'auth==1', + ], + 'password' => [ + 'name' => '登录密码', + 'type' => 'input', + 'placeholder' => '', + 'required' => true, + 'show' => 'auth==1', ], 'proxy' => [ 'name' => '使用代理服务器', @@ -1636,6 +1662,61 @@ class DeployHelper ], ], ], + 'unicloud' => [ + 'name' => 'uniCloud', + 'class' => 2, + 'icon' => 'unicloud.png', + 'desc' => '部署到uniCloud服务空间', + 'note' => null, + 'inputs' => [ + 'username' => [ + 'name' => '账号', + 'type' => 'input', + 'placeholder' => '', + 'required' => true, + ], + 'password' => [ + 'name' => '密码', + 'type' => 'input', + 'placeholder' => '', + 'required' => true, + ], + 'proxy' => [ + 'name' => '使用代理服务器', + 'type' => 'radio', + 'options' => [ + '0' => '否', + '1' => '是', + ], + 'value' => '0' + ], + ], + 'taskinputs' => [ + 'spaceId' => [ + 'name' => '服务空间ID', + 'type' => 'input', + 'placeholder' => 'spaceId', + 'required' => true, + ], + 'provider' => [ + 'name' => '空间提供商', + 'type' => 'select', + 'options' => [ + ['value'=>'aliyun', 'label'=>'阿里云'], + ['value'=>'tencent', 'label'=>'腾讯云'], + ['value'=>'alipay', 'label'=>'支付宝云'], + ], + 'value' => 'aliyun', + 'required' => true, + ], + 'domains' => [ + 'name' => '空间域名', + 'type' => 'input', + 'placeholder' => '多个域名可使用,分隔', + 'required' => true, + ], + ], + ], 'aws' => [ 'name' => 'AWS', 'class' => 2, diff --git a/app/lib/deploy/cdnfly.php b/app/lib/deploy/cdnfly.php index 80e59e5..06b43ed 100644 --- a/app/lib/deploy/cdnfly.php +++ b/app/lib/deploy/cdnfly.php @@ -11,6 +11,9 @@ class cdnfly implements DeployInterface private $url; private $api_key; private $api_secret; + private $auth = 0; + private $username; + private $password; private $proxy; public function __construct($config) @@ -18,13 +21,23 @@ class cdnfly implements DeployInterface $this->url = rtrim($config['url'], '/'); $this->api_key = $config['api_key']; $this->api_secret = $config['api_secret']; + $this->auth = isset($config['auth']) ? $config['auth'] : 0; + if ($this->auth == 1) { + $this->username = $config['username']; + $this->password = $config['password']; + } $this->proxy = $config['proxy'] == 1; } public function check() { - if (empty($this->url) || empty($this->api_key) || empty($this->api_secret)) throw new Exception('必填参数不能为空'); - $this->request('/v1/user'); + if ($this->auth == 1) { + if (empty($this->url) || empty($this->username) || empty($this->password)) throw new Exception('必填参数不能为空'); + $this->login(); + } else { + if (empty($this->url) || empty($this->api_key) || empty($this->api_secret)) throw new Exception('必填参数不能为空'); + $this->request('/v1/user'); + } } public function deploy($fullchain, $privatekey, $config, &$info) @@ -37,10 +50,46 @@ class cdnfly implements DeployInterface 'cert' => $fullchain, 'key' => $privatekey, ]; - $this->request('/v1/certs/' . $id, $params, 'PUT'); + if ($this->auth == 1) { + $access_token = $this->login(); + $url = $this->url . '/v1/certs/' . $id; + $body = json_encode($params); + $headers = [ + 'Access-Token' => $access_token, + ]; + $response = http_request($url, $body, null, null, $headers, $this->proxy, 'PUT'); + $result = json_decode($response['body'], true); + if (isset($result['code']) && $result['code'] == 0) { + } elseif (isset($result['msg'])) { + throw new Exception('证书ID:' . $id . '更新失败,' . $result['msg']); + } else { + throw new Exception('证书ID:' . $id . '更新失败,返回数据解析失败'); + } + } else { + $this->request('/v1/certs/' . $id, $params, 'PUT'); + } $this->log("证书ID:{$id}更新成功!"); } + public function login() + { + $url = $this->url . '/v1/login'; + $params = [ + 'account' => $this->username, + 'password' => $this->password, + ]; + $body = json_encode($params); + $response = http_request($url, $body, null, null, null, $this->proxy); + $result = json_decode($response['body'], true); + if (isset($result['code']) && $result['code'] == 0) { + return $result['data']['access_token']; + } elseif (isset($result['msg'])) { + throw new Exception($result['msg']); + } else { + throw new Exception('登录失败,返回数据解析失败'); + } + } + private function request($path, $params = null, $method = null) { $url = $this->url . $path; diff --git a/app/lib/deploy/unicloud.php b/app/lib/deploy/unicloud.php new file mode 100644 index 0000000..cd663e1 --- /dev/null +++ b/app/lib/deploy/unicloud.php @@ -0,0 +1,211 @@ +username = $config['username']; + $this->password = $config['password']; + $this->proxy = $config['proxy'] == 1; + $this->deviceId = getMillisecond() . random(7, 1); + } + + public function check() + { + if (empty($this->username) || empty($this->password)) throw new Exception('账号或密码不能为空'); + $this->login(); + } + + public function deploy($fullchain, $privatekey, $config, &$info) + { + if (empty($config['domains'])) throw new Exception('绑定的域名不能为空'); + $this->getToken(); + + $url = 'https://unicloud-api.dcloud.net.cn/unicloud/api/host/create-domain-with-cert'; + foreach (explode(',', $config['domains']) as $domain) { + $params = [ + 'appid' => '', + 'provider' => $config['provider'], + 'spaceId' => $config['spaceId'], + 'domain' => $domain, + 'cert' => rawurlencode($fullchain), + 'key' => rawurlencode($privatekey), + ]; + $post = json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + $headers = [ + 'Token' => $this->token, + ]; + $response = http_request($url, $post, null, null, $headers, $this->proxy); + $result = json_decode($response['body'], true); + if (isset($result['ret']) && $result['ret'] == 0) { + $this->log('域名:' . $domain . ' 证书更新成功!'); + } elseif(isset($result['desc'])) { + throw new Exception('域名:' . $domain . ' 证书更新失败:' . $result['desc']); + } else { + throw new Exception('域名:' . $domain . ' 证书更新失败:' . $response['body']); + } + } + } + + private function login() + { + $url = 'https://account.dcloud.net.cn/client'; + $clientInfo = $this->getClientInfo('__UNI__unicloud_console', '账号中心'); + $bizParams = [ + 'functionTarget' => 'uni-id-co', + 'functionArgs' => [ + 'method' => 'login', + 'params' => [[ + 'password' => $this->password, + 'captcha' => '', + 'resetAppId' => '__UNI__unicloud_console', + 'resetUniPlatform' => 'web', + 'isReturnToken' => false, + 'email' => $this->username, + ]], + 'clientInfo' => $clientInfo, + ], + ]; + $params = [ + 'method' => 'serverless.function.runtime.invoke', + 'params' => json_encode($bizParams, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'spaceId' => 'uni-id-server', + 'timestamp' => getMillisecond(), + ]; + $sign = $this->sign($params, 'ba461799-fde8-429f-8cc4-4b6d306e2339'); + $post = json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + $headers = [ + 'Origin' => 'https://account.dcloud.net.cn', + 'Referer' => 'https://account.dcloud.net.cn/', + 'X-Client-Info' => json_encode($clientInfo, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'X-Serverless-Sign' => $sign, + ]; + $response = http_request($url, $post, null, null, $headers, $this->proxy); + $result = json_decode($response['body'], true); + if (isset($result['success']) && $result['success'] == true) { + if (isset($result['data']['errCode']) && $result['data']['errCode'] == 0) { + return $result['data']['newToken']['token']; + } else { + throw new Exception('登录失败:' . $result['data']['errMsg']); + } + } else { + throw new Exception('登录失败:' . $response['body']); + } + } + + private function getToken() + { + $uniIdToken = $this->login(); + $url = 'https://unicloud.dcloud.net.cn/client'; + $clientInfo = $this->getClientInfo('__UNI__unicloud_console', 'uniCloud控制台'); + $bizParams = [ + 'functionTarget' => 'uni-cloud-kernel', + 'functionArgs' => [ + 'action' => 'user/getUserToken', + 'data' => [ + 'isLogin' => true + ], + 'clientInfo' => $clientInfo, + 'uniIdToken' => $uniIdToken, + ], + ]; + $params = [ + 'method' => 'serverless.function.runtime.invoke', + 'params' => json_encode($bizParams, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'spaceId' => 'dc-6nfabcn6ada8d3dd', + 'timestamp' => getMillisecond(), + ]; + $sign = $this->sign($params, '4c1f7fbf-c732-42b0-ab10-4634a8bbe834'); + $post = json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + $headers = [ + 'Origin' => 'https://account.dcloud.net.cn', + 'Referer' => 'https://account.dcloud.net.cn/', + 'X-Client-Info' => json_encode($clientInfo, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + 'X-Client-Token' => $uniIdToken, + 'X-Serverless-Sign' => $sign, + ]; + $response = http_request($url, $post, null, null, $headers, $this->proxy); + $result = json_decode($response['body'], true); + if (isset($result['success']) && $result['success'] == true) { + if (isset($result['data']['code']) && $result['data']['code'] == 0) { + if (isset($result['data']['data']['ret']) && $result['data']['data']['ret'] == 0) { + $this->token = $result['data']['data']['data']['token']; + return $result['data']['data']['data']['token']; + } else { + throw new Exception('获取token失败:' . $result['data']['data']['desc']); + } + } else { + throw new Exception('获取token失败:' . $response['body']); + } + } else { + throw new Exception('获取token失败:' . $response['body']); + } + } + + private function getClientInfo($appId, $appName, $appVersion = '1.0.0', $appVersionCode = '100') + { + $clientInfo = [ + 'PLATFORM' => 'web', + 'OS' => 'windows', + 'APPID' => $appId, + 'DEVICEID' => $this->deviceId, + 'scene' => 1001, + 'appId' => $appId, + 'appLanguage' => 'zh-Hans', + 'appName' => $appName, + 'appVersion' => $appVersion, + 'appVersionCode' => $appVersionCode, + 'browserName' => 'chrome', + 'browserVersion' => '122.0.6261.95', + 'deviceId' => $this->deviceId, + 'deviceModel' => 'PC', + 'deviceType' => 'pc', + 'hostName' => 'chrome', + 'hostVersion' => '122.0.6261.95', + 'osName' => 'windows', + 'osVersion' => '10 x64', + 'ua' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36', + 'uniCompilerVersion' => '4.45', + 'uniPlatform' => 'web', + 'uniRuntimeVersion' => '4.45', + 'locale' => 'zh-Hans', + 'LOCALE' => 'zh-Hans', + ]; + return $clientInfo; + } + + private function sign($data, $key) + { + ksort($data); + $signstr = ''; + foreach ($data as $k => $v) { + $signstr .= $k . '=' . $v . '&'; + } + $signstr = rtrim($signstr, '&'); + return hash_hmac('md5', $signstr, $key); + } + + public function setLogger($func) + { + $this->logger = $func; + } + + private function log($txt) + { + if ($this->logger) { + call_user_func($this->logger, $txt); + } + } +} diff --git a/app/view/domain/domain.html b/app/view/domain/domain.html index af2994f..a0beb10 100644 --- a/app/view/domain/domain.html +++ b/app/view/domain/domain.html @@ -301,7 +301,6 @@ $(document).ready(function(){ }, onPageChange: function(number, size){ if(size != defaultPageSize){ - defaultPageSize = size; setCookie('domain_pagesize', size); } }, diff --git a/app/view/domain/record.html b/app/view/domain/record.html index 763de3e..4f42403 100644 --- a/app/view/domain/record.html +++ b/app/view/domain/record.html @@ -359,7 +359,6 @@ $(document).ready(function(){ ], onPageChange: function(number, size){ if(size != defaultPageSize){ - defaultPageSize = size; setCookie('record_pagesize', size); } }, diff --git a/composer.lock b/composer.lock index a902d42..41c91bb 100644 --- a/composer.lock +++ b/composer.lock @@ -951,7 +951,7 @@ }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -1014,7 +1014,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -1025,6 +1025,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1034,7 +1038,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -1095,7 +1099,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -1106,6 +1110,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1115,7 +1123,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -1176,7 +1184,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -1187,6 +1195,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1196,7 +1208,7 @@ }, { "name": "symfony/polyfill-php81", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -1252,7 +1264,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" }, "funding": [ { @@ -1263,6 +1275,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1272,7 +1288,7 @@ }, { "name": "symfony/polyfill-php82", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php82.git", @@ -1328,7 +1344,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php82/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php82/tree/v1.33.0" }, "funding": [ { @@ -1339,6 +1355,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1866,7 +1886,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { @@ -1880,6 +1900,6 @@ "ext-sockets": "*", "ext-ssh2": "*" }, - "platform-dev": {}, + "platform-dev": [], "plugin-api-version": "2.6.0" } diff --git a/public/static/images/unicloud.png b/public/static/images/unicloud.png new file mode 100644 index 0000000..710f924 Binary files /dev/null and b/public/static/images/unicloud.png differ