diff --git a/class/core/site_api.py b/class/core/site_api.py index 69268a924..94486e60f 100755 --- a/class/core/site_api.py +++ b/class/core/site_api.py @@ -470,11 +470,21 @@ class site_api: stype = -1 toHttps = self.isToHttps(siteName) - id = mw.M('sites').where("name=?", (siteName,)).getField('id') + sid = mw.M('sites').where("name=?", (siteName,)).getField('id') domains = mw.M('domain').where( - "pid=?", (id,)).field('name').select() - data = {'status': status, 'domain': domains, 'key': key, - 'csr': csr, 'type': stype, 'httpTohttps': toHttps} + "pid=?", (sid,)).field('name').select() + + certData = self.getCertName(csrpath) + + data = { + 'status': status, + 'domain': domains, + 'key': key, + 'csr': csr, + 'type': stype, + 'httpTohttps': toHttps, + 'cert_data': certData, + } return mw.returnJson(True, 'OK', data) def setSslApi(self): @@ -804,7 +814,7 @@ class site_api: # print home_cert log_file = mw.getRunDir() + '/logs/acme.log' - mw.writeFile(log_file, '开始ACME申请', "wb+") + mw.writeFile(log_file, "开始ACME申请...\n", "wb+") cmd = 'export ACCOUNT_EMAIL=' + email + ' && ' + \ execStr + ' >> ' + log_file # print(domains) @@ -2434,27 +2444,67 @@ location ^~ {from} { except Exception as e: return mw.returnData(False, '证书保存失败!') + # 转换时间 + def strfDate(self, sdate): + return time.strftime('%Y-%m-%d', time.strptime(sdate, '%Y%m%d%H%M%S')) + # 获取证书名称 def getCertName(self, certPath): + if not os.path.exists(certPath): + return None try: - openssl = '/usr/local/openssl/bin/openssl' - if not os.path.exists(openssl): - openssl = 'openssl' - result = mw.execShell( - openssl + " x509 -in " + certPath + " -noout -subject -enddate -startdate -issuer") - tmp = result[0].split("\n") - data = {} - data['subject'] = tmp[0].split('=')[-1] - data['notAfter'] = self.strfToTime(tmp[1].split('=')[1]) - data['notBefore'] = self.strfToTime(tmp[2].split('=')[1]) - data['issuer'] = tmp[3].split('O=')[-1].split(',')[0] - if data['issuer'].find('/') != -1: - data['issuer'] = data['issuer'].split('/')[0] - result = mw.execShell( - openssl + " x509 -in " + certPath + " -noout -text|grep DNS") - data['dns'] = result[0].replace( - 'DNS:', '').replace(' ', '').strip().split(',') - return data + import OpenSSL + result = {} + x509 = OpenSSL.crypto.load_certificate( + OpenSSL.crypto.FILETYPE_PEM, mw.readFile(certPath)) + # 取产品名称 + issuer = x509.get_issuer() + result['issuer'] = '' + if hasattr(issuer, 'CN'): + result['issuer'] = issuer.CN + if not result['issuer']: + is_key = [b'0', '0'] + issue_comp = issuer.get_components() + if len(issue_comp) == 1: + is_key = [b'CN', 'CN'] + for iss in issue_comp: + if iss[0] in is_key: + result['issuer'] = iss[1].decode() + break + if not result['issuer']: + if hasattr(issuer, 'O'): + result['issuer'] = issuer.O + # 取到期时间 + result['notAfter'] = self.strfDate( + bytes.decode(x509.get_notAfter())[:-1]) + # 取申请时间 + result['notBefore'] = self.strfDate( + bytes.decode(x509.get_notBefore())[:-1]) + # 取可选名称 + result['dns'] = [] + for i in range(x509.get_extension_count()): + s_name = x509.get_extension(i) + if s_name.get_short_name() in [b'subjectAltName', 'subjectAltName']: + s_dns = str(s_name).split(',') + for d in s_dns: + result['dns'].append(d.split(':')[1]) + subject = x509.get_subject().get_components() + # 取主要认证名称 + if len(subject) == 1: + result['subject'] = subject[0][1].decode() + else: + if not result['dns']: + for sub in subject: + if sub[0] == b'CN': + result['subject'] = sub[1].decode() + break + if 'subject' in result: + result['dns'].append(result['subject']) + else: + result['subject'] = result['dns'][0] + result['endtime'] = int(int(time.mktime(time.strptime( + result['notAfter'], "%Y-%m-%d")) - time.time()) / 86400) + return result except: return None diff --git a/route/static/app/site.js b/route/static/app/site.js index 41d0e9e1d..ca1c84e22 100755 --- a/route/static/app/site.js +++ b/route/static/app/site.js @@ -1030,7 +1030,7 @@ function webEdit(id,website,endTime,addtime){ +"

"+lan.site.domain_man+"

