增加导入已有证书,支持天翼云CDN部署

This commit is contained in:
net909 2025-01-10 14:54:45 +08:00
parent 8d5a9bc083
commit 2c81b36249
15 changed files with 647 additions and 47 deletions

View File

@ -166,6 +166,11 @@ function getSubstr($str, $leftStr, $rightStr)
}
}
function arrays_are_equal($array1, $array2)
{
return empty(array_diff($array1, $array2)) && empty(array_diff($array2, $array1));
}
function checkRefererHost()
{
if (!Request::header('referer')) {

View File

@ -317,6 +317,72 @@ 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();
@ -368,7 +434,11 @@ class Cert extends BaseController
$max_domains = CertHelper::$cert_config[$account['type']]['max_domains'];
$wildcard = CertHelper::$cert_config[$account['type']]['wildcard'];
$cname = CertHelper::$cert_config[$account['type']]['cname'];
if (count($domains) > $max_domains) return ['code' => -1, 'msg' => '域名数量不能超过'.$max_domains.'个'];
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.'个'];
}
}
foreach($domains as $domain){
if(!$wildcard && strpos($domain, '*') !== false) return ['code' => -1, 'msg' => '该证书账户类型不支持泛域名'];
@ -438,6 +508,20 @@ 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()
{

View File

@ -1015,6 +1015,48 @@ class DeployHelper
],
],
],
'ctyun' => [
'name' => '天翼云',
'class' => 2,
'icon' => 'ctyun.ico',
'note' => '支持部署到天翼云CDN',
'inputs' => [
'AccessKeyId' => [
'name' => 'AccessKeyId',
'type' => 'input',
'placeholder' => '',
'required' => true,
],
'SecretAccessKey' => [
'name' => 'SecretAccessKey',
'type' => 'input',
'placeholder' => '',
'required' => true,
],
'proxy' => [
'name' => '使用代理服务器',
'type' => 'radio',
'options' => [
'0' => '否',
'1' => '是',
],
'value' => '0'
],
],
'taskinputs' => [
'product' => [
'name' => '产品',
'type' => 'hidden',
'value' => 'cdn',
],
'domain' => [
'name' => 'CDN域名',
'type' => 'input',
'placeholder' => '',
'required' => true,
],
],
],
'allwaf' => [
'name' => 'AllWAF',
'class' => 2,

163
app/lib/client/Ctyun.php Normal file
View File

@ -0,0 +1,163 @@
<?php
namespace app\lib\client;
use Exception;
/**
* 天翼云
*/
class Ctyun
{
private $AccessKeyId;
private $SecretAccessKey;
private $endpoint;
private $proxy = false;
public function __construct($AccessKeyId, $SecretAccessKey, $endpoint, $proxy = false)
{
$this->AccessKeyId = $AccessKeyId;
$this->SecretAccessKey = $SecretAccessKey;
$this->endpoint = $endpoint;
$this->proxy = $proxy;
}
/**
* @param string $method 请求方法
* @param string $path 请求路径
* @param array|null $query 请求参数
* @param array|null $params 请求体
* @return array
* @throws Exception
*/
public function request($method, $path, $query = null, $params = null)
{
if (!empty($query)) {
$query = array_filter($query, function ($a) { return $a !== null;});
}
if (!empty($params)) {
$params = array_filter($params, function ($a) { return $a !== null;});
}
$time = time();
$date = date("Ymd\THis\Z", $time);
$body = !empty($params) ? json_encode($params) : '';
$headers = [
'Host' => $this->endpoint,
'Eop-date' => $date,
'ctyun-eop-request-id' => getSid(),
];
if ($body) {
$headers['Content-Type'] = 'application/json';
}
$authorization = $this->generateSign($query, $headers, $body, $date);
$headers['Eop-Authorization'] = $authorization;
$url = 'https://' . $this->endpoint . $path;
if (!empty($query)) {
$url .= '?' . http_build_query($query);
}
$header = [];
foreach ($headers as $key => $value) {
$header[] = $key . ': ' . $value;
}
return $this->curl($method, $url, $body, $header);
}
private function generateSign($query, $headers, $body, $date)
{
// step 1: build canonical request string
$canonicalQueryString = $this->getCanonicalQueryString($query);
[$canonicalHeaders, $signedHeaders] = $this->getCanonicalHeaders($headers);
$hashedRequestPayload = hash("sha256", $body);
// step 2: build string to sign
$stringToSign = $canonicalHeaders . "\n"
. $canonicalQueryString . "\n"
. $hashedRequestPayload;
// step 3: sign string
$ktime = hash_hmac("sha256", $date, $this->SecretAccessKey, true);
$kAk = hash_hmac("sha256", $this->AccessKeyId, $ktime, true);
$kdate = hash_hmac("sha256", substr($date, 0, 8), $kAk, true);
$signature = hash_hmac("sha256", $stringToSign, $kdate, true);
$signature = base64_encode($signature);
// step 4: build authorization
$authorization = $this->AccessKeyId . " Headers=" . $signedHeaders . " Signature=" . $signature;
return $authorization;
}
private function escape($str)
{
$search = ['+', '*', '%7E'];
$replace = ['%20', '%2A', '~'];
return str_replace($search, $replace, urlencode($str));
}
private function getCanonicalQueryString($parameters)
{
if (empty($parameters)) return '';
ksort($parameters);
$canonicalQueryString = '';
foreach ($parameters as $key => $value) {
$canonicalQueryString .= '&' . $this->escape($key) . '=' . $this->escape($value);
}
return substr($canonicalQueryString, 1);
}
private function getCanonicalHeaders($oldheaders)
{
$headers = array();
foreach ($oldheaders as $key => $value) {
$headers[strtolower($key)] = trim($value);
}
ksort($headers);
$canonicalHeaders = '';
$signedHeaders = '';
foreach ($headers as $key => $value) {
$canonicalHeaders .= $key . ':' . $value . "\n";
$signedHeaders .= $key . ';';
}
$signedHeaders = substr($signedHeaders, 0, -1);
return [$canonicalHeaders, $signedHeaders];
}
private function curl($method, $url, $body, $header)
{
$ch = curl_init($url);
if ($this->proxy) {
curl_set_proxy($ch);
}
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
if (!empty($body)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
$response = curl_exec($ch);
$errno = curl_errno($ch);
if ($errno) {
curl_close($ch);
throw new Exception('Curl error: ' . curl_error($ch));
}
curl_close($ch);
$arr = json_decode($response, true);
if (isset($arr['statusCode']) && $arr['statusCode'] == 100000) {
return isset($arr['returnObj']) ? $arr['returnObj'] : true;
} elseif (isset($arr['errorMessage'])) {
throw new Exception($arr['errorMessage']);
} elseif (isset($arr['message'])) {
throw new Exception($arr['message']);
} else {
throw new Exception('返回数据解析失败');
}
}
}

View File

@ -52,14 +52,33 @@ class allwaf implements DeployInterface
$this->log('获取证书列表成功(total=' . count($list) . ')');
$certInfo = openssl_x509_parse($fullchain, true);
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
foreach ($list as $row) {
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 = [
'sslCertId' => $row['id'],
'isOn' => true,
'name' => $row['name'],
'description' => $row['description'],
'serverName' => $row['serverName'],
'name' => $cert_name,
'description' => $cert_name,
'serverName' => $certInfo['subject']['CN'],
'isCA' => false,
'certData' => base64_encode($fullchain),
'keyData' => base64_encode($privatekey),
@ -68,8 +87,8 @@ class allwaf implements DeployInterface
'dnsNames' => $domains,
'commonNames' => [$certInfo['issuer']['CN']],
];
$this->request('/SSLCertService/updateSSLCert', $params);
$this->log('证书ID:' . $row['id'] . '更新成功!');
$result = $this->request('/SSLCertService/createSSLCert', $params);
$this->log('证书ID:' . $result['sslCertId'] . '添加成功!');
}
}

81
app/lib/deploy/ctyun.php Normal file
View File

@ -0,0 +1,81 @@
<?php
namespace app\lib\deploy;
use app\lib\DeployInterface;
use app\lib\client\Ctyun as CtyunClient;
use Exception;
class ctyun implements DeployInterface
{
private $logger;
private $AccessKeyId;
private $SecretAccessKey;
private $proxy;
private $client;
public function __construct($config)
{
$this->AccessKeyId = $config['AccessKeyId'];
$this->SecretAccessKey = $config['SecretAccessKey'];
$this->proxy = isset($config['proxy']) ? $config['proxy'] == 1 : false;
$this->client = new CtyunClient($this->AccessKeyId, $this->SecretAccessKey, 'ctcdn-global.ctapi.ctyun.cn', $this->proxy);
}
public function check()
{
if (empty($this->AccessKeyId) || empty($this->SecretAccessKey)) throw new Exception('必填参数不能为空');
$this->client->request('GET', '/v1/cert/query-cert-list');
return true;
}
public function deploy($fullchain, $privatekey, $config, &$info)
{
$certInfo = openssl_x509_parse($fullchain, true);
if (!$certInfo) throw new Exception('证书解析失败');
$cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t'];
$param = [
'name' => $cert_name,
'key' => $privatekey,
'certs' => $fullchain,
];
try {
$this->client->request('POST', '/v1/cert/creat-cert', null, $param);
} catch (Exception $e) {
if (strpos($e->getMessage(), '已存在重名的证书') !== false) {
$this->log('已存在重名的证书 cert_name=' . $cert_name);
} else {
throw new Exception('上传证书失败:' . $e->getMessage());
}
}
$this->log('上传证书成功 cert_name=' . $cert_name);
$param = [
'domain' => $config['domain'],
'https_status' => 'on',
'cert_name' => $cert_name,
];
try {
$this->client->request('POST', '/v1/domain/update-domain', null, $param);
} catch (Exception $e) {
if (strpos($e->getMessage(), '请求已提交,请勿重复操作!') === false) {
throw new Exception($e->getMessage());
}
}
$this->log('CDN域名 ' . $config['domain'] . ' 部署证书成功!');
}
public function setLogger($func)
{
$this->logger = $func;
}
private function log($txt)
{
if ($this->logger) {
call_user_func($this->logger, $txt);
}
}
}

View File

@ -50,20 +50,39 @@ class goedge implements DeployInterface
throw new Exception('获取证书列表失败:' . $e->getMessage());
}
$list = json_decode(base64_decode($data['sslCertsJSON']), true);
if (!$list || empty($list)) {
if ($list === false) {
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'];
foreach ($list as $row) {
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 = [
'sslCertId' => $row['id'],
'isOn' => true,
'name' => $row['name'],
'description' => $row['description'],
'serverName' => $row['serverName'],
'name' => $cert_name,
'description' => $cert_name,
'serverName' => $certInfo['subject']['CN'],
'isCA' => false,
'certData' => base64_encode($fullchain),
'keyData' => base64_encode($privatekey),
@ -72,8 +91,8 @@ class goedge implements DeployInterface
'dnsNames' => $domains,
'commonNames' => [$certInfo['issuer']['CN']],
];
$this->request('/SSLCertService/updateSSLCert', $params);
$this->log('证书ID:' . $row['id'] . '更新成功!');
$result = $this->request('/SSLCertService/createSSLCert', $params);
$this->log('证书ID:' . $result['sslCertId'] . '添加成功!');
}
}

View File

@ -40,33 +40,35 @@ class opanel implements DeployInterface
$success = 0;
$errmsg = null;
foreach ($data['items'] as $row) {
if (empty($row['primaryDomain'])) continue;
$cert_domains = [];
$cert_domains[] = $row['primaryDomain'];
if(!empty($row['domains'])) $cert_domains += explode(',', $row['domains']);
$flag = false;
foreach ($cert_domains as $domain) {
if (in_array($domain, $domains)) {
$flag = true;
break;
if (!empty($data['items'])) {
foreach ($data['items'] as $row) {
if (empty($row['primaryDomain'])) continue;
$cert_domains = [];
$cert_domains[] = $row['primaryDomain'];
if(!empty($row['domains'])) $cert_domains += explode(',', $row['domains']);
$flag = false;
foreach ($cert_domains as $domain) {
if (in_array($domain, $domains)) {
$flag = true;
break;
}
}
}
if ($flag) {
$params = [
'sslID' => $row['id'],
'type' => 'paste',
'certificate' => $fullchain,
'privateKey' => $privatekey,
'description' => '',
];
try {
$this->request('/api/v1/websites/ssl/upload', $params);
$this->log("证书ID:{$row['id']}更新成功!");
$success++;
} catch (Exception $e) {
$errmsg = $e->getMessage();
$this->log("证书ID:{$row['id']}更新失败:" . $errmsg);
if ($flag) {
$params = [
'sslID' => $row['id'],
'type' => 'paste',
'certificate' => $fullchain,
'privateKey' => $privatekey,
'description' => '',
];
try {
$this->request('/api/v1/websites/ssl/upload', $params);
$this->log("证书ID:{$row['id']}更新成功!");
$success++;
} catch (Exception $e) {
$errmsg = $e->getMessage();
$this->log("证书ID:{$row['id']}更新失败:" . $errmsg);
}
}
}
}

View File

@ -68,7 +68,15 @@ class safeline implements DeployInterface
}
}
if ($success == 0) {
throw new Exception($errmsg ? $errmsg : '没有要更新的证书');
$params = [
'manual' => [
'crt' => $fullchain,
'key' => $privatekey,
],
'type' => 2,
];
$this->request('/api/open/cert', $params);
$this->log("证书上传成功!");
}
}

View File

@ -229,7 +229,7 @@ class MsgNotice
'content' => $content,
],
];
} elseif (strpos($url, 'open.feishu.cn')) {
} elseif (strpos($url, 'open.feishu.cn') || strpos($url, 'open.larksuite.com')) {
$content = str_replace(['\*', '**'], ['*', ''], strip_tags($content));
$post = [
'msg_type' => 'text',

View File

@ -29,7 +29,16 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
</div>
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
<a href="javascript:searchClear()" class="btn btn-default" title="刷新订单列表"><i class="fa fa-refresh"></i> 刷新</a>
<a href="/cert/order/add" class="btn btn-success"><i class="fa fa-plus"></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>
</form>
<table id="listTable">

View File

@ -0,0 +1,167 @@
{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}

View File

@ -136,7 +136,7 @@
<li><a href="/optimizeip/opiplist"><i class="fa fa-circle-o"></i> 任务管理</a></li>
</ul>
</li>
<li class="treeview {:checkIfActive('certaccount,account_form,certorder,order_form,deployaccount,deploytask,deploy_form,certset,cname')}">
<li class="treeview {:checkIfActive('certaccount,account_form,certorder,order_form,order_import,deployaccount,deploytask,deploy_form,certset,cname')}">
<a href="javascript:;">
<i class="fa fa-expeditedssl fa-fw"></i>
<span>SSL证书</span>

View File

@ -31,7 +31,7 @@ return [
'show_error_msg' => true,
'exception_tmpl' => \think\facade\App::getAppPath() . 'view/exception.tpl',
'version' => '1025',
'version' => '1026',
'dbversion' => '1023'
];

View File

@ -93,6 +93,7 @@ Route::group(function () {
Route::post('/cert/order/data', 'cert/order_data');
Route::post('/cert/order/process', 'cert/order_process');
Route::post('/cert/order/:action', 'cert/order_op');
Route::get('/cert/order/import', 'cert/order_import');
Route::get('/cert/order/:action', 'cert/order_form');
Route::get('/cert/deploytask', 'cert/deploytask');