diff --git a/frontend/src/gettext.ts b/frontend/src/gettext.ts index 658a833a..83d93684 100644 --- a/frontend/src/gettext.ts +++ b/frontend/src/gettext.ts @@ -11,3 +11,6 @@ export default createGettext({ translations: translations, silent: true }) + +export class useGettext { +} diff --git a/frontend/src/language/constants.ts b/frontend/src/language/constants.ts new file mode 100644 index 00000000..44d26630 --- /dev/null +++ b/frontend/src/language/constants.ts @@ -0,0 +1,7 @@ +import gettext from '@/gettext' + +const {$gettext} = gettext + +export const msg = [ + $gettext('The username or password is incorrect') +] diff --git a/frontend/src/language/en/app.po b/frontend/src/language/en/app.po index a2c7c60d..2eb6a8a6 100644 --- a/frontend/src/language/en/app.po +++ b/frontend/src/language/en/app.po @@ -25,7 +25,7 @@ msgstr "" #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:31 #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:32 -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:33 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:34 msgid "Add Directive Below" msgstr "Add Directive Below" @@ -60,7 +60,7 @@ msgstr "Auto-renewal disabled for %{name}" msgid "Auto-renewal enabled for %{name}" msgstr "Auto-renewal enabled for %{name}" -#: src/views/domain/DomainEdit.vue:158 +#: src/views/domain/DomainEdit.vue:166 msgid "Back" msgstr "Back" @@ -101,7 +101,7 @@ msgstr "Certificate Status" #: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:29 #: src/views/domain/ngx_conf/LocationEditor.vue:21 #: src/views/domain/ngx_conf/LocationEditor.vue:7 -#: src/views/domain/ngx_conf/NgxConfigEditor.vue:145 +#: src/views/domain/ngx_conf/NgxConfigEditor.vue:154 msgid "Comments" msgstr "Comments" @@ -304,7 +304,7 @@ msgstr "Login successful" msgid "Logout successful" msgstr "Logout successful" -#: src/views/domain/cert/IssueCert.vue:172 +#: src/views/domain/cert/IssueCert.vue:181 msgid "" "Make sure you have configured a reverse proxy for .well-known directory to " "HTTPChallengePort (default: 9180) before getting the certificate." @@ -384,7 +384,7 @@ msgstr "Not Found" msgid "Not Valid Before: %{date}" msgstr "Not Valid Before: %{date}" -#: src/views/domain/cert/IssueCert.vue:164 +#: src/views/domain/cert/IssueCert.vue:173 msgid "" "Note: The server_name in the current configuration must be the domain name " "you need to get the certificate." @@ -402,7 +402,7 @@ msgstr "" msgid "OS:" msgstr "OS:" -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:21 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:22 msgid "Params" msgstr "Params" @@ -447,13 +447,13 @@ msgstr "Receive" msgid "Reset" msgstr "" -#: src/views/config/ConfigEdit.vue:52 src/views/domain/DomainEdit.vue:161 +#: src/views/config/ConfigEdit.vue:52 src/views/domain/DomainEdit.vue:169 msgid "Save" msgstr "Save" #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:32 #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:33 -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:34 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:35 msgid "Save Directive" msgstr "Save Directive" @@ -482,7 +482,7 @@ msgstr "Send" #: src/views/config/ConfigEdit.vue:22 src/views/domain/DomainEdit.vue:44 #: src/views/domain/DomainEdit.vue:56 src/views/domain/DomainEdit.vue:65 #: src/views/domain/DomainEdit.vue:83 src/views/domain/DomainList.vue:78 -#: src/views/other/Install.vue:71 src/views/other/Login.vue:56 +#: src/views/other/Install.vue:71 msgid "Server error" msgstr "Server error" @@ -494,11 +494,11 @@ msgstr "Server Info" msgid "server_name not found in directives" msgstr "server_name not found in directives" -#: src/views/domain/cert/IssueCert.vue:155 src/views/domain/DomainAdd.vue:112 +#: src/views/domain/cert/IssueCert.vue:164 src/views/domain/DomainAdd.vue:112 msgid "server_name parameter is required" msgstr "server_name parameter is required" -#: src/views/domain/cert/IssueCert.vue:158 +#: src/views/domain/cert/IssueCert.vue:167 #: src/views/domain/cert/IssueCert.vue:34 msgid "server_name parameters more than one" msgstr "server_name parameters more than one" @@ -536,7 +536,7 @@ msgstr "Enabled" msgid "Terminal" msgstr "Terminal" -#: src/views/domain/cert/IssueCert.vue:168 +#: src/views/domain/cert/IssueCert.vue:177 msgid "" "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." @@ -548,6 +548,10 @@ msgstr "" msgid "The filename cannot contain the following characters: %{c}" msgstr "The filename cannot contain the following characters: %{c}" +#: src/language/constants.ts:6 +msgid "The username or password is incorrect" +msgstr "" + #: src/views/config/Config.vue:17 src/views/domain/DomainList.vue:36 #: src/views/user/User.vue:36 msgid "Updated at" diff --git a/frontend/src/language/messages.pot b/frontend/src/language/messages.pot index 7de45112..761bfe8e 100644 --- a/frontend/src/language/messages.pot +++ b/frontend/src/language/messages.pot @@ -19,7 +19,7 @@ msgstr "" #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:31 #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:32 -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:33 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:34 msgid "Add Directive Below" msgstr "" @@ -54,7 +54,7 @@ msgstr "" msgid "Auto-renewal enabled for %{name}" msgstr "" -#: src/views/domain/DomainEdit.vue:158 +#: src/views/domain/DomainEdit.vue:166 msgid "Back" msgstr "" @@ -94,7 +94,7 @@ msgstr "" #: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:29 #: src/views/domain/ngx_conf/LocationEditor.vue:21 #: src/views/domain/ngx_conf/LocationEditor.vue:7 -#: src/views/domain/ngx_conf/NgxConfigEditor.vue:145 +#: src/views/domain/ngx_conf/NgxConfigEditor.vue:154 msgid "Comments" msgstr "" @@ -308,7 +308,7 @@ msgstr "" msgid "Logout successful" msgstr "" -#: src/views/domain/cert/IssueCert.vue:172 +#: src/views/domain/cert/IssueCert.vue:181 msgid "Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate." msgstr "" @@ -387,7 +387,7 @@ msgstr "" msgid "Not Valid Before: %{date}" msgstr "" -#: src/views/domain/cert/IssueCert.vue:164 +#: src/views/domain/cert/IssueCert.vue:173 msgid "Note: The server_name in the current configuration must be the domain name you need to get the certificate." msgstr "" @@ -401,7 +401,7 @@ msgstr "" msgid "OS:" msgstr "" -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:21 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:22 msgid "Params" msgstr "" @@ -451,13 +451,13 @@ msgid "Reset" msgstr "" #: src/views/config/ConfigEdit.vue:52 -#: src/views/domain/DomainEdit.vue:161 +#: src/views/domain/DomainEdit.vue:169 msgid "Save" msgstr "" #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:32 #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:33 -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:34 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:35 msgid "Save Directive" msgstr "" @@ -492,7 +492,6 @@ msgstr "" #: src/views/domain/DomainEdit.vue:83 #: src/views/domain/DomainList.vue:78 #: src/views/other/Install.vue:71 -#: src/views/other/Login.vue:56 msgid "Server error" msgstr "" @@ -504,12 +503,12 @@ msgstr "" msgid "server_name not found in directives" msgstr "" -#: src/views/domain/cert/IssueCert.vue:155 +#: src/views/domain/cert/IssueCert.vue:164 #: src/views/domain/DomainAdd.vue:112 msgid "server_name parameter is required" msgstr "" -#: src/views/domain/cert/IssueCert.vue:158 +#: src/views/domain/cert/IssueCert.vue:167 #: src/views/domain/cert/IssueCert.vue:34 msgid "server_name parameters more than one" msgstr "" @@ -547,7 +546,7 @@ msgstr "" msgid "Terminal" msgstr "" -#: src/views/domain/cert/IssueCert.vue:168 +#: src/views/domain/cert/IssueCert.vue:177 msgid "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." msgstr "" @@ -555,6 +554,10 @@ msgstr "" msgid "The filename cannot contain the following characters: %{c}" msgstr "" +#: src/language/constants.ts:6 +msgid "The username or password is incorrect" +msgstr "" + #: src/views/config/Config.vue:17 #: src/views/domain/DomainList.vue:36 #: src/views/user/User.vue:36 diff --git a/frontend/src/language/translations.json b/frontend/src/language/translations.json index 593232ce..bba8674c 100644 --- a/frontend/src/language/translations.json +++ b/frontend/src/language/translations.json @@ -1 +1 @@ -{"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","server_name parameters more than one":"server_name parameters more than one","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":"關於","Action":"操作","Add Directive Below":"在下面新增指令","Add Location":"新增 Location","Add Site":"新增站點","Advance Mode":"高階模式","Are you sure you want to remove this directive?":"您確定要刪除這條指令?","Auto-renewal disabled for %{name}":"已關閉 %{name} 自動續簽","Auto-renewal enabled for %{name}":"已啟用 %{name} 自動續簽","Back":"返回","Base information":"基本訊息","Basic Mode":"基本模式","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":"建立時間","Dashboard":"儀表盤","Database (Optional, default: database)":"資料庫 (可選,預設: database)","Delete ID: %{id}":"刪除 ID: %{id}","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 對網站進行加密","Expiration Date: %{date}":"過期時間: %{date}","Failed to disable %{msg}":"禁用失敗 %{msg}","Failed to enable %{msg}":"啟用失敗 %{msg}","File Not Found":"未找到檔案","Finished":"完成","Getting the certificate, please wait...":"正在獲取憑證,請稍等...","Home":"首頁","Install":"安裝","Intermediate Certification Authorities: %{issuer}":"中級憑證頒發機構: %{issuer}","Leave blank for no change":"留空表示不修改","Load Averages:":"系統負載:","Location":"Location","Locations":"Locations","Login":"登入","Login successful":"登入成功","Logout successful":"登出成功","Manage Configs":"配置管理","Manage Sites":"網站管理","Manage Users":"使用者管理","Memory":"記憶體","Memory and Storage":"記憶體和存儲","Modify Config":"修改配置","Name":"名稱","Network":"網路","Network Statistics":"網路統計","Network Total Receive":"下載流量","Network Total Send":"上傳流量","Next":"下一步","No":"取消","Not Found":"找不到頁面","Not Valid Before: %{date}":"此前無效: %{date}","OK":"確定","OS:":"作業系統:","Params":"參數","Password":"密碼","Password (*)":"密碼 (*)","Path":"路徑","Please input your E-mail!":"請輸入您的郵箱!","Please input your password!":"請輸入您的密碼!","Please input your username!":"請輸入您的使用者名稱!","Project Team":"專案團隊","Reads":"讀","Receive":"下載","Save":"儲存","Save Directive":"儲存指令","Save error %{msg}":"儲存錯誤 %{msg}","Saved successfully":"儲存成功","Send":"上傳","Server error":"伺服器錯誤","Server Info":"伺服器資訊","server_name not found in directives":"未在指令集合中找到 server_name","server_name parameter is required":"必須為 server_name 指令指明參數","server_name parameters more than one":"server_name 指令包含多個參數","Single Directive":"單行指令","Sites List":"站點列表","Status":"狀態","Storage":"儲存","Subject Name: %{name}":"主體名稱: %{name}","Swap":"交換空間","Terminal":"終端","The filename cannot contain the following characters: %{c}":"檔名不能包含以下字元: %{c}","Updated at":"修改時間","Uptime:":"執行時間:","Username":"使用者名稱","Username (*)":"使用者名稱 (*)","Warning":"警告","Writes":"寫","Yes":"是的","License":{"Project":"開源軟體授權條款"}},"zh_CN":{"About":"关于","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?":"您确定要删除这条指令?","Auto-renewal disabled for %{name}":"成功关闭 %{name} 自动续签","Auto-renewal enabled for %{name}":"成功启用 %{name} 自动续签","Back":"返回","Back Home":"返回首页","Base information":"基本信息","Basic Mode":"基本模式","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":"创建时间","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 对网站进行加密","Expiration Date: %{date}":"过期时间: %{date}","Failed to disable %{msg}":"禁用失败 %{msg}","Failed to enable %{msg}":"启用失败 %{msg}","File Not Found":"未找到文件","Finished":"完成","Getting the certificate, please wait...":"正在获取证书,请稍等...","Home":"首页","Install":"安装","Install successfully":"安装成功","Intermediate Certification Authorities: %{issuer}":"中级证书颁发机构: %{issuer}","Leave blank for no change":"留空表示不修改","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":"下一步","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 必须为需要申请证书的域名。","OK":"确定","Params":"参数","Password":"密码","Password (*)":"密码 (*)","Path":"路径","Please input your E-mail!":"请输入您的邮箱!","Please input your password!":"请输入您的密码!","Please input your username!":"请输入您的用户名!","Project Team":"项目团队","Reads":"读","Receive":"下载","Reset":"重置","Save":"保存","Save Directive":"保存指令","Save error %{msg}":"保存错误 %{msg}","Save Successfully":"保存成功","Saved successfully":"保存成功","Send":"上传","Server error":"服务器错误","Server Info":"服务器信息","server_name not found in directives":"未在指令集合中找到 server_name","server_name parameter is required":"必须为 server_name 指令指明参数","server_name parameters more than one":"server_name 指令包含多个参数","Single Directive":"单行指令","Sites List":"站点列表","Status":"状态","Storage":"存储","Subject Name: %{name}":"主体名称: %{name}","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个月,则将自动续签。","The filename cannot contain the following characters: %{c}":"文件名不能包含以下字符: %{c}","Updated at":"修改时间","Uptime:":"运行时间:","Username":"用户名","Username (*)":"用户名 (*)","Warning":"警告","Writes":"写","Yes":"是的","License":{"Project":"开源许可"}}} \ No newline at end of file +{"zh_CN":{"About":"关于","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?":"您确定要删除这条指令?","Auto-renewal disabled for %{name}":"成功关闭 %{name} 自动续签","Auto-renewal enabled for %{name}":"成功启用 %{name} 自动续签","Back":"返回","Back Home":"返回首页","Base information":"基本信息","Basic Mode":"基本模式","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":"创建时间","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 对网站进行加密","Expiration Date: %{date}":"过期时间: %{date}","Failed to disable %{msg}":"禁用失败 %{msg}","Failed to enable %{msg}":"启用失败 %{msg}","File Not Found":"未找到文件","Finished":"完成","Getting the certificate, please wait...":"正在获取证书,请稍等...","Home":"首页","Install":"安装","Install successfully":"安装成功","Intermediate Certification Authorities: %{issuer}":"中级证书颁发机构: %{issuer}","Leave blank for no change":"留空表示不修改","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":"下一步","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 必须为需要申请证书的域名。","OK":"确定","Params":"参数","Password":"密码","Password (*)":"密码 (*)","Path":"路径","Please input your E-mail!":"请输入您的邮箱!","Please input your password!":"请输入您的密码!","Please input your username!":"请输入您的用户名!","Project Team":"项目团队","Reads":"读","Receive":"下载","Reset":"重置","Save":"保存","Save Directive":"保存指令","Save error %{msg}":"保存错误 %{msg}","Save Successfully":"保存成功","Saved successfully":"保存成功","Send":"上传","Server error":"服务器错误","Server Info":"服务器信息","server_name not found in directives":"未在指令集合中找到 server_name","server_name parameter is required":"必须为 server_name 指令指明参数","server_name parameters more than one":"server_name 指令包含多个参数","Single Directive":"单行指令","Sites List":"站点列表","Status":"状态","Storage":"存储","Subject Name: %{name}":"主体名称: %{name}","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个月,则将自动续签。","The filename cannot contain the following characters: %{c}":"文件名不能包含以下字符: %{c}","The username or password is incorrect":"用户名或密码错误","Updated at":"修改时间","Uptime:":"运行时间:","Username":"用户名","Username (*)":"用户名 (*)","Warning":"警告","Writes":"写","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","server_name parameters more than one":"server_name parameters more than one","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":"關於","Action":"操作","Add Directive Below":"在下面新增指令","Add Location":"新增 Location","Add Site":"新增站點","Advance Mode":"高階模式","Are you sure you want to remove this directive?":"您確定要刪除這條指令?","Auto-renewal disabled for %{name}":"已關閉 %{name} 自動續簽","Auto-renewal enabled for %{name}":"已啟用 %{name} 自動續簽","Back":"返回","Base information":"基本訊息","Basic Mode":"基本模式","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":"建立時間","Dashboard":"儀表盤","Database (Optional, default: database)":"資料庫 (可選,預設: database)","Delete ID: %{id}":"刪除 ID: %{id}","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 對網站進行加密","Expiration Date: %{date}":"過期時間: %{date}","Failed to disable %{msg}":"禁用失敗 %{msg}","Failed to enable %{msg}":"啟用失敗 %{msg}","File Not Found":"未找到檔案","Finished":"完成","Getting the certificate, please wait...":"正在獲取憑證,請稍等...","Home":"首頁","Install":"安裝","Intermediate Certification Authorities: %{issuer}":"中級憑證頒發機構: %{issuer}","Leave blank for no change":"留空表示不修改","Load Averages:":"系統負載:","Location":"Location","Locations":"Locations","Login":"登入","Login successful":"登入成功","Logout successful":"登出成功","Manage Configs":"配置管理","Manage Sites":"網站管理","Manage Users":"使用者管理","Memory":"記憶體","Memory and Storage":"記憶體和存儲","Modify Config":"修改配置","Name":"名稱","Network":"網路","Network Statistics":"網路統計","Network Total Receive":"下載流量","Network Total Send":"上傳流量","Next":"下一步","No":"取消","Not Found":"找不到頁面","Not Valid Before: %{date}":"此前無效: %{date}","OK":"確定","OS:":"作業系統:","Params":"參數","Password":"密碼","Password (*)":"密碼 (*)","Path":"路徑","Please input your E-mail!":"請輸入您的郵箱!","Please input your password!":"請輸入您的密碼!","Please input your username!":"請輸入您的使用者名稱!","Project Team":"專案團隊","Reads":"讀","Receive":"下載","Save":"儲存","Save Directive":"儲存指令","Save error %{msg}":"儲存錯誤 %{msg}","Saved successfully":"儲存成功","Send":"上傳","Server error":"伺服器錯誤","Server Info":"伺服器資訊","server_name not found in directives":"未在指令集合中找到 server_name","server_name parameter is required":"必須為 server_name 指令指明參數","server_name parameters more than one":"server_name 指令包含多個參數","Single Directive":"單行指令","Sites List":"站點列表","Status":"狀態","Storage":"儲存","Subject Name: %{name}":"主體名稱: %{name}","Swap":"交換空間","Terminal":"終端","The filename cannot contain the following characters: %{c}":"檔名不能包含以下字元: %{c}","Updated at":"修改時間","Uptime:":"執行時間:","Username":"使用者名稱","Username (*)":"使用者名稱 (*)","Warning":"警告","Writes":"寫","Yes":"是的","License":{"Project":"開源軟體授權條款"}}} \ 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 2ba8f47f..003a87e8 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 4d4d54db..44bd8226 100644 --- a/frontend/src/language/zh_CN/app.po +++ b/frontend/src/language/zh_CN/app.po @@ -28,7 +28,7 @@ msgstr "添加" #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:31 #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:32 -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:33 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:34 msgid "Add Directive Below" msgstr "在下面添加指令" @@ -62,7 +62,7 @@ msgstr "成功关闭 %{name} 自动续签" msgid "Auto-renewal enabled for %{name}" msgstr "成功启用 %{name} 自动续签" -#: src/views/domain/DomainEdit.vue:158 +#: src/views/domain/DomainEdit.vue:166 msgid "Back" msgstr "返回" @@ -102,7 +102,7 @@ msgstr "证书状态" #: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:29 #: src/views/domain/ngx_conf/LocationEditor.vue:21 #: src/views/domain/ngx_conf/LocationEditor.vue:7 -#: src/views/domain/ngx_conf/NgxConfigEditor.vue:145 +#: src/views/domain/ngx_conf/NgxConfigEditor.vue:154 msgid "Comments" msgstr "注释" @@ -304,7 +304,7 @@ msgstr "登录成功" msgid "Logout successful" msgstr "登出成功" -#: src/views/domain/cert/IssueCert.vue:172 +#: src/views/domain/cert/IssueCert.vue:181 msgid "" "Make sure you have configured a reverse proxy for .well-known directory to " "HTTPChallengePort (default: 9180) before getting the certificate." @@ -383,7 +383,7 @@ msgstr "找不到页面" msgid "Not Valid Before: %{date}" msgstr "此前无效: %{date}" -#: src/views/domain/cert/IssueCert.vue:164 +#: src/views/domain/cert/IssueCert.vue:173 msgid "" "Note: The server_name in the current configuration must be the domain name " "you need to get the certificate." @@ -399,7 +399,7 @@ msgstr "确定" msgid "OS:" msgstr "" -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:21 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:22 msgid "Params" msgstr "参数" @@ -444,13 +444,13 @@ msgstr "下载" msgid "Reset" msgstr "重置" -#: src/views/config/ConfigEdit.vue:52 src/views/domain/DomainEdit.vue:161 +#: src/views/config/ConfigEdit.vue:52 src/views/domain/DomainEdit.vue:169 msgid "Save" msgstr "保存" #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:32 #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:33 -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:34 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:35 msgid "Save Directive" msgstr "保存指令" @@ -478,7 +478,7 @@ msgstr "上传" #: src/views/config/ConfigEdit.vue:22 src/views/domain/DomainEdit.vue:44 #: src/views/domain/DomainEdit.vue:56 src/views/domain/DomainEdit.vue:65 #: src/views/domain/DomainEdit.vue:83 src/views/domain/DomainList.vue:78 -#: src/views/other/Install.vue:71 src/views/other/Login.vue:56 +#: src/views/other/Install.vue:71 msgid "Server error" msgstr "服务器错误" @@ -490,11 +490,11 @@ msgstr "服务器信息" msgid "server_name not found in directives" msgstr "未在指令集合中找到 server_name" -#: src/views/domain/cert/IssueCert.vue:155 src/views/domain/DomainAdd.vue:112 +#: src/views/domain/cert/IssueCert.vue:164 src/views/domain/DomainAdd.vue:112 msgid "server_name parameter is required" msgstr "必须为 server_name 指令指明参数" -#: src/views/domain/cert/IssueCert.vue:158 +#: src/views/domain/cert/IssueCert.vue:167 #: src/views/domain/cert/IssueCert.vue:34 msgid "server_name parameters more than one" msgstr "server_name 指令包含多个参数" @@ -531,7 +531,7 @@ msgstr "列表" msgid "Terminal" msgstr "终端" -#: src/views/domain/cert/IssueCert.vue:168 +#: src/views/domain/cert/IssueCert.vue:177 msgid "" "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." @@ -542,6 +542,10 @@ msgstr "" msgid "The filename cannot contain the following characters: %{c}" msgstr "文件名不能包含以下字符: %{c}" +#: src/language/constants.ts:6 +msgid "The username or password is incorrect" +msgstr "用户名或密码错误" + #: src/views/config/Config.vue:17 src/views/domain/DomainList.vue:36 #: src/views/user/User.vue:36 msgid "Updated at" diff --git a/frontend/src/language/zh_TW/app.po b/frontend/src/language/zh_TW/app.po index 4d34241e..9eee4eff 100644 --- a/frontend/src/language/zh_TW/app.po +++ b/frontend/src/language/zh_TW/app.po @@ -29,7 +29,7 @@ msgstr "" #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:31 #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:32 -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:33 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:34 msgid "Add Directive Below" msgstr "在下面新增指令" @@ -64,7 +64,7 @@ msgstr "已關閉 %{name} 自動續簽" msgid "Auto-renewal enabled for %{name}" msgstr "已啟用 %{name} 自動續簽" -#: src/views/domain/DomainEdit.vue:158 +#: src/views/domain/DomainEdit.vue:166 msgid "Back" msgstr "返回" @@ -105,7 +105,7 @@ msgstr "憑證狀態" #: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:29 #: src/views/domain/ngx_conf/LocationEditor.vue:21 #: src/views/domain/ngx_conf/LocationEditor.vue:7 -#: src/views/domain/ngx_conf/NgxConfigEditor.vue:145 +#: src/views/domain/ngx_conf/NgxConfigEditor.vue:154 msgid "Comments" msgstr "註釋" @@ -309,7 +309,7 @@ msgstr "登入成功" msgid "Logout successful" msgstr "登出成功" -#: src/views/domain/cert/IssueCert.vue:172 +#: src/views/domain/cert/IssueCert.vue:181 #, fuzzy msgid "" "Make sure you have configured a reverse proxy for .well-known directory to " @@ -390,7 +390,7 @@ msgstr "找不到頁面" msgid "Not Valid Before: %{date}" msgstr "此前無效: %{date}" -#: src/views/domain/cert/IssueCert.vue:164 +#: src/views/domain/cert/IssueCert.vue:173 #, fuzzy msgid "" "Note: The server_name in the current configuration must be the domain name " @@ -407,7 +407,7 @@ msgstr "確定" msgid "OS:" msgstr "作業系統:" -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:21 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:22 msgid "Params" msgstr "參數" @@ -452,13 +452,13 @@ msgstr "下載" msgid "Reset" msgstr "" -#: src/views/config/ConfigEdit.vue:52 src/views/domain/DomainEdit.vue:161 +#: src/views/config/ConfigEdit.vue:52 src/views/domain/DomainEdit.vue:169 msgid "Save" msgstr "儲存" #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:32 #: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:33 -#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:34 +#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:35 msgid "Save Directive" msgstr "儲存指令" @@ -487,7 +487,7 @@ msgstr "上傳" #: src/views/config/ConfigEdit.vue:22 src/views/domain/DomainEdit.vue:44 #: src/views/domain/DomainEdit.vue:56 src/views/domain/DomainEdit.vue:65 #: src/views/domain/DomainEdit.vue:83 src/views/domain/DomainList.vue:78 -#: src/views/other/Install.vue:71 src/views/other/Login.vue:56 +#: src/views/other/Install.vue:71 msgid "Server error" msgstr "伺服器錯誤" @@ -499,11 +499,11 @@ msgstr "伺服器資訊" msgid "server_name not found in directives" msgstr "未在指令集合中找到 server_name" -#: src/views/domain/cert/IssueCert.vue:155 src/views/domain/DomainAdd.vue:112 +#: src/views/domain/cert/IssueCert.vue:164 src/views/domain/DomainAdd.vue:112 msgid "server_name parameter is required" msgstr "必須為 server_name 指令指明參數" -#: src/views/domain/cert/IssueCert.vue:158 +#: src/views/domain/cert/IssueCert.vue:167 #: src/views/domain/cert/IssueCert.vue:34 msgid "server_name parameters more than one" msgstr "server_name 指令包含多個參數" @@ -541,7 +541,7 @@ msgstr "啟用" msgid "Terminal" msgstr "終端" -#: src/views/domain/cert/IssueCert.vue:168 +#: src/views/domain/cert/IssueCert.vue:177 #, fuzzy msgid "" "The certificate for the domain will be checked every hour, and will be " @@ -554,6 +554,10 @@ msgstr "" msgid "The filename cannot contain the following characters: %{c}" msgstr "檔名不能包含以下字元: %{c}" +#: src/language/constants.ts:6 +msgid "The username or password is incorrect" +msgstr "" + #: src/views/config/Config.vue:17 src/views/domain/DomainList.vue:36 #: src/views/user/User.vue:36 msgid "Updated at" diff --git a/frontend/src/views/other/Login.vue b/frontend/src/views/other/Login.vue index 14a8bb98..cd42c965 100644 --- a/frontend/src/views/other/Login.vue +++ b/frontend/src/views/other/Login.vue @@ -53,7 +53,7 @@ const onSubmit = () => { const next = (route.query?.next || '').toString() || '/' await router.push(next) }).catch(e => { - message.error(e.message ?? $gettext('Server error')) + message.error($gettext(e.message ?? 'Server error')) }) }) } diff --git a/main.go b/main.go index fde685a6..8957755d 100644 --- a/main.go +++ b/main.go @@ -5,10 +5,10 @@ import ( "flag" "github.com/0xJacky/Nginx-UI/server/analytic" "github.com/0xJacky/Nginx-UI/server/model" + "github.com/0xJacky/Nginx-UI/server/pkg/cert" + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "github.com/0xJacky/Nginx-UI/server/router" "github.com/0xJacky/Nginx-UI/server/settings" - "github.com/0xJacky/Nginx-UI/server/tool" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" "github.com/gin-gonic/gin" "github.com/go-co-op/gocron" "log" @@ -40,7 +40,7 @@ func main() { model.Init() s := gocron.NewScheduler(time.UTC) - job, err := s.Every(1).Hour().SingletonMode().Do(tool.AutoCert) + job, err := s.Every(1).Hour().SingletonMode().Do(cert.AutoCert) if err != nil { log.Fatalf("AutoCert Job: %v, Err: %v\n", job, err) diff --git a/server/api/api.go b/server/api/api.go index 930c84db..95ed77f6 100644 --- a/server/api/api.go +++ b/server/api/api.go @@ -41,8 +41,9 @@ func BindAndValid(c *gin.Context, target interface{}) bool { if !ok { log.Println("verrs", verrs) c.JSON(http.StatusNotAcceptable, gin.H{ - "message": "请求参数错误", + "message": "Requested with wrong parameters", "code": http.StatusNotAcceptable, + "error": verrs, }) return false } @@ -56,7 +57,7 @@ func BindAndValid(c *gin.Context, target interface{}) bool { c.JSON(http.StatusNotAcceptable, gin.H{ "errors": errs, - "message": "请求参数错误", + "message": "Requested with wrong parameters", "code": http.StatusNotAcceptable, }) diff --git a/server/api/auth.go b/server/api/auth.go index b01ce0f1..ff3a1b60 100644 --- a/server/api/auth.go +++ b/server/api/auth.go @@ -23,7 +23,7 @@ func Login(c *gin.Context) { if err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(user.Password)); err != nil { c.JSON(http.StatusForbidden, gin.H{ - "message": "用户名或密码错误", + "message": "The username or password is incorrect", }) return } diff --git a/server/api/cert.go b/server/api/cert.go index 09103cdd..fad64fb5 100644 --- a/server/api/cert.go +++ b/server/api/cert.go @@ -1,8 +1,8 @@ package api import ( - "github.com/0xJacky/Nginx-UI/server/tool" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" + "github.com/0xJacky/Nginx-UI/server/pkg/cert" + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "log" @@ -13,7 +13,7 @@ import ( func CertInfo(c *gin.Context) { domain := c.Param("domain") - key, err := tool.GetCertInfo(domain) + key, err := cert.GetCertInfo(domain) if err != nil { c.JSON(http.StatusOK, gin.H{ @@ -61,7 +61,7 @@ func IssueCert(c *gin.Context) { if mt == websocket.TextMessage && string(message) == "go" { - err = tool.IssueCert(domain) + err = cert.IssueCert(domain) if err != nil { diff --git a/server/api/config.go b/server/api/config.go index e23a362b..8c6b535e 100644 --- a/server/api/config.go +++ b/server/api/config.go @@ -1,10 +1,9 @@ package api import ( - "github.com/0xJacky/Nginx-UI/server/tool" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" + "github.com/0xJacky/Nginx-UI/server/pkg/config_list" + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "github.com/gin-gonic/gin" - "io/ioutil" "log" "net/http" "os" @@ -21,7 +20,7 @@ func GetConfigs(c *gin.Context) { "modify": "time", } - configFiles, err := ioutil.ReadDir(nginx.GetNginxConfPath("/")) + configFiles, err := os.ReadDir(nginx.GetNginxConfPath("/")) if err != nil { ErrHandler(c, err) @@ -32,17 +31,18 @@ func GetConfigs(c *gin.Context) { for i := range configFiles { file := configFiles[i] + fileInfo, _ := file.Info() if !file.IsDir() && "." != file.Name()[0:1] { configs = append(configs, gin.H{ "name": file.Name(), - "size": file.Size(), - "modify": file.ModTime(), + "size": fileInfo.Size(), + "modify": fileInfo.ModTime(), }) } } - configs = tool.Sort(orderBy, sort, mySort[orderBy], configs) + configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs) c.JSON(http.StatusOK, gin.H{ "data": configs, @@ -53,7 +53,7 @@ func GetConfig(c *gin.Context) { name := c.Param("name") path := filepath.Join(nginx.GetNginxConfPath("/"), name) - content, err := ioutil.ReadFile(path) + content, err := os.ReadFile(path) if err != nil { ErrHandler(c, err) @@ -93,7 +93,7 @@ func AddConfig(c *gin.Context) { } if content != "" { - err := ioutil.WriteFile(path, []byte(content), 0644) + err = os.WriteFile(path, []byte(content), 0644) if err != nil { ErrHandler(c, err) return @@ -131,7 +131,7 @@ func EditConfig(c *gin.Context) { path := filepath.Join(nginx.GetNginxConfPath("/"), name) content := request.Content - origContent, err := ioutil.ReadFile(path) + origContent, err := os.ReadFile(path) if err != nil { ErrHandler(c, err) return @@ -139,7 +139,7 @@ func EditConfig(c *gin.Context) { if content != "" && content != string(origContent) { // model.CreateBackup(path) - err := ioutil.WriteFile(path, []byte(content), 0644) + err = os.WriteFile(path, []byte(content), 0644) if err != nil { ErrHandler(c, err) return diff --git a/server/api/domain.go b/server/api/domain.go index 29259458..d74d2bde 100644 --- a/server/api/domain.go +++ b/server/api/domain.go @@ -2,10 +2,9 @@ package api import ( "github.com/0xJacky/Nginx-UI/server/model" - "github.com/0xJacky/Nginx-UI/server/tool" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" + "github.com/0xJacky/Nginx-UI/server/pkg/config_list" + nginx2 "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "github.com/gin-gonic/gin" - "io/ioutil" "net/http" "os" "path/filepath" @@ -22,14 +21,14 @@ func GetDomains(c *gin.Context) { "modify": "time", } - configFiles, err := ioutil.ReadDir(nginx.GetNginxConfPath("sites-available")) + configFiles, err := os.ReadDir(nginx2.GetNginxConfPath("sites-available")) if err != nil { ErrHandler(c, err) return } - enabledConfig, err := ioutil.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled"))) + enabledConfig, err := os.ReadDir(filepath.Join(nginx2.GetNginxConfPath("sites-enabled"))) if err != nil { ErrHandler(c, err) @@ -45,17 +44,18 @@ func GetDomains(c *gin.Context) { for i := range configFiles { file := configFiles[i] + fileInfo, _ := file.Info() if !file.IsDir() { configs = append(configs, gin.H{ "name": file.Name(), - "size": file.Size(), - "modify": file.ModTime(), + "size": fileInfo.Size(), + "modify": fileInfo.ModTime(), "enabled": enabledConfigMap[file.Name()], }) } } - configs = tool.Sort(orderBy, sort, mySort[orderBy], configs) + configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs) c.JSON(http.StatusOK, gin.H{ "data": configs, @@ -64,14 +64,14 @@ func GetDomains(c *gin.Context) { func GetDomain(c *gin.Context) { name := c.Param("name") - path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name) + path := filepath.Join(nginx2.GetNginxConfPath("sites-available"), name) enabled := true - if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) { + if _, err := os.Stat(filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) { enabled = false } - config, err := nginx.ParseNgxConfig(path) + config, err := nginx2.ParseNgxConfig(path) if err != nil { ErrHandler(c, err) @@ -95,18 +95,18 @@ func EditDomain(c *gin.Context) { name := c.Param("name") request := make(gin.H) err = c.BindJSON(&request) - path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name) + path := filepath.Join(nginx2.GetNginxConfPath("sites-available"), name) - err = ioutil.WriteFile(path, []byte(request["content"].(string)), 0644) + err = os.WriteFile(path, []byte(request["content"].(string)), 0644) if err != nil { ErrHandler(c, err) return } - enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name) + enabledConfigFilePath := filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), name) if _, err = os.Stat(enabledConfigFilePath); err == nil { // Test nginx configuration - err = nginx.TestNginxConf() + err = nginx2.TestNginxConf() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "message": err.Error(), @@ -114,7 +114,7 @@ func EditDomain(c *gin.Context) { return } - output := nginx.ReloadNginx() + output := nginx2.ReloadNginx() if output != "" && strings.Contains(output, "error") { c.JSON(http.StatusInternalServerError, gin.H{ @@ -128,8 +128,8 @@ func EditDomain(c *gin.Context) { } 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(nginx2.GetNginxConfPath("sites-available"), c.Param("name")) + enabledConfigFilePath := filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), c.Param("name")) _, err := os.Stat(configFilePath) @@ -148,7 +148,7 @@ func EnableDomain(c *gin.Context) { } // Test nginx config, if not pass then rollback. - err = nginx.TestNginxConf() + err = nginx2.TestNginxConf() if err != nil { _ = os.Remove(enabledConfigFilePath) c.JSON(http.StatusInternalServerError, gin.H{ @@ -157,7 +157,7 @@ func EnableDomain(c *gin.Context) { return } - output := nginx.ReloadNginx() + output := nginx2.ReloadNginx() if output != "" && strings.Contains(output, "error") { c.JSON(http.StatusInternalServerError, gin.H{ @@ -172,7 +172,7 @@ func EnableDomain(c *gin.Context) { } func DisableDomain(c *gin.Context) { - enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name")) + enabledConfigFilePath := filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), c.Param("name")) _, err := os.Stat(enabledConfigFilePath) @@ -196,7 +196,7 @@ func DisableDomain(c *gin.Context) { return } - output := nginx.ReloadNginx() + output := nginx2.ReloadNginx() if output != "" { c.JSON(http.StatusInternalServerError, gin.H{ @@ -213,8 +213,8 @@ func DisableDomain(c *gin.Context) { 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) + availablePath := filepath.Join(nginx2.GetNginxConfPath("sites-available"), name) + enabledPath := filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), name) if _, err = os.Stat(availablePath); os.IsNotExist(err) { c.JSON(http.StatusNotFound, gin.H{ diff --git a/server/api/ngx.go b/server/api/ngx.go index bbfd32eb..9cef7daf 100644 --- a/server/api/ngx.go +++ b/server/api/ngx.go @@ -2,14 +2,14 @@ package api import ( "bufio" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" + nginx2 "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "github.com/gin-gonic/gin" "net/http" "strings" ) func BuildNginxConfig(c *gin.Context) { - var ngxConf nginx.NgxConfig + var ngxConf nginx2.NgxConfig if !BindAndValid(c, &ngxConf) { return } @@ -30,7 +30,7 @@ func TokenizeNginxConfig(c *gin.Context) { scanner := bufio.NewScanner(strings.NewReader(json.Content)) - ngxConfig, err := nginx.ParseNgxConfigByScanner("", scanner) + ngxConfig, err := nginx2.ParseNgxConfigByScanner("", scanner) if err != nil { ErrHandler(c, err) diff --git a/server/api/pty.go b/server/api/pty.go index 76fd07db..f6716dae 100644 --- a/server/api/pty.go +++ b/server/api/pty.go @@ -1,7 +1,7 @@ package api import ( - "github.com/0xJacky/Nginx-UI/server/tool/pty" + "github.com/0xJacky/Nginx-UI/server/pkg/pty" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "log" diff --git a/server/api/template.go b/server/api/template.go index 4dab63d0..c7b5a5cb 100644 --- a/server/api/template.go +++ b/server/api/template.go @@ -1,8 +1,8 @@ package api import ( + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "github.com/0xJacky/Nginx-UI/server/settings" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" "github.com/gin-gonic/gin" "net/http" "strings" diff --git a/server/api/user.go b/server/api/user.go index 13b64da9..38700e8e 100644 --- a/server/api/user.go +++ b/server/api/user.go @@ -91,7 +91,7 @@ func EditUser(c *gin.Context) { } edit.Name = json.Name - // 改密码加密 + // encrypt passowrd if json.Password != "" { var pwd []byte pwd, err = bcrypt.GenerateFromPassword([]byte(json.Password), bcrypt.DefaultCost) diff --git a/server/model/cert.go b/server/model/cert.go index f6d9d682..ecd8578a 100644 --- a/server/model/cert.go +++ b/server/model/cert.go @@ -1,8 +1,8 @@ package model import ( - "github.com/0xJacky/Nginx-UI/server/tool/nginx" - "io/ioutil" + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" + "os" "path/filepath" ) @@ -29,7 +29,7 @@ func GetAutoCertList() (c []Cert) { db.Find(&t) // check if this domain is enabled - enabledConfig, err := ioutil.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled"))) + enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled"))) if err != nil { return diff --git a/server/model/config-backup.go b/server/model/config-backup.go index d8be5841..7160547d 100644 --- a/server/model/config-backup.go +++ b/server/model/config-backup.go @@ -1,8 +1,8 @@ package model import ( - "io/ioutil" "log" + "os" "path/filepath" ) @@ -36,7 +36,7 @@ func GetBackup(id int) (config ConfigBackup) { } func CreateBackup(path string) { - content, err := ioutil.ReadFile(path) + content, err := os.ReadFile(path) if err != nil { log.Println(err) } diff --git a/server/pkg/cert/cert.go b/server/pkg/cert/cert.go new file mode 100644 index 00000000..58838c47 --- /dev/null +++ b/server/pkg/cert/cert.go @@ -0,0 +1,188 @@ +package cert + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "github.com/0xJacky/Nginx-UI/server/model" + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" + "github.com/0xJacky/Nginx-UI/server/settings" + "github.com/go-acme/lego/v4/certcrypto" + "github.com/go-acme/lego/v4/certificate" + "github.com/go-acme/lego/v4/challenge/http01" + "github.com/go-acme/lego/v4/lego" + "github.com/go-acme/lego/v4/registration" + "github.com/pkg/errors" + "io" + "log" + "net" + "net/http" + "os" + "path/filepath" + "time" +) + +// MyUser You'll need a user or account type that implements acme.User +type MyUser struct { + Email string + Registration *registration.Resource + key crypto.PrivateKey +} + +func (u *MyUser) GetEmail() string { + return u.Email +} +func (u *MyUser) GetRegistration() *registration.Resource { + return u.Registration +} +func (u *MyUser) GetPrivateKey() crypto.PrivateKey { + return u.key +} + +func AutoCert() { + defer func() { + if err := recover(); err != nil { + log.Println("[AutoCert] Recover", err) + } + }() + log.Println("[AutoCert] Start") + autoCertList := model.GetAutoCertList() + for i := range autoCertList { + domain := autoCertList[i].Domain + key, err := GetCertInfo(domain) + if err != nil { + log.Println("GetCertInfo Err", err) + // Get certificate info error, ignore this domain + continue + } + // before 1 mo + if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) { + continue + } + // after 1 mo, reissue certificate + err = IssueCert(domain) + if err != nil { + log.Println(err) + } + } +} + +func GetCertInfo(domain string) (key *x509.Certificate, err error) { + + var response *http.Response + + client := &http.Client{ + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + Timeout: 5 * time.Second, + }).DialContext, + DisableKeepAlives: true, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + Timeout: 5 * time.Second, + } + + response, err = client.Get("https://" + domain) + + if err != nil { + err = errors.Wrap(err, "get cert info error") + return + } + + defer func(Body io.ReadCloser) { + err = Body.Close() + if err != nil { + log.Println(err) + return + } + }(response.Body) + + key = response.TLS.PeerCertificates[0] + + return +} + +func IssueCert(domain string) error { + // Create a user. New accounts need an email and private key to start. + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return errors.Wrap(err, "issue cert generate key error") + } + + myUser := MyUser{ + Email: settings.ServerSettings.Email, + key: privateKey, + } + + config := lego.NewConfig(&myUser) + + if settings.ServerSettings.Demo { + config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory" + } + + config.Certificate.KeyType = certcrypto.RSA2048 + + // A client facilitates communication with the CA server. + client, err := lego.NewClient(config) + if err != nil { + return errors.Wrap(err, "issue cert new client error") + } + + err = client.Challenge.SetHTTP01Provider( + http01.NewProviderServer("", + settings.ServerSettings.HTTPChallengePort, + ), + ) + if err != nil { + return errors.Wrap(err, "issue cert challenge fail") + } + + // New users will need to register + reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) + if err != nil { + log.Println(err) + return errors.Wrap(err, "issue cert register fail") + } + myUser.Registration = reg + + request := certificate.ObtainRequest{ + Domains: []string{domain}, + Bundle: true, + } + certificates, err := client.Certificate.Obtain(request) + if err != nil { + return errors.Wrap(err, "issue cert fail to obtain") + } + saveDir := nginx.GetNginxConfPath("ssl/" + domain) + if _, err = os.Stat(saveDir); os.IsNotExist(err) { + err = os.Mkdir(saveDir, 0755) + if err != nil { + return errors.Wrap(err, "issue cert fail to create") + } + } + + // Each certificate comes back with the cert bytes, the bytes of the client's + // private key, and a certificate URL. SAVE THESE TO DISK. + err = os.WriteFile(filepath.Join(saveDir, "fullchain.cer"), + certificates.Certificate, 0644) + + if err != nil { + log.Println(err) + return errors.Wrap(err, "issue cert write fullchain.cer fail") + } + + err = os.WriteFile(filepath.Join(saveDir, domain+".key"), + certificates.PrivateKey, 0644) + + if err != nil { + log.Println(err) + return errors.Wrap(err, "issue cert write key fail") + } + + nginx.ReloadNginx() + + return nil +} diff --git a/server/tool/config_list.go b/server/pkg/config_list/config_list.go similarity index 98% rename from server/tool/config_list.go rename to server/pkg/config_list/config_list.go index 59d4e33a..2366f50b 100644 --- a/server/tool/config_list.go +++ b/server/pkg/config_list/config_list.go @@ -1,4 +1,4 @@ -package tool +package config_list import ( "github.com/gin-gonic/gin" diff --git a/server/tool/nginx/build_config.go b/server/pkg/nginx/build_config.go similarity index 100% rename from server/tool/nginx/build_config.go rename to server/pkg/nginx/build_config.go diff --git a/server/tool/nginx/format_code.go b/server/pkg/nginx/format_code.go similarity index 100% rename from server/tool/nginx/format_code.go rename to server/pkg/nginx/format_code.go diff --git a/server/tool/nginx/nginx.go b/server/pkg/nginx/nginx.go similarity index 100% rename from server/tool/nginx/nginx.go rename to server/pkg/nginx/nginx.go diff --git a/server/tool/nginx/parse.go b/server/pkg/nginx/parse.go similarity index 100% rename from server/tool/nginx/parse.go rename to server/pkg/nginx/parse.go diff --git a/server/tool/nginx/tokenize.go b/server/pkg/nginx/tokenize.go similarity index 100% rename from server/tool/nginx/tokenize.go rename to server/pkg/nginx/tokenize.go diff --git a/server/tool/nginx/type.go b/server/pkg/nginx/type.go similarity index 100% rename from server/tool/nginx/type.go rename to server/pkg/nginx/type.go diff --git a/server/tool/pty/pipeline.go b/server/pkg/pty/pipeline.go similarity index 100% rename from server/tool/pty/pipeline.go rename to server/pkg/pty/pipeline.go diff --git a/server/tool/pty/type.go b/server/pkg/pty/type.go similarity index 100% rename from server/tool/pty/type.go rename to server/pkg/pty/type.go diff --git a/server/test/acme_test.go b/server/test/acme_test.go index e48c7edd..3000e2d3 100644 --- a/server/test/acme_test.go +++ b/server/test/acme_test.go @@ -2,7 +2,7 @@ package test import ( "fmt" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "io/ioutil" "log" "os" diff --git a/server/test/cert_test.go b/server/test/cert_test.go index ca1c9f7f..7ca61207 100644 --- a/server/test/cert_test.go +++ b/server/test/cert_test.go @@ -2,7 +2,7 @@ package test import ( "fmt" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "log" "os" "os/exec" @@ -35,6 +35,4 @@ func TestCert(t *testing.T) { } log.Println("[found]", "cert key") - - log.Println("申请成功") } diff --git a/server/test/ngx_conf_parse_test.go b/server/test/ngx_conf_parse_test.go index ebed5f00..e61b497f 100644 --- a/server/test/ngx_conf_parse_test.go +++ b/server/test/ngx_conf_parse_test.go @@ -2,7 +2,7 @@ package test import ( "fmt" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" + "github.com/0xJacky/Nginx-UI/server/pkg/nginx" "testing" ) diff --git a/server/tool/cert.go b/server/tool/cert.go deleted file mode 100644 index 53306c82..00000000 --- a/server/tool/cert.go +++ /dev/null @@ -1,189 +0,0 @@ -package tool - -import ( - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/tls" - "crypto/x509" - "github.com/0xJacky/Nginx-UI/server/model" - "github.com/0xJacky/Nginx-UI/server/settings" - "github.com/0xJacky/Nginx-UI/server/tool/nginx" - "github.com/go-acme/lego/v4/certcrypto" - "github.com/go-acme/lego/v4/certificate" - "github.com/go-acme/lego/v4/challenge/http01" - "github.com/go-acme/lego/v4/lego" - "github.com/go-acme/lego/v4/registration" - "github.com/pkg/errors" - "io" - "io/ioutil" - "log" - "net" - "net/http" - "os" - "path/filepath" - "time" -) - -// MyUser You'll need a user or account type that implements acme.User -type MyUser struct { - Email string - Registration *registration.Resource - key crypto.PrivateKey -} - -func (u *MyUser) GetEmail() string { - return u.Email -} -func (u *MyUser) GetRegistration() *registration.Resource { - return u.Registration -} -func (u *MyUser) GetPrivateKey() crypto.PrivateKey { - return u.key -} - -func AutoCert() { - defer func() { - if err := recover(); err != nil { - log.Println("[AutoCert] Recover", err) - } - }() - log.Println("[AutoCert] Start") - autoCertList := model.GetAutoCertList() - for i := range autoCertList { - domain := autoCertList[i].Domain - key, err := GetCertInfo(domain) - if err != nil { - log.Println("GetCertInfo Err", err) - // 获取证书信息失败,本次跳过 - continue - } - // 未到一个月 - if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) { - continue - } - // 过一个月了,重新申请证书 - err = IssueCert(domain) - if err != nil { - log.Println(err) - } - } -} - -func GetCertInfo(domain string) (key *x509.Certificate, err error) { - - var response *http.Response - - client := &http.Client{ - Transport: &http.Transport{ - DialContext: (&net.Dialer{ - Timeout: 5 * time.Second, - }).DialContext, - DisableKeepAlives: true, - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - }, - Timeout: 5 * time.Second, - } - - response, err = client.Get("https://" + domain) - - if err != nil { - err = errors.Wrap(err, "get cert info error") - return - } - - defer func(Body io.ReadCloser) { - err = Body.Close() - if err != nil { - log.Println(err) - return - } - }(response.Body) - - key = response.TLS.PeerCertificates[0] - - return -} - -func IssueCert(domain string) error { - // Create a user. New accounts need an email and private key to start. - privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return errors.Wrap(err, "issue cert generate key error") - } - - myUser := MyUser{ - Email: settings.ServerSettings.Email, - key: privateKey, - } - - config := lego.NewConfig(&myUser) - - if settings.ServerSettings.Demo { - config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory" - } - - config.Certificate.KeyType = certcrypto.RSA2048 - - // A client facilitates communication with the CA server. - client, err := lego.NewClient(config) - if err != nil { - return errors.Wrap(err, "issue cert new client error") - } - - err = client.Challenge.SetHTTP01Provider( - http01.NewProviderServer("", - settings.ServerSettings.HTTPChallengePort, - ), - ) - if err != nil { - return errors.Wrap(err, "issue cert challenge fail") - } - - // New users will need to register - reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) - if err != nil { - log.Println(err) - return errors.Wrap(err, "issue cert register fail") - } - myUser.Registration = reg - - request := certificate.ObtainRequest{ - Domains: []string{domain}, - Bundle: true, - } - certificates, err := client.Certificate.Obtain(request) - if err != nil { - return errors.Wrap(err, "issue cert fail to obtain") - } - saveDir := nginx.GetNginxConfPath("ssl/" + domain) - if _, err = os.Stat(saveDir); os.IsNotExist(err) { - err = os.Mkdir(saveDir, 0755) - if err != nil { - return errors.Wrap(err, "issue cert fail to create") - } - } - - // Each certificate comes back with the cert bytes, the bytes of the client's - // private key, and a certificate URL. SAVE THESE TO DISK. - err = ioutil.WriteFile(filepath.Join(saveDir, "fullchain.cer"), - certificates.Certificate, 0644) - - if err != nil { - log.Println(err) - return errors.Wrap(err, "issue cert write fullchain.cer fail") - } - - err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"), - certificates.PrivateKey, 0644) - - if err != nil { - log.Println(err) - return errors.Wrap(err, "issue cert write key fail") - } - - nginx.ReloadNginx() - - return nil -}