From 3b459e0349566061d8fe1dc27f494dbe9da28b06 Mon Sep 17 00:00:00 2001 From: midoks Date: Tue, 6 Dec 2022 17:35:23 +0800 Subject: [PATCH] =?UTF-8?q?panel=20ssl=20=E6=B5=8B=E8=AF=95=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + class/core/config_api.py | 39 +++--------- class/core/mw.py | 94 +++++++++++++++++++++++++++++ class/core/site_api.py | 69 +-------------------- data/tpl/nginx_panel.conf | 28 +++++++++ route/static/app/config.js | 34 +++++++++-- route/templates/default/config.html | 6 +- 7 files changed, 165 insertions(+), 106 deletions(-) create mode 100755 data/tpl/nginx_panel.conf diff --git a/.gitignore b/.gitignore index cc7321583..e9b75d3a5 100644 --- a/.gitignore +++ b/.gitignore @@ -106,6 +106,7 @@ venv.bak/ .idea/*.iml tmp/* *.swp +*.pem *.zip logs/* data/*.db diff --git a/class/core/config_api.py b/class/core/config_api.py index 4872067d3..7b077dbb4 100755 --- a/class/core/config_api.py +++ b/class/core/config_api.py @@ -354,9 +354,14 @@ class config_api: # 获取面板证书 def getPanelSslApi(self): cert = {} + + if not os.path.exists('ssl/certificate.pem'): + mw.createSSL() + cert['privateKey'] = mw.readFile('ssl/privateKey.pem') cert['certPem'] = mw.readFile('ssl/certificate.pem') cert['rep'] = os.path.exists('ssl/input.pl') + cert['info'] = mw.getCertName('ssl/certificate.pem') return mw.getJson(cert) # 保存面板证书 @@ -385,11 +390,11 @@ class config_api: os.system('rm -f ' + sslConf) return mw.returnJson(True, 'SSL已关闭,请使用http协议访问面板!') else: - os.system('pip install cffi==1.10') - os.system('pip install cryptography==2.1') - os.system('pip install pyOpenSSL==16.2') + # os.system('pip install cffi==1.10') + # os.system('pip install cryptography==2.1') + # os.system('pip install pyOpenSSL==16.2') try: - if not self.createSSL(): + if not mw.createSSL(): return mw.returnJson(False, '开启失败,无法自动安装pyOpenSSL组件!

请尝试手动安装: pip install pyOpenSSL

') mw.writeFile(sslConf, 'True') except Exception as ex: @@ -401,32 +406,6 @@ class config_api: return mw.getJson(data) ##### ----- end ----- ### - # 自签证书 - def createSSL(self): - if os.path.exists('ssl/input.pl'): - return True - import OpenSSL - key = OpenSSL.crypto.PKey() - key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) - cert = OpenSSL.crypto.X509() - cert.set_serial_number(0) - cert.get_subject().CN = mw.getLocalIp() - cert.set_issuer(cert.get_subject()) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(86400 * 3650) - cert.set_pubkey(key) - cert.sign(key, 'md5') - cert_ca = OpenSSL.crypto.dump_certificate( - OpenSSL.crypto.FILETYPE_PEM, cert) - private_key = OpenSSL.crypto.dump_privatekey( - OpenSSL.crypto.FILETYPE_PEM, key) - if len(cert_ca) > 100 and len(private_key) > 100: - mw.writeFile('ssl/certificate.pem', cert_ca) - mw.writeFile('ssl/privateKey.pem', private_key) - print(cert_ca, private_key) - return True - return False - # 获取临时登录列表 def getTempLoginApi(self): if 'tmp_login_expire' in session: diff --git a/class/core/mw.py b/class/core/mw.py index b88eb7b22..35e0fde47 100755 --- a/class/core/mw.py +++ b/class/core/mw.py @@ -1282,6 +1282,100 @@ def get_string_arr(t): t_arr.append(str(i) + str(j)) return t_arr + # 转换时间 + + +def strfDate(sdate): + return time.strftime('%Y-%m-%d', time.strptime(sdate, '%Y%m%d%H%M%S')) + + +# 获取证书名称 +def getCertName(certPath): + if not os.path.exists(certPath): + return None + try: + import OpenSSL + result = {} + x509 = OpenSSL.crypto.load_certificate( + OpenSSL.crypto.FILETYPE_PEM, 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'] = strfDate( + bytes.decode(x509.get_notAfter())[:-1]) + # 取申请时间 + result['notBefore'] = 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 Exception as e: + # print(getTracebackInfo()) + return None + + +def createSSL(): + # 自签证书 + if os.path.exists('ssl/input.pl'): + return True + import OpenSSL + key = OpenSSL.crypto.PKey() + key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) + cert = OpenSSL.crypto.X509() + cert.set_serial_number(0) + cert.get_subject().CN = getLocalIp() + cert.set_issuer(cert.get_subject()) + cert.gmtime_adj_notBefore(0) + cert.gmtime_adj_notAfter(86400 * 3650) + cert.set_pubkey(key) + cert.sign(key, 'md5') + cert_ca = OpenSSL.crypto.dump_certificate( + OpenSSL.crypto.FILETYPE_PEM, cert) + private_key = OpenSSL.crypto.dump_privatekey( + OpenSSL.crypto.FILETYPE_PEM, key) + if len(cert_ca) > 100 and len(private_key) > 100: + writeFile('ssl/certificate.pem', cert_ca, 'wb+') + writeFile('ssl/privateKey.pem', private_key, 'wb+') + return True + return False + def getSSHPort(): try: diff --git a/class/core/site_api.py b/class/core/site_api.py index 492469866..52a98b43a 100755 --- a/class/core/site_api.py +++ b/class/core/site_api.py @@ -589,7 +589,7 @@ class site_api: key = mw.readFile(key_path) csr = mw.readFile(csr_path) - cert_data = self.getCertName(csr_path) + cert_data = mw.getCertName(csr_path) data = { 'status': status, 'domain': domains, @@ -2582,7 +2582,6 @@ location ^~ {from} {\n\ conf = conf.replace(listen, listen + http_ssl) mw.backFile(file) - mw.writeFile(file, conf) isError = mw.checkWebConfig() if(isError != True): @@ -2599,7 +2598,7 @@ location ^~ {from} {\n\ def saveCert(self, keyPath, certPath): try: - certInfo = self.getCertName(certPath) + certInfo = mw.getCertName(certPath) if not certInfo: return mw.returnData(False, '证书解析失败!') vpath = self.sslDir + '/' + certInfo['subject'].strip() @@ -2612,70 +2611,6 @@ location ^~ {from} {\n\ 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: - 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 - # 清除多余user.ini def delUserInI(self, path, up=0): for p1 in os.listdir(path): diff --git a/data/tpl/nginx_panel.conf b/data/tpl/nginx_panel.conf new file mode 100755 index 000000000..cdd4baf0d --- /dev/null +++ b/data/tpl/nginx_panel.conf @@ -0,0 +1,28 @@ +server +{ + listen {$PORT}; + listen [::]:{$PORT}; + server_name {$SERVER_NAME}; + index index.php index.html index.htm default.php default.htm default.html; + root {$ROOT_DIR}; + + #SSL-START + #error_page 404/404.html; + #SSL-END + + + #禁止访问的文件或目录 + location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md) + { + return 404; + } + + #一键申请SSL证书验证目录相关设置 + location ~ \.well-known{ + allow all; + } + + + access_log {$LOGPATH}/{$SERVER_NAME}.log main; + error_log {$LOGPATH}/{$SERVER_NAME}.error.log; +} \ No newline at end of file diff --git a/route/static/app/config.js b/route/static/app/config.js index de0c0c7d3..47bf0c270 100755 --- a/route/static/app/config.js +++ b/route/static/app/config.js @@ -68,7 +68,6 @@ $('input[name="backup_path"]').change(function(){ $('input[name="bind_domain"]').change(function(){ var domain = $(this).val(); - console.log(domain); $('.btn_bind_domain').removeAttr('disabled'); $('.btn_bind_domain').unbind().click(function(){ $.post('/config/set_panel_domain','domain='+domain, function(rdata){ @@ -77,6 +76,13 @@ $('input[name="bind_domain"]').change(function(){ }); }); +$('input[name="bind_ssl"]').click(function(){ + var open_ssl = $(this).prop("checked"); + $.post('/config/set_panel_ssl',{}, function(rdata){ + showMsg(rdata.msg,function(){window.location.reload();},{icon:rdata.status?1:2},2000); + },'json'); +}); + /** op **/ @@ -353,13 +359,29 @@ function getPanelSSL(){ var loadT = layer.msg('正在获取证书信息...',{icon:16,time:0,shade: [0.3, '#000']}); $.post('/config/get_panel_ssl',{},function(cert){ layer.close(loadT); + + + var cert_data = ''; + if (cert['info']){ + cert_data = "
\ +
证书品牌:"+cert['info']['issuer']+"
\ +
到期时间:剩余"+cert['info']['endtime']+"天到期
\ +
\ +
\ +
认证域名:"+cert['info']['subject']+"
\ +
"; + } + var certBody = '
\
\ -
密钥(KEY)
\ - \ -
\ -
证书(PEM格式)
\ - \ + '+cert_data+'\ +
\ +
密钥(KEY)
\ + \ +
\ +
证书(PEM格式)
\ + \ +
\
\
\ \ diff --git a/route/templates/default/config.html b/route/templates/default/config.html index 09aea88d4..3ae0615a2 100755 --- a/route/templates/default/config.html +++ b/route/templates/default/config.html @@ -121,13 +121,13 @@ 为面板绑定一个访问域名,注意:一旦绑定域名,只能通过域名访问面板

- +

BasicAuth认证