Enhanced domain add

This commit is contained in:
0xJacky 2022-05-07 21:51:03 +08:00
parent 0fe9bf56d6
commit 60919aea4c
22 changed files with 4058 additions and 3652 deletions

View file

@ -1,6 +1,6 @@
{
"name": "nginx-ui-frontend",
"version": "1.2.2",
"version": "1.3.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",

View file

@ -115,7 +115,7 @@
<p v-if="!dataSource[d.dataIndex] && d.empty_description" v-html="d.empty_description"/>
</a-form-item>
<a-form-item>
<a-form-item v-if="$slots.supplement||$slots.action">
<slot name="supplement"/>
<slot name="action"/>
</a-form-item>

View file

@ -23,28 +23,27 @@ msgstr ""
msgid "Action"
msgstr ""
#: src/router/index.js:47 src/views/domain/DomainAdd.vue:18
#: src/router/index.js:47 src/views/domain/DomainAdd.vue:27
msgid "Add Site"
msgstr ""
#: src/views/domain/DomainAdd.vue:2
msgid ""
"Add site here first, then you can configure TLS on the domain edit page."
msgstr ""
#: src/views/domain/DomainEdit.vue:194
#: src/views/domain/DomainAdd.vue:86 src/views/domain/DomainEdit.vue:172
msgid "Auto-renewal disabled for %{name}"
msgstr ""
#: src/views/domain/DomainEdit.vue:188
#: src/views/domain/DomainAdd.vue:80 src/views/domain/DomainEdit.vue:166
msgid "Auto-renewal enabled for %{name}"
msgstr ""
#: src/views/domain/DomainAdd.vue:37
msgid "Base information"
msgstr ""
#: src/views/other/About.vue:11
msgid "Build with"
msgstr ""
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:23
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:24
msgid "Cancel"
msgstr ""
@ -76,6 +75,10 @@ msgstr ""
msgid "Configurations"
msgstr ""
#: src/views/domain/DomainAdd.vue:40
msgid "Configure SSL"
msgstr ""
#: src/views/dashboard/DashBoard.vue:207
msgid "CPU Status"
msgstr ""
@ -84,6 +87,10 @@ msgstr ""
msgid "CPU:"
msgstr ""
#: src/views/domain/DomainAdd.vue:31 src/views/domain/DomainAdd.vue:5
msgid "Create Another"
msgstr ""
#: src/views/user/User.vue:23
msgid "Created at"
msgstr ""
@ -104,7 +111,7 @@ msgstr ""
msgid "Development Mode"
msgstr ""
#: src/views/domain/DomainEdit.vue:196
#: src/views/domain/DomainAdd.vue:88 src/views/domain/DomainEdit.vue:174
msgid "Disable auto-renewal failed for %{name}"
msgstr ""
@ -121,10 +128,14 @@ msgstr ""
msgid "Disk IO"
msgstr ""
#: src/views/domain/DomainEdit.vue:133
#: src/views/domain/DomainEdit.vue:134
msgid "Do you want to change the template to support the TLS?"
msgstr ""
#: src/views/domain/DomainAdd.vue:111
msgid "Domain Config Created Successfully"
msgstr ""
#: src/views/domain/DomainEdit.vue:42
msgid "Edit %{n}"
msgstr ""
@ -145,11 +156,11 @@ msgstr ""
msgid "Email (*)"
msgstr ""
#: src/views/domain/DomainEdit.vue:190
#: src/views/domain/DomainAdd.vue:82 src/views/domain/DomainEdit.vue:168
msgid "Enable auto-renewal failed for %{name}"
msgstr ""
#: src/views/domain/DomainAdd.vue:33
#: src/views/domain/DomainAdd.vue:39
msgid "Enable failed"
msgstr ""
@ -162,7 +173,7 @@ msgstr ""
msgid "Enabled"
msgstr ""
#: src/views/domain/DomainAdd.vue:27 src/views/domain/DomainList.vue:46
#: src/views/domain/DomainAdd.vue:36 src/views/domain/DomainList.vue:46
msgid "Enabled successfully"
msgstr ""
@ -182,11 +193,16 @@ msgstr ""
msgid "File Not Found"
msgstr ""
#: src/views/domain/DomainAdd.vue:43
msgid "Finished"
msgstr ""
#: src/views/domain/DomainAdd.vue:13 src/views/domain/DomainAdd.vue:2
#: src/views/domain/DomainEdit.vue:9 src/views/domain/DomainEdit.vue:3
msgid "Getting Certificate from Let's Encrypt"
msgstr ""
#: src/views/domain/DomainEdit.vue:156
#: src/views/domain/methods.js:34
msgid "Getting the certificate, please wait..."
msgstr ""
@ -265,6 +281,10 @@ msgstr ""
msgid "Memory"
msgstr ""
#: src/views/domain/DomainAdd.vue:28 src/views/domain/DomainAdd.vue:2
msgid "Modify Config"
msgstr ""
#: src/views/config/Config.vue:5 src/views/domain/DomainList.vue:5
msgid "Name"
msgstr ""
@ -281,6 +301,10 @@ msgstr ""
msgid "Network Total Send"
msgstr ""
#: src/views/domain/DomainAdd.vue:38
msgid "Next"
msgstr ""
#: src/router/index.js:105
msgid "Not Found"
msgstr ""
@ -289,7 +313,7 @@ msgstr ""
msgid "Not Valid Before: %{date}"
msgstr ""
#: src/views/domain/DomainEdit.vue:155
#: src/views/domain/methods.js:33
msgid ""
"Note: The server_name in the current configuration must be the domain name "
"you need to get the certificate."
@ -343,18 +367,17 @@ msgstr ""
msgid "Root Directory (root)"
msgstr ""
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
#: src/views/domain/DomainEdit.vue:24
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainEdit.vue:27
msgid "Save"
msgstr ""
#: src/views/config/ConfigEdit.vue:47 src/views/domain/DomainAdd.vue:38
#: src/views/domain/DomainEdit.vue:151
#: src/views/config/ConfigEdit.vue:47 src/views/domain/DomainAdd.vue:43
#: src/views/domain/DomainAdd.vue:54 src/views/domain/DomainEdit.vue:152
msgid "Save error %{msg}"
msgstr ""
#: src/views/config/ConfigEdit.vue:44 src/views/domain/DomainAdd.vue:24
#: src/views/domain/DomainEdit.vue:145
#: src/views/config/ConfigEdit.vue:44 src/views/domain/DomainAdd.vue:33
#: src/views/domain/DomainAdd.vue:51 src/views/domain/DomainEdit.vue:146
msgid "Saved successfully"
msgstr ""
@ -362,7 +385,7 @@ msgstr ""
msgid "Send"
msgstr ""
#: src/views/config/ConfigEdit.vue:35 src/views/domain/DomainEdit.vue:71
#: src/views/config/ConfigEdit.vue:35 src/views/domain/DomainEdit.vue:72
#: src/views/other/Login.vue:35
msgid "Server error"
msgstr ""
@ -379,6 +402,10 @@ msgstr ""
msgid "Sites List"
msgstr ""
#: src/views/domain/DomainAdd.vue:20 src/views/domain/DomainAdd.vue:9
msgid "Skip"
msgstr ""
#: src/views/domain/DomainList.vue:11
msgid "Status"
msgstr ""
@ -418,11 +445,12 @@ msgid ""
"changed after it has been created."
msgstr ""
#: src/views/domain/DomainAdd.vue:15 src/views/domain/DomainAdd.vue:4
#: src/views/domain/DomainEdit.vue:11 src/views/domain/DomainEdit.vue:5
msgid "This feature is not available in demo."
msgstr ""
#: src/views/domain/DomainEdit.vue:134
#: src/views/domain/DomainEdit.vue:135
msgid "This operation will lose the custom configuration."
msgstr ""

View file

@ -25,28 +25,27 @@ msgstr "关于"
msgid "Action"
msgstr "操作"
#: src/router/index.js:47 src/views/domain/DomainAdd.vue:18
#: src/router/index.js:47 src/views/domain/DomainAdd.vue:27
msgid "Add Site"
msgstr "添加站点"
#: src/views/domain/DomainAdd.vue:2
msgid ""
"Add site here first, then you can configure TLS on the domain edit page."
msgstr "在这里添加站点,完成后可进入编辑页面配置 TLS。"
#: src/views/domain/DomainEdit.vue:194
#: src/views/domain/DomainAdd.vue:86 src/views/domain/DomainEdit.vue:172
msgid "Auto-renewal disabled for %{name}"
msgstr "成功关闭 %{name} 自动续签"
#: src/views/domain/DomainEdit.vue:188
#: src/views/domain/DomainAdd.vue:80 src/views/domain/DomainEdit.vue:166
msgid "Auto-renewal enabled for %{name}"
msgstr "成功启用 %{name} 自动续签"
#: src/views/domain/DomainAdd.vue:37
msgid "Base information"
msgstr "基本信息"
#: src/views/other/About.vue:11
msgid "Build with"
msgstr "构建基于"
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:23
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:24
msgid "Cancel"
msgstr "取消"
@ -78,6 +77,10 @@ msgstr "配置名称"
msgid "Configurations"
msgstr "配置"
#: src/views/domain/DomainAdd.vue:40
msgid "Configure SSL"
msgstr "配置 SSL"
#: src/views/dashboard/DashBoard.vue:207
msgid "CPU Status"
msgstr "CPU 状态"
@ -86,6 +89,10 @@ msgstr "CPU 状态"
msgid "CPU:"
msgstr ""
#: src/views/domain/DomainAdd.vue:31 src/views/domain/DomainAdd.vue:5
msgid "Create Another"
msgstr "再创建一个"
#: src/views/user/User.vue:23
msgid "Created at"
msgstr "创建时间"
@ -106,7 +113,7 @@ msgstr "检测到版本更新,页面将会刷新。"
msgid "Development Mode"
msgstr "开发模式"
#: src/views/domain/DomainEdit.vue:196
#: src/views/domain/DomainAdd.vue:88 src/views/domain/DomainEdit.vue:174
msgid "Disable auto-renewal failed for %{name}"
msgstr "关闭 %{name} 自动续签失败"
@ -123,10 +130,14 @@ msgstr "禁用成功"
msgid "Disk IO"
msgstr "磁盘 IO"
#: src/views/domain/DomainEdit.vue:133
#: src/views/domain/DomainEdit.vue:134
msgid "Do you want to change the template to support the TLS?"
msgstr "你想要改变模板以支持 TLS 吗?"
#: src/views/domain/DomainAdd.vue:111
msgid "Domain Config Created Successfully"
msgstr "域名配置文件创建成功"
#: src/views/domain/DomainEdit.vue:42
msgid "Edit %{n}"
msgstr "编辑 %{n}"
@ -147,11 +158,11 @@ msgstr "编辑站点"
msgid "Email (*)"
msgstr "邮箱 (*)"
#: src/views/domain/DomainEdit.vue:190
#: src/views/domain/DomainAdd.vue:82 src/views/domain/DomainEdit.vue:168
msgid "Enable auto-renewal failed for %{name}"
msgstr "启用 %{name} 自动续签失败"
#: src/views/domain/DomainAdd.vue:33
#: src/views/domain/DomainAdd.vue:39
msgid "Enable failed"
msgstr "启用失败"
@ -164,7 +175,7 @@ msgstr "启用 TLS"
msgid "Enabled"
msgstr "启用"
#: src/views/domain/DomainAdd.vue:27 src/views/domain/DomainList.vue:46
#: src/views/domain/DomainAdd.vue:36 src/views/domain/DomainList.vue:46
msgid "Enabled successfully"
msgstr "启用成功"
@ -184,11 +195,16 @@ msgstr "启用失败 %{msg}"
msgid "File Not Found"
msgstr "未找到文件"
#: src/views/domain/DomainAdd.vue:43
msgid "Finished"
msgstr "完成"
#: src/views/domain/DomainAdd.vue:13 src/views/domain/DomainAdd.vue:2
#: src/views/domain/DomainEdit.vue:9 src/views/domain/DomainEdit.vue:3
msgid "Getting Certificate from Let's Encrypt"
msgstr "从 Let's Encrypt 获取证书"
#: src/views/domain/DomainEdit.vue:156
#: src/views/domain/methods.js:34
msgid "Getting the certificate, please wait..."
msgstr "正在获取证书,请稍等..."
@ -269,6 +285,10 @@ msgstr "用户管理"
msgid "Memory"
msgstr "内存"
#: src/views/domain/DomainAdd.vue:28 src/views/domain/DomainAdd.vue:2
msgid "Modify Config"
msgstr "修改配置文件"
#: src/views/config/Config.vue:5 src/views/domain/DomainList.vue:5
msgid "Name"
msgstr "名称"
@ -285,6 +305,10 @@ msgstr "下载流量"
msgid "Network Total Send"
msgstr "上传流量"
#: src/views/domain/DomainAdd.vue:38
msgid "Next"
msgstr "下一步"
#: src/router/index.js:105
msgid "Not Found"
msgstr "找不到页面"
@ -293,7 +317,7 @@ msgstr "找不到页面"
msgid "Not Valid Before: %{date}"
msgstr "此前无效: %{date}"
#: src/views/domain/DomainEdit.vue:155
#: src/views/domain/methods.js:33
msgid ""
"Note: The server_name in the current configuration must be the domain name "
"you need to get the certificate."
@ -347,18 +371,17 @@ msgstr "下载"
msgid "Root Directory (root)"
msgstr "网站根目录 (root)"
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
#: src/views/domain/DomainEdit.vue:24
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainEdit.vue:27
msgid "Save"
msgstr "保存"
#: src/views/config/ConfigEdit.vue:47 src/views/domain/DomainAdd.vue:38
#: src/views/domain/DomainEdit.vue:151
#: src/views/config/ConfigEdit.vue:47 src/views/domain/DomainAdd.vue:43
#: src/views/domain/DomainAdd.vue:54 src/views/domain/DomainEdit.vue:152
msgid "Save error %{msg}"
msgstr "保存错误 %{msg}"
#: src/views/config/ConfigEdit.vue:44 src/views/domain/DomainAdd.vue:24
#: src/views/domain/DomainEdit.vue:145
#: src/views/config/ConfigEdit.vue:44 src/views/domain/DomainAdd.vue:33
#: src/views/domain/DomainAdd.vue:51 src/views/domain/DomainEdit.vue:146
msgid "Saved successfully"
msgstr "保存成功"
@ -366,7 +389,7 @@ msgstr "保存成功"
msgid "Send"
msgstr "上传"
#: src/views/config/ConfigEdit.vue:35 src/views/domain/DomainEdit.vue:71
#: src/views/config/ConfigEdit.vue:35 src/views/domain/DomainEdit.vue:72
#: src/views/other/Login.vue:35
msgid "Server error"
msgstr "服务器错误"
@ -383,6 +406,10 @@ msgstr "网站域名 (server_name)"
msgid "Sites List"
msgstr "站点列表"
#: src/views/domain/DomainAdd.vue:20 src/views/domain/DomainAdd.vue:9
msgid "Skip"
msgstr "跳过"
#: src/views/domain/DomainList.vue:11
msgid "Status"
msgstr "状态"
@ -423,14 +450,15 @@ msgid ""
"fields in your configuration file. The configuration filename cannot be "
"changed after it has been created."
msgstr ""
"只有在您的配置文件中有相应字段时,下列的配置才能生效。配置文件名称创建后不"
"修改。"
"只有在您的配置文件中有相应字段时,下列的配置才能生效。配置文件名称创建后不"
"修改。"
#: src/views/domain/DomainAdd.vue:15 src/views/domain/DomainAdd.vue:4
#: src/views/domain/DomainEdit.vue:11 src/views/domain/DomainEdit.vue:5
msgid "This feature is not available in demo."
msgstr "该功能在 Demo 中不可用。"
#: src/views/domain/DomainEdit.vue:134
#: src/views/domain/DomainEdit.vue:135
msgid "This operation will lose the custom configuration."
msgstr "该操作将会丢失自定义配置。"
@ -455,6 +483,10 @@ msgstr "用户名 (*)"
msgid "Writes"
msgstr "写"
#~ msgid ""
#~ "Add site here first, then you can configure TLS on the domain edit page."
#~ msgstr "在这里添加站点,完成后可进入编辑页面配置 TLS。"
#~ msgid "Server Status"
#~ msgstr "服务器状态"

Binary file not shown.

View file

@ -11,7 +11,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: easygettext\n"
"X-Generator: Poedit 2.2\n"
"X-Generator: Poedit 3.0.1\n"
#: src/router/index.js:99
msgid "404 Not Found"
@ -26,28 +26,27 @@ msgstr "關於"
msgid "Action"
msgstr "操作"
#: src/router/index.js:47 src/views/domain/DomainAdd.vue:18
#: src/router/index.js:47 src/views/domain/DomainAdd.vue:27
msgid "Add Site"
msgstr "新增站點"
#: src/views/domain/DomainAdd.vue:2
msgid ""
"Add site here first, then you can configure TLS on the domain edit page."
msgstr "在這裡新增站點,完成後可進入編輯頁面配置 TLS。"
#: src/views/domain/DomainEdit.vue:194
#: src/views/domain/DomainAdd.vue:86 src/views/domain/DomainEdit.vue:172
msgid "Auto-renewal disabled for %{name}"
msgstr "成功關閉 %{name} 自動續簽"
#: src/views/domain/DomainEdit.vue:188
#: src/views/domain/DomainAdd.vue:80 src/views/domain/DomainEdit.vue:166
msgid "Auto-renewal enabled for %{name}"
msgstr "成功啟用 %{name} 自動續簽"
#: src/views/domain/DomainAdd.vue:37
msgid "Base information"
msgstr "基本訊息"
#: src/views/other/About.vue:11
msgid "Build with"
msgstr "構建基於"
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:23
#: src/views/config/ConfigEdit.vue:5 src/views/domain/DomainEdit.vue:24
msgid "Cancel"
msgstr "取消"
@ -79,6 +78,10 @@ msgstr "配置名稱"
msgid "Configurations"
msgstr "配置"
#: src/views/domain/DomainAdd.vue:40
msgid "Configure SSL"
msgstr "配置 SSL"
#: src/views/dashboard/DashBoard.vue:207
msgid "CPU Status"
msgstr "中央處理器狀態"
@ -87,6 +90,10 @@ msgstr "中央處理器狀態"
msgid "CPU:"
msgstr "中央處理器:"
#: src/views/domain/DomainAdd.vue:31 src/views/domain/DomainAdd.vue:5
msgid "Create Another"
msgstr "再創建一個"
#: src/views/user/User.vue:23
msgid "Created at"
msgstr "建立時間"
@ -107,7 +114,7 @@ msgstr "檢測到版本更新,頁面將會重新整理。"
msgid "Development Mode"
msgstr "開發模式"
#: src/views/domain/DomainEdit.vue:196
#: src/views/domain/DomainAdd.vue:88 src/views/domain/DomainEdit.vue:174
msgid "Disable auto-renewal failed for %{name}"
msgstr "關閉 %{name} 自動續簽失敗"
@ -124,10 +131,14 @@ msgstr "禁用成功"
msgid "Disk IO"
msgstr "磁碟 IO"
#: src/views/domain/DomainEdit.vue:133
#: src/views/domain/DomainEdit.vue:134
msgid "Do you want to change the template to support the TLS?"
msgstr "你想要改變模板以支援 TLS 嗎?"
#: src/views/domain/DomainAdd.vue:111
msgid "Domain Config Created Successfully"
msgstr "域名配置文件創建成功"
#: src/views/domain/DomainEdit.vue:42
msgid "Edit %{n}"
msgstr "編輯 %{n}"
@ -148,11 +159,11 @@ msgstr "編輯站點"
msgid "Email (*)"
msgstr "郵箱 (*)"
#: src/views/domain/DomainEdit.vue:190
#: src/views/domain/DomainAdd.vue:82 src/views/domain/DomainEdit.vue:168
msgid "Enable auto-renewal failed for %{name}"
msgstr "啟用 %{name} 自動續簽失敗"
#: src/views/domain/DomainAdd.vue:33
#: src/views/domain/DomainAdd.vue:39
msgid "Enable failed"
msgstr "啟用失敗"
@ -165,7 +176,7 @@ msgstr "啟用 TLS"
msgid "Enabled"
msgstr "啟用"
#: src/views/domain/DomainAdd.vue:27 src/views/domain/DomainList.vue:46
#: src/views/domain/DomainAdd.vue:36 src/views/domain/DomainList.vue:46
msgid "Enabled successfully"
msgstr "啟用成功"
@ -185,11 +196,16 @@ msgstr "啟用失敗 %{msg}"
msgid "File Not Found"
msgstr "未找到檔案"
#: src/views/domain/DomainAdd.vue:43
msgid "Finished"
msgstr "完成"
#: src/views/domain/DomainAdd.vue:13 src/views/domain/DomainAdd.vue:2
#: src/views/domain/DomainEdit.vue:9 src/views/domain/DomainEdit.vue:3
msgid "Getting Certificate from Let's Encrypt"
msgstr "從 Let's Encrypt 獲取證書"
#: src/views/domain/DomainEdit.vue:156
#: src/views/domain/methods.js:34
msgid "Getting the certificate, please wait..."
msgstr "正在獲取證書,請稍等..."
@ -247,6 +263,7 @@ msgid "Logout successful"
msgstr "登出成功"
#: src/views/domain/DomainEdit.vue:12 src/views/domain/DomainEdit.vue:6
#, fuzzy
msgid ""
"Make sure you have configured a reverse proxy for .well-known directory to "
"HTTPChallengePort (default: 9180) before getting the certificate."
@ -270,6 +287,10 @@ msgstr "使用者管理"
msgid "Memory"
msgstr "記憶體"
#: src/views/domain/DomainAdd.vue:28 src/views/domain/DomainAdd.vue:2
msgid "Modify Config"
msgstr "修改配置"
#: src/views/config/Config.vue:5 src/views/domain/DomainList.vue:5
msgid "Name"
msgstr "名稱"
@ -286,6 +307,10 @@ msgstr "下載流量"
msgid "Network Total Send"
msgstr "上傳流量"
#: src/views/domain/DomainAdd.vue:38
msgid "Next"
msgstr "下一步"
#: src/router/index.js:105
msgid "Not Found"
msgstr "找不到頁面"
@ -294,7 +319,7 @@ msgstr "找不到頁面"
msgid "Not Valid Before: %{date}"
msgstr "此前無效: %{date}"
#: src/views/domain/DomainEdit.vue:155
#: src/views/domain/methods.js:33
msgid ""
"Note: The server_name in the current configuration must be the domain name "
"you need to get the certificate."
@ -348,18 +373,17 @@ msgstr "下載"
msgid "Root Directory (root)"
msgstr "網站根目錄 (root)"
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainAdd.vue:6
#: src/views/domain/DomainEdit.vue:24
#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainEdit.vue:27
msgid "Save"
msgstr "儲存"
#: src/views/config/ConfigEdit.vue:47 src/views/domain/DomainAdd.vue:38
#: src/views/domain/DomainEdit.vue:151
#: src/views/config/ConfigEdit.vue:47 src/views/domain/DomainAdd.vue:43
#: src/views/domain/DomainAdd.vue:54 src/views/domain/DomainEdit.vue:152
msgid "Save error %{msg}"
msgstr "儲存錯誤 %{msg}"
#: src/views/config/ConfigEdit.vue:44 src/views/domain/DomainAdd.vue:24
#: src/views/domain/DomainEdit.vue:145
#: src/views/config/ConfigEdit.vue:44 src/views/domain/DomainAdd.vue:33
#: src/views/domain/DomainAdd.vue:51 src/views/domain/DomainEdit.vue:146
msgid "Saved successfully"
msgstr "儲存成功"
@ -367,7 +391,7 @@ msgstr "儲存成功"
msgid "Send"
msgstr "上傳"
#: src/views/config/ConfigEdit.vue:35 src/views/domain/DomainEdit.vue:71
#: src/views/config/ConfigEdit.vue:35 src/views/domain/DomainEdit.vue:72
#: src/views/other/Login.vue:35
msgid "Server error"
msgstr "伺服器錯誤"
@ -384,6 +408,10 @@ msgstr "網站域名 (server_name)"
msgid "Sites List"
msgstr "站點列表"
#: src/views/domain/DomainAdd.vue:20 src/views/domain/DomainAdd.vue:9
msgid "Skip"
msgstr "跳過"
#: src/views/domain/DomainList.vue:11
msgid "Status"
msgstr "狀態"
@ -419,6 +447,7 @@ msgid "The filename cannot contain the following characters: %{c}"
msgstr "檔名不能包含以下字元: %{c}"
#: src/views/domain/DomainEdit.vue:4
#, fuzzy
msgid ""
"The following values will only take effect if you have the corresponding "
"fields in your configuration file. The configuration filename cannot be "
@ -427,11 +456,12 @@ msgstr ""
"只有在您的配置檔案中有相應欄位時,下列的配置才能生效。配置檔名稱建立後不可修"
"改。"
#: src/views/domain/DomainAdd.vue:15 src/views/domain/DomainAdd.vue:4
#: src/views/domain/DomainEdit.vue:11 src/views/domain/DomainEdit.vue:5
msgid "This feature is not available in demo."
msgstr "此功能在演示中不可用。"
#: src/views/domain/DomainEdit.vue:134
#: src/views/domain/DomainEdit.vue:135
msgid "This operation will lose the custom configuration."
msgstr "該操作將會丟失自定義配置。"
@ -456,6 +486,10 @@ msgstr "使用者名稱 (*)"
msgid "Writes"
msgstr "寫"
#~ msgid ""
#~ "Add site here first, then you can configure TLS on the domain edit page."
#~ msgstr "在這裡新增站點,完成後可進入編輯頁面配置 TLS。"
#~ msgid "Server Status"
#~ msgstr "伺服器狀態"

File diff suppressed because one or more lines are too long

View file

@ -13,7 +13,7 @@
<script>
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar'
import VueItextarea from '@/components/VueItextarea/VueItextarea'
import {$gettext, $interpolate} from "@/lib/translate/gettext"
import $gettext, {$interpolate} from "@/lib/translate/gettext";
export default {
name: 'DomainEdit',

View file

@ -1,59 +1,163 @@
<template>
<a-card :title="$gettext('Add Site')">
<p v-translate>Add site here first, then you can configure TLS on the domain edit page.</p>
<std-data-entry :data-list="columns" :data-source="config"/>
<footer-tool-bar>
<a-button
type="primary"
@click="save"
<div class="container">
<a-steps :current="current_step" size="small">
<a-step :title="$gettext('Base information')" />
<a-step :title="$gettext('Configure SSL')" />
<a-step :title="$gettext('Finished')" />
</a-steps>
<std-data-entry :data-list="columns" :data-source="config" :error="error" v-show="current_step===0"/>
<template v-if="current_step===1">
<a-button
@click="issue_cert"
type="primary" ghost
style="margin: 10px 0"
:disabled="is_demo"
>
<translate>Getting Certificate from Let's Encrypt</translate>
</a-button>
<p v-if="is_demo" v-translate>This feature is not available in demo.</p>
<std-data-entry :data-list="columnsSSL" :data-source="config" :error="error" />
<a-space style="margin-right: 10px">
<a-button
v-if="current_step===1"
@click="current_step++"
>
<translate>Skip</translate>
</a-button>
</a-space>
</template>
<a-result
v-if="current_step===2"
status="success"
:title="$gettext('Domain Config Created Successfully')"
>
<translate>Save</translate>
</a-button>
</footer-tool-bar>
<template #extra>
<a-button type="primary" @click="goto_modify">
<translate>Modify Config</translate>
</a-button>
<a-button @click="create_another">
<translate>Create Another</translate>
</a-button>
</template>
</a-result>
<a-space v-if="current_step<2">
<a-button
type="primary"
@click="save"
:disabled="!config.name"
>
<translate>Next</translate>
</a-button>
</a-space>
</div>
</a-card>
</template>
<script>
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar'
import StdDataEntry from '@/components/StdDataEntry/StdDataEntry'
import {columns} from '@/views/domain/columns'
import {unparse} from '@/views/domain/methods'
import $gettext, {$interpolate} from "@/lib/translate/gettext";
import {columns, columnsSSL} from '@/views/domain/columns'
import {unparse, issue_cert} from '@/views/domain/methods'
import $gettext, {$interpolate} from "@/lib/translate/gettext"
export default {
name: 'DomainAdd',
components: {StdDataEntry, FooterToolBar},
components: {StdDataEntry},
data() {
return {
config: {},
columns: columns.slice(0, -1) // SSL
config: {
http_listen_port: 80,
https_listen_port: 443
},
columns: columns.slice(0, -1), // SSL
error: {},
current_step: 0,
columnsSSL
}
},
beforeCreate() {
watch: {
'config.auto_cert'() {
this.change_auto_cert()
}
},
methods: {
save() {
this.$api.domain.get_template('http-conf').then(r => {
let text = unparse(r.template, this.config)
this.$api.domain.save(this.config.name, {content: text, enabled: true}).then(() => {
this.$message.success($gettext('Saved successfully'))
if (this.current_step===0) {
this.$api.domain.get_template('http-conf').then(r => {
let text = unparse(r.template, this.config)
this.$api.domain.enable(this.config.name).then(() => {
this.$message.success($gettext('Enabled successfully'))
this.$api.domain.save(this.config.name, {content: text, enabled: true}).then(() => {
this.$message.success($gettext('Saved successfully'))
this.$router.push('/domain/' + this.config.name)
this.$api.domain.enable(this.config.name).then(() => {
this.$message.success($gettext('Enabled successfully'))
this.current_step++
}).catch(r => {
this.$message.error(r.message ?? $gettext('Enable failed'), 10)
})
}).catch(r => {
console.log(r)
this.$message.error(r.message ?? $gettext('Enable failed'), 10)
this.$message.error($interpolate($gettext('Save error %{msg}'), {msg: r.message ?? ""}), 10)
})
}).catch(r => {
console.log(r)
this.$message.error($interpolate($gettext('Save error %{msg}'), {msg: r.message ?? ""}), 10)
})
})
} else if (this.current_step === 1) {
this.$api.domain.get_template('https-conf').then(r => {
let text = unparse(r.template, this.config)
this.$api.domain.save(this.config.name, {content: text, enabled: true}).then(() => {
this.$message.success($gettext('Saved successfully'))
this.current_step++
}).catch(r => {
this.$message.error($interpolate($gettext('Save error %{msg}'), {msg: r.message ?? ""}), 10)
})
})
}
},
issue_cert() {
issue_cert(this.config.server_name, this.callback)
},
callback(ssl_certificate, ssl_certificate_key) {
this.$set(this.config, 'ssl_certificate', ssl_certificate)
this.$set(this.config, 'ssl_certificate_key', ssl_certificate_key)
},
goto_modify() {
this.$router.push('/domain/'+this.config.name)
},
create_another() {
this.current_step = 0
this.config = {
http_listen_port: 80,
https_listen_port: 443
}
},
change_auto_cert() {
if (this.config.auto_cert) {
this.$api.domain.add_auto_cert(this.config.name).then(() => {
this.$message.success($interpolate($gettext('Auto-renewal enabled for %{name}'), {name: this.config.name}))
}).catch(e => {
this.$message.error(e.message ?? $interpolate($gettext('Enable auto-renewal failed for %{name}'), {name: this.config.name}))
})
} else {
this.$api.domain.remove_auto_cert(this.config.name).then(() => {
this.$message.success($interpolate($gettext('Auto-renewal disabled for %{name}'), {name: this.config.name}))
}).catch(e => {
this.$message.error(e.message ?? $interpolate($gettext('Disable auto-renewal failed for %{name}'), {name: this.config.name}))
})
}
}
},
computed: {
is_demo() {
return this.$store.getters.env.demo === true
}
}
}
@ -63,4 +167,9 @@ export default {
.ant-steps {
padding: 10px 0 20px 0;
}
.container {
max-width: 800px;
margin: 0 auto
}
</style>

View file

@ -26,8 +26,12 @@
<footer-tool-bar>
<a-space>
<a-button @click="$router.go(-1)"><translate>Cancel</translate></a-button>
<a-button type="primary" @click="save"><translate>Save</translate></a-button>
<a-button @click="$router.go(-1)">
<translate>Cancel</translate>
</a-button>
<a-button type="primary" @click="save">
<translate>Save</translate>
</a-button>
</a-space>
</footer-tool-bar>
</div>
@ -39,9 +43,10 @@ import StdDataEntry from '@/components/StdDataEntry/StdDataEntry'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar'
import VueItextarea from '@/components/VueItextarea/VueItextarea'
import {columns, columnsSSL} from '@/views/domain/columns'
import {unparse} from '@/views/domain/methods'
import {unparse, issue_cert} from '@/views/domain/methods'
import CertInfo from '@/views/domain/CertInfo'
import {$gettext, $interpolate} from "@/lib/translate/gettext"
import {$gettext, $interpolate} from '@/lib/translate/gettext'
export default {
name: 'DomainEdit',
@ -185,52 +190,29 @@ export default {
}
}).catch(r => {
console.log(r)
this.$message.error($interpolate($gettext('Save error %{msg}'), {msg: r.message ?? ""}), 10)
this.$message.error($interpolate($gettext('Save error %{msg}'), {msg: r.message ?? ''}), 10)
})
},
issue_cert() {
this.$message.info($gettext('Note: The server_name in the current configuration must be the domain name you need to get the certificate.'), 15)
this.$message.info($gettext('Getting the certificate, please wait...'), 15)
this.ws = new WebSocket(this.getWebSocketRoot() + '/cert/issue/' + this.config.server_name
+ '?token=' + btoa(this.$store.state.user.token))
this.ws.onopen = () => {
this.ws.send('go')
}
this.ws.onmessage = m => {
const r = JSON.parse(m.data)
switch (r.status) {
case 'success':
this.$message.success(r.message, 10)
break
case 'info':
this.$message.info(r.message, 10)
break
case 'error':
this.$message.error(r.message, 10)
break
}
if (r.status === 'success' && r.ssl_certificate !== undefined && r.ssl_certificate_key !== undefined) {
this.config.ssl_certificate = r.ssl_certificate
this.config.ssl_certificate_key = r.ssl_certificate_key
if (this.$refs['cert-info']) this.$refs['cert-info'].get()
}
}
issue_cert(this.config.server_name, this.callback)
},
callback(ssl_certificate, ssl_certificate_key) {
this.$set(this.config, 'ssl_certificate', ssl_certificate)
this.$set(this.config, 'ssl_certificate_key', ssl_certificate_key)
if (this.$refs['cert-info']) this.$refs['cert-info'].get()
},
change_auto_cert() {
if (this.config.auto_cert) {
this.$api.domain.add_auto_cert(this.name).then(() => {
this.$message.success($interpolate($gettext('Auto-renewal enabled for %{name}'), {name: this.name}))
this.$message.success($interpolate($gettext('Auto-renewal enabled for %{name}', {name: this.name})))
}).catch(e => {
this.$message.error(e.message ?? $interpolate($gettext('Enable auto-renewal failed for %{name}'), {name: this.name}))
this.$message.error(e.message ?? $interpolate($gettext('Enable auto-renewal failed for %{name}', {name: this.name})))
})
} else {
this.$api.domain.remove_auto_cert(this.name).then(() => {
this.$message.success($interpolate($gettext('Auto-renewal disabled for %{name}'), {name: this.name}))
this.$message.success($interpolate($gettext('Auto-renewal disabled for %{name}', {name: this.name})))
}).catch(e => {
this.$message.error(e.message ?? $interpolate($gettext('Disable auto-renewal failed for %{name}'), {name: this.name}))
this.$message.error(e.message ?? $interpolate($gettext('Disable auto-renewal failed for %{name}', {name: this.name})))
})
}
}
@ -246,7 +228,7 @@ export default {
}
},
is_demo() {
return this.$store.getters.env.demo===true
return this.$store.getters.env.demo === true
}
}
}

View file

@ -1,3 +1,6 @@
import $gettext from '@/lib/translate/gettext'
import store from '@/lib/store'
import Vue from 'vue'
const unparse = (text, config) => {
// http_listen_port: /listen (.*);/i,
// https_listen_port: /listen (.*) ssl/i,
@ -26,4 +29,34 @@ const unparse = (text, config) => {
return text
}
export {unparse}
const issue_cert = (server_name, callback) => {
Vue.prototype.$message.info($gettext('Note: The server_name in the current configuration must be the domain name you need to get the certificate.'), 15)
Vue.prototype.$message.info($gettext('Getting the certificate, please wait...'), 15)
const ws = new WebSocket(Vue.prototype.getWebSocketRoot() + '/cert/issue/' + server_name
+ '?token=' + btoa(store.state.user.token))
ws.onopen = () => {
ws.send('go')
}
ws.onmessage = m => {
const r = JSON.parse(m.data)
switch (r.status) {
case 'success':
Vue.prototype.$message.success(r.message, 10)
break
case 'info':
Vue.prototype.$message.info(r.message, 10)
break
case 'error':
Vue.prototype.$message.error(r.message, 10)
break
}
if (r.status === 'success' && r.ssl_certificate !== undefined && r.ssl_certificate_key !== undefined) {
callback(r.ssl_certificate, r.ssl_certificate_key)
}
}
}
export {unparse, issue_cert}

View file

@ -1 +1,2 @@
{"version":"1.2.2","build_id":1,"total_build":49}
{"version":"1.3.0","build_id":1,"total_build":51}

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@ import (
"encoding/json"
"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/gorilla/websocket"
"log"
@ -96,7 +97,7 @@ func IssueCert(c *gin.Context) {
return
}
sslCertificatePath := tool.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
sslCertificatePath := nginx.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
_, err = os.Stat(sslCertificatePath)
if err != nil {
@ -122,7 +123,7 @@ func IssueCert(c *gin.Context) {
return
}
sslCertificateKeyPath := tool.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
sslCertificateKeyPath := nginx.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
_, err = os.Stat(sslCertificateKeyPath)
if err != nil {

View file

@ -2,6 +2,7 @@ package api
import (
"github.com/0xJacky/Nginx-UI/server/tool"
"github.com/0xJacky/Nginx-UI/server/tool/nginx"
"github.com/gin-gonic/gin"
"io/ioutil"
"log"
@ -19,7 +20,7 @@ func GetConfigs(c *gin.Context) {
"modify": "time",
}
configFiles, err := ioutil.ReadDir(tool.GetNginxConfPath("/"))
configFiles, err := ioutil.ReadDir(nginx.GetNginxConfPath("/"))
if err != nil {
ErrHandler(c, err)
@ -49,7 +50,7 @@ func GetConfigs(c *gin.Context) {
func GetConfig(c *gin.Context) {
name := c.Param("name")
path := filepath.Join(tool.GetNginxConfPath("/"), name)
path := filepath.Join(nginx.GetNginxConfPath("/"), name)
content, err := ioutil.ReadFile(path)
@ -80,7 +81,7 @@ func AddConfig(c *gin.Context) {
name := request.Name
content := request.Content
path := filepath.Join(tool.GetNginxConfPath("/"), name)
path := filepath.Join(nginx.GetNginxConfPath("/"), name)
log.Println(path)
if _, err = os.Stat(path); err == nil {
@ -98,7 +99,7 @@ func AddConfig(c *gin.Context) {
}
}
output := tool.ReloadNginx()
output := nginx.ReloadNginx()
if output != "" {
c.JSON(http.StatusInternalServerError, gin.H{
@ -126,7 +127,7 @@ func EditConfig(c *gin.Context) {
ErrHandler(c, err)
return
}
path := filepath.Join(tool.GetNginxConfPath("/"), name)
path := filepath.Join(nginx.GetNginxConfPath("/"), name)
content := request.Content
origContent, err := ioutil.ReadFile(path)
@ -144,7 +145,7 @@ func EditConfig(c *gin.Context) {
}
}
output := tool.ReloadNginx()
output := nginx.ReloadNginx()
if output != "" {
c.JSON(http.StatusInternalServerError, gin.H{

View file

@ -3,6 +3,7 @@ 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/gin-gonic/gin"
"io/ioutil"
"net/http"
@ -20,25 +21,25 @@ func GetDomains(c *gin.Context) {
"modify": "time",
}
configFiles, err := ioutil.ReadDir(tool.GetNginxConfPath("sites-available"))
configFiles, err := ioutil.ReadDir(nginx.GetNginxConfPath("sites-available"))
if err != nil {
ErrHandler(c, err)
return
}
enabledConfig, err := ioutil.ReadDir(filepath.Join(tool.GetNginxConfPath("sites-enabled")))
enabledConfig, err := ioutil.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
if err != nil {
ErrHandler(c, err)
return
}
enabledConfigMap := make(map[string]bool)
for i := range enabledConfig {
enabledConfigMap[enabledConfig[i].Name()] = true
}
if err != nil {
ErrHandler(c, err)
return
}
var configs []gin.H
for i := range configFiles {
@ -62,10 +63,10 @@ func GetDomains(c *gin.Context) {
func GetDomain(c *gin.Context) {
name := c.Param("name")
path := filepath.Join(tool.GetNginxConfPath("sites-available"), name)
path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
enabled := true
if _, err := os.Stat(filepath.Join(tool.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
enabled = false
}
@ -98,7 +99,7 @@ func EditDomain(c *gin.Context) {
name := c.Param("name")
request := make(gin.H)
err = c.BindJSON(&request)
path := filepath.Join(tool.GetNginxConfPath("sites-available"), name)
path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
err = ioutil.WriteFile(path, []byte(request["content"].(string)), 0644)
if err != nil {
@ -106,10 +107,10 @@ func EditDomain(c *gin.Context) {
return
}
enabledConfigFilePath := filepath.Join(tool.GetNginxConfPath("sites-enabled"), name)
enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
if _, err = os.Stat(enabledConfigFilePath); err == nil {
// 测试配置文件
err = tool.TestNginxConf(enabledConfigFilePath)
err = nginx.TestNginxConf()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(),
@ -117,7 +118,7 @@ func EditDomain(c *gin.Context) {
return
}
output := tool.ReloadNginx()
output := nginx.ReloadNginx()
if output != "" {
c.JSON(http.StatusInternalServerError, gin.H{
@ -131,8 +132,8 @@ func EditDomain(c *gin.Context) {
}
func EnableDomain(c *gin.Context) {
configFilePath := filepath.Join(tool.GetNginxConfPath("sites-available"), c.Param("name"))
enabledConfigFilePath := filepath.Join(tool.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)
@ -149,7 +150,7 @@ func EnableDomain(c *gin.Context) {
}
// 测试配置文件,不通过则撤回启用
err = tool.TestNginxConf(enabledConfigFilePath)
err = nginx.TestNginxConf()
if err != nil {
_ = os.Remove(enabledConfigFilePath)
c.JSON(http.StatusInternalServerError, gin.H{
@ -158,7 +159,7 @@ func EnableDomain(c *gin.Context) {
return
}
output := tool.ReloadNginx()
output := nginx.ReloadNginx()
if output != "" {
c.JSON(http.StatusInternalServerError, gin.H{
@ -173,7 +174,7 @@ func EnableDomain(c *gin.Context) {
}
func DisableDomain(c *gin.Context) {
enabledConfigFilePath := filepath.Join(tool.GetNginxConfPath("sites-enabled"), c.Param("name"))
enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
_, err := os.Stat(enabledConfigFilePath)
@ -189,7 +190,15 @@ func DisableDomain(c *gin.Context) {
return
}
output := tool.ReloadNginx()
// delete auto cert record
cert := model.Cert{Domain: c.Param("name")}
err = cert.Remove()
if err != nil {
ErrHandler(c, err)
return
}
output := nginx.ReloadNginx()
if output != "" {
c.JSON(http.StatusInternalServerError, gin.H{
@ -206,8 +215,8 @@ func DisableDomain(c *gin.Context) {
func DeleteDomain(c *gin.Context) {
var err error
name := c.Param("name")
availablePath := filepath.Join(tool.GetNginxConfPath("sites-available"), name)
enabledPath := filepath.Join(tool.GetNginxConfPath("sites-enabled"), 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{

View file

@ -1,5 +1,11 @@
package model
import (
"github.com/0xJacky/Nginx-UI/server/tool/nginx"
"io/ioutil"
"path/filepath"
)
type Cert struct {
Model
Domain string `json:"domain"`
@ -19,7 +25,27 @@ func FirstOrCreateCert(domain string) (c Cert, err error) {
}
func GetAutoCertList() (c []Cert) {
db.Find(&c)
var t []Cert
db.Find(&t)
// check if this domain is enabled
enabledConfig, err := ioutil.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
if err != nil {
return
}
enabledConfigMap := make(map[string]bool)
for i := range enabledConfig {
enabledConfigMap[enabledConfig[i].Name()] = true
}
for _, v := range t {
if enabledConfigMap[v.Domain] == true {
c = append(c, v)
}
}
return
}

View file

@ -2,7 +2,7 @@ package test
import (
"fmt"
"github.com/0xJacky/Nginx-UI/server/tool"
"github.com/0xJacky/Nginx-UI/server/tool/nginx"
"io/ioutil"
"log"
"os"
@ -46,7 +46,7 @@ func TestAcme(t *testing.T) {
"install",
"--log",
"--home", "/usr/local/acme.sh",
"--cert-home", tool.GetNginxConfPath("ssl")).
"--cert-home", nginx.GetNginxConfPath("ssl")).
CombinedOutput()
if err != nil {
log.Println(err)

View file

@ -2,7 +2,7 @@ package test
import (
"fmt"
"github.com/0xJacky/Nginx-UI/server/tool"
"github.com/0xJacky/Nginx-UI/server/tool/nginx"
"log"
"os"
"os/exec"
@ -20,14 +20,14 @@ func TestCert(t *testing.T) {
}
fmt.Printf("%s\n", out)
_, err = os.Stat(tool.GetNginxConfPath("ssl/test.ojbk.me/fullchain.cer"))
_, err = os.Stat(nginx.GetNginxConfPath("ssl/test.ojbk.me/fullchain.cer"))
if err != nil {
log.Println(err)
return
}
log.Println("[found]", "fullchain.cer")
_, err = os.Stat(tool.GetNginxConfPath("ssl/test.ojbk.me/test.ojbk.me.key"))
_, err = os.Stat(nginx.GetNginxConfPath("ssl/test.ojbk.me/test.ojbk.me.key"))
if err != nil {
log.Println(err)

View file

@ -1,178 +1,179 @@
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/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"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"time"
"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"
"io"
"io/ioutil"
"log"
"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
Email string
Registration *registration.Resource
key crypto.PrivateKey
}
func (u *MyUser) GetEmail() string {
return u.Email
return u.Email
}
func (u MyUser) GetRegistration() *registration.Resource {
return u.Registration
return u.Registration
}
func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
return u.key
return u.key
}
func AutoCert() {
for {
log.Println("[AutoCert] Start")
autoCertList := model.GetAutoCertList()
for i := range autoCertList {
domain := autoCertList[i].Domain
key, err := GetCertInfo(domain)
if err != nil {
// 获取证书信息失败,本次跳过
continue
}
// 未到一个月
if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) {
continue
}
// 过一个月了,重新申请证书
err = IssueCert(domain)
if err != nil {
log.Println(err)
}
}
time.Sleep(1 * time.Hour)
}
for {
log.Println("[AutoCert] Start")
autoCertList := model.GetAutoCertList()
for i := range autoCertList {
domain := autoCertList[i].Domain
key, err := GetCertInfo(domain)
if err != nil {
// 获取证书信息失败,本次跳过
continue
}
// 未到一个月
if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) {
continue
}
// 过一个月了,重新申请证书
err = IssueCert(domain)
if err != nil {
log.Println(err)
}
}
time.Sleep(1 * time.Hour)
}
}
func GetCertInfo(domain string) (key *x509.Certificate, err error) {
var response *http.Response
var response *http.Response
ts := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
ts := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: ts}
client := &http.Client{Transport: ts}
response, err = client.Get("https://" + domain)
response, err = client.Get("https://" + domain)
if err != nil {
return
}
if err != nil {
return
}
defer func(Body io.ReadCloser) {
err = Body.Close()
if err != nil {
log.Println(err)
return
}
}(response.Body)
defer func(Body io.ReadCloser) {
err = Body.Close()
if err != nil {
log.Println(err)
return
}
}(response.Body)
key = response.TLS.PeerCertificates[0]
key = response.TLS.PeerCertificates[0]
return
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 {
log.Println(err)
return err
}
// Create a user. New accounts need an email and private key to start.
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Println(err)
return err
}
myUser := MyUser{
Email: settings.ServerSettings.Email,
key: privateKey,
}
myUser := MyUser{
Email: settings.ServerSettings.Email,
key: privateKey,
}
config := lego.NewConfig(&myUser)
config := lego.NewConfig(&myUser)
if settings.ServerSettings.Demo {
config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
}
config.Certificate.KeyType = certcrypto.RSA2048
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 {
log.Println(err)
return err
}
// A client facilitates communication with the CA server.
client, err := lego.NewClient(config)
if err != nil {
log.Println(err)
return err
}
err = client.Challenge.SetHTTP01Provider(
http01.NewProviderServer("",
settings.ServerSettings.HTTPChallengePort,
),
)
if err != nil {
log.Println(err)
return err
}
err = client.Challenge.SetHTTP01Provider(
http01.NewProviderServer("",
settings.ServerSettings.HTTPChallengePort,
),
)
if err != nil {
log.Println(err)
return err
}
// New users will need to register
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
if err != nil {
log.Println(err)
return err
}
myUser.Registration = reg
// New users will need to register
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
if err != nil {
log.Println(err)
return err
}
myUser.Registration = reg
request := certificate.ObtainRequest{
Domains: []string{domain},
Bundle: true,
}
certificates, err := client.Certificate.Obtain(request)
if err != nil {
log.Println(err)
return err
}
saveDir := GetNginxConfPath("ssl/" + domain)
if _, err := os.Stat(saveDir); os.IsNotExist(err) {
err = os.Mkdir(saveDir, 0755)
if err != nil {
log.Println("fail to create", saveDir)
return err
}
}
request := certificate.ObtainRequest{
Domains: []string{domain},
Bundle: true,
}
certificates, err := client.Certificate.Obtain(request)
if err != nil {
log.Println(err)
return err
}
saveDir := nginx.GetNginxConfPath("ssl/" + domain)
if _, err := os.Stat(saveDir); os.IsNotExist(err) {
err = os.Mkdir(saveDir, 0755)
if err != nil {
log.Println("fail to create", saveDir)
return err
}
}
// 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 err
}
err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"),
certificates.PrivateKey, 0644)
if err != nil {
log.Println(err)
return err
}
// 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 err
}
err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"),
certificates.PrivateKey, 0644)
if err != nil {
log.Println(err)
return err
}
ReloadNginx()
nginx.ReloadNginx()
return nil
return nil
}

View file

@ -1,4 +1,4 @@
package tool
package nginx
import (
"errors"
@ -9,7 +9,7 @@ import (
"strings"
)
func TestNginxConf(filePath string) error {
func TestNginxConf() error {
out, err := exec.Command("nginx", "-t").CombinedOutput()
if err != nil {
log.Println(err)