支持添加的子级域名申请SSL

This commit is contained in:
net909 2025-04-26 20:19:28 +08:00
parent 1723761b94
commit 76e9adb405
9 changed files with 33 additions and 336 deletions

View File

@ -1,6 +1,7 @@
<?php <?php
// 应用公共文件 // 应用公共文件
use think\facade\Db; use think\facade\Db;
use think\facade\Config;
use think\facade\Request; use think\facade\Request;
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, $header = 0, $ua = 0, $nobody = 0, $addheader = 0)
@ -294,6 +295,16 @@ function convert_second($s)
function getMainDomain($host) function getMainDomain($host)
{ {
if (filter_var($host, FILTER_VALIDATE_IP)) return $host; if (filter_var($host, FILTER_VALIDATE_IP)) return $host;
$domains = config('temp.domains');
if (!$domains) {
$domains = Db::name('domain')->column('name');
config(['domains'=>$domains], 'temp');
}
foreach ($domains as $domain) {
if (str_ends_with($host, $domain)) {
return $domain;
}
}
$domain_root = file_get_contents(app()->getBasePath() . 'data' . DIRECTORY_SEPARATOR . 'domain_root.txt'); $domain_root = file_get_contents(app()->getBasePath() . 'data' . DIRECTORY_SEPARATOR . 'domain_root.txt');
$domain_root = explode("\r\n", $domain_root); $domain_root = explode("\r\n", $domain_root);
$data = explode('.', $host); $data = explode('.', $host);

View File

@ -483,7 +483,6 @@ class Cert extends BaseController
foreach($domains as $domain){ foreach($domains as $domain){
if (!$wildcard && strpos($domain, '*') !== false) return ['code' => -1, 'msg' => '该证书账户类型不支持泛域名']; if (!$wildcard && strpos($domain, '*') !== false) return ['code' => -1, 'msg' => '该证书账户类型不支持泛域名'];
if (preg_match('/[\x{4e00}-\x{9fa5}]/u', $domain) && !function_exists('idn_to_ascii')) return ['code' => -1, 'msg' => '域名包含中文请开启intl扩展'];
$mainDomain = getMainDomain($domain); $mainDomain = getMainDomain($domain);
$drow = Db::name('domain')->where('name', $mainDomain)->find(); $drow = Db::name('domain')->where('name', $mainDomain)->find();
if (!$drow) { if (!$drow) {

View File

@ -449,7 +449,7 @@ class Domain extends BaseController
if (!checkPermission(0, $drow['name'])) return json(['code' => -1, 'msg' => '无权限']); if (!checkPermission(0, $drow['name'])) return json(['code' => -1, 'msg' => '无权限']);
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
$domainRecords = $dns->getSubDomainRecords($rr, 1, 99); $domainRecords = $dns->getSubDomainRecords($rr, 1, 100);
if (!$domainRecords) return json(['code' => -1, 'msg' => '获取记录列表失败,' . $dns->getError()]); if (!$domainRecords) return json(['code' => -1, 'msg' => '获取记录列表失败,' . $dns->getError()]);
list($recordLine, $minTTL) = $this->get_line_and_ttl($drow); list($recordLine, $minTTL) = $this->get_line_and_ttl($drow);
@ -846,7 +846,7 @@ class Domain extends BaseController
$line = DnsHelper::$line_name[$dnstype]['DEF']; $line = DnsHelper::$line_name[$dnstype]['DEF'];
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
$domainRecords = $dns->getSubDomainRecords($name, 1, 99); $domainRecords = $dns->getSubDomainRecords($name, 1, 100);
if (!$domainRecords) return json(['code' => -1, 'msg' => '获取记录列表失败,' . $dns->getError()]); if (!$domainRecords) return json(['code' => -1, 'msg' => '获取记录列表失败,' . $dns->getError()]);
if (empty($domainRecords['list'])) return json(['code' => -1, 'msg' => '没有可修改的记录']); if (empty($domainRecords['list'])) return json(['code' => -1, 'msg' => '没有可修改的记录']);

View File

@ -190,6 +190,7 @@ class aliyun implements DeployInterface
$cert_id = null; $cert_id = null;
$cert_name = null; $cert_name = null;
$casid = null;
foreach ($data['Result'] as $cert) { foreach ($data['Result'] as $cert) {
$domains = explode(',', $cert['SAN']); $domains = explode(',', $cert['SAN']);
$flag = true; $flag = true;
@ -202,6 +203,7 @@ class aliyun implements DeployInterface
if ($flag) { if ($flag) {
$cert_id = $cert['Id']; $cert_id = $cert['Id'];
$cert_name = $cert['CommonName']; $cert_name = $cert['CommonName'];
$casid = $cert['CasId'];
break; break;
} }
} }
@ -215,6 +217,10 @@ class aliyun implements DeployInterface
if ($cert_id) { if ($cert_id) {
$param['Update'] = 'true'; $param['Update'] = 'true';
$param['Id'] = $cert_id; $param['Id'] = $cert_id;
if ($casid == $cas_id) {
$this->log('ESA站点 ' . $sitename . ' 证书已配置,无需重复操作');
return;
}
} }
$client->request($param); $client->request($param);
if ($cert_id) { if ($cert_id) {

View File

@ -68,6 +68,7 @@ class jdcloud implements DnsInterface
//获取解析记录列表 //获取解析记录列表
public function getDomainRecords($PageNumber = 1, $PageSize = 20, $KeyWord = null, $SubDomain = null, $Value = null, $Type = null, $Line = null, $Status = null) public function getDomainRecords($PageNumber = 1, $PageSize = 20, $KeyWord = null, $SubDomain = null, $Value = null, $Type = null, $Line = null, $Status = null)
{ {
if ($PageSize > 99) $PageSize = 99;
$query = ['pageNumber' => $PageNumber, 'pageSize' => $PageSize]; $query = ['pageNumber' => $PageNumber, 'pageSize' => $PageSize];
if (!isNullOrEmpty($SubDomain)) { if (!isNullOrEmpty($SubDomain)) {
$SubDomain = strtolower($SubDomain); $SubDomain = strtolower($SubDomain);

View File

@ -1,222 +0,0 @@
{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">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">邮件通知</label>
<div class="col-sm-9"><select class="form-control" name="notice_mail" default="{:config_get('notice_mail')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">微信公众号通知</label>
<div class="col-sm-9"><select class="form-control" name="notice_wxtpl" default="{:config_get('notice_wxtpl')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Telegram机器人通知</label>
<div class="col-sm-9"><select class="form-control" name="notice_tgbot" default="{:config_get('notice_tgbot')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/></div>
</div>
</form>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">发信邮箱设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">发信模式</label>
<div class="col-sm-9"><select class="form-control" name="mail_type" default="{:config_get('mail_type')}"><option value="0">SMTP发信</option><option value="1">搜狐Sendcloud</option><option value="2">阿里云邮件推送</option></select></div>
</div>
<div id="frame_set1">
<div class="form-group">
<label class="col-sm-3 control-label">SMTP服务器</label>
<div class="col-sm-9"><input type="text" name="mail_smtp" value="{:config_get('mail_smtp')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">SMTP端口</label>
<div class="col-sm-9"><input type="text" name="mail_port" value="{:config_get('mail_port')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">邮箱账号</label>
<div class="col-sm-9"><input type="text" name="mail_name" value="{:config_get('mail_name')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">邮箱密码</label>
<div class="col-sm-9"><input type="text" name="mail_pwd" value="{:config_get('mail_pwd')}" class="form-control"/></div>
</div>
</div>
<div id="frame_set2">
<div class="form-group">
<label class="col-sm-3 control-label">API_USER</label>
<div class="col-sm-9"><input type="text" name="mail_apiuser" value="{:config_get('mail_apiuser')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">API_KEY</label>
<div class="col-sm-9"><input type="text" name="mail_apikey" value="{:config_get('mail_apikey')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">发信邮箱</label>
<div class="col-sm-9"><input type="text" name="mail_name2" value="{:config_get('mail_name')}" class="form-control"/></div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">收信邮箱</label>
<div class="col-sm-9"><input type="text" name="mail_recv" value="{:config_get('mail_recv')}" class="form-control" placeholder="不填默认为发信邮箱"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
<a href="javascript:mailtest()" class="btn btn-default btn-block">发送测试邮件</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<span class="glyphicon glyphicon-info-sign"></span>
使用普通模式发信时建议使用QQ邮箱SMTP服务器smtp.qq.com端口465或587密码是QQ邮箱设置界面生成的<a href="https://service.mail.qq.com/detail/0/75" target="_blank" rel="noreferrer">授权码</a><br/>阿里云邮件推送:<a href="https://www.aliyun.com/product/directmail" target="_blank" rel="noreferrer">点此进入</a><a href="https://usercenter.console.aliyun.com/#/manage/ak" target="_blank" rel="noreferrer">获取AK/SK</a>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">微信公众号消息接口设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">appToken</label>
<div class="col-sm-9"><input type="text" name="wechat_apptoken" value="{:config_get('wechat_apptoken')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">用户UID</label>
<div class="col-sm-9"><input type="text" name="wechat_appuid" value="{:config_get('wechat_appuid')}" class="form-control"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/></div>
</div>
</form>
</div>
<div class="panel-footer">
<b>WxPusher</b><a href="https://wxpusher.zjiecode.com/admin/" target="_blank" rel="noopener noreferrer">点此进入</a> ,注册并且创建应用 -> 将appToken填写到上方输入框 -> 扫码关注应用 -> 在用户列表查看自己的UID填写到上方输入框<br/>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">Telegram机器人接口设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">Token</label>
<div class="col-sm-9"><input type="text" name="tgbot_token" value="{:config_get('tgbot_token')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Chat Id</label>
<div class="col-sm-9"><input type="text" name="tgbot_chatid" value="{:config_get('tgbot_chatid')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">使用代理服务器</label>
<div class="col-sm-9"><select class="form-control" name="tgbot_proxy" default="{:config_get('tgbot_proxy')}"><option value="0"></option><option value="1"></option></select></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
<a href="javascript:tgbottest()" class="btn btn-default btn-block">发送测试消息</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<a href="https://t.me/BotFather" target="_blank" rel="noopener noreferrer">@BotFather</a>对话,使用/newbot命令创建一个新的机器人根据提示输入机器人的名称和用户名可得到Token或使用/mybots命令查看已创建的机器人<a href="https://t.me/getmyid_bot" target="_blank" rel="noopener noreferrer">@getmyid_bot</a>对话可得到Chat Id<br/>
</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);
}
$("select[name='mail_type']").change(function(){
if($(this).val() == 0){
$("#frame_set1").show();
$("#frame_set2").hide();
}else{
$("#frame_set1").hide();
$("#frame_set2").show();
}
});
$("select[name='mail_type']").change();
function saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '',
data : $(obj).serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert('设置保存成功!<br/>重启检测进程或容器后生效', {
icon: 1,
closeBtn: false
}, function(){
window.location.reload()
});
}else{
layer.alert(data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
return false;
}
function mailtest(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'GET',
url : '/dmonitor/mailtest',
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1});
}else{
layer.alert(data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
function tgbottest(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'GET',
url : '/dmonitor/tgbottest',
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1});
}else{
layer.alert(data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
</script>
{/block}

View File

@ -1,110 +0,0 @@
{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">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">代理IP</label>
<div class="col-sm-9"><input type="text" name="proxy_server" value="{:config_get('proxy_server')}" class="form-control"/></div>
</div><br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理端口</label>
<div class="col-sm-9"><input type="text" name="proxy_port" value="{:config_get('proxy_port')}" class="form-control"/></div>
</div><br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理账号</label>
<div class="col-sm-9"><input type="text" name="proxy_user" value="{:config_get('proxy_user')}" class="form-control" placeholder="没有请留空"/></div>
</div><br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理密码</label>
<div class="col-sm-9"><input type="text" name="proxy_pwd" value="{:config_get('proxy_pwd')}" class="form-control" placeholder="没有请留空"/></div>
</div><br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理协议</label>
<div class="col-sm-9"><select class="form-control" name="proxy_type" default="{:config_get('proxy_type')}">
<option value="http">HTTP</option>
<option value="https">HTTPS</option>
<option value="sock4">SOCK4</option>
<option value="sock5">SOCK5</option>
</select></div>
</div><br/>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/><br/>
<a href="javascript:proxytest()" class="btn btn-default btn-block">测试连通性</a></div>
</div>
</form>
</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 saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '',
data : $(obj).serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert('设置保存成功!', {
icon: 1,
closeBtn: false
}, function(){
window.location.reload()
});
}else{
layer.alert(data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
return false;
}
function proxytest(){
var proxy_server = $("input[name='proxy_server']").val();
var proxy_port = $("input[name='proxy_port']").val();
var proxy_user = $("input[name='proxy_user']").val();
var proxy_pwd = $("input[name='proxy_pwd']").val();
var proxy_type = $("select[name='proxy_type']").val();
if(proxy_server=='' || proxy_port==''){
layer.alert('代理服务器和端口不能为空!');
return false;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/dmonitor/proxytest',
data : {proxy_server:proxy_server, proxy_port:proxy_port, proxy_user:proxy_user, proxy_pwd:proxy_pwd, proxy_type:proxy_type},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert('连通性测试成功!', {icon: 1})
}else{
layer.alert('连通性测试失败:'+data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
</script>
{/block}

View File

@ -183,6 +183,11 @@ $(document).ready(function(){
$('#certdeploy_status_0').html(data.certdeploy_status_0); $('#certdeploy_status_0').html(data.certdeploy_status_0);
$('#certdeploy_status_1').html(data.certdeploy_status_1); $('#certdeploy_status_1').html(data.certdeploy_status_1);
$('#certdeploy_status_2').html(data.certdeploy_status_2); $('#certdeploy_status_2').html(data.certdeploy_status_2);
$('.badge').each(function() {
if ($(this).text().trim() === '0') {
$(this).css('opacity', '0.4');
}
});
$.ajax({ $.ajax({
url: '{$checkupdate}', url: '{$checkupdate}',
type: 'get', type: 'get',

View File

@ -38,10 +38,17 @@
"ext-pdo": "*", "ext-pdo": "*",
"ext-gd": "*", "ext-gd": "*",
"ext-curl": "*", "ext-curl": "*",
"ext-openssl": "*",
"ext-sockets": "*",
"ext-mbstring": "*",
"ext-ssh2": "*",
"ext-ftp": "*",
"topthink/framework": "^6.0.0", "topthink/framework": "^6.0.0",
"topthink/think-orm": "^2.0", "topthink/think-orm": "^2.0",
"topthink/think-view": "^1.0", "topthink/think-view": "^1.0",
"cccyun/think-captcha": "^3.0" "cccyun/think-captcha": "^3.0",
"symfony/polyfill-intl-idn": "^1.31",
"symfony/polyfill-php80": "^1.31"
}, },
"require-dev": { "require-dev": {
"symfony/var-dumper": "^4.2", "symfony/var-dumper": "^4.2",