diff --git a/frontend/src/api/cert.ts b/frontend/src/api/cert.ts
new file mode 100644
index 00000000..6edf2470
--- /dev/null
+++ b/frontend/src/api/cert.ts
@@ -0,0 +1,5 @@
+import Curd from '@/api/curd'
+
+const cert = new Curd('/cert')
+
+export default cert
diff --git a/frontend/src/api/domain.ts b/frontend/src/api/domain.ts
index 0e6b55ab..ce927e07 100644
--- a/frontend/src/api/domain.ts
+++ b/frontend/src/api/domain.ts
@@ -13,13 +13,13 @@ class Domain extends Curd {
get_template() {
return http.get('template')
}
-
+
add_auto_cert(domain: string) {
- return http.post('cert/' + domain)
+ return http.post('auto_cert/' + domain)
}
remove_auto_cert(domain: string) {
- return http.delete('cert/' + domain)
+ return http.delete('auto_cert/' + domain)
}
}
diff --git a/frontend/src/language/en/app.po b/frontend/src/language/en/app.po
index 303d0066..be5d523e 100644
--- a/frontend/src/language/en/app.po
+++ b/frontend/src/language/en/app.po
@@ -17,7 +17,8 @@ msgstr "About"
msgid "Access Logs"
msgstr ""
-#: src/views/domain/DomainList.vue:47 src/views/user/User.vue:43
+#: src/views/config/config.ts:36 src/views/domain/DomainList.vue:47
+#: src/views/user/User.vue:43
msgid "Action"
msgstr "Action"
@@ -205,6 +206,10 @@ msgstr ""
msgid "Development Mode"
msgstr "Development Mode"
+#: src/views/config/config.ts:20
+msgid "Dir"
+msgstr ""
+
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
msgid "Directive"
msgstr "Directive"
@@ -308,6 +313,10 @@ msgstr "Failed to enable %{msg}"
msgid "Failed to get certificate information"
msgstr ""
+#: src/views/config/config.ts:22
+msgid "File"
+msgstr ""
+
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
msgid "File Not Found"
msgstr "File Not Found"
@@ -444,7 +453,8 @@ msgstr "Modify Config"
msgid "Modify Config"
msgstr "Modify Config"
-#: src/views/domain/DomainEdit.vue:36 src/views/domain/DomainList.vue:15
+#: src/views/config/config.ts:9 src/views/domain/DomainEdit.vue:36
+#: src/views/domain/DomainList.vue:15
msgid "Name"
msgstr "Name"
@@ -730,7 +740,12 @@ msgstr ""
msgid "Theme"
msgstr ""
-#: src/views/domain/DomainList.vue:41 src/views/user/User.vue:37
+#: src/language/constants.ts:23 src/views/config/config.ts:14
+msgid "Type"
+msgstr ""
+
+#: src/views/config/config.ts:29 src/views/domain/DomainList.vue:41
+#: src/views/user/User.vue:37
msgid "Updated at"
msgstr "Updated at"
diff --git a/frontend/src/language/messages.pot b/frontend/src/language/messages.pot
index 18fa0233..847ab782 100644
--- a/frontend/src/language/messages.pot
+++ b/frontend/src/language/messages.pot
@@ -11,6 +11,7 @@ msgstr ""
msgid "Access Logs"
msgstr ""
+#: src/views/config/config.ts:36
#: src/views/domain/DomainList.vue:47
#: src/views/user/User.vue:43
msgid "Action"
@@ -203,6 +204,10 @@ msgstr ""
msgid "Development Mode"
msgstr ""
+#: src/views/config/config.ts:20
+msgid "Dir"
+msgstr ""
+
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
msgid "Directive"
msgstr ""
@@ -320,6 +325,10 @@ msgstr ""
msgid "Failed to get certificate information"
msgstr ""
+#: src/views/config/config.ts:22
+msgid "File"
+msgstr ""
+
#: src/views/other/Error.vue:3
#: src/views/other/Error.vue:4
msgid "File Not Found"
@@ -456,6 +465,7 @@ msgstr ""
msgid "Modify Config"
msgstr ""
+#: src/views/config/config.ts:9
#: src/views/domain/DomainEdit.vue:36
#: src/views/domain/DomainList.vue:15
msgid "Name"
@@ -747,6 +757,12 @@ msgstr ""
msgid "Theme"
msgstr ""
+#: src/language/constants.ts:23
+#: src/views/config/config.ts:14
+msgid "Type"
+msgstr ""
+
+#: src/views/config/config.ts:29
#: src/views/domain/DomainList.vue:41
#: src/views/user/User.vue:37
msgid "Updated at"
diff --git a/frontend/src/language/translations.json b/frontend/src/language/translations.json
index bd22dd78..7ac418fd 100644
--- a/frontend/src/language/translations.json
+++ b/frontend/src/language/translations.json
@@ -1 +1 @@
-{"zh_CN":{"About":"关于","Access Logs":"访问日志","Action":"操作","Add":"添加","Add Directive Below":"在下面添加指令","Add Location":"添加 Location","Add Site":"添加站点","Advance Mode":"高级模式","Are you sure you want to delete?":"您确定要删除吗?","Are you sure you want to remove this directive?":"您确定要删除这条指令?","Are you sure you want to remove this location?":"您确定要删除这个 Location?","Auto":"自动","Auto Refresh":"自动刷新","Auto-renewal disabled for %{name}":"成功关闭 %{name} 自动续签","Auto-renewal enabled for %{name}":"成功启用 %{name} 自动续签","Back":"返回","Back Home":"返回首页","Base information":"基本信息","Basic Mode":"基本模式","Batch Modify":"批量修改","Build with":"构建基于","Cancel":"取消","Certificate has expired":"此证书已过期","Certificate is valid":"此证书有效","Certificate Status":"证书状态","Comments":"注释","Configuration Name":"配置名称","Configurations":"配置","Configure SSL":"配置 SSL","Content":"内容","CPU Status":"CPU 状态","CPU:":"CPU:","Create Another":"再创建一个","Created at":"创建时间","Creating client facilitates communication with the CA server":"正在创建客户端用于与 CA 服务器通信","Dark":"深色","Dashboard":"仪表盘","Database (Optional, default: database)":"数据库 (可选,默认: database)","Delete":"删除","Delete ID: %{id}":"删除 ID: %{id}","Delete site: %{site_name}":"删除站点: %{site_name}","Development Mode":"开发模式","Directive":"指令","Directives":"指令","Disable auto-renewal failed for %{name}":"关闭 %{name} 自动续签失败","Disabled":"禁用","Disabled successfully":"禁用成功","Disk IO":"磁盘 IO","Domain Config Created Successfully":"域名配置文件创建成功","Edit %{n}":"编辑 %{n}","Edit Configuration":"编辑配置","Edit Site":"编辑站点","Email (*)":"邮箱 (*)","Enable auto-renewal failed for %{name}":"启用 %{name} 自动续签失败","Enable failed":"启用失败","Enable TLS":"启用 TLS","Enabled":"启用","Enabled successfully":"启用成功","Encrypt website with Let's Encrypt":"用 Let's Encrypt 对网站进行加密","Error Logs":"错误日志","Expiration Date: %{date}":"过期时间: %{date}","Export":"导出","Failed to disable %{msg}":"禁用失败 %{msg}","Failed to enable %{msg}":"启用失败 %{msg}","Failed to get certificate information":"获取证书信息失败","File Not Found":"未找到文件","Filter":"过滤","Finished":"完成","Generate":"生成","Generating private key for registering account":"正在生成私钥用于注册账户","Getting the certificate, please wait...":"正在获取证书,请稍等...","Home":"首页","HTTP Challenge Port":"HTTP Challenge 监听端口","HTTP Port":"HTTP 监听端口","Install":"安装","Install successfully":"安装成功","Intermediate Certification Authorities: %{issuer}":"中级证书颁发机构: %{issuer}","Issued certificate successfully":"证书申请成功","Jwt Secret":"Jwt 密钥","Leave blank for no change":"留空表示不修改","Light":"浅色","Load Averages:":"系统负载:","Location":"Location","Locations":"Locations","Login":"登录","Login successful":"登录成功","Logout successful":"登出成功","Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.":"在获取签发证书前,请确保配置文件中已将 .well-known 目录反向代理到 HTTPChallengePort (默认: 9180)","Manage Configs":"配置管理","Manage Sites":"网站管理","Manage Users":"用户管理","Memory":"内存","Memory and Storage":"内存与存储","Modify":"修改","Modify Config":"修改配置文件","Name":"名称","Network":"网络","Network Statistics":"流量统计","Network Total Receive":"下载流量","Network Total Send":"上传流量","Next":"下一步","Nginx Access Log Path":"Nginx 访问日志路径","Nginx Error Log Path":"Nginx 错误日志路径","Nginx Log":"Nginx 日志","No":"取消","Not Found":"找不到页面","Not Valid Before: %{date}":"此前无效: %{date}","Note: The server_name in the current configuration must be the domain name you need to get the certificate.":"注意:当前配置中的 server_name 必须为需要申请证书的域名。","Obtaining certificate":"正在获取证书","OK":"确定","OS:":"OS:","Params":"参数","Password":"密码","Password (*)":"密码 (*)","Path":"路径","Please input your E-mail!":"请输入您的邮箱!","Please input your password!":"请输入您的密码!","Please input your username!":"请输入您的用户名!","Preference":"偏好设置","Preparing lego configurations":"正在准备 Lego 的配置","Prohibit changing root password in demo":"禁止在演示模式下修改 root 账户的密码","Prohibit deleting the default user":"禁止删除默认用户","Project Team":"项目团队","Reads":"读","Receive":"下载","Registering user":"正在注册用户","Reloading nginx":"正在重载 Nginx","Reset":"重置","Run Mode":"运行模式","Save":"保存","Save Directive":"保存指令","Save error %{msg}":"保存错误 %{msg}","Save successfully":"保存成功","Save Successfully":"保存成功","Saved successfully":"保存成功","Selector":"选择器","Send":"上传","Server error":"服务器错误","Server Info":"服务器信息","server_name not found in directives":"未在指令集合中找到 server_name","server_name parameter is required":"必须为 server_name 指令指明参数","Single Directive":"单行指令","Site Logs":"站点列表","Sites List":"站点列表","Status":"状态","Storage":"存储","Subject Name: %{name}":"主体名称: %{name}","Swap":"Swap","Table":"列表","Terminal":"终端","Terminal Start Command":"终端启动命令","The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.":"系统将会每小时检测一次该域名证书,若距离上次签发已超过1个月,则将自动续签。","The filename cannot contain the following characters: %{c}":"文件名不能包含以下字符: %{c}","The username or password is incorrect":"用户名或密码错误","Theme":"主题","Updated at":"修改时间","Updated successfully":"更新成功","Uptime:":"运行时间:","Username":"用户名","Username (*)":"用户名 (*)","Using HTTP01 challenge provider":"使用 HTTP01 challenge provider","Warning":"警告","Writes":"写","Writing certificate private key to disk":"正在将证书私钥写入磁盘","Writing certificate to disk":"正在将证书写入磁盘","Yes":"是的","License":{"Project":"开源许可"}},"en":{"About":"About","Action":"Action","Add Directive Below":"Add Directive Below","Add Location":"Add Location","Add Site":"Add Site","Advance Mode":"Advance Mode","Are you sure you want to remove this directive?":"Are you sure you want to remove this directive?","Auto-renewal disabled for %{name}":"Auto-renewal disabled for %{name}","Auto-renewal enabled for %{name}":"Auto-renewal enabled for %{name}","Back":"Back","Base information":"Base information","Basic Mode":"Basic Mode","Build with":"Build with","Cancel":"Cancel","Certificate has expired":"Certificate has expired","Certificate is valid":"Certificate is valid","Certificate Status":"Certificate Status","Comments":"Comments","Configuration Name":"Configuration Name","Configurations":"Configurations","Configure SSL":"Configure SSL","Content":"Content","CPU Status":"CPU Status","CPU:":"CPU:","Create Another":"Create Another","Created at":"Created at","Dashboard":"Dashboard","Database (Optional, default: database)":"Database (Optional, default: database)","Development Mode":"Development Mode","Directive":"Directive","Directives":"Directives","Disable auto-renewal failed for %{name}":"Disable auto-renewal failed for %{name}","Disabled":"Disabled","Disabled successfully":"Disabled successfully","Disk IO":"Disk IO","Domain Config Created Successfully":"Domain Config Created Successfully","Edit %{n}":"Edit %{n}","Edit Configuration":"Edit Configuration","Edit Site":"Edit Site","Email (*)":"Email (*)","Enable auto-renewal failed for %{name}":"Enable auto-renewal failed for %{name}","Enable failed":"Enable failed","Enable TLS":"Enable TLS","Enabled":"Enabled","Enabled successfully":"Enabled successfully","Encrypt website with Let's Encrypt":"Encrypt website with Let's Encrypt","Expiration Date: %{date}":"Expiration Date: %{date}","Failed to disable %{msg}":"Failed to disable %{msg}","Failed to enable %{msg}":"Failed to enable %{msg}","File Not Found":"File Not Found","Finished":"Finished","Getting the certificate, please wait...":"Getting the certificate, please wait...","Home":"Home","Install":"Install","Intermediate Certification Authorities: %{issuer}":"Intermediate Certification Authorities: %{issuer}","Leave blank for no change":"Leave blank for no change","Load Averages:":"Load Averages:","Location":"Location","Locations":"Locations","Login":"Login","Login successful":"Login successful","Logout successful":"Logout successful","Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.":"Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.","Manage Configs":"Manage Configs","Manage Sites":"Manage Sites","Manage Users":"Manage Users","Memory":"Memory","Memory and Storage":"Memory and Storage","Modify Config":"Modify Config","Name":"Name","Network":"Network","Network Statistics":"Network Statistics","Network Total Receive":"Network Total Receive","Network Total Send":"Network Total Send","Next":"Next","No":"No","Not Found":"Not Found","Not Valid Before: %{date}":"Not Valid Before: %{date}","Note: The server_name in the current configuration must be the domain name you need to get the certificate.":"Note: The server_name in the current configuration must be the domain name you need to get the certificate.","OS:":"OS:","Params":"Params","Password":"Password","Password (*)":"Password (*)","Path":"Path","Please input your E-mail!":"Please input your E-mail!","Please input your password!":"Please input your password!","Please input your username!":"Please input your username!","Project Team":"Project Team","Reads":"Reads","Receive":"Receive","Save":"Save","Save Directive":"Save Directive","Save error %{msg}":"Save error %{msg}","Saved successfully":"Saved successfully","Send":"Send","Server error":"Server error","Server Info":"Server Info","server_name not found in directives":"server_name not found in directives","server_name parameter is required":"server_name parameter is required","Single Directive":"Single Directive","Sites List":"Sites List","Status":"Status","Storage":"Storage","Subject Name: %{name}":"Subject Name: %{name}","Swap":"Swap","Terminal":"Terminal","The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.":"The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.","The filename cannot contain the following characters: %{c}":"The filename cannot contain the following characters: %{c}","Updated at":"Updated at","Uptime:":"Uptime:","Username":"Username","Username (*)":"Username (*)","Warning":"Warning","Writes":"Writes","Yes":"Yes","License":{"Project":"License"}},"zh_TW":{"About":"關於","Access Logs":"訪問日誌","Action":"操作","Add":"新增","Add Directive Below":"在下面新增指令","Add Location":"新增 Location","Add Site":"新增站點","Advance Mode":"高階模式","Are you sure you want to delete?":"你確定你要刪除?","Are you sure you want to remove this directive?":"您確定要刪除這條指令?","Are you sure you want to remove this location?":"您確定要刪除此 Location 嗎?","Auto":"自動","Auto Refresh":"自動刷新","Auto-renewal disabled for %{name}":"已關閉 %{name} 自動續簽","Auto-renewal enabled for %{name}":"已啟用 %{name} 自動續簽","Back":"返回","Back Home":"回到首頁","Base information":"基本訊息","Basic Mode":"基本模式","Batch Modify":"批量修改","Build with":"構建基於","Cancel":"取消","Certificate has expired":"此憑證已過期","Certificate is valid":"此憑證有效","Certificate Status":"憑證狀態","Comments":"註釋","Configuration Name":"配置名稱","Configurations":"配置","Configure SSL":"配置 SSL","Content":"內容","CPU Status":"中央處理器狀態","CPU:":"中央處理器:","Create Another":"再創建一個","Created at":"建立時間","Creating client facilitates communication with the CA server":"創建客戶端方便與CA服務器通信","Dark":"深色","Dashboard":"儀表盤","Database (Optional, default: database)":"資料庫 (可選,預設: database)","Delete":"刪除","Delete ID: %{id}":"刪除 ID: %{id}","Delete site: %{site_name}":"刪除站點:%{site_name}","Development Mode":"開發模式","Directive":"指令","Directives":"指令","Disable auto-renewal failed for %{name}":"關閉 %{name} 自動續簽失敗","Disabled":"禁用","Disabled successfully":"禁用成功","Disk IO":"磁碟 IO","Domain Config Created Successfully":"域名配置文件創建成功","Edit %{n}":"編輯 %{n}","Edit Configuration":"編輯配置","Edit Site":"編輯站點","Email (*)":"郵箱 (*)","Enable auto-renewal failed for %{name}":"啟用 %{name} 自動續簽失敗","Enable failed":"啟用失敗","Enable TLS":"啟用 TLS","Enabled":"啟用","Enabled successfully":"啟用成功","Encrypt website with Let's Encrypt":"用 Let's Encrypt 對網站進行加密","Error Logs":"錯誤日志","Expiration Date: %{date}":"過期時間: %{date}","Export":"導出","Failed to disable %{msg}":"禁用失敗 %{msg}","Failed to enable %{msg}":"啟用失敗 %{msg}","Failed to get certificate information":"獲取證書信息失敗","File Not Found":"未找到檔案","Filter":"篩選","Finished":"完成","Generate":"生成","Generating private key for registering account":"生成註冊賬號私鑰","Getting the certificate, please wait...":"正在獲取憑證,請稍等...","Home":"首頁","Install":"安裝","Install successfully":"安裝成功","Intermediate Certification Authorities: %{issuer}":"中級憑證頒發機構: %{issuer}","Issued certificate successfully":"頒發證書成功","Leave blank for no change":"留空表示不修改","Light":"淺色","Load Averages:":"系統負載:","Location":"Location","Locations":"Locations","Login":"登入","Login successful":"登入成功","Logout successful":"登出成功","Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.":"在獲取證書前,請確保配置檔案中已將 .well-known 目錄反向代理到 HTTPChallengePort (預設: 9180)","Manage Configs":"配置管理","Manage Sites":"網站管理","Manage Users":"使用者管理","Memory":"記憶體","Memory and Storage":"記憶體和存儲","Modify":"修改","Modify Config":"修改配置","Name":"名稱","Network":"網路","Network Statistics":"網路統計","Network Total Receive":"下載流量","Network Total Send":"上傳流量","Next":"下一步","Nginx Log":"Nginx 日誌","No":"取消","Not Found":"找不到頁面","Not Valid Before: %{date}":"此前無效: %{date}","Note: The server_name in the current configuration must be the domain name you need to get the certificate.":"注意:當前配置中的 server_name 必須為需要申請證書的域名。","Obtaining certificate":"正在獲取證書,請稍等...","OK":"確定","OS:":"作業系統:","Params":"參數","Password":"密碼","Password (*)":"密碼 (*)","Path":"路徑","Please input your E-mail!":"請輸入您的郵箱!","Please input your password!":"請輸入您的密碼!","Please input your username!":"請輸入您的使用者名稱!","Preference":"設定","Preparing lego configurations":"準備 Lego 配置","Prohibit changing root password in demo":"禁止在demo中修改root密碼","Prohibit deleting the default user":"禁止刪除默認用戶","Project Team":"專案團隊","Reads":"讀","Receive":"下載","Registering user":"註冊用戶","Reloading nginx":"重载 Nginx","Reset":"重設","Save":"儲存","Save Directive":"儲存指令","Save error %{msg}":"儲存錯誤 %{msg}","Save successfully":"保存成功","Save Successfully":"保存成功","Saved successfully":"儲存成功","Selector":"選擇器","Send":"上傳","Server error":"伺服器錯誤","Server Info":"伺服器資訊","server_name not found in directives":"未在指令集合中找到 server_name","server_name parameter is required":"必須為 server_name 指令指明參數","Single Directive":"單行指令","Site Logs":"網站日誌","Sites List":"站點列表","Status":"狀態","Storage":"儲存","Subject Name: %{name}":"主體名稱: %{name}","Swap":"交換空間","Table":"表格","Terminal":"終端","The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.":"系統將會每小時檢測一次該域名證書,若距離上次簽發已超過1個月,則將自動續簽。
如果您之前沒有證書,請先點選「從 Let's Encrypt 獲取證書」。","The filename cannot contain the following characters: %{c}":"檔名不能包含以下字元: %{c}","The username or password is incorrect":"用戶名或密碼不正確","Theme":"外觀樣式","Updated at":"修改時間","Updated successfully":"已成功更新","Uptime:":"執行時間:","Username":"使用者名稱","Username (*)":"使用者名稱 (*)","Using HTTP01 challenge provider":"使用 HTTP01 挑戰提供者","Warning":"警告","Writes":"寫","Writing certificate private key to disk":"將證書私鑰寫入磁盤","Writing certificate to disk":"將證書寫入磁盤","Yes":"是的","License":{"Project":"開源軟體授權條款"}}}
\ No newline at end of file
+{"zh_CN":{"About":"关于","Access Logs":"访问日志","Action":"操作","Add":"添加","Add Directive Below":"在下面添加指令","Add Location":"添加 Location","Add Site":"添加站点","Advance Mode":"高级模式","Are you sure you want to delete?":"您确定要删除吗?","Are you sure you want to remove this directive?":"您确定要删除这条指令?","Are you sure you want to remove this location?":"您确定要删除这个 Location?","Auto":"自动","Auto Refresh":"自动刷新","Auto-renewal disabled for %{name}":"成功关闭 %{name} 自动续签","Auto-renewal enabled for %{name}":"成功启用 %{name} 自动续签","Back":"返回","Back Home":"返回首页","Base information":"基本信息","Basic Mode":"基本模式","Batch Modify":"批量修改","Build with":"构建基于","Cancel":"取消","Certificate has expired":"此证书已过期","Certificate is valid":"此证书有效","Certificate Status":"证书状态","Comments":"注释","Configuration Name":"配置名称","Configurations":"配置","Configure SSL":"配置 SSL","Content":"内容","CPU Status":"CPU 状态","CPU:":"CPU:","Create Another":"再创建一个","Created at":"创建时间","Creating client facilitates communication with the CA server":"正在创建客户端用于与 CA 服务器通信","Dark":"深色","Dashboard":"仪表盘","Database (Optional, default: database)":"数据库 (可选,默认: database)","Delete":"删除","Delete ID: %{id}":"删除 ID: %{id}","Delete site: %{site_name}":"删除站点: %{site_name}","Development Mode":"开发模式","Dir":"目录","Directive":"指令","Directives":"指令","Disable auto-renewal failed for %{name}":"关闭 %{name} 自动续签失败","Disabled":"禁用","Disabled successfully":"禁用成功","Disk IO":"磁盘 IO","Domain Config Created Successfully":"域名配置文件创建成功","Edit %{n}":"编辑 %{n}","Edit Configuration":"编辑配置","Edit Site":"编辑站点","Email (*)":"邮箱 (*)","Enable auto-renewal failed for %{name}":"启用 %{name} 自动续签失败","Enable failed":"启用失败","Enable TLS":"启用 TLS","Enabled":"启用","Enabled successfully":"启用成功","Encrypt website with Let's Encrypt":"用 Let's Encrypt 对网站进行加密","Error Logs":"错误日志","Expiration Date: %{date}":"过期时间: %{date}","Export":"导出","Failed to disable %{msg}":"禁用失败 %{msg}","Failed to enable %{msg}":"启用失败 %{msg}","Failed to get certificate information":"获取证书信息失败","File":"文件","File Not Found":"未找到文件","Filter":"过滤","Finished":"完成","Generate":"生成","Generating private key for registering account":"正在生成私钥用于注册账户","Getting the certificate, please wait...":"正在获取证书,请稍等...","Home":"首页","HTTP Challenge Port":"HTTP Challenge 监听端口","HTTP Port":"HTTP 监听端口","Install":"安装","Install successfully":"安装成功","Intermediate Certification Authorities: %{issuer}":"中级证书颁发机构: %{issuer}","Issued certificate successfully":"证书申请成功","Jwt Secret":"Jwt 密钥","Leave blank for no change":"留空表示不修改","Light":"浅色","Load Averages:":"系统负载:","Location":"Location","Locations":"Locations","Login":"登录","Login successful":"登录成功","Logout successful":"登出成功","Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.":"在获取签发证书前,请确保配置文件中已将 .well-known 目录反向代理到 HTTPChallengePort (默认: 9180)","Manage Configs":"配置管理","Manage Sites":"网站管理","Manage Users":"用户管理","Memory":"内存","Memory and Storage":"内存与存储","Modify":"修改","Modify Config":"修改配置文件","Name":"名称","Network":"网络","Network Statistics":"流量统计","Network Total Receive":"下载流量","Network Total Send":"上传流量","Next":"下一步","Nginx Access Log Path":"Nginx 访问日志路径","Nginx Error Log Path":"Nginx 错误日志路径","Nginx Log":"Nginx 日志","No":"取消","Not Found":"找不到页面","Not Valid Before: %{date}":"此前无效: %{date}","Note: The server_name in the current configuration must be the domain name you need to get the certificate.":"注意:当前配置中的 server_name 必须为需要申请证书的域名。","Obtaining certificate":"正在获取证书","OK":"确定","OS:":"OS:","Params":"参数","Password":"密码","Password (*)":"密码 (*)","Path":"路径","Please input your E-mail!":"请输入您的邮箱!","Please input your password!":"请输入您的密码!","Please input your username!":"请输入您的用户名!","Preference":"偏好设置","Preparing lego configurations":"正在准备 Lego 的配置","Prohibit changing root password in demo":"禁止在演示模式下修改 root 账户的密码","Prohibit deleting the default user":"禁止删除默认用户","Project Team":"项目团队","Reads":"读","Receive":"下载","Registering user":"正在注册用户","Reloading nginx":"正在重载 Nginx","Reset":"重置","Run Mode":"运行模式","Save":"保存","Save Directive":"保存指令","Save error %{msg}":"保存错误 %{msg}","Save successfully":"保存成功","Save Successfully":"保存成功","Saved successfully":"保存成功","Selector":"选择器","Send":"上传","Server error":"服务器错误","Server Info":"服务器信息","server_name not found in directives":"未在指令集合中找到 server_name","server_name parameter is required":"必须为 server_name 指令指明参数","Single Directive":"单行指令","Site Logs":"站点列表","Sites List":"站点列表","Status":"状态","Storage":"存储","Subject Name: %{name}":"主体名称: %{name}","Swap":"Swap","Table":"列表","Terminal":"终端","Terminal Start Command":"终端启动命令","The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.":"系统将会每小时检测一次该域名证书,若距离上次签发已超过1个月,则将自动续签。","The filename cannot contain the following characters: %{c}":"文件名不能包含以下字符: %{c}","The username or password is incorrect":"用户名或密码错误","Theme":"主题","Type":"类型","Updated at":"修改时间","Updated successfully":"更新成功","Uptime:":"运行时间:","Username":"用户名","Username (*)":"用户名 (*)","Using HTTP01 challenge provider":"使用 HTTP01 challenge provider","Warning":"警告","Writes":"写","Writing certificate private key to disk":"正在将证书私钥写入磁盘","Writing certificate to disk":"正在将证书写入磁盘","Yes":"是的","License":{"Project":"开源许可"}},"zh_TW":{"About":"關於","Access Logs":"訪問日誌","Action":"操作","Add":"新增","Add Directive Below":"在下面新增指令","Add Location":"新增 Location","Add Site":"新增站點","Advance Mode":"高階模式","Are you sure you want to delete?":"你確定你要刪除?","Are you sure you want to remove this directive?":"您確定要刪除這條指令?","Are you sure you want to remove this location?":"您確定要刪除此 Location 嗎?","Auto":"自動","Auto Refresh":"自動刷新","Auto-renewal disabled for %{name}":"已關閉 %{name} 自動續簽","Auto-renewal enabled for %{name}":"已啟用 %{name} 自動續簽","Back":"返回","Back Home":"回到首頁","Base information":"基本訊息","Basic Mode":"基本模式","Batch Modify":"批量修改","Build with":"構建基於","Cancel":"取消","Certificate has expired":"此憑證已過期","Certificate is valid":"此憑證有效","Certificate Status":"憑證狀態","Comments":"註釋","Configuration Name":"配置名稱","Configurations":"配置","Configure SSL":"配置 SSL","Content":"內容","CPU Status":"中央處理器狀態","CPU:":"中央處理器:","Create Another":"再創建一個","Created at":"建立時間","Creating client facilitates communication with the CA server":"創建客戶端方便與CA服務器通信","Dark":"深色","Dashboard":"儀表盤","Database (Optional, default: database)":"資料庫 (可選,預設: database)","Delete":"刪除","Delete ID: %{id}":"刪除 ID: %{id}","Delete site: %{site_name}":"刪除站點:%{site_name}","Development Mode":"開發模式","Directive":"指令","Directives":"指令","Disable auto-renewal failed for %{name}":"關閉 %{name} 自動續簽失敗","Disabled":"禁用","Disabled successfully":"禁用成功","Disk IO":"磁碟 IO","Domain Config Created Successfully":"域名配置文件創建成功","Edit %{n}":"編輯 %{n}","Edit Configuration":"編輯配置","Edit Site":"編輯站點","Email (*)":"郵箱 (*)","Enable auto-renewal failed for %{name}":"啟用 %{name} 自動續簽失敗","Enable failed":"啟用失敗","Enable TLS":"啟用 TLS","Enabled":"啟用","Enabled successfully":"啟用成功","Encrypt website with Let's Encrypt":"用 Let's Encrypt 對網站進行加密","Error Logs":"錯誤日志","Expiration Date: %{date}":"過期時間: %{date}","Export":"導出","Failed to disable %{msg}":"禁用失敗 %{msg}","Failed to enable %{msg}":"啟用失敗 %{msg}","Failed to get certificate information":"獲取證書信息失敗","File Not Found":"未找到檔案","Filter":"篩選","Finished":"完成","Generate":"生成","Generating private key for registering account":"生成註冊賬號私鑰","Getting the certificate, please wait...":"正在獲取憑證,請稍等...","Home":"首頁","Install":"安裝","Install successfully":"安裝成功","Intermediate Certification Authorities: %{issuer}":"中級憑證頒發機構: %{issuer}","Issued certificate successfully":"頒發證書成功","Leave blank for no change":"留空表示不修改","Light":"淺色","Load Averages:":"系統負載:","Location":"Location","Locations":"Locations","Login":"登入","Login successful":"登入成功","Logout successful":"登出成功","Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.":"在獲取證書前,請確保配置檔案中已將 .well-known 目錄反向代理到 HTTPChallengePort (預設: 9180)","Manage Configs":"配置管理","Manage Sites":"網站管理","Manage Users":"使用者管理","Memory":"記憶體","Memory and Storage":"記憶體和存儲","Modify":"修改","Modify Config":"修改配置","Name":"名稱","Network":"網路","Network Statistics":"網路統計","Network Total Receive":"下載流量","Network Total Send":"上傳流量","Next":"下一步","Nginx Log":"Nginx 日誌","No":"取消","Not Found":"找不到頁面","Not Valid Before: %{date}":"此前無效: %{date}","Note: The server_name in the current configuration must be the domain name you need to get the certificate.":"注意:當前配置中的 server_name 必須為需要申請證書的域名。","Obtaining certificate":"正在獲取證書,請稍等...","OK":"確定","OS:":"作業系統:","Params":"參數","Password":"密碼","Password (*)":"密碼 (*)","Path":"路徑","Please input your E-mail!":"請輸入您的郵箱!","Please input your password!":"請輸入您的密碼!","Please input your username!":"請輸入您的使用者名稱!","Preference":"設定","Preparing lego configurations":"準備 Lego 配置","Prohibit changing root password in demo":"禁止在demo中修改root密碼","Prohibit deleting the default user":"禁止刪除默認用戶","Project Team":"專案團隊","Reads":"讀","Receive":"下載","Registering user":"註冊用戶","Reloading nginx":"重载 Nginx","Reset":"重設","Save":"儲存","Save Directive":"儲存指令","Save error %{msg}":"儲存錯誤 %{msg}","Save successfully":"保存成功","Save Successfully":"保存成功","Saved successfully":"儲存成功","Selector":"選擇器","Send":"上傳","Server error":"伺服器錯誤","Server Info":"伺服器資訊","server_name not found in directives":"未在指令集合中找到 server_name","server_name parameter is required":"必須為 server_name 指令指明參數","Single Directive":"單行指令","Site Logs":"網站日誌","Sites List":"站點列表","Status":"狀態","Storage":"儲存","Subject Name: %{name}":"主體名稱: %{name}","Swap":"交換空間","Table":"表格","Terminal":"終端","The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.":"系統將會每小時檢測一次該域名證書,若距離上次簽發已超過1個月,則將自動續簽。
如果您之前沒有證書,請先點選「從 Let's Encrypt 獲取證書」。","The filename cannot contain the following characters: %{c}":"檔名不能包含以下字元: %{c}","The username or password is incorrect":"用戶名或密碼不正確","Theme":"外觀樣式","Updated at":"修改時間","Updated successfully":"已成功更新","Uptime:":"執行時間:","Username":"使用者名稱","Username (*)":"使用者名稱 (*)","Using HTTP01 challenge provider":"使用 HTTP01 挑戰提供者","Warning":"警告","Writes":"寫","Writing certificate private key to disk":"將證書私鑰寫入磁盤","Writing certificate to disk":"將證書寫入磁盤","Yes":"是的","License":{"Project":"開源軟體授權條款"}},"en":{"About":"About","Action":"Action","Add Directive Below":"Add Directive Below","Add Location":"Add Location","Add Site":"Add Site","Advance Mode":"Advance Mode","Are you sure you want to remove this directive?":"Are you sure you want to remove this directive?","Auto-renewal disabled for %{name}":"Auto-renewal disabled for %{name}","Auto-renewal enabled for %{name}":"Auto-renewal enabled for %{name}","Back":"Back","Base information":"Base information","Basic Mode":"Basic Mode","Build with":"Build with","Cancel":"Cancel","Certificate has expired":"Certificate has expired","Certificate is valid":"Certificate is valid","Certificate Status":"Certificate Status","Comments":"Comments","Configuration Name":"Configuration Name","Configurations":"Configurations","Configure SSL":"Configure SSL","Content":"Content","CPU Status":"CPU Status","CPU:":"CPU:","Create Another":"Create Another","Created at":"Created at","Dashboard":"Dashboard","Database (Optional, default: database)":"Database (Optional, default: database)","Development Mode":"Development Mode","Directive":"Directive","Directives":"Directives","Disable auto-renewal failed for %{name}":"Disable auto-renewal failed for %{name}","Disabled":"Disabled","Disabled successfully":"Disabled successfully","Disk IO":"Disk IO","Domain Config Created Successfully":"Domain Config Created Successfully","Edit %{n}":"Edit %{n}","Edit Configuration":"Edit Configuration","Edit Site":"Edit Site","Email (*)":"Email (*)","Enable auto-renewal failed for %{name}":"Enable auto-renewal failed for %{name}","Enable failed":"Enable failed","Enable TLS":"Enable TLS","Enabled":"Enabled","Enabled successfully":"Enabled successfully","Encrypt website with Let's Encrypt":"Encrypt website with Let's Encrypt","Expiration Date: %{date}":"Expiration Date: %{date}","Failed to disable %{msg}":"Failed to disable %{msg}","Failed to enable %{msg}":"Failed to enable %{msg}","File Not Found":"File Not Found","Finished":"Finished","Getting the certificate, please wait...":"Getting the certificate, please wait...","Home":"Home","Install":"Install","Intermediate Certification Authorities: %{issuer}":"Intermediate Certification Authorities: %{issuer}","Leave blank for no change":"Leave blank for no change","Load Averages:":"Load Averages:","Location":"Location","Locations":"Locations","Login":"Login","Login successful":"Login successful","Logout successful":"Logout successful","Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.":"Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.","Manage Configs":"Manage Configs","Manage Sites":"Manage Sites","Manage Users":"Manage Users","Memory":"Memory","Memory and Storage":"Memory and Storage","Modify Config":"Modify Config","Name":"Name","Network":"Network","Network Statistics":"Network Statistics","Network Total Receive":"Network Total Receive","Network Total Send":"Network Total Send","Next":"Next","No":"No","Not Found":"Not Found","Not Valid Before: %{date}":"Not Valid Before: %{date}","Note: The server_name in the current configuration must be the domain name you need to get the certificate.":"Note: The server_name in the current configuration must be the domain name you need to get the certificate.","OS:":"OS:","Params":"Params","Password":"Password","Password (*)":"Password (*)","Path":"Path","Please input your E-mail!":"Please input your E-mail!","Please input your password!":"Please input your password!","Please input your username!":"Please input your username!","Project Team":"Project Team","Reads":"Reads","Receive":"Receive","Save":"Save","Save Directive":"Save Directive","Save error %{msg}":"Save error %{msg}","Saved successfully":"Saved successfully","Send":"Send","Server error":"Server error","Server Info":"Server Info","server_name not found in directives":"server_name not found in directives","server_name parameter is required":"server_name parameter is required","Single Directive":"Single Directive","Sites List":"Sites List","Status":"Status","Storage":"Storage","Subject Name: %{name}":"Subject Name: %{name}","Swap":"Swap","Terminal":"Terminal","The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.":"The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.","The filename cannot contain the following characters: %{c}":"The filename cannot contain the following characters: %{c}","Updated at":"Updated at","Uptime:":"Uptime:","Username":"Username","Username (*)":"Username (*)","Warning":"Warning","Writes":"Writes","Yes":"Yes","License":{"Project":"License"}}}
\ No newline at end of file
diff --git a/frontend/src/language/zh_CN/app.mo b/frontend/src/language/zh_CN/app.mo
index 9c51b4ba..94ea7ba5 100644
Binary files a/frontend/src/language/zh_CN/app.mo and b/frontend/src/language/zh_CN/app.mo differ
diff --git a/frontend/src/language/zh_CN/app.po b/frontend/src/language/zh_CN/app.po
index 3beda9dd..9cfc6551 100644
--- a/frontend/src/language/zh_CN/app.po
+++ b/frontend/src/language/zh_CN/app.po
@@ -20,7 +20,8 @@ msgstr "关于"
msgid "Access Logs"
msgstr "访问日志"
-#: src/views/domain/DomainList.vue:47 src/views/user/User.vue:43
+#: src/views/config/config.ts:36 src/views/domain/DomainList.vue:47
+#: src/views/user/User.vue:43
msgid "Action"
msgstr "操作"
@@ -204,6 +205,10 @@ msgstr "删除站点: %{site_name}"
msgid "Development Mode"
msgstr "开发模式"
+#: src/views/config/config.ts:20
+msgid "Dir"
+msgstr "目录"
+
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
msgid "Directive"
msgstr "指令"
@@ -307,6 +312,10 @@ msgstr "启用失败 %{msg}"
msgid "Failed to get certificate information"
msgstr "获取证书信息失败"
+#: src/views/config/config.ts:22
+msgid "File"
+msgstr "文件"
+
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
msgid "File Not Found"
msgstr "未找到文件"
@@ -440,7 +449,8 @@ msgstr "修改"
msgid "Modify Config"
msgstr "修改配置文件"
-#: src/views/domain/DomainEdit.vue:36 src/views/domain/DomainList.vue:15
+#: src/views/config/config.ts:9 src/views/domain/DomainEdit.vue:36
+#: src/views/domain/DomainList.vue:15
msgid "Name"
msgstr "名称"
@@ -717,7 +727,12 @@ msgstr "用户名或密码错误"
msgid "Theme"
msgstr "主题"
-#: src/views/domain/DomainList.vue:41 src/views/user/User.vue:37
+#: src/language/constants.ts:23 src/views/config/config.ts:14
+msgid "Type"
+msgstr "类型"
+
+#: src/views/config/config.ts:29 src/views/domain/DomainList.vue:41
+#: src/views/user/User.vue:37
msgid "Updated at"
msgstr "修改时间"
diff --git a/frontend/src/language/zh_TW/app.po b/frontend/src/language/zh_TW/app.po
index d408649f..71d3995b 100644
--- a/frontend/src/language/zh_TW/app.po
+++ b/frontend/src/language/zh_TW/app.po
@@ -21,7 +21,8 @@ msgstr "關於"
msgid "Access Logs"
msgstr "訪問日誌"
-#: src/views/domain/DomainList.vue:47 src/views/user/User.vue:43
+#: src/views/config/config.ts:36 src/views/domain/DomainList.vue:47
+#: src/views/user/User.vue:43
msgid "Action"
msgstr "操作"
@@ -205,6 +206,10 @@ msgstr "刪除站點:%{site_name}"
msgid "Development Mode"
msgstr "開發模式"
+#: src/views/config/config.ts:20
+msgid "Dir"
+msgstr ""
+
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
msgid "Directive"
msgstr "指令"
@@ -308,6 +313,10 @@ msgstr "啟用失敗 %{msg}"
msgid "Failed to get certificate information"
msgstr "獲取證書信息失敗"
+#: src/views/config/config.ts:22
+msgid "File"
+msgstr ""
+
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
msgid "File Not Found"
msgstr "未找到檔案"
@@ -443,7 +452,8 @@ msgstr "修改"
msgid "Modify Config"
msgstr "修改配置"
-#: src/views/domain/DomainEdit.vue:36 src/views/domain/DomainList.vue:15
+#: src/views/config/config.ts:9 src/views/domain/DomainEdit.vue:36
+#: src/views/domain/DomainList.vue:15
msgid "Name"
msgstr "名稱"
@@ -724,7 +734,12 @@ msgstr "用戶名或密碼不正確"
msgid "Theme"
msgstr "外觀樣式"
-#: src/views/domain/DomainList.vue:41 src/views/user/User.vue:37
+#: src/language/constants.ts:23 src/views/config/config.ts:14
+msgid "Type"
+msgstr ""
+
+#: src/views/config/config.ts:29 src/views/domain/DomainList.vue:41
+#: src/views/user/User.vue:37
msgid "Updated at"
msgstr "修改時間"
diff --git a/frontend/src/routes/index.ts b/frontend/src/routes/index.ts
index 2c843213..54d0d39b 100644
--- a/frontend/src/routes/index.ts
+++ b/frontend/src/routes/index.ts
@@ -10,7 +10,8 @@ import {
InfoCircleOutlined,
UserOutlined,
FileTextOutlined,
- SettingOutlined
+ SettingOutlined,
+ SafetyCertificateOutlined
} from '@ant-design/icons-vue'
const {$gettext} = gettext
@@ -91,6 +92,14 @@ export const routes = [
hiddenInSidebar: true
}
},
+ {
+ path: 'cert',
+ name: () => $gettext('Certification'),
+ component: () => import('@/views/cert/Cert.vue'),
+ meta: {
+ icon: SafetyCertificateOutlined
+ }
+ },
{
path: 'terminal',
name: () => $gettext('Terminal'),
diff --git a/frontend/src/version.json b/frontend/src/version.json
index 75a1ec37..fd5fa9ae 100644
--- a/frontend/src/version.json
+++ b/frontend/src/version.json
@@ -1 +1 @@
-{"version":"1.7.0","build_id":62,"total_build":132}
\ No newline at end of file
+{"version":"1.7.0","build_id":63,"total_build":133}
\ No newline at end of file
diff --git a/frontend/src/views/cert/Cert.vue b/frontend/src/views/cert/Cert.vue
new file mode 100644
index 00000000..7cd2cbec
--- /dev/null
+++ b/frontend/src/views/cert/Cert.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
diff --git a/frontend/src/views/config/config.tsx b/frontend/src/views/config/config.ts
similarity index 96%
rename from frontend/src/views/config/config.tsx
rename to frontend/src/views/config/config.ts
index 662a77e7..63a1bc18 100644
--- a/frontend/src/views/config/config.tsx
+++ b/frontend/src/views/config/config.ts
@@ -3,7 +3,6 @@ import gettext from '@/gettext'
const {$gettext} = gettext
-import {Badge} from 'ant-design-vue'
import {h} from 'vue'
const configColumns = [{
diff --git a/frontend/src/views/template/Template.vue b/frontend/src/views/template/Template.vue
new file mode 100644
index 00000000..0f413ca3
--- /dev/null
+++ b/frontend/src/views/template/Template.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/frontend/version.json b/frontend/version.json
index 75a1ec37..fd5fa9ae 100644
--- a/frontend/version.json
+++ b/frontend/version.json
@@ -1 +1 @@
-{"version":"1.7.0","build_id":62,"total_build":132}
\ No newline at end of file
+{"version":"1.7.0","build_id":63,"total_build":133}
\ No newline at end of file
diff --git a/server/api/cert.go b/server/api/cert.go
index 58a59d49..38bd43a5 100644
--- a/server/api/cert.go
+++ b/server/api/cert.go
@@ -6,6 +6,7 @@ import (
"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
+ "github.com/spf13/cast"
"log"
"net/http"
"strings"
@@ -117,7 +118,8 @@ func IssueCert(c *gin.Context) {
}
err = certModel.Updates(&model.Cert{
- SSLCertificatePath: sslCertificatePath,
+ SSLCertificatePath: sslCertificatePath,
+ SSLCertificateKeyPath: sslCertificateKeyPath,
})
if err != nil {
@@ -137,3 +139,108 @@ func IssueCert(c *gin.Context) {
}
}
+
+func GetCertList(c *gin.Context) {
+ certList := model.GetCertList(c.Query("name"), c.Query("domain"))
+
+ c.JSON(http.StatusOK, gin.H{
+ "data": certList,
+ })
+}
+
+func GetCert(c *gin.Context) {
+ certModel, err := model.FirstCertByID(cast.ToInt(c.Param("id")))
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ c.JSON(http.StatusOK, certModel)
+}
+
+func AddCert(c *gin.Context) {
+ var json struct {
+ Name string `json:"name" binding:"required"`
+ Domain string `json:"domain" binding:"required"`
+ SSLCertificatePath string `json:"ssl_certificate_path" binding:"required"`
+ SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
+ }
+ if !BindAndValid(c, &json) {
+ return
+ }
+ certModel, err := model.FirstOrCreateCert(json.Domain)
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ err = certModel.Updates(&model.Cert{
+ Name: json.Name,
+ Domain: json.Domain,
+ SSLCertificatePath: json.SSLCertificatePath,
+ SSLCertificateKeyPath: json.SSLCertificateKeyPath,
+ })
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ c.JSON(http.StatusOK, nil)
+}
+
+func ModifyCert(c *gin.Context) {
+ id := cast.ToInt(c.Param("id"))
+ certModel, err := model.FirstCertByID(id)
+
+ var json struct {
+ Name string `json:"name" binding:"required"`
+ Domain string `json:"domain" binding:"required"`
+ SSLCertificatePath string `json:"ssl_certificate_path" binding:"required"`
+ SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
+ }
+
+ if !BindAndValid(c, &json) {
+ return
+ }
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ err = certModel.Updates(&model.Cert{
+ Name: json.Name,
+ Domain: json.Domain,
+ SSLCertificatePath: json.SSLCertificatePath,
+ SSLCertificateKeyPath: json.SSLCertificateKeyPath,
+ })
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ c.JSON(http.StatusOK, certModel)
+}
+
+func RemoveCert(c *gin.Context) {
+ id := cast.ToInt(c.Param("id"))
+ certModel, err := model.FirstCertByID(id)
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ err = certModel.Remove()
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ c.JSON(http.StatusOK, nil)
+}
diff --git a/server/api/domain.go b/server/api/domain.go
index 00d5161c..211d2061 100644
--- a/server/api/domain.go
+++ b/server/api/domain.go
@@ -1,365 +1,381 @@
package api
import (
- "github.com/0xJacky/Nginx-UI/server/model"
- "github.com/0xJacky/Nginx-UI/server/pkg/cert"
- "github.com/0xJacky/Nginx-UI/server/pkg/config_list"
- "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
- "github.com/gin-gonic/gin"
- "log"
- "net/http"
- "os"
- "path/filepath"
- "strings"
- "time"
+ "github.com/0xJacky/Nginx-UI/server/model"
+ "github.com/0xJacky/Nginx-UI/server/pkg/cert"
+ "github.com/0xJacky/Nginx-UI/server/pkg/config_list"
+ "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
+ "github.com/gin-gonic/gin"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
)
func GetDomains(c *gin.Context) {
- name := c.Query("name")
- orderBy := c.Query("order_by")
- sort := c.DefaultQuery("sort", "desc")
+ name := c.Query("name")
+ orderBy := c.Query("order_by")
+ sort := c.DefaultQuery("sort", "desc")
- mySort := map[string]string{
- "enabled": "bool",
- "name": "string",
- "modify": "time",
- }
+ mySort := map[string]string{
+ "enabled": "bool",
+ "name": "string",
+ "modify": "time",
+ }
- configFiles, err := os.ReadDir(nginx.GetNginxConfPath("sites-available"))
+ configFiles, err := os.ReadDir(nginx.GetNginxConfPath("sites-available"))
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
+ enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- enabledConfigMap := make(map[string]bool)
- for i := range enabledConfig {
- enabledConfigMap[enabledConfig[i].Name()] = true
- }
+ enabledConfigMap := make(map[string]bool)
+ for i := range enabledConfig {
+ enabledConfigMap[enabledConfig[i].Name()] = true
+ }
- var configs []gin.H
+ var configs []gin.H
- for i := range configFiles {
- file := configFiles[i]
- fileInfo, _ := file.Info()
- if !file.IsDir() {
- if name != "" && !strings.Contains(file.Name(), name) {
- continue
- }
- configs = append(configs, gin.H{
- "name": file.Name(),
- "size": fileInfo.Size(),
- "modify": fileInfo.ModTime(),
- "enabled": enabledConfigMap[file.Name()],
- })
- }
- }
+ for i := range configFiles {
+ file := configFiles[i]
+ fileInfo, _ := file.Info()
+ if !file.IsDir() {
+ if name != "" && !strings.Contains(file.Name(), name) {
+ continue
+ }
+ configs = append(configs, gin.H{
+ "name": file.Name(),
+ "size": fileInfo.Size(),
+ "modify": fileInfo.ModTime(),
+ "enabled": enabledConfigMap[file.Name()],
+ })
+ }
+ }
- configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs)
+ configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs)
- c.JSON(http.StatusOK, gin.H{
- "data": configs,
- })
+ c.JSON(http.StatusOK, gin.H{
+ "data": configs,
+ })
}
type CertificateInfo struct {
- SubjectName string `json:"subject_name"`
- IssuerName string `json:"issuer_name"`
- NotAfter time.Time `json:"not_after"`
- NotBefore time.Time `json:"not_before"`
+ SubjectName string `json:"subject_name"`
+ IssuerName string `json:"issuer_name"`
+ NotAfter time.Time `json:"not_after"`
+ NotBefore time.Time `json:"not_before"`
}
func GetDomain(c *gin.Context) {
- rewriteName, ok := c.Get("rewriteConfigFileName")
+ rewriteName, ok := c.Get("rewriteConfigFileName")
- name := c.Param("name")
+ name := c.Param("name")
- // for modify filename
- if ok {
- name = rewriteName.(string)
- }
+ // for modify filename
+ if ok {
+ name = rewriteName.(string)
+ }
- path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+ path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
- enabled := true
- if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
- enabled = false
- }
+ enabled := true
+ if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
+ enabled = false
+ }
- config, err := nginx.ParseNgxConfig(path)
+ config, err := nginx.ParseNgxConfig(path)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- certInfoMap := make(map[int]CertificateInfo)
- var serverName string
- for serverIdx, server := range config.Servers {
- for _, directive := range server.Directives {
+ certInfoMap := make(map[int]CertificateInfo)
+ var serverName string
+ for serverIdx, server := range config.Servers {
+ for _, directive := range server.Directives {
- if directive.Directive == "server_name" {
- serverName = strings.ReplaceAll(directive.Params, " ", "_")
- continue
- }
+ if directive.Directive == "server_name" {
+ serverName = strings.ReplaceAll(directive.Params, " ", "_")
+ continue
+ }
- if directive.Directive == "ssl_certificate" {
+ if directive.Directive == "ssl_certificate" {
- pubKey, err := cert.GetCertInfo(directive.Params)
+ pubKey, err := cert.GetCertInfo(directive.Params)
- if err != nil {
- log.Println("Failed to get certificate information", err)
- break
- }
+ if err != nil {
+ log.Println("Failed to get certificate information", err)
+ break
+ }
- certInfoMap[serverIdx] = CertificateInfo{
- SubjectName: pubKey.Subject.CommonName,
- IssuerName: pubKey.Issuer.CommonName,
- NotAfter: pubKey.NotAfter,
- NotBefore: pubKey.NotBefore,
- }
+ certInfoMap[serverIdx] = CertificateInfo{
+ SubjectName: pubKey.Subject.CommonName,
+ IssuerName: pubKey.Issuer.CommonName,
+ NotAfter: pubKey.NotAfter,
+ NotBefore: pubKey.NotBefore,
+ }
- break
- }
- }
- }
+ break
+ }
+ }
+ }
- _, err = model.FirstCert(serverName)
+ certModel, _ := model.FirstCert(serverName)
- c.JSON(http.StatusOK, gin.H{
- "enabled": enabled,
- "name": name,
- "config": config.BuildConfig(),
- "tokenized": config,
- "auto_cert": err == nil,
- "cert_info": certInfoMap,
- })
+ c.JSON(http.StatusOK, gin.H{
+ "enabled": enabled,
+ "name": name,
+ "config": config.BuildConfig(),
+ "tokenized": config,
+ "auto_cert": certModel.AutoCert == model.AutoCertEnabled,
+ "cert_info": certInfoMap,
+ })
}
func EditDomain(c *gin.Context) {
- name := c.Param("name")
+ name := c.Param("name")
- if name == "" {
- c.JSON(http.StatusNotAcceptable, gin.H{
- "message": "param name is empty",
- })
- return
- }
+ if name == "" {
+ c.JSON(http.StatusNotAcceptable, gin.H{
+ "message": "param name is empty",
+ })
+ return
+ }
- var json struct {
- Name string `json:"name" binding:"required"`
- Content string `json:"content"`
- }
+ var json struct {
+ Name string `json:"name" binding:"required"`
+ Content string `json:"content"`
+ }
- if !BindAndValid(c, &json) {
- return
- }
+ if !BindAndValid(c, &json) {
+ return
+ }
- path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+ path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
- err := os.WriteFile(path, []byte(json.Content), 0644)
- if err != nil {
- ErrHandler(c, err)
- return
- }
- enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
- // rename the config file if needed
- if name != json.Name {
- newPath := filepath.Join(nginx.GetNginxConfPath("sites-available"), json.Name)
- // recreate soft link
- log.Println(enabledConfigFilePath)
- if _, err = os.Stat(enabledConfigFilePath); err == nil {
- log.Println(enabledConfigFilePath)
- _ = os.Remove(enabledConfigFilePath)
- enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), json.Name)
- err = os.Symlink(newPath, enabledConfigFilePath)
+ err := os.WriteFile(path, []byte(json.Content), 0644)
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+ enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
+ // rename the config file if needed
+ if name != json.Name {
+ newPath := filepath.Join(nginx.GetNginxConfPath("sites-available"), json.Name)
+ // recreate soft link
+ log.Println(enabledConfigFilePath)
+ if _, err = os.Stat(enabledConfigFilePath); err == nil {
+ log.Println(enabledConfigFilePath)
+ _ = os.Remove(enabledConfigFilePath)
+ enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), json.Name)
+ err = os.Symlink(newPath, enabledConfigFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
- }
- err = os.Rename(path, newPath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
- name = json.Name
- c.Set("rewriteConfigFileName", name)
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+ }
+ err = os.Rename(path, newPath)
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+ name = json.Name
+ c.Set("rewriteConfigFileName", name)
- }
+ }
- enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
- if _, err = os.Stat(enabledConfigFilePath); err == nil {
- // Test nginx configuration
- err = nginx.TestNginxConf()
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": err.Error(),
- })
- return
- }
+ enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
+ if _, err = os.Stat(enabledConfigFilePath); err == nil {
+ // Test nginx configuration
+ err = nginx.TestNginxConf()
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": err.Error(),
+ })
+ return
+ }
- output := nginx.ReloadNginx()
+ output := nginx.ReloadNginx()
- if output != "" && strings.Contains(output, "error") {
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": output,
- })
- return
- }
- }
+ if output != "" && strings.Contains(output, "error") {
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": output,
+ })
+ return
+ }
+ }
- GetDomain(c)
+ GetDomain(c)
}
func EnableDomain(c *gin.Context) {
- configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name"))
- enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
+ configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name"))
+ enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
- _, err := os.Stat(configFilePath)
+ _, err := os.Stat(configFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) {
- err = os.Symlink(configFilePath, enabledConfigFilePath)
+ if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) {
+ err = os.Symlink(configFilePath, enabledConfigFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+ }
- // Test nginx config, if not pass then rollback.
- err = nginx.TestNginxConf()
- if err != nil {
- _ = os.Remove(enabledConfigFilePath)
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": err.Error(),
- })
- return
- }
+ // Test nginx config, if not pass then rollback.
+ err = nginx.TestNginxConf()
+ if err != nil {
+ _ = os.Remove(enabledConfigFilePath)
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": err.Error(),
+ })
+ return
+ }
- output := nginx.ReloadNginx()
+ output := nginx.ReloadNginx()
- if output != "" && strings.Contains(output, "error") {
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": output,
- })
- return
- }
+ if output != "" && strings.Contains(output, "error") {
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": output,
+ })
+ return
+ }
- c.JSON(http.StatusOK, gin.H{
- "message": "ok",
- })
+ c.JSON(http.StatusOK, gin.H{
+ "message": "ok",
+ })
}
func DisableDomain(c *gin.Context) {
- enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
+ enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
- _, err := os.Stat(enabledConfigFilePath)
+ _, err := os.Stat(enabledConfigFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- err = os.Remove(enabledConfigFilePath)
+ err = os.Remove(enabledConfigFilePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- // delete auto cert record
- certModel := model.Cert{Domain: c.Param("name")}
- err = certModel.Remove()
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ // delete auto cert record
+ certModel := model.Cert{Domain: c.Param("name")}
+ err = certModel.Remove()
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- output := nginx.ReloadNginx()
+ output := nginx.ReloadNginx()
- if output != "" {
- c.JSON(http.StatusInternalServerError, gin.H{
- "message": output,
- })
- return
- }
+ if output != "" {
+ c.JSON(http.StatusInternalServerError, gin.H{
+ "message": output,
+ })
+ return
+ }
- c.JSON(http.StatusOK, gin.H{
- "message": "ok",
- })
+ c.JSON(http.StatusOK, gin.H{
+ "message": "ok",
+ })
}
func DeleteDomain(c *gin.Context) {
- var err error
- name := c.Param("name")
- availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
- enabledPath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
+ var err error
+ name := c.Param("name")
+ availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+ enabledPath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
- if _, err = os.Stat(availablePath); os.IsNotExist(err) {
- c.JSON(http.StatusNotFound, gin.H{
- "message": "site not found",
- })
- return
- }
+ if _, err = os.Stat(availablePath); os.IsNotExist(err) {
+ c.JSON(http.StatusNotFound, gin.H{
+ "message": "site not found",
+ })
+ return
+ }
- if _, err = os.Stat(enabledPath); err == nil {
- c.JSON(http.StatusNotAcceptable, gin.H{
- "message": "site is enabled",
- })
- return
- }
+ if _, err = os.Stat(enabledPath); err == nil {
+ c.JSON(http.StatusNotAcceptable, gin.H{
+ "message": "site is enabled",
+ })
+ return
+ }
- certModel := model.Cert{Domain: name}
- _ = certModel.Remove()
+ certModel := model.Cert{Domain: name}
+ _ = certModel.Remove()
- err = os.Remove(availablePath)
+ err = os.Remove(availablePath)
- if err != nil {
- ErrHandler(c, err)
- return
- }
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
- c.JSON(http.StatusOK, gin.H{
- "message": "ok",
- })
+ c.JSON(http.StatusOK, gin.H{
+ "message": "ok",
+ })
}
func AddDomainToAutoCert(c *gin.Context) {
- domain := c.Param("domain")
+ domain := c.Param("domain")
+ domain = strings.ReplaceAll(domain, " ", "_")
+ certModel, err := model.FirstOrCreateCert(domain)
- certModel, err := model.FirstOrCreateCert(domain)
- if err != nil {
- ErrHandler(c, err)
- return
- }
- c.JSON(http.StatusOK, certModel)
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ err = certModel.Updates(&model.Cert{
+ AutoCert: model.AutoCertEnabled,
+ })
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+
+ c.JSON(http.StatusOK, certModel)
}
func RemoveDomainFromAutoCert(c *gin.Context) {
- certModel := model.Cert{
- Domain: c.Param("domain"),
- }
- err := certModel.Remove()
+ domain := c.Param("domain")
+ domain = strings.ReplaceAll(domain, " ", "_")
+ certModel := model.Cert{
+ Domain: domain,
+ }
- if err != nil {
- ErrHandler(c, err)
- return
- }
- c.JSON(http.StatusOK, nil)
+ err := certModel.Updates(&model.Cert{
+ AutoCert: model.AutoCertDisabled,
+ })
+
+ if err != nil {
+ ErrHandler(c, err)
+ return
+ }
+ c.JSON(http.StatusOK, nil)
}
diff --git a/server/model/cert.go b/server/model/cert.go
index efabea4f..86f49e3d 100644
--- a/server/model/cert.go
+++ b/server/model/cert.go
@@ -6,10 +6,18 @@ import (
"path/filepath"
)
+const (
+ AutoCertEnabled = 1
+ AutoCertDisabled = -1
+)
+
type Cert struct {
Model
- Domain string `json:"domain"`
- SSLCertificatePath string `json:"ssl_certificate_path"`
+ Name string `json:"name"`
+ Domain string `json:"domain"`
+ SSLCertificatePath string `json:"ssl_certificate_path"`
+ SSLCertificateKeyPath string `json:"ssl_certificate_key_path"`
+ AutoCert int `json:"auto_cert"`
}
func FirstCert(domain string) (c Cert, err error) {
@@ -27,7 +35,7 @@ func FirstOrCreateCert(domain string) (c Cert, err error) {
func GetAutoCertList() (c []Cert) {
var t []Cert
- db.Find(&t)
+ db.Where("auto_cert", AutoCertEnabled).Find(&t)
// check if this domain is enabled
enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
@@ -50,6 +58,24 @@ func GetAutoCertList() (c []Cert) {
return
}
+func GetCertList(name, domain string) (c []Cert) {
+ tx := db
+ if name != "" {
+ tx = tx.Where("name LIKE ? or domain LIKE ?", "%"+name+"%", "%"+name+"%")
+ }
+ if domain != "" {
+ tx = tx.Where("domain LIKE ?", "%"+domain+"%")
+ }
+ tx.Find(&c)
+ return
+}
+
+func FirstCertByID(id int) (c Cert, err error) {
+ err = db.First(&c, id).Error
+
+ return
+}
+
func (c *Cert) Updates(n *Cert) error {
return db.Model(c).Updates(n).Error
}
diff --git a/server/router/routers.go b/server/router/routers.go
index b6017350..e782a106 100644
--- a/server/router/routers.go
+++ b/server/router/routers.go
@@ -77,10 +77,15 @@ func InitRouter() *gin.Engine {
g.GET("cert/issue", api.IssueCert)
+ g.GET("certs", api.GetCertList)
+ g.GET("cert/:id", api.GetCert)
+ g.POST("cert", api.AddCert)
+ g.POST("cert/:id", api.ModifyCert)
+ g.DELETE("cert/:id", api.RemoveCert)
// Add domain to auto-renew cert list
- g.POST("cert/:domain", api.AddDomainToAutoCert)
+ g.POST("auto_cert/:domain", api.AddDomainToAutoCert)
// Delete domain from auto-renew cert list
- g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert)
+ g.DELETE("auto_cert/:domain", api.RemoveDomainFromAutoCert)
// pty
g.GET("pty", api.Pty)