This commit is contained in:
midoks
2022-11-13 10:09:32 +08:00
parent b2546d71a5
commit 9abe3ec166
3 changed files with 158 additions and 117 deletions
+42
View File
@@ -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)
-103
View File
@@ -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
View File
@@ -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());