mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-10 04:59:25 +08:00
up
This commit is contained in:
@@ -1218,6 +1218,48 @@ fullchain.pem 粘贴到证书输入框
|
||||
except:
|
||||
write_log("|-[{}]续签失败".format(siteName))
|
||||
|
||||
def apply_cert_api(self, args):
|
||||
'''
|
||||
申请证书 - api
|
||||
'''
|
||||
if not 'id' in args:
|
||||
return mw.returnJson(False, '网站id不能为空!')
|
||||
# 是否为指定站点
|
||||
if mw.M('sites').where('id=?', (args.id,)).count():
|
||||
project_info = public.M('sites').where(
|
||||
'id=?', (args.id,)).getField('project_config')
|
||||
try:
|
||||
project_info = json.loads(project_info)
|
||||
if not os.path.exists(project_info['ssl_path']):
|
||||
os.makedirs(project_info['ssl_path'])
|
||||
path = project_info['ssl_path']
|
||||
args.auth_to = path
|
||||
if args.auto_wildcard == '1':
|
||||
self._auto_wildcard = True
|
||||
return self.applyCert(json.loads(args.domains), args.auth_type, args.auth_to)
|
||||
except:
|
||||
return mw.returnJson(False, '当前Java项目配置文件存在问题,请重新建立')
|
||||
else:
|
||||
if re.match(r"^\d+$", args.auth_to):
|
||||
import panelSite
|
||||
path = mw.M('sites').where(
|
||||
'id=?', (args.id,)).getField('path')
|
||||
args.auth_to = path + '/' + panelSite.panelSite().GetRunPath(args)
|
||||
args.auth_to = args.auth_to.replace("//", "/")
|
||||
if args.auth_to[-1] == '/':
|
||||
args.auth_to = args.auth_to[:-1]
|
||||
|
||||
if not os.path.exists(args.auth_to):
|
||||
return mw.returnJson(False, '无效的站点目录,请检查指定站点是否存在!')
|
||||
|
||||
check_result = self.checkAuthEnv(args)
|
||||
if check_result:
|
||||
return check_result
|
||||
|
||||
if args.auto_wildcard == '1':
|
||||
self._auto_wildcard = True
|
||||
return self.apply_cert(json.loads(args.domains), args.auth_type, args.auth_to)
|
||||
|
||||
def renewCert(self, index):
|
||||
writeLog("", "wb+")
|
||||
# self.D('renew_cert', index)
|
||||
|
||||
@@ -652,118 +652,15 @@ class site_api:
|
||||
csrpath = letpath + "/fullchain.pem" # 生成证书路径
|
||||
keypath = letpath + "/privkey.pem" # 密钥文件路径
|
||||
|
||||
actionstr = updateOf
|
||||
siteInfo = mw.M('sites').where(
|
||||
'name=?', (siteName,)).field('id,name,path').find()
|
||||
path = self.getSitePath(siteName)
|
||||
srcPath = siteInfo['path']
|
||||
|
||||
# 检测acem是否安装
|
||||
if mw.isAppleSystem():
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
acem = '/Users/' + user + '/.acme.sh/acme.sh'
|
||||
else:
|
||||
acem = '/root/.acme.sh/acme.sh'
|
||||
if not os.path.exists(acem):
|
||||
acem = '/.acme.sh/acme.sh'
|
||||
if not os.path.exists(acem):
|
||||
try:
|
||||
mw.execShell("curl -sS curl https://get.acme.sh | sh")
|
||||
except:
|
||||
return mw.returnJson(False, '尝试自动安装ACME失败,请通过以下命令尝试手动安装<p>安装命令: curl https://get.acme.sh | sh</p>' + acem)
|
||||
if not os.path.exists(acem):
|
||||
return mw.returnJson(False, '尝试自动安装ACME失败,请通过以下命令尝试手动安装<p>安装命令: curl https://get.acme.sh | sh</p>' + acem)
|
||||
|
||||
# 避免频繁执行
|
||||
checkAcmeRun = mw.execShell('ps -ef|grep acme.sh |grep -v grep')
|
||||
if checkAcmeRun[0] != '':
|
||||
return mw.returnJson(False, '正在申请或更新SSL中...')
|
||||
|
||||
if force == 'true':
|
||||
force_bool = True
|
||||
|
||||
if renew == 'true':
|
||||
execStr = acem + " --renew --yes-I-know-dns-manual-mode-enough-go-ahead-please"
|
||||
else:
|
||||
execStr = acem + " --issue --force"
|
||||
|
||||
# 确定主域名顺序
|
||||
domainsTmp = []
|
||||
if siteName in domains:
|
||||
domainsTmp.append(siteName)
|
||||
for domainTmp in domains:
|
||||
if domainTmp == siteName:
|
||||
continue
|
||||
domainsTmp.append(domainTmp)
|
||||
domains = domainsTmp
|
||||
|
||||
domainCount = 0
|
||||
for domain in domains:
|
||||
if mw.checkIp(domain):
|
||||
continue
|
||||
if domain.find('*.') != -1:
|
||||
return mw.returnJson(False, '泛域名不能使用【文件验证】的方式申请证书!')
|
||||
execStr += ' -w ' + path
|
||||
execStr += ' -d ' + domain
|
||||
domainCount += 1
|
||||
if domainCount == 0:
|
||||
return mw.returnJson(False, '请选择域名(不包括IP地址与泛域名)!')
|
||||
|
||||
home_path = '/root/.acme.sh/' + domains[0]
|
||||
home_cert = home_path + '/fullchain.cer'
|
||||
home_key = home_path + '/' + domains[0] + '.key'
|
||||
|
||||
if not os.path.exists(home_cert):
|
||||
home_path = '/.acme.sh/' + domains[0]
|
||||
home_cert = home_path + '/fullchain.cer'
|
||||
home_key = home_path + '/' + domains[0] + '.key'
|
||||
|
||||
if mw.isAppleSystem():
|
||||
user = mw.execShell(
|
||||
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
|
||||
acem = '/Users/' + user + '/.acme.sh/'
|
||||
if not os.path.exists(home_cert):
|
||||
home_path = acem + domains[0]
|
||||
home_cert = home_path + '/fullchain.cer'
|
||||
home_key = home_path + '/' + domains[0] + '.key'
|
||||
|
||||
# print home_cert
|
||||
cmd = 'export ACCOUNT_EMAIL=' + email + ' && ' + execStr
|
||||
# print(domains)
|
||||
# print(cmd)
|
||||
result = mw.execShell(cmd)
|
||||
|
||||
if not os.path.exists(home_cert.replace("\*", "*")):
|
||||
data = {}
|
||||
data['err'] = result
|
||||
data['out'] = result[0]
|
||||
data['msg'] = '签发失败,我们无法验证您的域名:<p>1、检查域名是否绑定到对应站点</p>\
|
||||
<p>2、检查域名是否正确解析到本服务器,或解析还未完全生效</p>\
|
||||
<p>3、如果您的站点设置了反向代理,或使用了CDN,请先将其关闭</p>\
|
||||
<p>4、如果您的站点设置了301重定向,请先将其关闭</p>\
|
||||
<p>5、如果以上检查都确认没有问题,请尝试更换DNS服务商</p>'
|
||||
data['result'] = {}
|
||||
if result[1].find('new-authz error:') != -1:
|
||||
data['result'] = json.loads(
|
||||
re.search("{.+}", result[1]).group())
|
||||
if data['result']['status'] == 429:
|
||||
data['msg'] = '签发失败,您尝试申请证书的失败次数已达上限!<p>1、检查域名是否绑定到对应站点</p>\
|
||||
<p>2、检查域名是否正确解析到本服务器,或解析还未完全生效</p>\
|
||||
<p>3、如果您的站点设置了反向代理,或使用了CDN,请先将其关闭</p>\
|
||||
<p>4、如果您的站点设置了301重定向,请先将其关闭</p>\
|
||||
<p>5、如果以上检查都确认没有问题,请尝试更换DNS服务商</p>'
|
||||
data['status'] = False
|
||||
return mw.getJson(data)
|
||||
|
||||
if not os.path.exists(letpath):
|
||||
mw.execShell("mkdir -p " + letpath)
|
||||
mw.execShell("ln -sf \"" + home_cert + "\" \"" + csrpath + '"')
|
||||
mw.execShell("ln -sf \"" + home_key + "\" \"" + keypath + '"')
|
||||
mw.execShell('echo "let" > "' + letpath + '/README"')
|
||||
if(actionstr == '2'):
|
||||
return mw.returnJson(True, '证书已更新!')
|
||||
|
||||
# 写入配置文件
|
||||
result = self.setSslConf(siteName)
|
||||
if not result['status']:
|
||||
|
||||
+116
-14
@@ -1974,7 +1974,14 @@ function httpToHttps(siteName){
|
||||
|
||||
|
||||
//SSL
|
||||
function opSSL(type,id,siteName){
|
||||
function opSSL(type, id, siteName, callback){
|
||||
|
||||
var now = '<div class="myKeyCon ptb15"><div class="ssl-con-key pull-left mr20">密钥(KEY)<br><textarea id="key" class="bt-input-text"></textarea></div>'
|
||||
+ '<div class="ssl-con-key pull-left">证书(PEM格式)<br><textarea id="csr" class="bt-input-text"></textarea></div>'
|
||||
+ '<div class="ssl-btn pull-left mtb15" style="width:100%"><button class="btn btn-success btn-sm" onclick="saveSSL(\''+siteName+'\')">保存</button></div></div>'
|
||||
+ '<ul class="help-info-text c7 pull-left"><li>粘贴您的*.key以及*.pem内容,然后保存即可。</li>\
|
||||
<li>如果浏览器提示证书链不完整,请检查是否正确拼接PEM证书</li><li>PEM格式证书 = 域名证书.crt + 根证书(root_bundle).crt</li>\
|
||||
<li>在未指定SSL默认站点时,未开启SSL的站点使用HTTPS会直接访问到已开启SSL的站点</li></ul>';
|
||||
|
||||
var lets = '<div class="btssl"><div class="label-input-group">'
|
||||
+ '<div class="line mtb10"><form><span class="tname text-center">验证方式</span><div style="margin-top:7px;display:inline-block"><input type="radio" name="c_type" onclick="file_check()" id="check_file" checked="checked" />\
|
||||
@@ -1988,20 +1995,21 @@ function opSSL(type,id,siteName){
|
||||
<li>若您的站点使用了CDN或301重定向会导致续签失败</li>\
|
||||
<li>在未指定SSL默认站点时,未开启SSL的站点使用HTTPS会直接访问到已开启SSL的站点</li></ul>'
|
||||
+ '</div>';
|
||||
|
||||
var other = '<div class="myKeyCon ptb15"><div class="ssl-con-key pull-left mr20">密钥(KEY)<br><textarea id="key" class="bt-input-text"></textarea></div>'
|
||||
+ '<div class="ssl-con-key pull-left">证书(PEM格式)<br><textarea id="csr" class="bt-input-text"></textarea></div>'
|
||||
+ '<div class="ssl-btn pull-left mtb15" style="width:100%"><button class="btn btn-success btn-sm" onclick="saveSSL(\''+siteName+'\')">保存</button></div></div>'
|
||||
+ '<ul class="help-info-text c7 pull-left"><li>粘贴您的*.key以及*.pem内容,然后保存即可。</li>\
|
||||
<li>如果浏览器提示证书链不完整,请检查是否正确拼接PEM证书</li><li>PEM格式证书 = 域名证书.crt + 根证书(root_bundle).crt</li>\
|
||||
<li>在未指定SSL默认站点时,未开启SSL的站点使用HTTPS会直接访问到已开启SSL的站点</li></ul>';
|
||||
|
||||
var now = '<div class="myKeyCon ptb15"><div class="ssl-con-key pull-left mr20">密钥(KEY)<br><textarea id="key" class="bt-input-text"></textarea></div>'
|
||||
+ '<div class="ssl-con-key pull-left">证书(PEM格式)<br><textarea id="csr" class="bt-input-text"></textarea></div>'
|
||||
+ '<div class="ssl-btn pull-left mtb15" style="width:100%"><button class="btn btn-success btn-sm" onclick="saveSSL(\''+siteName+'\')">保存</button></div></div>'
|
||||
+ '<ul class="help-info-text c7 pull-left"><li>粘贴您的*.key以及*.pem内容,然后保存即可。</li>\
|
||||
<li>如果浏览器提示证书链不完整,请检查是否正确拼接PEM证书</li><li>PEM格式证书 = 域名证书.crt + 根证书(root_bundle).crt</li>\
|
||||
<li>在未指定SSL默认站点时,未开启SSL的站点使用HTTPS会直接访问到已开启SSL的站点</li></ul>';
|
||||
var acme = '<div class="btssl"><div class="label-input-group">'
|
||||
+ '<div class="line mtb10"><form><span class="tname text-center">验证方式</span><div style="margin-top:7px;display:inline-block"><input type="radio" name="c_type" onclick="file_check()" id="check_file" checked="checked" />\
|
||||
<label class="mr20" for="check_file" style="font-weight:normal">文件验证</label></label></div></form></div>'
|
||||
+ '<div class="check_message line"><div style="margin-left:100px"><input type="checkbox" name="checkDomain" id="checkDomain" checked=""><label class="mr20" for="checkDomain" style="font-weight:normal">提前校验域名(提前发现问题,减少失败率)</label></div></div>'
|
||||
+ '</div><div class="line mtb10"><span class="tname text-center">管理员邮箱</span><input class="bt-input-text" style="width:240px;" type="text" name="admin_email" /></div>'
|
||||
+ '<div class="line mtb10"><span class="tname text-center">域名</span><ul id="ymlist" style="padding: 5px 10px;max-height:180px;overflow:auto; width:240px;border:#ccc 1px solid;border-radius:3px"></ul></div>'
|
||||
+ '<div class="line mtb10" style="margin-left:100px"><button class="btn btn-success btn-sm letsApply">申请</button></div>'
|
||||
+ '<ul class="help-info-text c7" id="lets_help"><li>申请之前,请确保域名已解析,如未解析会导致审核失败</li>\
|
||||
<li>Let\'s Encrypt免费证书,有效期3个月,支持多域名。默认会自动续签</li>\
|
||||
<li>若您的站点使用了CDN或301重定向会导致续签失败</li>\
|
||||
<li>在未指定SSL默认站点时,未开启SSL的站点使用HTTPS会直接访问到已开启SSL的站点</li></ul>'
|
||||
+ '</div>';
|
||||
|
||||
|
||||
switch(type){
|
||||
case 'lets':
|
||||
if(getCookie('letssl') == 1){
|
||||
@@ -2059,7 +2067,73 @@ function opSSL(type,id,siteName){
|
||||
domains = JSON.stringify(str);
|
||||
newSSL(siteName,domains);
|
||||
|
||||
});
|
||||
|
||||
if (typeof (callback) != 'undefined'){
|
||||
callback(rdata);
|
||||
}
|
||||
},'json');
|
||||
break;
|
||||
case 'acme':
|
||||
if(getCookie('letssl') == 1){
|
||||
$.post('/site/get_ssl','siteName='+siteName,function(data){
|
||||
var rdata = data['data'];
|
||||
if(rdata.csr === false){
|
||||
setCookie('letssl',0);
|
||||
opSSL(type,id,siteName);
|
||||
return;
|
||||
}
|
||||
var lets = '<div class="myKeyCon ptb15"><div class="ssl-con-key pull-left mr20">密钥(KEY)<br><textarea id="key" class="bt-input-text" readonly="" style="background-color:#f6f6f6">'+rdata.key+'</textarea></div>'
|
||||
+ '<div class="ssl-con-key pull-left">证书(PEM格式)<br><textarea id="csr" class="bt-input-text" readonly="" style="background-color:#f6f6f6">'+rdata.csr+'</textarea></div>'
|
||||
+ '</div>'
|
||||
+ '<ul class="help-info-text c7 pull-left"><li>已为您自动生成Let\'s Encrypt免费证书</li>\
|
||||
<li>如需使用其他SSL,请切换其他证书后粘贴您的KEY以及PEM内容,然后保存即可。</li></ul>';
|
||||
$(".tab-con").html(lets);
|
||||
$(".help-info-text").after("<div class='line mtb15'><button class='btn btn-default btn-sm' onclick=\"ocSSL('close_ssl_conf','"+siteName+"')\" style='margin-left:10px'>关闭SSL</button></div>");
|
||||
},'json');
|
||||
return;
|
||||
}
|
||||
$(".tab-con").html(lets);
|
||||
var opt='';
|
||||
$.post('/site/get_site_domains',{id:id}, function(rdata) {
|
||||
var data = rdata['data'];
|
||||
for(var i=0;i<data.domains.length;i++){
|
||||
var isIP = isValidIP(data.domains[i].name);
|
||||
var x = isContains(data.domains[i].name, '*');
|
||||
if(!isIP && !x){
|
||||
opt+='<li style="line-height:26px"><input type="checkbox" style="margin-right:5px; vertical-align:-2px" value="'+data.domains[i].name+'">'+data.domains[i].name+'</li>'
|
||||
}
|
||||
}
|
||||
$("input[name='admin_email']").val(data.email);
|
||||
$("#ymlist").html(opt);
|
||||
$("#ymlist li input").click(function(e){
|
||||
e.stopPropagation();
|
||||
})
|
||||
$("#ymlist li").click(function(){
|
||||
var o = $(this).find("input");
|
||||
if(o.prop("checked")){
|
||||
o.prop("checked",false)
|
||||
}
|
||||
else{
|
||||
o.prop("checked",true);
|
||||
}
|
||||
})
|
||||
$(".letsApply").click(function(){
|
||||
var c = $("#ymlist input[type='checkbox']");
|
||||
var str = [];
|
||||
var domains = '';
|
||||
for(var i=0; i<c.length; i++){
|
||||
if(c[i].checked){
|
||||
str.push(c[i].value);
|
||||
}
|
||||
}
|
||||
domains = JSON.stringify(str);
|
||||
newAcmeSSL(siteName,domains);
|
||||
});
|
||||
|
||||
if (typeof (callback) != 'undefined'){
|
||||
callback(rdata);
|
||||
}
|
||||
},'json');
|
||||
break;
|
||||
case 'now':
|
||||
@@ -2080,6 +2154,9 @@ function opSSL(type,id,siteName){
|
||||
if(rdata.csr == false) rdata.csr = '';
|
||||
$("#key").val(rdata.key);
|
||||
$("#csr").val(rdata.csr);
|
||||
if (typeof (callback) != 'undefined'){
|
||||
callback(rdata);
|
||||
}
|
||||
},'json');
|
||||
break;
|
||||
case 'other':
|
||||
@@ -2176,6 +2253,31 @@ function newSSL(siteName,domains){
|
||||
},'json');
|
||||
}
|
||||
|
||||
function newAcmeSSL(siteName,domains){
|
||||
var loadT = layer.msg('正在校验域名,请稍后...',{icon:16,time:0,shade: [0.3, '#000']});
|
||||
var force = '';
|
||||
if($("#checkDomain").prop("checked")) force = '&force=true';
|
||||
var email = $("input[name='admin_email']").val();
|
||||
$.post('/site/create_acme','siteName='+siteName+'&domains='+domains+'&updateOf=1&email='+email + force,function(rdata){
|
||||
layer.close(loadT);
|
||||
if(rdata.status){
|
||||
var mykeyhtml = '<div class="myKeyCon ptb15"><div class="ssl-con-key pull-left mr20">密钥(KEY)<br><textarea id="key" class="bt-input-text" readonly="" style="background-color:#f6f6f6">'+rdata.data.key+'</textarea></div>'
|
||||
+ '<div class="ssl-con-key pull-left">证书(PEM格式)<br><textarea id="csr" class="bt-input-text" readonly="" style="background-color:#f6f6f6">'+rdata.data.csr+'</textarea></div>'
|
||||
+ '</div>'
|
||||
+ '<ul class="help-info-text c7 pull-left"><li>已为您自动生成Let\'s Encrypt免费证书;</li>\
|
||||
<li>如需使用其他SSL,请切换其他证书后粘贴您的KEY以及PEM内容,然后保存即可。</li></ul>';
|
||||
$(".btssl").html(mykeyhtml);
|
||||
layer.msg(rdata.data.msg,{icon:rdata.status?1:2});
|
||||
setCookie('letssl',1);
|
||||
return;
|
||||
}
|
||||
|
||||
setCookie('letssl',0);
|
||||
layer.msg(rdata.msg,{icon:2,area:'500px',time:0,shade:0.3,shadeClose:true});
|
||||
|
||||
},'json');
|
||||
}
|
||||
|
||||
//保存SSL
|
||||
function saveSSL(siteName){
|
||||
var data = 'type=1&siteName='+siteName+'&key='+encodeURIComponent($("#key").val())+'&csr='+encodeURIComponent($("#csr").val());
|
||||
|
||||
Reference in New Issue
Block a user