diff --git a/catch/domain/DomainService.php b/catch/domain/DomainService.php index 2395aa2..06d5ae0 100644 --- a/catch/domain/DomainService.php +++ b/catch/domain/DomainService.php @@ -12,7 +12,9 @@ namespace catchAdmin\domain; use catchAdmin\domain\support\contract\DomainActionInterface; +use catchAdmin\domain\support\contract\DomainRecordInterface; use catchAdmin\domain\support\driver\aliyun\Domain; +use catchAdmin\domain\support\driver\aliyun\DomainRecord; use catcher\ModuleService; class DomainService extends ModuleService @@ -29,22 +31,23 @@ class DomainService extends ModuleService return require __DIR__ . DIRECTORY_SEPARATOR . 'config.php'; } + /** + * @return string + */ public function loadRouteFrom() { // TODO: Implement loadRouteFrom() method. return __DIR__ . DIRECTORY_SEPARATOR . 'route.php'; } + /** + * + */ protected function registerInstance() { $default = config('catch.domains.default'); - - switch ($default) { - case 'aliyun': - $this->app->instance(DomainActionInterface::class, new Domain); - break; - default: - break; - } + + $this->app->instance(DomainActionInterface::class, $this->app->make(__NAMESPACE__ . '\\support\\driver\\' . $default . '\Domain')); + $this->app->instance(DomainRecordInterface::class, $this->app->make(__NAMESPACE__ . '\\support\\driver\\' . $default . '\DomainRecord')); } } diff --git a/catch/domain/README.md b/catch/domain/README.md new file mode 100644 index 0000000..5747dbf --- /dev/null +++ b/catch/domain/README.md @@ -0,0 +1,46 @@ +## 域名管理 +- 阿里云(主支持) +- 腾讯云(需要做适配) + +#### 配置 +首先在 .env 文件设置 +``` +[ALIYUN] +ACCESS_KEY= +ACCESS_SECRET= + +[QCLOUD] +ACCESS_KEY= +ACCESS_SECRET= +``` +也可以在 config.php 文件配置 +``` +'domains' => [ + // 默认阿里云 + 'default' => 'aliyun', + + /** + * 阿里云配置 + * + */ + 'aliyun' => [ + 'api_domain' => 'http://alidns.aliyuncs.com', + + 'access_key' => Env::get('aliyun.access_key', ''), + + 'access_secret' => Env::get('aliyun.access_secret', ''), + ], + + /** + * 腾讯云配置 + * + */ + 'qcloud' => [ + 'api_domain' => 'cns.api.qcloud.com', + + 'access_key' => Env::get('qcloud.access_key', ''), + + 'access_secret' => Env::get('qcloud.access_secret', ''), + ] +] +``` \ No newline at end of file diff --git a/catch/domain/config.php b/catch/domain/config.php index 3f8e214..d1c4f0f 100644 --- a/catch/domain/config.php +++ b/catch/domain/config.php @@ -8,6 +8,9 @@ // +---------------------------------------------------------------------- // | Author: JaguarJack [ njphper@gmail.com ] // +---------------------------------------------------------------------- + +use think\facade\Env; + return [ 'domains' => [ // 默认阿里云 @@ -20,9 +23,9 @@ return [ 'aliyun' => [ 'api_domain' => 'http://alidns.aliyuncs.com', - 'access_key' => 'LTAI4G2JF2iiJEfnQYm4vhvr', + 'access_key' => Env::get('aliyun.access_key', ''), - 'access_secret' => 'YDe2sff7uDN1nRPdfvVAFCW6lLaOrC', + 'access_secret' => Env::get('aliyun.access_secret', ''), ], /** @@ -30,8 +33,11 @@ return [ * */ 'qcloud' => [ - 'access_key' => '', - 'access_secret' => '', + 'api_domain' => 'cns.api.qcloud.com', + + 'access_key' => Env::get('qcloud.access_key', ''), + + 'access_secret' => Env::get('qcloud.access_secret', ''), ] ] ]; \ No newline at end of file diff --git a/catch/domain/controller/Domain.php b/catch/domain/controller/Domain.php index 7d465f9..095b758 100644 --- a/catch/domain/controller/Domain.php +++ b/catch/domain/controller/Domain.php @@ -36,18 +36,6 @@ class Domain extends CatchController return CatchResponse::paginate($this->domain->getList($request->param())); } - /** - * 保存 - * - * @time 2020/09/11 18:14 - * @param Request Request - * @return \think\Response - */ - public function save(Request $request) - { - return CatchResponse::success($this->domain->add($request->post())); - } - /** * 读取 * @@ -57,32 +45,6 @@ class Domain extends CatchController */ public function read($name) { - return CatchResponse::success($this->domain->info($name)); + return CatchResponse::success($this->domain->read(str_replace('-', '.', $name))); } - - /** - * 更新 - * - * @time 2020/09/11 18:14 - * @param Request $request - * @return \think\Response - */ - public function update(Request $request, $name) - { - return CatchResponse::success($this->model->updateBy($id, $request->post())); - } - - /** - * 删除 - * - * @time 2020/09/11 18:14 - * @param $name - * @return \think\Response - */ - public function delete($name) - { - return CatchResponse::success($this->domain->delete($name)); - } - - } \ No newline at end of file diff --git a/catch/domain/controller/DomainRecord.php b/catch/domain/controller/DomainRecord.php new file mode 100644 index 0000000..a5f95f6 --- /dev/null +++ b/catch/domain/controller/DomainRecord.php @@ -0,0 +1,99 @@ +domainRecord = $record; + } + + /** + * 列表 + * + * @time 2020/09/11 18:14 + * @param Request $request + * @return \think\Response + */ + public function index(Request $request): \think\Response + { + return CatchResponse::paginate($this->domainRecord->getList($request->param())); + } + + /** + * 保存 + * + * @time 2020/09/11 18:14 + * @param Request Request + * @return \think\Response + */ + public function save(Request $request): \think\Response + { + return CatchResponse::success($this->domainRecord->store($request->post())); + } + + /** + * 读取 + * + * @time 2020/09/11 18:14 + * @param $name + * @return \think\Response + */ + public function read($name): \think\Response + { + return CatchResponse::success($this->domainRecord->read($name)); + } + + /** + * 更新 + * + * @time 2020/09/11 18:14 + * @param Request $request + * @param $id + * @return \think\Response + */ + public function update($id, Request $request): \think\Response + { + return CatchResponse::success($this->domainRecord->update($id, $request->post())); + } + + /** + * 删除 + * + * @time 2020/09/11 18:14 + * @param $id + * @return \think\Response + */ + public function delete($id): \think\Response + { + return CatchResponse::success($this->domainRecord->delete($id)); + } + + /** + * 设置状态 + * + * @param $id + * @param $status + * @return \think\response\Json + */ + public function enable($id, $status) + { + return CatchResponse::success($this->domainRecord->enable($id, $status)); + } +} \ No newline at end of file diff --git a/catch/domain/module.json b/catch/domain/module.json index 61aa08d..375dead 100644 --- a/catch/domain/module.json +++ b/catch/domain/module.json @@ -11,5 +11,5 @@ "aliases": {}, "files": [], "requires": [], - "enable": true + "enable": false } diff --git a/catch/domain/route.php b/catch/domain/route.php index 6a9615e..59cb332 100644 --- a/catch/domain/route.php +++ b/catch/domain/route.php @@ -10,9 +10,14 @@ // +---------------------------------------------------------------------- // you should use `$router` +use catchAdmin\domain\controller\DomainRecord; + $router->group(function () use ($router){ // 域名管理 - $router->resource('domain', '\catchAdmin\domain\controller\Domain'); + $router->get('domain', '\catchAdmin\domain\controller\Domain@index'); + $router->get('domain/', '\catchAdmin\domain\controller\Domain@read'); // 域名解析管理 + $router->resource('record/domain', DomainRecord::class); + $router->put('record/domain//', '\catchAdmin\domain\controller\DomainRecord@enable'); })->middleware('auth'); diff --git a/catch/domain/support/CommonParams.php b/catch/domain/support/CommonParams.php index 102dfc6..1f0f557 100644 --- a/catch/domain/support/CommonParams.php +++ b/catch/domain/support/CommonParams.php @@ -11,6 +11,7 @@ namespace catchAdmin\domain\support; use catchAdmin\domain\support\signature\Aliyun; +use catchAdmin\domain\support\signature\Qcloud; /** * 公共参数 @@ -20,13 +21,20 @@ use catchAdmin\domain\support\signature\Aliyun; */ class CommonParams { + /** + * 阿里云公共参数 + * + * @param array $params + * @param string $method + * @return array + */ public static function aliyun(array $params, $method = 'GET') { date_default_timezone_set('UTC'); $params = array_merge($params, [ 'Format' => 'json', - 'Version' => '2015-01-09', + 'Version' => '2015-01-09', 'AccessKeyId' => config('catch.domains.aliyun.access_key'), 'SignatureMethod' => 'HMAC-SHA1', 'Timestamp' => date('Y-m-d\TH:i:s\Z'), @@ -38,4 +46,25 @@ class CommonParams return $params; } + + /** + * 腾讯云公共参数 + * + * @param array $params + * @param string $method + * @return array + */ + public static function qcloud(array $params, $method = 'GET') + { + $params = array_merge($params, [ + 'SecretId' => config('catch.domains.qcloud.access_key'), + 'SignatureMethod' => 'HmacSHA1', + 'Timestamp' => time(), + 'Nonce' => uniqid() + ]); + + $params['Signature'] = (new Qcloud($params))->signature($method); + + return $params; + } } \ No newline at end of file diff --git a/catch/domain/support/Transformer.php b/catch/domain/support/Transformer.php index 1fa04a7..d786dc7 100644 --- a/catch/domain/support/Transformer.php +++ b/catch/domain/support/Transformer.php @@ -14,7 +14,13 @@ use think\Paginator; class Transformer { - public static function aliyunDomainPaginate($data) + /** + * 分页展示 + * + * @param array $data + * @return mixed + */ + public static function aliyunDomainPaginate(array $data) { $list = []; @@ -24,31 +30,83 @@ class Transformer 'created_at' => date('Y-m-d', $item['CreateTimestamp']/1000), 'dns_server' => $item['DnsServers']['DnsServer'], 'from' => $item['VersionName'], - 'expired_at' => substr($item['InstanceEndTime'], 0, 10), + 'free' => $item['VersionCode'] === 'mianfei', 'record_count' => $item['RecordCount'], - 'registrant_email' => $item['RegistrantEmail'], 'tags' => $item['Tags']['Tag'], 'id' => $item['DomainId'] ]; } - var_dump($list); + return Paginator::make($list, $data['PageSize'], $data['PageNumber'], $data['TotalCount']); } - public static function aliyunDomainRecordPaginate($data) + /** + * 腾讯云域名列表 + * + * @param array $data + * @param $page + * @param $limit + * @return Paginator|\think\paginator\driver\Bootstrap + */ + public static function qcloudDomainPaginate(array $data, $page, $limit) + { + $info = $data['data']['info']; + $domains = $data['data']['domains']; + + $list = []; + + foreach ($domains as $item) { + $list[] = [ + 'name' => $item['name'], + 'created_at' => $item['created_on'], + 'dns_server' => [], + 'from' => 'qcloud', + 'free' => $item['grade'] === 'DP_Free', + 'record_count' => $item['records'], + 'tags' => [], + 'id' => $item['id'] + ]; + } + + return Paginator::make($list, $limit, $page + 1,$info['domain_total']); + } + + /** + * 阿里云域名解析 + * + * @param array $data + * @return mixed + */ + public static function aliyunDomainRecordPaginate(array $data) { $list = []; - foreach ($data['Domains']['Domain'] as $item) { - $list[] = [ - 'name' => $item['DomainName'], - 'created_at' => date('Y-m-d', $item['CreateTimestamp']/1000), - 'dns_server' => $item['DnsServers']['DnsServer'], - 'from' => $item['VersionName'], - 'tags' => $item['Tags']['Tag'], - ]; + foreach ($data['DomainRecords']['Record'] as &$item) { + $list[] = array_change_key_case($item); } return Paginator::make($list, $data['PageSize'], $data['PageNumber'], $data['TotalCount']); } + + /** + * DNS 记录 + * + * @param array $data + * @param $page + * @param $limit + * @return Paginator|\think\paginator\driver\Bootstrap + */ + public static function qcloudDomainRecordPaginate(array $data, $page, $limit) + { + $list = []; + + foreach ($data['data']['records'] as &$item) { + $item['status'] = $item['status'] === 'enabled' ? 'ENABLE' : 'DISABLE'; + $item['rr'] = $item['name']; + $item['recordid'] = $item['id']; + $list[] = array_change_key_case($item); + } + + return Paginator::make($list, $limit, $page + 1, $data['data']['info']['record_total']); + } } \ No newline at end of file diff --git a/catch/domain/support/contract/DomainActionInterface.php b/catch/domain/support/contract/DomainActionInterface.php index 0cd449d..d4a6e72 100644 --- a/catch/domain/support/contract/DomainActionInterface.php +++ b/catch/domain/support/contract/DomainActionInterface.php @@ -18,5 +18,5 @@ interface DomainActionInterface public function delete(array $params); - public function read(array $params); + public function read($name); } \ No newline at end of file diff --git a/catch/domain/support/contract/DomainRecordInterface.php b/catch/domain/support/contract/DomainRecordInterface.php index 3259991..0fd3f42 100644 --- a/catch/domain/support/contract/DomainRecordInterface.php +++ b/catch/domain/support/contract/DomainRecordInterface.php @@ -16,9 +16,12 @@ interface DomainRecordInterface public function store(array $params); - public function delete(array $params); + public function delete($recordId); public function read(array $params); - public function update(array $params); + public function update($recordId, array $params); + + public function enable($recordId, $status); + } \ No newline at end of file diff --git a/catch/domain/support/driver/ApiTrait.php b/catch/domain/support/driver/ApiTrait.php index 18ff00b..09fdaef 100644 --- a/catch/domain/support/driver/ApiTrait.php +++ b/catch/domain/support/driver/ApiTrait.php @@ -19,7 +19,14 @@ trait ApiTrait { $name = config('catch.domains.default'); - return Http::query(CommonParams::{$name}($params)) - ->get(config('catch.domains.' . $name . '.api_domain'))->json(); + $apiDomain = config('catch.domains.' . $name . '.api_domain'); + + if (strpos($apiDomain, 'https') === false && + strpos($apiDomain, 'http') === false) { + $apiDomain = 'https://' . $apiDomain . '/v2/index.php'; + } + + return Http::ignoreSsl()->query(CommonParams::{$name}($params)) + ->get($apiDomain)->json(); } } \ No newline at end of file diff --git a/catch/domain/support/driver/aliyun/Domain.php b/catch/domain/support/driver/aliyun/Domain.php index 06b31e0..7f5c1da 100644 --- a/catch/domain/support/driver/aliyun/Domain.php +++ b/catch/domain/support/driver/aliyun/Domain.php @@ -44,12 +44,12 @@ class Domain implements DomainActionInterface ]); } - public function read(array $params) + public function read($name) { // TODO: Implement info() method. return $this->get([ 'Action' => 'DescribeDomainInfo', - 'DomainName' => $params['name'] + 'DomainName' => $name ]); } } \ No newline at end of file diff --git a/catch/domain/support/driver/aliyun/DomainRecord.php b/catch/domain/support/driver/aliyun/DomainRecord.php index 358b3ba..1f581a1 100644 --- a/catch/domain/support/driver/aliyun/DomainRecord.php +++ b/catch/domain/support/driver/aliyun/DomainRecord.php @@ -12,44 +12,93 @@ namespace catchAdmin\domain\support\driver\aliyun; use catchAdmin\domain\support\contract\DomainRecordInterface; use catchAdmin\domain\support\driver\ApiTrait; +use catchAdmin\domain\support\Transformer; class DomainRecord implements DomainRecordInterface { use ApiTrait; + /** + * 列表 + * + * @param array $params + * @return mixed + */ public function getList(array $params) { - // TODO: Implement getList() method. - return $this->get([ + $data = [ 'Action' => 'DescribeDomainRecords', 'DomainName' => $params['name'], 'PageNumber' => $params['page'] ?? 1, 'PageSize' => $params['limit'] ?? 20, - '' - ]); + ]; + + if ($params['rr']) { + $data['RRKeyWord'] = $params['rr']; + } + + if ($params['type']) { + $data['TypeKeyWord'] = $params['type']; + } + + if ($params['value']) { + $data['ValueKeyWord'] = $params['value']; + } + + if ($params['line']) { + $data['Line'] = $params['line']; + } + + if ($params['status']) { + $data['Status'] = $params['status']; + } + + // TODO: Implement getList() method. + return Transformer::aliyunDomainRecordPaginate($this->get($data)); } + /** + * 新增解析 + * + * @param array $params + * @return array + * + */ public function store(array $params) { // TODO: Implement add() method. return $this->get([ 'Action' => 'AddDomainRecord', 'DomainName' => $params['name'], - 'RR' => $params['record'], + 'RR' => $params['rr'], 'Type' => $params['type'], - 'Value' => $params['ip'] + 'Value' => $params['value'], + 'Line' => $params['line'], + 'TTL' => $params['ttl'], ]); } - public function delete(array $params) + /** + * 删除解析 + * + * @param $recordId + * @return array + */ + public function delete($recordId) { // TODO: Implement delete() method. return $this->get([ 'Action' => 'DeleteDomainRecord', - 'RecordId' => $params['record_id'] + 'RecordId' => $recordId ]); } + /** + * 获取解析记录 + * + * @param array $params + * @return array + */ public function read(array $params) { // TODO: Implement info() method. @@ -59,15 +108,40 @@ class DomainRecord implements DomainRecordInterface ]); } - public function update(array $params) + /** + * 更新解析 + * + * @param array $params + * @param $recordId + * @return array + */ + public function update($recordId, array $params) { // TODO: Implement update() method. return $this->get([ 'Action' => 'UpdateDomainRecord', - 'RecordId' => $params['record_id'], - 'RR' => $params['record'], + 'RecordId' => $recordId, + 'RR' => $params['rr'], 'Type' => $params['type'], - 'Value' => $params['ip'] + 'Value' => $params['value'], + 'Line' => $params['line'], + 'TTL' => $params['ttl'], + ]); + } + + /** + * 设置状态 + * + * @param $recordId + * @param $status + * @return array + */ + public function enable($recordId, $status) + { + return $this->get([ + 'Action' => 'SetDomainRecordStatus', + 'RecordId' => $recordId, + 'Status' => ucfirst(strtolower($status)) ]); } } \ No newline at end of file diff --git a/catch/domain/support/driver/qcloud/Domain.php b/catch/domain/support/driver/qcloud/Domain.php new file mode 100644 index 0000000..d8848b0 --- /dev/null +++ b/catch/domain/support/driver/qcloud/Domain.php @@ -0,0 +1,56 @@ +get([ + 'Action' => 'DomainList', + 'offset' => $offset, + 'length' => $length + ]), $offset, $length); + } + + public function store(array $params) + { + // TODO: Implement add() method. + } + + public function delete(array $params) + { + // TODO: Implement delete() method. + return $this->get([ + 'Action' => 'DeleteDomain', + 'DomainName' => $params['name'], + ]); + } + + public function read($name) + { + // TODO: Implement info() method. + return $this->get([ + 'Action' => 'DescribeDomainInfo', + 'DomainName' => $name + ]); + } +} \ No newline at end of file diff --git a/catch/domain/support/driver/qcloud/DomainRecord.php b/catch/domain/support/driver/qcloud/DomainRecord.php new file mode 100644 index 0000000..4c65bc1 --- /dev/null +++ b/catch/domain/support/driver/qcloud/DomainRecord.php @@ -0,0 +1,125 @@ + 'RecordList', + 'domain' => $params['name'], + 'offset' => ($params['page'] ?? 1) - 1, + 'length' => $params['limit'] ?? 10, + ]; + + if ($params['rr']) { + $data['subDomain'] = $params['rr']; + } + + if ($params['type']) { + $data['recordType'] = $params['type']; + } + + // TODO: Implement getList() method. + return Transformer::qcloudDomainRecordPaginate($this->get($data), $data['offset'], $data['length']); + } + + /** + * 新增解析 + * + * @param array $params + * @return array + * + */ + public function store(array $params) + { + // TODO: Implement add() method. + return $this->get([ + 'Action' => 'RecordCreate', + 'domain' => $params['name'], + 'subDomain' => $params['rr'], + 'recordType' => $params['type'], + 'value' => $params['value'], + 'recordLine' => $params['line'], + 'ttl' => $params['ttl'], + ]); + } + + /** + * 删除解析 + * + * @param $recordId + * @return array + */ + public function delete($recordId) + { + // TODO: Implement delete() method. + return $this->get([ + 'Action' => 'RecordDelete', + 'recordId' => $recordId + ]); + } + + /** + * 更新解析 + * + * @param array $params + * @param $recordId + * @return array + */ + public function update($recordId, array $params) + { + // TODO: Implement update() method. + return $this->get([ + 'Action' => 'RecordModify', + 'recordId' => $recordId, + 'subDomain' => $params['rr'], + 'recordType' => $params['type'], + 'value' => $params['value'], + 'recordLine' => $params['line'], + 'ttl' => $params['ttl'], + ]); + } + + /** + * 设置状态 + * + * @param $recordId + * @param $status + * @return array + */ + public function enable($recordId, $status) + { + return $this->get([ + 'Action' => 'RecordStatus', + 'recordId' => $recordId, + 'Status' => strtolower($status) + ]); + } + + public function read(array $params) + { + // TODO: Implement read() method. + } +} \ No newline at end of file diff --git a/catch/domain/support/signature/Qcloud.php b/catch/domain/support/signature/Qcloud.php new file mode 100644 index 0000000..95b17d1 --- /dev/null +++ b/catch/domain/support/signature/Qcloud.php @@ -0,0 +1,63 @@ +params = $params; + } + + /** + * key 替换 + * + * @param $key + * @return mixed|string|string[] + */ + protected function replaceKey($key) + { + return strpos($key, '_') === false ? + $key : str_replace('_', '.', $key); + } + + /** + * 签名 + * + * @time 2020年09月25日 + * @param $method + * @return string + */ + public function signature(string $method) + { + ksort($this->params); + + $queryString = ''; + + foreach ($this->params as $key => $param) { + $queryString .= '&' . $this->replaceKey($key) . '=' . $param; + } + + $signString = $method . config('catch.domains.qcloud.api_domain') . '/v2/index.php?' + . substr($queryString, 1); + + return base64_encode(hash_hmac('sha1', $signString, config('catch.domains.qcloud.access_secret'), true)); + } +} \ No newline at end of file