" +" "+eMenu+"" +"" - +"
" + +"
" +"", success:function(){ @@ -1134,78 +1134,6 @@ function setSecurity(name,id){ } -//木马扫描 -function CheckSafe(id,act){ - if(act != undefined){ - var loadT = layer.msg(lan.site.the_msg,{icon:16,time:0,shade: [0.3, '#000']}); - $.post('/site?action=CheckSafe','id='+id,function(rdata){ - $(".btnStart").hide() - setTimeout(function(){ - CheckSafe(id); - },3000); - GetTaskCount(); - layer.close(loadT) - layer.msg(rdata.msg,{icon:rdata.status?1:5}); - }); - - return; - } - - $.post('/site?action=GetCheckSafe','id='+id,function(rdata){ - var done = "\ - \ - "+lan.site.scanned+":"+rdata.count+""+lan.site.risk_quantity+":"+rdata.error+""; - - if(rdata['scan']) done = ""+lan.site.scanned+":"+rdata.count+""+lan.site.risk_quantity+":"+rdata.error+""; - var echoHtml = "
" - + done - +"
" - for(var i=0;i"+lan.site.danger+""+lan.site.danger_fun_no+":"+rdata.phpini[i].function+"
"+lan.site.file+":/www/server/php/"+rdata.phpini[i].version+"/etc/php.ini"; - } - - if(!rdata.sshd){ - echoHtml += ""+lan.site.ssh_port+""+lan.site.high_risk+""+lan.site.sshd_tampering+""; - } - - if(!rdata.userini){ - echoHtml += ""+lan.site.xss_attack+""+lan.site.danger+""+lan.site.site_xss_attack+""; - } - - for(var i=0;i"+rdata.data[i].level+"文件:"+rdata.data[i].filename+"
"+lan.site.mod_time+":"+rdata.data[i].etime+"
"+lan.site.code+":"+rdata.data[i].code+""; - } - - var body = "
" - +"
" - +"" - +"" + echoHtml + "" - +"
"+lan.site.behavior+""+lan.site.risk+""+lan.site.details+"
" - - $("#webedit-con").html(body); - $(".btnStart").click(function(){ - fly('btnStart'); - }); - if(rdata['scan']){ - c = $("#site_"+id).attr('class'); - if(c != 'active') return; - setTimeout(function(){ - CheckSafe(id); - },1000); - } - }); -} - -function UpdateRulelist(){ - var loadT = layer.msg(lan.site.to_update,{icon:16,time:0,shade: [0.3, '#000']}); - $.post('/site?action=UpdateRulelist','',function(rdata){ - layer.close(loadT) - layer.msg(rdata.msg,{icon:rdata.status?1:5}); - }); - -} - - //流量限制 function limitNet(id){ $.post('/site/get_limit_net','id='+id, function(rdata){ @@ -1409,15 +1337,6 @@ function delDirBind(id,siteId){ },'json'); }); } - -//开启缓存 -function openCache(siteName){ - var loadT = layer.msg(lan.site.the_msg,{icon:16,time:0,shade: [0.3, '#000']}); - $.post('/site?action=ProxyCache',{siteName:siteName},function(rdata){ - layer.close(loadT); - layer.msg(rdata.msg,{icon:rdata.status?1:2}); - }); -} //301重定向 function to301(siteName, type, obj){ @@ -1890,37 +1809,37 @@ function setSSL(id,siteName){ + '
'; // 关闭\ $("#webedit-con").html(sslHtml); - opSSL('now',id,siteName); $(".tab-nav span").click(function(){ $(this).addClass("on").siblings().removeClass("on"); }); - var loadT = layer.msg(lan.site.the_msg,{icon:16,time:0,shade: [0.3, '#000']}); - $.post('/site/get_ssl','siteName='+siteName,function(rdata){ - layer.close(loadT); - $("#toHttps").attr('checked',rdata.data.httpTohttps); - switch(rdata.data.type){ - case 1: - $(".tab-nav span").eq(1).addClass("on").siblings().removeClass("on"); - setCookie('letssl',1); - var lets = '
密钥(KEY)
' - + '
证书(PEM格式)
' - + '
' - + '
  • 已为您自动生成Let\'s Encrypt免费证书;
  • \ -
  • 如需使用其他SSL,请切换其他证书后粘贴您的KEY以及PEM内容,然后保存即可。
' - $(".tab-con").html(lets); - $(".help-info-text").after("
"); - break; - case 0: - case 3: - $(".tab-nav span").eq(1).addClass("on").siblings().removeClass("on"); - opSSL('other',id,siteName); - break; - case 2: - $(".tab-nav span").eq(0).addClass("on").siblings().removeClass("on"); - opSSL('a',id,siteName); - break; - } - },'json'); + opSSL('now',id,siteName); + // var loadT = layer.msg(lan.site.the_msg,{icon:16,time:0,shade: [0.3, '#000']}); + // $.post('/site/get_ssl',{'siteName':siteName },function(rdata){ + // layer.close(loadT); + // $("#toHttps").attr('checked',rdata.data.httpTohttps); + // switch(rdata.data.type){ + // case 1: + // $(".tab-nav span").eq(1).addClass("on").siblings().removeClass("on"); + // setCookie('letssl',1); + // var lets = '
密钥(KEY)
' + // + '
证书(PEM格式)
' + // + '
' + // + '
  • 已为您自动生成Let\'s Encrypt免费证书;
  • \ + //
  • 如需使用其他SSL,请切换其他证书后粘贴您的KEY以及PEM内容,然后保存即可。
' + // $(".tab-con").html(lets); + // $(".help-info-text").after("
"); + // break; + // case 0: + // case 3: + // $(".tab-nav span").eq(1).addClass("on").siblings().removeClass("on"); + // opSSL('other',id,siteName); + // break; + // case 2: + // $(".tab-nav span").eq(0).addClass("on").siblings().removeClass("on"); + // opSSL('a',id,siteName); + // break; + // } + // },'json'); } @@ -1979,9 +1898,15 @@ function httpToHttps(siteName){ //SSL function opSSL(type, id, siteName, callback){ - var now = '
密钥(KEY)
' - + '
证书(PEM格式)
' - + '
' + var now = '
\ + \ +
\ +
密钥(KEY)
\ +
证书(PEM格式)
\ +
\ +
\ +
\ +
' + '
  • 粘贴您的*.key以及*.pem内容,然后保存即可。
  • \
  • 如果浏览器提示证书链不完整,请检查是否正确拼接PEM证书
  • PEM格式证书 = 域名证书.crt + 根证书(root_bundle).crt
  • \
  • 在未指定SSL默认站点时,未开启SSL的站点使用HTTPS会直接访问到已开启SSL的站点
'; @@ -2147,22 +2072,38 @@ function opSSL(type, id, siteName, callback){ $.post('site/get_ssl','siteName='+siteName,function(data){ layer.close(loadT); var rdata = data['data']; - if (rdata.type == 0){ - setCookie('letssl', 1); - } + + var issuer = rdata['cert_data']['issuer'].split(" "); + var domains = rdata['cert_data']['dns'].join("、"); + + var cert_data = "
\ +
证书品牌:"+issuer[0]+"
\ +
到期时间:剩余"+rdata['cert_data']['endtime']+"天到期
\ +
\ +
\ +
认证域名:"+domains+"
\ +
强制HTTPS:
\ +
"; + $(".ssl_state_info").html(cert_data); + $(".ssl_state_info").css('display','block'); + + + console.log(rdata); if(rdata.status){ + $(".ssl-btn").append(""); } if(rdata.key == false) rdata.key = ''; if(rdata.csr == false) rdata.csr = ''; $("#key").val(rdata.key); $("#csr").val(rdata.csr); + if (typeof (callback) != 'undefined'){ callback(rdata); } },'json'); break; - case 'other': + default: layer.msg("错误类型", {icon:5}); break; } diff --git a/route/static/css/site.css b/route/static/css/site.css index b864d9eca..4c17ca18f 100755 --- a/route/static/css/site.css +++ b/route/static/css/site.css @@ -1497,11 +1497,11 @@ html .menu .menu_exit:hover { position: absolute; top: 0; width: 100%; - z-index: 0 + z-index: 0; } .soft-man .rowbg .col-lg-3 { - cursor: default + cursor: default; } .soft-man .rowbg .col-lg-3:hover { @@ -1540,16 +1540,16 @@ html .menu .menu_exit:hover { } .bw-info ul li { height: 56px; - line-height: 56px + line-height: 56px; } .bw-info ul li.bi-line { - border-bottom: #ddd solid 1px + border-bottom: #ddd solid 1px; } .bw-info ul li span { display: block; - margin-right: 15px + margin-right: 15px; } .btn-zhm { @@ -1557,7 +1557,83 @@ html .menu .menu_exit:hover { display: none; position: absolute; right: 42px; - top: 0 + top: 0; +} + +.ellipsis_text { + width: 220px; + text-overflow: ellipsis; + overflow: hidden; +} + +.ssl_state_info{ + padding: 15px 30px; + background: #f5faf2; + margin-top: 5px; + border-radius: 4px; + border: 1px solid #EAF1F2; + font-size: 12px; + position: relative; +} + +.ssl_state_info .state_item{ + width: 49%; + height: 25px; + line-height: 25px; + display: inline-block; + vertical-align: top; +} + +.ssl_state_info .state_item span{ + height: 25px; + line-height: 25px; + vertical-align: top; +} + + +.ssl_state_info .state_item span:nth-child(1){ + font-weight: bold; + color: #666; +} + + + +.ssl_state_info .state_item .switch{ + display: inline-block; +} + + +.ssl_state_info .state_item .switch-btn{ + margin-bottom: 0; + height: 1.9rem; + width: 3.2rem; + position: relative; + top; +} + +.custom_certificate_info{ + margin-top: 15px; +} + +.custom_certificate_info .state_item{ + width: 48%; + height: 50px; + display: inline-block; + margin-right: 4%; +} +.custom_certificate_info .state_item:nth-child(2){ + margin-right: 0; +} + +.custom_certificate_info .state_item span{ + width:100%; + margin-bottom: 5px; +} + +.custom_certificate_info .state_item textarea{ + width: 100%; + height: 250px; + line-height: 25px; } .line {