Explorar o código

feat: added DNS credentials manager

0xJacky %!s(int64=2) %!d(string=hai) anos
pai
achega
fcc22632ec

+ 102 - 71
frontend/src/language/en/app.po

@@ -9,20 +9,21 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
-#: src/routes/index.ts:143
+#: src/routes/index.ts:155
 msgid "About"
 msgstr "About"
 
-#: src/routes/index.ts:111 src/views/domain/ngx_conf/LogEntry.vue:64
+#: src/routes/index.ts:123 src/views/domain/ngx_conf/LogEntry.vue:64
 msgid "Access Logs"
 msgstr ""
 
-#: src/views/cert/Cert.vue:74 src/views/config/config.ts:36
-#: src/views/domain/DomainList.vue:48 src/views/user/User.vue:43
+#: src/views/cert/Cert.vue:74 src/views/cert/DNSCredential.vue:32
+#: src/views/config/config.ts:35 src/views/domain/DomainList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgstr "Action"
 
-#: src/components/StdDataDisplay/StdCurd.vue:145
+#: src/components/StdDataDisplay/StdCurd.vue:146
 #: src/components/StdDataDisplay/StdCurd.vue:25
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:28
 #: src/views/domain/ngx_conf/NgxConfigEditor.vue:47
@@ -48,9 +49,8 @@ msgstr "Add Location"
 msgid "Add Site"
 msgstr "Add Site"
 
-#: src/views/domain/cert/components/DNSChallenge.vue:12
-#: src/views/domain/cert/components/DNSChallenge.vue:13
-#: src/views/domain/cert/components/DNSChallenge.vue:14
+#: src/views/cert/DNSChallenge.vue:12 src/views/cert/DNSChallenge.vue:13
+#: src/views/cert/DNSChallenge.vue:14
 #, fuzzy
 msgid "Additional"
 msgstr "Add Location"
@@ -192,7 +192,7 @@ msgstr "Certificate has expired"
 msgid "Certificate is valid"
 msgstr "Certificate is valid"
 
-#: src/views/cert/Cert.vue:34 src/views/domain/cert/Cert.vue:37
+#: src/views/cert/Cert.vue:34 src/views/domain/cert/Cert.vue:36
 msgid "Certificate Status"
 msgstr "Certificate Status"
 
@@ -201,7 +201,12 @@ msgstr "Certificate Status"
 msgid "Certification"
 msgstr "Certificate is valid"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+#: src/routes/index.ts:97
+#, fuzzy
+msgid "Certification List"
+msgstr "Certificate is valid"
+
+#: src/views/domain/cert/components/AutoCertStepOne.vue:40
 msgid "Challenge Method"
 msgstr ""
 
@@ -238,7 +243,7 @@ msgstr ""
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:33
 #: src/views/domain/ngx_conf/LocationEditor.vue:35
 #: src/views/domain/ngx_conf/LocationEditor.vue:52
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:246
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:250
 msgid "Comments"
 msgstr "Comments"
 
@@ -247,7 +252,7 @@ msgstr "Comments"
 msgid "Config Name"
 msgstr "Configuration Name"
 
-#: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:81
+#: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:79
 #, fuzzy
 msgid "Config Templates"
 msgstr "Configurations"
@@ -286,7 +291,7 @@ msgstr "CPU Status"
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/views/domain/DomainAdd.vue:149
+#: src/views/domain/DomainAdd.vue:148
 msgid "Create Another"
 msgstr "Create Another"
 
@@ -299,7 +304,10 @@ msgid "Creating client facilitates communication with the CA server"
 msgstr ""
 
 #: src/views/domain/cert/components/DNSChallenge.vue:6
-#: src/views/domain/cert/components/DNSChallenge.vue:7
+msgid "Credential"
+msgstr ""
+
+#: src/views/cert/DNSChallenge.vue:6 src/views/cert/DNSChallenge.vue:7
 msgid "Credentials"
 msgstr ""
 
@@ -349,7 +357,7 @@ msgstr ""
 msgid "Delete ID: %{id}"
 msgstr ""
 
-#: src/views/domain/DomainList.vue:82
+#: src/views/domain/DomainList.vue:81
 msgid "Delete site: %{site_name}"
 msgstr ""
 
@@ -368,7 +376,7 @@ msgstr ""
 msgid "Development Mode"
 msgstr "Development Mode"
 
-#: src/views/config/config.ts:20
+#: src/views/config/config.ts:19
 msgid "Dir"
 msgstr ""
 
@@ -387,13 +395,13 @@ msgstr "Disable auto-renewal failed for %{name}"
 
 #: src/views/cert/Cert.vue:47 src/views/domain/cert/ChangeCert.vue:45
 #: src/views/domain/DomainEdit.vue:10 src/views/domain/DomainEdit.vue:11
-#: src/views/domain/DomainList.vue:16 src/views/domain/DomainList.vue:35
+#: src/views/domain/DomainList.vue:16 src/views/domain/DomainList.vue:34
 #: src/views/domain/DomainList.vue:7 src/views/domain/DomainList.vue:8
 #: src/views/domain/DomainList.vue:9
 msgid "Disabled"
 msgstr "Disabled"
 
-#: src/views/domain/DomainEdit.vue:159 src/views/domain/DomainList.vue:70
+#: src/views/domain/DomainEdit.vue:159 src/views/domain/DomainList.vue:69
 msgid "Disabled successfully"
 msgstr "Disabled successfully"
 
@@ -401,17 +409,22 @@ msgstr "Disabled successfully"
 msgid "Disk IO"
 msgstr "Disk IO"
 
+#: src/routes/index.ts:102 src/views/cert/DNSCredential.vue:2
+msgid "DNS Credentials"
+msgstr ""
+
+#: src/views/cert/DNSChallenge.vue:3
 #: src/views/domain/cert/components/DNSChallenge.vue:3
 msgid "DNS Provider"
 msgstr ""
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:32
-#: src/views/domain/cert/components/AutoCertStepOne.vue:43
-#: src/views/domain/cert/components/AutoCertStepOne.vue:48
+#: src/views/domain/cert/components/AutoCertStepOne.vue:30
+#: src/views/domain/cert/components/AutoCertStepOne.vue:41
+#: src/views/domain/cert/components/AutoCertStepOne.vue:46
 msgid "DNS01"
 msgstr ""
 
-#: src/views/domain/cert/components/ObtainCert.vue:180
+#: src/views/domain/cert/components/ObtainCert.vue:178
 msgid "Do you want to disable auto-cert renewal?"
 msgstr ""
 
@@ -425,11 +438,16 @@ msgstr "Are you sure you want to remove this directive?"
 msgid "Do you want to enable this site?"
 msgstr "Are you sure you want to remove this directive?"
 
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:31
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:30
 #, fuzzy
 msgid "Do you want to enable TLS?"
 msgstr "Are you sure you want to remove this directive?"
 
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:196
+#, fuzzy
+msgid "Do you want to remove this server?"
+msgstr "Are you sure you want to remove this directive?"
+
 #: src/views/domain/DomainAdd.vue:58
 msgid "Domain Config Created Successfully"
 msgstr "Domain Config Created Successfully"
@@ -477,7 +495,7 @@ msgstr "Email (*)"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "Enable auto-renewal failed for %{name}"
 
-#: src/views/domain/DomainAdd.vue:51
+#: src/views/domain/DomainAdd.vue:50
 msgid "Enable failed"
 msgstr "Enable failed"
 
@@ -489,12 +507,12 @@ msgstr "Enable TLS"
 #: src/views/domain/DomainEdit.vue:29 src/views/domain/DomainEdit.vue:7
 #: src/views/domain/DomainEdit.vue:8 src/views/domain/DomainList.vue:10
 #: src/views/domain/DomainList.vue:11 src/views/domain/DomainList.vue:12
-#: src/views/domain/DomainList.vue:19 src/views/domain/DomainList.vue:32
+#: src/views/domain/DomainList.vue:19 src/views/domain/DomainList.vue:31
 msgid "Enabled"
 msgstr "Enabled"
 
-#: src/views/domain/DomainAdd.vue:47 src/views/domain/DomainEdit.vue:150
-#: src/views/domain/DomainList.vue:60
+#: src/views/domain/DomainAdd.vue:46 src/views/domain/DomainEdit.vue:150
+#: src/views/domain/DomainList.vue:59
 msgid "Enabled successfully"
 msgstr "Enabled successfully"
 
@@ -506,7 +524,7 @@ msgstr "Encrypt website with Let's Encrypt"
 msgid "Error"
 msgstr ""
 
-#: src/routes/index.ts:115 src/views/domain/ngx_conf/LogEntry.vue:68
+#: src/routes/index.ts:127 src/views/domain/ngx_conf/LogEntry.vue:68
 msgid "Error Logs"
 msgstr ""
 
@@ -527,11 +545,11 @@ msgstr "Expiration Date: %{date}"
 msgid "Export"
 msgstr ""
 
-#: src/views/domain/DomainEdit.vue:162 src/views/domain/DomainList.vue:74
+#: src/views/domain/DomainEdit.vue:162 src/views/domain/DomainList.vue:73
 msgid "Failed to disable %{msg}"
 msgstr "Failed to disable %{msg}"
 
-#: src/views/domain/DomainEdit.vue:153 src/views/domain/DomainList.vue:64
+#: src/views/domain/DomainEdit.vue:153 src/views/domain/DomainList.vue:63
 msgid "Failed to enable %{msg}"
 msgstr "Failed to enable %{msg}"
 
@@ -543,7 +561,7 @@ msgstr ""
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr ""
 
-#: src/views/config/config.ts:22
+#: src/views/config/config.ts:21
 msgid "File"
 msgstr ""
 
@@ -629,9 +647,9 @@ msgstr ""
 msgid "HTTP Port"
 msgstr ""
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:29
-#: src/views/domain/cert/components/AutoCertStepOne.vue:40
-#: src/views/domain/cert/components/AutoCertStepOne.vue:45
+#: src/views/domain/cert/components/AutoCertStepOne.vue:27
+#: src/views/domain/cert/components/AutoCertStepOne.vue:38
+#: src/views/domain/cert/components/AutoCertStepOne.vue:43
 msgid "HTTP01"
 msgstr ""
 
@@ -643,7 +661,7 @@ msgstr ""
 msgid "Initialing core upgrader"
 msgstr ""
 
-#: src/routes/index.ts:155 src/views/other/Install.vue:128
+#: src/routes/index.ts:167 src/views/other/Install.vue:128
 msgid "Install"
 msgstr "Install"
 
@@ -698,11 +716,11 @@ msgstr "Location"
 msgid "Locations"
 msgstr "Locations"
 
-#: src/routes/index.ts:161 src/views/other/Login.vue:105
+#: src/routes/index.ts:173 src/views/other/Login.vue:104
 msgid "Login"
 msgstr "Login"
 
-#: src/views/other/Login.vue:53
+#: src/views/other/Login.vue:52
 msgid "Login successful"
 msgstr "Login successful"
 
@@ -751,7 +769,7 @@ msgstr "Memory and Storage"
 msgid "Modify"
 msgstr "Modify Config"
 
-#: src/views/domain/DomainAdd.vue:146
+#: src/views/domain/DomainAdd.vue:145
 msgid "Modify Config"
 msgstr "Modify Config"
 
@@ -761,9 +779,10 @@ msgstr "Modify Config"
 msgid "Multi-line Directive"
 msgstr "Single Directive"
 
-#: src/views/cert/Cert.vue:16 src/views/config/config.ts:9
-#: src/views/domain/cert/ChangeCert.vue:19 src/views/domain/DomainEdit.vue:32
-#: src/views/domain/DomainList.vue:16 src/views/domain/SiteDuplicate.vue:5
+#: src/views/cert/Cert.vue:16 src/views/cert/DNSCredential.vue:13
+#: src/views/config/config.ts:8 src/views/domain/cert/ChangeCert.vue:19
+#: src/views/domain/DomainEdit.vue:32 src/views/domain/DomainList.vue:15
+#: src/views/domain/SiteDuplicate.vue:5
 msgid "Name"
 msgstr "Name"
 
@@ -790,7 +809,7 @@ msgstr ""
 #: src/views/domain/cert/components/ObtainCert.vue:12
 #: src/views/domain/cert/components/ObtainCert.vue:13
 #: src/views/domain/cert/components/ObtainCert.vue:21
-#: src/views/domain/DomainAdd.vue:136
+#: src/views/domain/DomainAdd.vue:135
 msgid "Next"
 msgstr "Next"
 
@@ -813,7 +832,7 @@ msgstr ""
 msgid "Nginx Error Log Path"
 msgstr ""
 
-#: src/routes/index.ts:105 src/views/nginx_log/NginxLog.vue:2
+#: src/routes/index.ts:117 src/views/nginx_log/NginxLog.vue:2
 #: src/views/preference/Preference.vue:8
 msgid "Nginx Log"
 msgstr ""
@@ -836,7 +855,7 @@ msgstr "Saved successfully"
 msgid "No"
 msgstr "No"
 
-#: src/routes/index.ts:167 src/routes/index.ts:169
+#: src/routes/index.ts:179 src/routes/index.ts:181
 msgid "Not Found"
 msgstr "Not Found"
 
@@ -844,6 +863,7 @@ msgstr "Not Found"
 msgid "Not Valid Before: %{date}"
 msgstr "Not Valid Before: %{date}"
 
+#: src/views/cert/DNSCredential.vue:6
 #: src/views/domain/cert/components/AutoCertStepOne.vue:17
 msgid "Note"
 msgstr ""
@@ -906,13 +926,19 @@ msgstr ""
 msgid "Performing core upgrade"
 msgstr ""
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+#: src/views/cert/DNSCredential.vue:44
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
-"provider. We will add a TXT record to the DNS records of your domain for "
-"ownership verification. Once the verification is complete, the record will "
-"be removed. Please note that the time configurations below are all in "
-"seconds."
+"provider. We will add one or more TXT records to the DNS records of your "
+"domain for ownership verification. Once the verification is complete, the "
+"records will be removed. Please note that the time configurations below are "
+"all in seconds."
+msgstr ""
+
+#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+msgid ""
+"Please first add credentials in Certification > DNS Credentials, and then "
+"select one of the credentials below to request the API of the DNS provider."
 msgstr ""
 
 #: src/views/domain/SiteDuplicate.vue:28
@@ -925,15 +951,15 @@ msgstr ""
 msgid "Please input your E-mail!"
 msgstr "Please input your E-mail!"
 
-#: src/views/other/Install.vue:48 src/views/other/Login.vue:42
+#: src/views/other/Install.vue:48 src/views/other/Login.vue:41
 msgid "Please input your password!"
 msgstr "Please input your password!"
 
-#: src/views/other/Install.vue:42 src/views/other/Login.vue:36
+#: src/views/other/Install.vue:42 src/views/other/Login.vue:35
 msgid "Please input your username!"
 msgstr "Please input your username!"
 
-#: src/routes/index.ts:128 src/views/preference/Preference.vue:2
+#: src/routes/index.ts:140 src/views/preference/Preference.vue:2
 msgid "Preference"
 msgstr ""
 
@@ -954,6 +980,10 @@ msgstr ""
 msgid "Project Team"
 msgstr "Project Team"
 
+#: src/views/cert/DNSCredential.vue:21
+msgid "Provider"
+msgstr ""
+
 #: src/views/dashboard/DashBoard.vue:109
 msgid "Reads"
 msgstr "Reads"
@@ -1048,25 +1078,25 @@ msgstr "Save"
 msgid "Save Directive"
 msgstr "Save Directive"
 
-#: src/views/config/ConfigEdit.vue:53 src/views/domain/DomainAdd.vue:55
-#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:37
+#: src/views/config/ConfigEdit.vue:53 src/views/domain/DomainAdd.vue:54
+#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:36
 msgid "Save error %{msg}"
 msgstr "Save error %{msg}"
 
-#: src/components/StdDataDisplay/StdBatchEdit.vue:40
+#: src/components/StdDataDisplay/StdBatchEdit.vue:39
 #: src/views/preference/Preference.vue:60
 #, fuzzy
 msgid "Save successfully"
 msgstr "Saved successfully"
 
-#: src/components/StdDataDisplay/StdCurd.vue:108
+#: src/components/StdDataDisplay/StdCurd.vue:109
 #, fuzzy
 msgid "Save Successfully"
 msgstr "Saved successfully"
 
-#: src/views/config/ConfigEdit.vue:51 src/views/domain/DomainAdd.vue:44
+#: src/views/config/ConfigEdit.vue:51 src/views/domain/DomainAdd.vue:43
 #: src/views/domain/DomainEdit.vue:142
-#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:35
+#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:34
 msgid "Saved successfully"
 msgstr "Saved successfully"
 
@@ -1080,11 +1110,11 @@ msgstr "Send"
 
 #: src/components/NginxControl/NginxControl.vue:33
 #: src/components/NginxControl/NginxControl.vue:50
-#: src/components/StdDataDisplay/StdBatchEdit.vue:43
+#: src/components/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDataDisplay/StdTable.vue:168
 #: src/components/StdDataDisplay/StdTable.vue:343
 #: src/components/StdDataDisplay/StdTable.vue:463
-#: src/views/config/ConfigEdit.vue:37 src/views/domain/DomainList.vue:84
+#: src/views/config/ConfigEdit.vue:37 src/views/domain/DomainList.vue:83
 #: src/views/other/Install.vue:71 src/views/preference/Preference.vue:62
 #: src/views/system/Upgrade.vue:40
 msgid "Server error"
@@ -1101,7 +1131,7 @@ msgstr "server_name not found in directives"
 #: src/views/domain/cert/components/AutoCertStepOne.vue:10
 #: src/views/domain/cert/components/AutoCertStepOne.vue:5
 #: src/views/domain/cert/components/AutoCertStepOne.vue:6
-#: src/views/domain/DomainAdd.vue:111
+#: src/views/domain/DomainAdd.vue:110
 msgid "server_name parameter is required"
 msgstr "server_name parameter is required"
 
@@ -1114,7 +1144,7 @@ msgstr ""
 msgid "Single Directive"
 msgstr "Single Directive"
 
-#: src/routes/index.ts:119
+#: src/routes/index.ts:131
 #, fuzzy
 msgid "Site Logs"
 msgstr "Sites List"
@@ -1143,7 +1173,7 @@ msgstr "Certificate Status"
 msgid "SSL Certification Key Content"
 msgstr "Certificate Status"
 
-#: src/views/domain/DomainList.vue:25
+#: src/views/domain/DomainList.vue:24
 msgid "Status"
 msgstr "Status"
 
@@ -1163,7 +1193,7 @@ msgstr "Subject Name: %{name}"
 msgid "Swap"
 msgstr "Swap"
 
-#: src/routes/index.ts:136
+#: src/routes/index.ts:148
 msgid "System"
 msgstr ""
 
@@ -1172,7 +1202,7 @@ msgstr ""
 msgid "Table"
 msgstr "Enabled"
 
-#: src/routes/index.ts:97 src/views/pty/Terminal.vue:2
+#: src/routes/index.ts:109 src/views/pty/Terminal.vue:2
 msgid "Terminal"
 msgstr "Terminal"
 
@@ -1214,7 +1244,7 @@ msgstr ""
 msgid "This auto-cert item is invalid, please remove it."
 msgstr ""
 
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:32
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:31
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
 "add a location which can proxy the request from authority to backend, and we "
@@ -1222,12 +1252,13 @@ msgid ""
 "continue?"
 msgstr ""
 
-#: src/views/config/config.ts:14
+#: src/views/config/config.ts:13
 msgid "Type"
 msgstr ""
 
-#: src/views/cert/Cert.vue:68 src/views/config/config.ts:29
-#: src/views/domain/DomainList.vue:42 src/views/user/User.vue:37
+#: src/views/cert/Cert.vue:68 src/views/cert/DNSCredential.vue:26
+#: src/views/config/config.ts:28 src/views/domain/DomainList.vue:41
+#: src/views/user/User.vue:37
 msgid "Updated at"
 msgstr "Updated at"
 
@@ -1236,7 +1267,7 @@ msgstr "Updated at"
 msgid "Updated successfully"
 msgstr "Saved successfully"
 
-#: src/routes/index.ts:147 src/views/system/Upgrade.vue:2
+#: src/routes/index.ts:159 src/views/system/Upgrade.vue:2
 #: src/views/system/Upgrade.vue:28 src/views/system/Upgrade.vue:29
 #: src/views/system/Upgrade.vue:33 src/views/system/Upgrade.vue:37
 #: src/views/system/Upgrade.vue:41 src/views/system/Upgrade.vue:44
@@ -1286,7 +1317,7 @@ msgstr ""
 msgid "Warning"
 msgstr "Warning"
 
-#: src/views/domain/cert/components/ObtainCert.vue:181
+#: src/views/domain/cert/components/ObtainCert.vue:179
 msgid ""
 "We will remove the HTTPChallenge configuration from this file and reload the "
 "Nginx. Are you sure you want to continue?"

+ 98 - 68
frontend/src/language/messages.pot

@@ -2,23 +2,24 @@ msgid ""
 msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 
-#: src/routes/index.ts:143
+#: src/routes/index.ts:155
 msgid "About"
 msgstr ""
 
-#: src/routes/index.ts:111
+#: src/routes/index.ts:123
 #: src/views/domain/ngx_conf/LogEntry.vue:64
 msgid "Access Logs"
 msgstr ""
 
 #: src/views/cert/Cert.vue:74
-#: src/views/config/config.ts:36
-#: src/views/domain/DomainList.vue:48
+#: src/views/cert/DNSCredential.vue:32
+#: src/views/config/config.ts:35
+#: src/views/domain/DomainList.vue:47
 #: src/views/user/User.vue:43
 msgid "Action"
 msgstr ""
 
-#: src/components/StdDataDisplay/StdCurd.vue:145
+#: src/components/StdDataDisplay/StdCurd.vue:146
 #: src/components/StdDataDisplay/StdCurd.vue:25
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:28
 #: src/views/domain/ngx_conf/NgxConfigEditor.vue:47
@@ -45,9 +46,9 @@ msgstr ""
 msgid "Add Site"
 msgstr ""
 
-#: src/views/domain/cert/components/DNSChallenge.vue:12
-#: src/views/domain/cert/components/DNSChallenge.vue:13
-#: src/views/domain/cert/components/DNSChallenge.vue:14
+#: src/views/cert/DNSChallenge.vue:12
+#: src/views/cert/DNSChallenge.vue:13
+#: src/views/cert/DNSChallenge.vue:14
 msgid "Additional"
 msgstr ""
 
@@ -193,7 +194,7 @@ msgid "Certificate is valid"
 msgstr ""
 
 #: src/views/cert/Cert.vue:34
-#: src/views/domain/cert/Cert.vue:37
+#: src/views/domain/cert/Cert.vue:36
 msgid "Certificate Status"
 msgstr ""
 
@@ -202,7 +203,11 @@ msgstr ""
 msgid "Certification"
 msgstr ""
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+#: src/routes/index.ts:97
+msgid "Certification List"
+msgstr ""
+
+#: src/views/domain/cert/components/AutoCertStepOne.vue:40
 msgid "Challenge Method"
 msgstr ""
 
@@ -242,7 +247,7 @@ msgstr ""
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:33
 #: src/views/domain/ngx_conf/LocationEditor.vue:35
 #: src/views/domain/ngx_conf/LocationEditor.vue:52
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:246
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:250
 msgid "Comments"
 msgstr ""
 
@@ -250,7 +255,7 @@ msgstr ""
 msgid "Config Name"
 msgstr ""
 
-#: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:81
+#: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:79
 msgid "Config Templates"
 msgstr ""
 
@@ -289,7 +294,7 @@ msgstr ""
 msgid "CPU:"
 msgstr ""
 
-#: src/views/domain/DomainAdd.vue:149
+#: src/views/domain/DomainAdd.vue:148
 msgid "Create Another"
 msgstr ""
 
@@ -302,7 +307,11 @@ msgid "Creating client facilitates communication with the CA server"
 msgstr ""
 
 #: src/views/domain/cert/components/DNSChallenge.vue:6
-#: src/views/domain/cert/components/DNSChallenge.vue:7
+msgid "Credential"
+msgstr ""
+
+#: src/views/cert/DNSChallenge.vue:6
+#: src/views/cert/DNSChallenge.vue:7
 msgid "Credentials"
 msgstr ""
 
@@ -356,7 +365,7 @@ msgstr ""
 msgid "Delete ID: %{id}"
 msgstr ""
 
-#: src/views/domain/DomainList.vue:82
+#: src/views/domain/DomainList.vue:81
 msgid "Delete site: %{site_name}"
 msgstr ""
 
@@ -376,7 +385,7 @@ msgstr ""
 msgid "Development Mode"
 msgstr ""
 
-#: src/views/config/config.ts:20
+#: src/views/config/config.ts:19
 msgid "Dir"
 msgstr ""
 
@@ -398,7 +407,7 @@ msgstr ""
 #: src/views/domain/DomainEdit.vue:10
 #: src/views/domain/DomainEdit.vue:11
 #: src/views/domain/DomainList.vue:16
-#: src/views/domain/DomainList.vue:35
+#: src/views/domain/DomainList.vue:34
 #: src/views/domain/DomainList.vue:7
 #: src/views/domain/DomainList.vue:8
 #: src/views/domain/DomainList.vue:9
@@ -406,7 +415,7 @@ msgid "Disabled"
 msgstr ""
 
 #: src/views/domain/DomainEdit.vue:159
-#: src/views/domain/DomainList.vue:70
+#: src/views/domain/DomainList.vue:69
 msgid "Disabled successfully"
 msgstr ""
 
@@ -414,17 +423,23 @@ msgstr ""
 msgid "Disk IO"
 msgstr ""
 
+#: src/routes/index.ts:102
+#: src/views/cert/DNSCredential.vue:2
+msgid "DNS Credentials"
+msgstr ""
+
+#: src/views/cert/DNSChallenge.vue:3
 #: src/views/domain/cert/components/DNSChallenge.vue:3
 msgid "DNS Provider"
 msgstr ""
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:32
-#: src/views/domain/cert/components/AutoCertStepOne.vue:43
-#: src/views/domain/cert/components/AutoCertStepOne.vue:48
+#: src/views/domain/cert/components/AutoCertStepOne.vue:30
+#: src/views/domain/cert/components/AutoCertStepOne.vue:41
+#: src/views/domain/cert/components/AutoCertStepOne.vue:46
 msgid "DNS01"
 msgstr ""
 
-#: src/views/domain/cert/components/ObtainCert.vue:180
+#: src/views/domain/cert/components/ObtainCert.vue:178
 msgid "Do you want to disable auto-cert renewal?"
 msgstr ""
 
@@ -436,10 +451,14 @@ msgstr ""
 msgid "Do you want to enable this site?"
 msgstr ""
 
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:31
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:30
 msgid "Do you want to enable TLS?"
 msgstr ""
 
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:196
+msgid "Do you want to remove this server?"
+msgstr ""
+
 #: src/views/domain/DomainAdd.vue:58
 msgid "Domain Config Created Successfully"
 msgstr ""
@@ -490,7 +509,7 @@ msgstr ""
 msgid "Enable auto-renewal failed for %{name}"
 msgstr ""
 
-#: src/views/domain/DomainAdd.vue:51
+#: src/views/domain/DomainAdd.vue:50
 msgid "Enable failed"
 msgstr ""
 
@@ -507,13 +526,13 @@ msgstr ""
 #: src/views/domain/DomainList.vue:11
 #: src/views/domain/DomainList.vue:12
 #: src/views/domain/DomainList.vue:19
-#: src/views/domain/DomainList.vue:32
+#: src/views/domain/DomainList.vue:31
 msgid "Enabled"
 msgstr ""
 
-#: src/views/domain/DomainAdd.vue:47
+#: src/views/domain/DomainAdd.vue:46
 #: src/views/domain/DomainEdit.vue:150
-#: src/views/domain/DomainList.vue:60
+#: src/views/domain/DomainList.vue:59
 msgid "Enabled successfully"
 msgstr ""
 
@@ -525,7 +544,7 @@ msgstr ""
 msgid "Error"
 msgstr ""
 
-#: src/routes/index.ts:115
+#: src/routes/index.ts:127
 #: src/views/domain/ngx_conf/LogEntry.vue:68
 msgid "Error Logs"
 msgstr ""
@@ -550,12 +569,12 @@ msgid "Export"
 msgstr ""
 
 #: src/views/domain/DomainEdit.vue:162
-#: src/views/domain/DomainList.vue:74
+#: src/views/domain/DomainList.vue:73
 msgid "Failed to disable %{msg}"
 msgstr ""
 
 #: src/views/domain/DomainEdit.vue:153
-#: src/views/domain/DomainList.vue:64
+#: src/views/domain/DomainList.vue:63
 msgid "Failed to enable %{msg}"
 msgstr ""
 
@@ -567,7 +586,7 @@ msgstr ""
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr ""
 
-#: src/views/config/config.ts:22
+#: src/views/config/config.ts:21
 msgid "File"
 msgstr ""
 
@@ -652,9 +671,9 @@ msgstr ""
 msgid "HTTP Port"
 msgstr ""
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:29
-#: src/views/domain/cert/components/AutoCertStepOne.vue:40
-#: src/views/domain/cert/components/AutoCertStepOne.vue:45
+#: src/views/domain/cert/components/AutoCertStepOne.vue:27
+#: src/views/domain/cert/components/AutoCertStepOne.vue:38
+#: src/views/domain/cert/components/AutoCertStepOne.vue:43
 msgid "HTTP01"
 msgstr ""
 
@@ -666,7 +685,7 @@ msgstr ""
 msgid "Initialing core upgrader"
 msgstr ""
 
-#: src/routes/index.ts:155
+#: src/routes/index.ts:167
 #: src/views/other/Install.vue:128
 msgid "Install"
 msgstr ""
@@ -722,12 +741,12 @@ msgstr ""
 msgid "Locations"
 msgstr ""
 
-#: src/routes/index.ts:161
-#: src/views/other/Login.vue:105
+#: src/routes/index.ts:173
+#: src/views/other/Login.vue:104
 msgid "Login"
 msgstr ""
 
-#: src/views/other/Login.vue:53
+#: src/views/other/Login.vue:52
 msgid "Login successful"
 msgstr ""
 
@@ -774,7 +793,7 @@ msgstr ""
 msgid "Modify"
 msgstr ""
 
-#: src/views/domain/DomainAdd.vue:146
+#: src/views/domain/DomainAdd.vue:145
 msgid "Modify Config"
 msgstr ""
 
@@ -784,10 +803,11 @@ msgid "Multi-line Directive"
 msgstr ""
 
 #: src/views/cert/Cert.vue:16
-#: src/views/config/config.ts:9
+#: src/views/cert/DNSCredential.vue:13
+#: src/views/config/config.ts:8
 #: src/views/domain/cert/ChangeCert.vue:19
 #: src/views/domain/DomainEdit.vue:32
-#: src/views/domain/DomainList.vue:16
+#: src/views/domain/DomainList.vue:15
 #: src/views/domain/SiteDuplicate.vue:5
 msgid "Name"
 msgstr ""
@@ -815,7 +835,7 @@ msgstr ""
 #: src/views/domain/cert/components/ObtainCert.vue:12
 #: src/views/domain/cert/components/ObtainCert.vue:13
 #: src/views/domain/cert/components/ObtainCert.vue:21
-#: src/views/domain/DomainAdd.vue:136
+#: src/views/domain/DomainAdd.vue:135
 msgid "Next"
 msgstr ""
 
@@ -837,7 +857,7 @@ msgstr ""
 msgid "Nginx Error Log Path"
 msgstr ""
 
-#: src/routes/index.ts:105
+#: src/routes/index.ts:117
 #: src/views/nginx_log/NginxLog.vue:2
 #: src/views/preference/Preference.vue:8
 msgid "Nginx Log"
@@ -859,8 +879,8 @@ msgstr ""
 msgid "No"
 msgstr ""
 
-#: src/routes/index.ts:167
-#: src/routes/index.ts:169
+#: src/routes/index.ts:179
+#: src/routes/index.ts:181
 msgid "Not Found"
 msgstr ""
 
@@ -868,6 +888,7 @@ msgstr ""
 msgid "Not Valid Before: %{date}"
 msgstr ""
 
+#: src/views/cert/DNSCredential.vue:6
 #: src/views/domain/cert/components/AutoCertStepOne.vue:17
 msgid "Note"
 msgstr ""
@@ -931,8 +952,12 @@ msgstr ""
 msgid "Performing core upgrade"
 msgstr ""
 
+#: src/views/cert/DNSCredential.vue:44
+msgid "Please fill in the API authentication credentials provided by your DNS provider. We will add one or more TXT records to the DNS records of your domain for ownership verification. Once the verification is complete, the records will be removed. Please note that the time configurations below are all in seconds."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:42
-msgid "Please fill in the API authentication credentials provided by your DNS provider. We will add a TXT record to the DNS records of your domain for ownership verification. Once the verification is complete, the record will be removed. Please note that the time configurations below are all in seconds."
+msgid "Please first add credentials in Certification > DNS Credentials, and then select one of the credentials below to request the API of the DNS provider."
 msgstr ""
 
 #: src/views/domain/SiteDuplicate.vue:28
@@ -944,16 +969,16 @@ msgid "Please input your E-mail!"
 msgstr ""
 
 #: src/views/other/Install.vue:48
-#: src/views/other/Login.vue:42
+#: src/views/other/Login.vue:41
 msgid "Please input your password!"
 msgstr ""
 
 #: src/views/other/Install.vue:42
-#: src/views/other/Login.vue:36
+#: src/views/other/Login.vue:35
 msgid "Please input your username!"
 msgstr ""
 
-#: src/routes/index.ts:128
+#: src/routes/index.ts:140
 #: src/views/preference/Preference.vue:2
 msgid "Preference"
 msgstr ""
@@ -974,6 +999,10 @@ msgstr ""
 msgid "Project Team"
 msgstr ""
 
+#: src/views/cert/DNSCredential.vue:21
+msgid "Provider"
+msgstr ""
+
 #: src/views/dashboard/DashBoard.vue:109
 msgid "Reads"
 msgstr ""
@@ -1080,24 +1109,24 @@ msgid "Save Directive"
 msgstr ""
 
 #: src/views/config/ConfigEdit.vue:53
-#: src/views/domain/DomainAdd.vue:55
-#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:37
+#: src/views/domain/DomainAdd.vue:54
+#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:36
 msgid "Save error %{msg}"
 msgstr ""
 
-#: src/components/StdDataDisplay/StdBatchEdit.vue:40
+#: src/components/StdDataDisplay/StdBatchEdit.vue:39
 #: src/views/preference/Preference.vue:60
 msgid "Save successfully"
 msgstr ""
 
-#: src/components/StdDataDisplay/StdCurd.vue:108
+#: src/components/StdDataDisplay/StdCurd.vue:109
 msgid "Save Successfully"
 msgstr ""
 
 #: src/views/config/ConfigEdit.vue:51
-#: src/views/domain/DomainAdd.vue:44
+#: src/views/domain/DomainAdd.vue:43
 #: src/views/domain/DomainEdit.vue:142
-#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:35
+#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:34
 msgid "Saved successfully"
 msgstr ""
 
@@ -1112,12 +1141,12 @@ msgstr ""
 
 #: src/components/NginxControl/NginxControl.vue:33
 #: src/components/NginxControl/NginxControl.vue:50
-#: src/components/StdDataDisplay/StdBatchEdit.vue:43
+#: src/components/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDataDisplay/StdTable.vue:168
 #: src/components/StdDataDisplay/StdTable.vue:343
 #: src/components/StdDataDisplay/StdTable.vue:463
 #: src/views/config/ConfigEdit.vue:37
-#: src/views/domain/DomainList.vue:84
+#: src/views/domain/DomainList.vue:83
 #: src/views/other/Install.vue:71
 #: src/views/preference/Preference.vue:62
 #: src/views/system/Upgrade.vue:40
@@ -1135,7 +1164,7 @@ msgstr ""
 #: src/views/domain/cert/components/AutoCertStepOne.vue:10
 #: src/views/domain/cert/components/AutoCertStepOne.vue:5
 #: src/views/domain/cert/components/AutoCertStepOne.vue:6
-#: src/views/domain/DomainAdd.vue:111
+#: src/views/domain/DomainAdd.vue:110
 msgid "server_name parameter is required"
 msgstr ""
 
@@ -1148,7 +1177,7 @@ msgstr ""
 msgid "Single Directive"
 msgstr ""
 
-#: src/routes/index.ts:119
+#: src/routes/index.ts:131
 msgid "Site Logs"
 msgstr ""
 
@@ -1172,7 +1201,7 @@ msgstr ""
 msgid "SSL Certification Key Content"
 msgstr ""
 
-#: src/views/domain/DomainList.vue:25
+#: src/views/domain/DomainList.vue:24
 msgid "Status"
 msgstr ""
 
@@ -1192,7 +1221,7 @@ msgstr ""
 msgid "Swap"
 msgstr ""
 
-#: src/routes/index.ts:136
+#: src/routes/index.ts:148
 msgid "System"
 msgstr ""
 
@@ -1200,7 +1229,7 @@ msgstr ""
 msgid "Table"
 msgstr ""
 
-#: src/routes/index.ts:97
+#: src/routes/index.ts:109
 #: src/views/pty/Terminal.vue:2
 msgid "Terminal"
 msgstr ""
@@ -1233,17 +1262,18 @@ msgstr ""
 msgid "This auto-cert item is invalid, please remove it."
 msgstr ""
 
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:32
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:31
 msgid "To make sure the certification auto-renewal can work normally, we need to add a location which can proxy the request from authority to backend, and we need to save this file and reload the Nginx. Are you sure you want to continue?"
 msgstr ""
 
-#: src/views/config/config.ts:14
+#: src/views/config/config.ts:13
 msgid "Type"
 msgstr ""
 
 #: src/views/cert/Cert.vue:68
-#: src/views/config/config.ts:29
-#: src/views/domain/DomainList.vue:42
+#: src/views/cert/DNSCredential.vue:26
+#: src/views/config/config.ts:28
+#: src/views/domain/DomainList.vue:41
 #: src/views/user/User.vue:37
 msgid "Updated at"
 msgstr ""
@@ -1252,7 +1282,7 @@ msgstr ""
 msgid "Updated successfully"
 msgstr ""
 
-#: src/routes/index.ts:147
+#: src/routes/index.ts:159
 #: src/views/system/Upgrade.vue:2
 #: src/views/system/Upgrade.vue:28
 #: src/views/system/Upgrade.vue:29
@@ -1307,7 +1337,7 @@ msgstr ""
 msgid "Warning"
 msgstr ""
 
-#: src/views/domain/cert/components/ObtainCert.vue:181
+#: src/views/domain/cert/components/ObtainCert.vue:179
 msgid "We will remove the HTTPChallenge configuration from this file and reload the Nginx. Are you sure you want to continue?"
 msgstr ""
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
frontend/src/language/translations.json


BIN=BIN
frontend/src/language/zh_CN/app.mo


+ 105 - 74
frontend/src/language/zh_CN/app.po

@@ -12,20 +12,21 @@ msgstr ""
 "Generated-By: easygettext\n"
 "X-Generator: Poedit 3.2.2\n"
 
-#: src/routes/index.ts:143
+#: src/routes/index.ts:155
 msgid "About"
 msgstr "关于"
 
-#: src/routes/index.ts:111 src/views/domain/ngx_conf/LogEntry.vue:64
+#: src/routes/index.ts:123 src/views/domain/ngx_conf/LogEntry.vue:64
 msgid "Access Logs"
 msgstr "访问日志"
 
-#: src/views/cert/Cert.vue:74 src/views/config/config.ts:36
-#: src/views/domain/DomainList.vue:48 src/views/user/User.vue:43
+#: src/views/cert/Cert.vue:74 src/views/cert/DNSCredential.vue:32
+#: src/views/config/config.ts:35 src/views/domain/DomainList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgstr "操作"
 
-#: src/components/StdDataDisplay/StdCurd.vue:145
+#: src/components/StdDataDisplay/StdCurd.vue:146
 #: src/components/StdDataDisplay/StdCurd.vue:25
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:28
 #: src/views/domain/ngx_conf/NgxConfigEditor.vue:47
@@ -51,9 +52,8 @@ msgstr "添加 Location"
 msgid "Add Site"
 msgstr "添加站点"
 
-#: src/views/domain/cert/components/DNSChallenge.vue:12
-#: src/views/domain/cert/components/DNSChallenge.vue:13
-#: src/views/domain/cert/components/DNSChallenge.vue:14
+#: src/views/cert/DNSChallenge.vue:12 src/views/cert/DNSChallenge.vue:13
+#: src/views/cert/DNSChallenge.vue:14
 msgid "Additional"
 msgstr "额外选项"
 
@@ -188,7 +188,7 @@ msgstr "此证书已过期"
 msgid "Certificate is valid"
 msgstr "此证书有效"
 
-#: src/views/cert/Cert.vue:34 src/views/domain/cert/Cert.vue:37
+#: src/views/cert/Cert.vue:34 src/views/domain/cert/Cert.vue:36
 msgid "Certificate Status"
 msgstr "证书状态"
 
@@ -196,7 +196,11 @@ msgstr "证书状态"
 msgid "Certification"
 msgstr "证书"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+#: src/routes/index.ts:97
+msgid "Certification List"
+msgstr "证书列表"
+
+#: src/views/domain/cert/components/AutoCertStepOne.vue:40
 msgid "Challenge Method"
 msgstr "挑战方法"
 
@@ -232,7 +236,7 @@ msgstr "清空"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:33
 #: src/views/domain/ngx_conf/LocationEditor.vue:35
 #: src/views/domain/ngx_conf/LocationEditor.vue:52
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:246
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:250
 msgid "Comments"
 msgstr "注释"
 
@@ -240,7 +244,7 @@ msgstr "注释"
 msgid "Config Name"
 msgstr "配置文件名称"
 
-#: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:81
+#: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:79
 msgid "Config Templates"
 msgstr "配置"
 
@@ -278,7 +282,7 @@ msgstr "CPU 状态"
 msgid "CPU:"
 msgstr "CPU:"
 
-#: src/views/domain/DomainAdd.vue:149
+#: src/views/domain/DomainAdd.vue:148
 msgid "Create Another"
 msgstr "再创建一个"
 
@@ -291,7 +295,10 @@ msgid "Creating client facilitates communication with the CA server"
 msgstr "正在创建客户端用于与 CA 服务器通信"
 
 #: src/views/domain/cert/components/DNSChallenge.vue:6
-#: src/views/domain/cert/components/DNSChallenge.vue:7
+msgid "Credential"
+msgstr "DNS 凭证"
+
+#: src/views/cert/DNSChallenge.vue:6 src/views/cert/DNSChallenge.vue:7
 msgid "Credentials"
 msgstr "凭证"
 
@@ -341,7 +348,7 @@ msgstr "删除"
 msgid "Delete ID: %{id}"
 msgstr "删除 ID: %{id}"
 
-#: src/views/domain/DomainList.vue:82
+#: src/views/domain/DomainList.vue:81
 msgid "Delete site: %{site_name}"
 msgstr "删除站点: %{site_name}"
 
@@ -360,7 +367,7 @@ msgstr "描述"
 msgid "Development Mode"
 msgstr "开发模式"
 
-#: src/views/config/config.ts:20
+#: src/views/config/config.ts:19
 msgid "Dir"
 msgstr "目录"
 
@@ -379,13 +386,13 @@ msgstr "关闭 %{name} 自动续签失败"
 
 #: src/views/cert/Cert.vue:47 src/views/domain/cert/ChangeCert.vue:45
 #: src/views/domain/DomainEdit.vue:10 src/views/domain/DomainEdit.vue:11
-#: src/views/domain/DomainList.vue:16 src/views/domain/DomainList.vue:35
+#: src/views/domain/DomainList.vue:16 src/views/domain/DomainList.vue:34
 #: src/views/domain/DomainList.vue:7 src/views/domain/DomainList.vue:8
 #: src/views/domain/DomainList.vue:9
 msgid "Disabled"
 msgstr "禁用"
 
-#: src/views/domain/DomainEdit.vue:159 src/views/domain/DomainList.vue:70
+#: src/views/domain/DomainEdit.vue:159 src/views/domain/DomainList.vue:69
 msgid "Disabled successfully"
 msgstr "禁用成功"
 
@@ -393,17 +400,22 @@ msgstr "禁用成功"
 msgid "Disk IO"
 msgstr "磁盘 IO"
 
+#: src/routes/index.ts:102 src/views/cert/DNSCredential.vue:2
+msgid "DNS Credentials"
+msgstr "DNS 凭证"
+
+#: src/views/cert/DNSChallenge.vue:3
 #: src/views/domain/cert/components/DNSChallenge.vue:3
 msgid "DNS Provider"
 msgstr "DNS供应商"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:32
-#: src/views/domain/cert/components/AutoCertStepOne.vue:43
-#: src/views/domain/cert/components/AutoCertStepOne.vue:48
+#: src/views/domain/cert/components/AutoCertStepOne.vue:30
+#: src/views/domain/cert/components/AutoCertStepOne.vue:41
+#: src/views/domain/cert/components/AutoCertStepOne.vue:46
 msgid "DNS01"
 msgstr "DNS01"
 
-#: src/views/domain/cert/components/ObtainCert.vue:180
+#: src/views/domain/cert/components/ObtainCert.vue:178
 msgid "Do you want to disable auto-cert renewal?"
 msgstr "你想禁用自动更新证书吗?"
 
@@ -415,10 +427,14 @@ msgstr "你想停用这个网站吗?"
 msgid "Do you want to enable this site?"
 msgstr "你想启用这个网站吗?"
 
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:31
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:30
 msgid "Do you want to enable TLS?"
 msgstr "你想启用TLS吗?"
 
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:196
+msgid "Do you want to remove this server?"
+msgstr "你想删除这个服务器吗?"
+
 #: src/views/domain/DomainAdd.vue:58
 msgid "Domain Config Created Successfully"
 msgstr "域名配置文件创建成功"
@@ -465,7 +481,7 @@ msgstr "邮箱 (*)"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "启用 %{name} 自动续签失败"
 
-#: src/views/domain/DomainAdd.vue:51
+#: src/views/domain/DomainAdd.vue:50
 msgid "Enable failed"
 msgstr "启用失败"
 
@@ -477,12 +493,12 @@ msgstr "启用 TLS"
 #: src/views/domain/DomainEdit.vue:29 src/views/domain/DomainEdit.vue:7
 #: src/views/domain/DomainEdit.vue:8 src/views/domain/DomainList.vue:10
 #: src/views/domain/DomainList.vue:11 src/views/domain/DomainList.vue:12
-#: src/views/domain/DomainList.vue:19 src/views/domain/DomainList.vue:32
+#: src/views/domain/DomainList.vue:19 src/views/domain/DomainList.vue:31
 msgid "Enabled"
 msgstr "启用"
 
-#: src/views/domain/DomainAdd.vue:47 src/views/domain/DomainEdit.vue:150
-#: src/views/domain/DomainList.vue:60
+#: src/views/domain/DomainAdd.vue:46 src/views/domain/DomainEdit.vue:150
+#: src/views/domain/DomainList.vue:59
 msgid "Enabled successfully"
 msgstr "启用成功"
 
@@ -494,7 +510,7 @@ msgstr "用 Let's Encrypt 对网站进行加密"
 msgid "Error"
 msgstr "错误"
 
-#: src/routes/index.ts:115 src/views/domain/ngx_conf/LogEntry.vue:68
+#: src/routes/index.ts:127 src/views/domain/ngx_conf/LogEntry.vue:68
 msgid "Error Logs"
 msgstr "错误日志"
 
@@ -515,11 +531,11 @@ msgstr "过期时间: %{date}"
 msgid "Export"
 msgstr "导出"
 
-#: src/views/domain/DomainEdit.vue:162 src/views/domain/DomainList.vue:74
+#: src/views/domain/DomainEdit.vue:162 src/views/domain/DomainList.vue:73
 msgid "Failed to disable %{msg}"
 msgstr "禁用失败 %{msg}"
 
-#: src/views/domain/DomainEdit.vue:153 src/views/domain/DomainList.vue:64
+#: src/views/domain/DomainEdit.vue:153 src/views/domain/DomainList.vue:63
 msgid "Failed to enable %{msg}"
 msgstr "启用失败 %{msg}"
 
@@ -531,7 +547,7 @@ msgstr "获取证书信息失败"
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr "保存失败,在配置中检测到语法错误。"
 
-#: src/views/config/config.ts:22
+#: src/views/config/config.ts:21
 msgid "File"
 msgstr "文件"
 
@@ -614,9 +630,9 @@ msgstr "HTTP Challenge 监听端口"
 msgid "HTTP Port"
 msgstr "HTTP 监听端口"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:29
-#: src/views/domain/cert/components/AutoCertStepOne.vue:40
-#: src/views/domain/cert/components/AutoCertStepOne.vue:45
+#: src/views/domain/cert/components/AutoCertStepOne.vue:27
+#: src/views/domain/cert/components/AutoCertStepOne.vue:38
+#: src/views/domain/cert/components/AutoCertStepOne.vue:43
 msgid "HTTP01"
 msgstr "HTTP01"
 
@@ -628,7 +644,7 @@ msgstr "初始化核心升级程序错误"
 msgid "Initialing core upgrader"
 msgstr "初始化核心升级器"
 
-#: src/routes/index.ts:155 src/views/other/Install.vue:128
+#: src/routes/index.ts:167 src/views/other/Install.vue:128
 msgid "Install"
 msgstr "安装"
 
@@ -681,11 +697,11 @@ msgstr "Location"
 msgid "Locations"
 msgstr "Locations"
 
-#: src/routes/index.ts:161 src/views/other/Login.vue:105
+#: src/routes/index.ts:173 src/views/other/Login.vue:104
 msgid "Login"
 msgstr "登录"
 
-#: src/views/other/Login.vue:53
+#: src/views/other/Login.vue:52
 msgid "Login successful"
 msgstr "登录成功"
 
@@ -732,7 +748,7 @@ msgstr "内存与存储"
 msgid "Modify"
 msgstr "修改"
 
-#: src/views/domain/DomainAdd.vue:146
+#: src/views/domain/DomainAdd.vue:145
 msgid "Modify Config"
 msgstr "修改配置文件"
 
@@ -741,9 +757,10 @@ msgstr "修改配置文件"
 msgid "Multi-line Directive"
 msgstr "单行指令"
 
-#: src/views/cert/Cert.vue:16 src/views/config/config.ts:9
-#: src/views/domain/cert/ChangeCert.vue:19 src/views/domain/DomainEdit.vue:32
-#: src/views/domain/DomainList.vue:16 src/views/domain/SiteDuplicate.vue:5
+#: src/views/cert/Cert.vue:16 src/views/cert/DNSCredential.vue:13
+#: src/views/config/config.ts:8 src/views/domain/cert/ChangeCert.vue:19
+#: src/views/domain/DomainEdit.vue:32 src/views/domain/DomainList.vue:15
+#: src/views/domain/SiteDuplicate.vue:5
 msgid "Name"
 msgstr "名称"
 
@@ -770,7 +787,7 @@ msgstr "新版本发布"
 #: src/views/domain/cert/components/ObtainCert.vue:12
 #: src/views/domain/cert/components/ObtainCert.vue:13
 #: src/views/domain/cert/components/ObtainCert.vue:21
-#: src/views/domain/DomainAdd.vue:136
+#: src/views/domain/DomainAdd.vue:135
 msgid "Next"
 msgstr "下一步"
 
@@ -792,7 +809,7 @@ msgstr "控制 Nginx"
 msgid "Nginx Error Log Path"
 msgstr "Nginx 错误日志路径"
 
-#: src/routes/index.ts:105 src/views/nginx_log/NginxLog.vue:2
+#: src/routes/index.ts:117 src/views/nginx_log/NginxLog.vue:2
 #: src/views/preference/Preference.vue:8
 msgid "Nginx Log"
 msgstr "Nginx 日志"
@@ -813,7 +830,7 @@ msgstr "Nginx 重启成功"
 msgid "No"
 msgstr "取消"
 
-#: src/routes/index.ts:167 src/routes/index.ts:169
+#: src/routes/index.ts:179 src/routes/index.ts:181
 msgid "Not Found"
 msgstr "找不到页面"
 
@@ -821,6 +838,7 @@ msgstr "找不到页面"
 msgid "Not Valid Before: %{date}"
 msgstr "此前无效: %{date}"
 
+#: src/views/cert/DNSCredential.vue:6
 #: src/views/domain/cert/components/AutoCertStepOne.vue:17
 msgid "Note"
 msgstr "注意"
@@ -881,17 +899,25 @@ msgstr "执行核心升级错误"
 msgid "Performing core upgrade"
 msgstr "正在进行核心升级"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+#: src/views/cert/DNSCredential.vue:44
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
-"provider. We will add a TXT record to the DNS records of your domain for "
-"ownership verification. Once the verification is complete, the record will "
-"be removed. Please note that the time configurations below are all in "
-"seconds."
+"provider. We will add one or more TXT records to the DNS records of your "
+"domain for ownership verification. Once the verification is complete, the "
+"records will be removed. Please note that the time configurations below are "
+"all in seconds."
+msgstr ""
+"请填写您的DNS提供商提供的API认证凭证。我们将在你的域名的DNS记录中添加一个或多"
+"个TXT记录,以进行所有权验证。一旦验证完成,这些记录将被删除。请注意,下面的时"
+"间配置都是以秒为单位。"
+
+#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+msgid ""
+"Please first add credentials in Certification > DNS Credentials, and then "
+"select one of the credentials below to request the API of the DNS provider."
 msgstr ""
-"请填写您的DNS提供商提供的API认证凭证。我们将在你的域名的DNS记录中添加一条TXT"
-"记录,用于所有权验证。一旦验证完成,该记录将被删除。请注意,下面的时间配置都"
-"是以秒为单位。"
+"请首先在 “证书”>”DNS凭证 \"中添加凭证,然后在下方选择一个凭证,请求DNS提供商"
+"的API。"
 
 #: src/views/domain/SiteDuplicate.vue:28
 msgid ""
@@ -903,15 +929,15 @@ msgstr "请输入名称,这将被用作新配置的文件名!"
 msgid "Please input your E-mail!"
 msgstr "请输入您的邮箱!"
 
-#: src/views/other/Install.vue:48 src/views/other/Login.vue:42
+#: src/views/other/Install.vue:48 src/views/other/Login.vue:41
 msgid "Please input your password!"
 msgstr "请输入您的密码!"
 
-#: src/views/other/Install.vue:42 src/views/other/Login.vue:36
+#: src/views/other/Install.vue:42 src/views/other/Login.vue:35
 msgid "Please input your username!"
 msgstr "请输入您的用户名!"
 
-#: src/routes/index.ts:128 src/views/preference/Preference.vue:2
+#: src/routes/index.ts:140 src/views/preference/Preference.vue:2
 msgid "Preference"
 msgstr "偏好设置"
 
@@ -931,6 +957,10 @@ msgstr "禁止删除默认用户"
 msgid "Project Team"
 msgstr "项目团队"
 
+#: src/views/cert/DNSCredential.vue:21
+msgid "Provider"
+msgstr "提供商"
+
 #: src/views/dashboard/DashBoard.vue:109
 msgid "Reads"
 msgstr "读"
@@ -1023,23 +1053,23 @@ msgstr "保存"
 msgid "Save Directive"
 msgstr "保存指令"
 
-#: src/views/config/ConfigEdit.vue:53 src/views/domain/DomainAdd.vue:55
-#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:37
+#: src/views/config/ConfigEdit.vue:53 src/views/domain/DomainAdd.vue:54
+#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:36
 msgid "Save error %{msg}"
 msgstr "保存错误 %{msg}"
 
-#: src/components/StdDataDisplay/StdBatchEdit.vue:40
+#: src/components/StdDataDisplay/StdBatchEdit.vue:39
 #: src/views/preference/Preference.vue:60
 msgid "Save successfully"
 msgstr "保存成功"
 
-#: src/components/StdDataDisplay/StdCurd.vue:108
+#: src/components/StdDataDisplay/StdCurd.vue:109
 msgid "Save Successfully"
 msgstr "保存成功"
 
-#: src/views/config/ConfigEdit.vue:51 src/views/domain/DomainAdd.vue:44
+#: src/views/config/ConfigEdit.vue:51 src/views/domain/DomainAdd.vue:43
 #: src/views/domain/DomainEdit.vue:142
-#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:35
+#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:34
 msgid "Saved successfully"
 msgstr "保存成功"
 
@@ -1053,11 +1083,11 @@ msgstr "上传"
 
 #: src/components/NginxControl/NginxControl.vue:33
 #: src/components/NginxControl/NginxControl.vue:50
-#: src/components/StdDataDisplay/StdBatchEdit.vue:43
+#: src/components/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDataDisplay/StdTable.vue:168
 #: src/components/StdDataDisplay/StdTable.vue:343
 #: src/components/StdDataDisplay/StdTable.vue:463
-#: src/views/config/ConfigEdit.vue:37 src/views/domain/DomainList.vue:84
+#: src/views/config/ConfigEdit.vue:37 src/views/domain/DomainList.vue:83
 #: src/views/other/Install.vue:71 src/views/preference/Preference.vue:62
 #: src/views/system/Upgrade.vue:40
 msgid "Server error"
@@ -1074,7 +1104,7 @@ msgstr "未在指令集合中找到 server_name"
 #: src/views/domain/cert/components/AutoCertStepOne.vue:10
 #: src/views/domain/cert/components/AutoCertStepOne.vue:5
 #: src/views/domain/cert/components/AutoCertStepOne.vue:6
-#: src/views/domain/DomainAdd.vue:111
+#: src/views/domain/DomainAdd.vue:110
 msgid "server_name parameter is required"
 msgstr "必须为 server_name 指令指明参数"
 
@@ -1087,7 +1117,7 @@ msgstr "正在设置环境变量"
 msgid "Single Directive"
 msgstr "单行指令"
 
-#: src/routes/index.ts:119
+#: src/routes/index.ts:131
 msgid "Site Logs"
 msgstr "站点列表"
 
@@ -1111,7 +1141,7 @@ msgstr "SSL证书内容"
 msgid "SSL Certification Key Content"
 msgstr "SSL证书密钥内容"
 
-#: src/views/domain/DomainList.vue:25
+#: src/views/domain/DomainList.vue:24
 msgid "Status"
 msgstr "状态"
 
@@ -1131,7 +1161,7 @@ msgstr "主体名称: %{name}"
 msgid "Swap"
 msgstr "Swap"
 
-#: src/routes/index.ts:136
+#: src/routes/index.ts:148
 msgid "System"
 msgstr "系统"
 
@@ -1139,7 +1169,7 @@ msgstr "系统"
 msgid "Table"
 msgstr "列表"
 
-#: src/routes/index.ts:97 src/views/pty/Terminal.vue:2
+#: src/routes/index.ts:109 src/views/pty/Terminal.vue:2
 msgid "Terminal"
 msgstr "终端"
 
@@ -1176,7 +1206,7 @@ msgstr "主题"
 msgid "This auto-cert item is invalid, please remove it."
 msgstr "这个证书自动续期项目是无效的,请删除。"
 
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:32
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:31
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
 "add a location which can proxy the request from authority to backend, and we "
@@ -1186,12 +1216,13 @@ msgstr ""
 "为了确保认证自动更新能够正常工作,我们需要添加一个能够代理从权威机构到后端的"
 "请求的 Location,并且我们需要保存这个文件并重新加载Nginx。你确定要继续吗?"
 
-#: src/views/config/config.ts:14
+#: src/views/config/config.ts:13
 msgid "Type"
 msgstr "类型"
 
-#: src/views/cert/Cert.vue:68 src/views/config/config.ts:29
-#: src/views/domain/DomainList.vue:42 src/views/user/User.vue:37
+#: src/views/cert/Cert.vue:68 src/views/cert/DNSCredential.vue:26
+#: src/views/config/config.ts:28 src/views/domain/DomainList.vue:41
+#: src/views/user/User.vue:37
 msgid "Updated at"
 msgstr "修改时间"
 
@@ -1199,7 +1230,7 @@ msgstr "修改时间"
 msgid "Updated successfully"
 msgstr "更新成功"
 
-#: src/routes/index.ts:147 src/views/system/Upgrade.vue:2
+#: src/routes/index.ts:159 src/views/system/Upgrade.vue:2
 #: src/views/system/Upgrade.vue:28 src/views/system/Upgrade.vue:29
 #: src/views/system/Upgrade.vue:33 src/views/system/Upgrade.vue:37
 #: src/views/system/Upgrade.vue:41 src/views/system/Upgrade.vue:44
@@ -1248,7 +1279,7 @@ msgstr "查看"
 msgid "Warning"
 msgstr "警告"
 
-#: src/views/domain/cert/components/ObtainCert.vue:181
+#: src/views/domain/cert/components/ObtainCert.vue:179
 msgid ""
 "We will remove the HTTPChallenge configuration from this file and reload the "
 "Nginx. Are you sure you want to continue?"

BIN=BIN
frontend/src/language/zh_TW/app.mo


+ 105 - 74
frontend/src/language/zh_TW/app.po

@@ -13,20 +13,21 @@ msgstr ""
 "Generated-By: easygettext\n"
 "X-Generator: Poedit 3.2.2\n"
 
-#: src/routes/index.ts:143
+#: src/routes/index.ts:155
 msgid "About"
 msgstr "關於"
 
-#: src/routes/index.ts:111 src/views/domain/ngx_conf/LogEntry.vue:64
+#: src/routes/index.ts:123 src/views/domain/ngx_conf/LogEntry.vue:64
 msgid "Access Logs"
 msgstr "訪問日誌"
 
-#: src/views/cert/Cert.vue:74 src/views/config/config.ts:36
-#: src/views/domain/DomainList.vue:48 src/views/user/User.vue:43
+#: src/views/cert/Cert.vue:74 src/views/cert/DNSCredential.vue:32
+#: src/views/config/config.ts:35 src/views/domain/DomainList.vue:47
+#: src/views/user/User.vue:43
 msgid "Action"
 msgstr "操作"
 
-#: src/components/StdDataDisplay/StdCurd.vue:145
+#: src/components/StdDataDisplay/StdCurd.vue:146
 #: src/components/StdDataDisplay/StdCurd.vue:25
 #: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:28
 #: src/views/domain/ngx_conf/NgxConfigEditor.vue:47
@@ -52,9 +53,8 @@ msgstr "新增 Location"
 msgid "Add Site"
 msgstr "新增站點"
 
-#: src/views/domain/cert/components/DNSChallenge.vue:12
-#: src/views/domain/cert/components/DNSChallenge.vue:13
-#: src/views/domain/cert/components/DNSChallenge.vue:14
+#: src/views/cert/DNSChallenge.vue:12 src/views/cert/DNSChallenge.vue:13
+#: src/views/cert/DNSChallenge.vue:14
 msgid "Additional"
 msgstr "其他設定"
 
@@ -189,7 +189,7 @@ msgstr "此憑證已過期"
 msgid "Certificate is valid"
 msgstr "此憑證有效"
 
-#: src/views/cert/Cert.vue:34 src/views/domain/cert/Cert.vue:37
+#: src/views/cert/Cert.vue:34 src/views/domain/cert/Cert.vue:36
 msgid "Certificate Status"
 msgstr "憑證狀態"
 
@@ -197,7 +197,11 @@ msgstr "憑證狀態"
 msgid "Certification"
 msgstr "證照"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+#: src/routes/index.ts:97
+msgid "Certification List"
+msgstr "認證清單"
+
+#: src/views/domain/cert/components/AutoCertStepOne.vue:40
 msgid "Challenge Method"
 msgstr "挑戰方式"
 
@@ -233,7 +237,7 @@ msgstr "清除"
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:33
 #: src/views/domain/ngx_conf/LocationEditor.vue:35
 #: src/views/domain/ngx_conf/LocationEditor.vue:52
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:246
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:250
 msgid "Comments"
 msgstr "註釋"
 
@@ -241,7 +245,7 @@ msgstr "註釋"
 msgid "Config Name"
 msgstr "配置名稱"
 
-#: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:81
+#: src/views/domain/ngx_conf/config_template/ConfigTemplate.vue:79
 msgid "Config Templates"
 msgstr "配置模板"
 
@@ -279,7 +283,7 @@ msgstr "中央處理器狀態"
 msgid "CPU:"
 msgstr "中央處理器:"
 
-#: src/views/domain/DomainAdd.vue:149
+#: src/views/domain/DomainAdd.vue:148
 msgid "Create Another"
 msgstr "再創建一個"
 
@@ -292,7 +296,10 @@ msgid "Creating client facilitates communication with the CA server"
 msgstr "創建客戶端方便與CA服務器通信"
 
 #: src/views/domain/cert/components/DNSChallenge.vue:6
-#: src/views/domain/cert/components/DNSChallenge.vue:7
+msgid "Credential"
+msgstr "憑證"
+
+#: src/views/cert/DNSChallenge.vue:6 src/views/cert/DNSChallenge.vue:7
 msgid "Credentials"
 msgstr "登入資訊"
 
@@ -342,7 +349,7 @@ msgstr "刪除"
 msgid "Delete ID: %{id}"
 msgstr "刪除 ID: %{id}"
 
-#: src/views/domain/DomainList.vue:82
+#: src/views/domain/DomainList.vue:81
 msgid "Delete site: %{site_name}"
 msgstr "刪除站點:%{site_name}"
 
@@ -361,7 +368,7 @@ msgstr "敘述"
 msgid "Development Mode"
 msgstr "開發模式"
 
-#: src/views/config/config.ts:20
+#: src/views/config/config.ts:19
 msgid "Dir"
 msgstr "目錄"
 
@@ -380,13 +387,13 @@ msgstr "關閉 %{name} 自動續簽失敗"
 
 #: src/views/cert/Cert.vue:47 src/views/domain/cert/ChangeCert.vue:45
 #: src/views/domain/DomainEdit.vue:10 src/views/domain/DomainEdit.vue:11
-#: src/views/domain/DomainList.vue:16 src/views/domain/DomainList.vue:35
+#: src/views/domain/DomainList.vue:16 src/views/domain/DomainList.vue:34
 #: src/views/domain/DomainList.vue:7 src/views/domain/DomainList.vue:8
 #: src/views/domain/DomainList.vue:9
 msgid "Disabled"
 msgstr "禁用"
 
-#: src/views/domain/DomainEdit.vue:159 src/views/domain/DomainList.vue:70
+#: src/views/domain/DomainEdit.vue:159 src/views/domain/DomainList.vue:69
 msgid "Disabled successfully"
 msgstr "禁用成功"
 
@@ -394,17 +401,22 @@ msgstr "禁用成功"
 msgid "Disk IO"
 msgstr "磁碟 IO"
 
+#: src/routes/index.ts:102 src/views/cert/DNSCredential.vue:2
+msgid "DNS Credentials"
+msgstr "DNS 憑據"
+
+#: src/views/cert/DNSChallenge.vue:3
 #: src/views/domain/cert/components/DNSChallenge.vue:3
 msgid "DNS Provider"
 msgstr "DNS 供應商"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:32
-#: src/views/domain/cert/components/AutoCertStepOne.vue:43
-#: src/views/domain/cert/components/AutoCertStepOne.vue:48
+#: src/views/domain/cert/components/AutoCertStepOne.vue:30
+#: src/views/domain/cert/components/AutoCertStepOne.vue:41
+#: src/views/domain/cert/components/AutoCertStepOne.vue:46
 msgid "DNS01"
 msgstr "DNS01"
 
-#: src/views/domain/cert/components/ObtainCert.vue:180
+#: src/views/domain/cert/components/ObtainCert.vue:178
 msgid "Do you want to disable auto-cert renewal?"
 msgstr "您要禁用自動證書續訂嗎?"
 
@@ -416,10 +428,14 @@ msgstr "你想禁用這個網站嗎?"
 msgid "Do you want to enable this site?"
 msgstr "您要啟用此站點嗎?"
 
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:31
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:30
 msgid "Do you want to enable TLS?"
 msgstr "您想啟用 TLS 嗎?"
 
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:196
+msgid "Do you want to remove this server?"
+msgstr "您要刪除此服務器嗎?"
+
 #: src/views/domain/DomainAdd.vue:58
 msgid "Domain Config Created Successfully"
 msgstr "域名配置文件創建成功"
@@ -466,7 +482,7 @@ msgstr "郵箱 (*)"
 msgid "Enable auto-renewal failed for %{name}"
 msgstr "啟用 %{name} 自動續簽失敗"
 
-#: src/views/domain/DomainAdd.vue:51
+#: src/views/domain/DomainAdd.vue:50
 msgid "Enable failed"
 msgstr "啟用失敗"
 
@@ -478,12 +494,12 @@ msgstr "啟用 TLS"
 #: src/views/domain/DomainEdit.vue:29 src/views/domain/DomainEdit.vue:7
 #: src/views/domain/DomainEdit.vue:8 src/views/domain/DomainList.vue:10
 #: src/views/domain/DomainList.vue:11 src/views/domain/DomainList.vue:12
-#: src/views/domain/DomainList.vue:19 src/views/domain/DomainList.vue:32
+#: src/views/domain/DomainList.vue:19 src/views/domain/DomainList.vue:31
 msgid "Enabled"
 msgstr "啟用"
 
-#: src/views/domain/DomainAdd.vue:47 src/views/domain/DomainEdit.vue:150
-#: src/views/domain/DomainList.vue:60
+#: src/views/domain/DomainAdd.vue:46 src/views/domain/DomainEdit.vue:150
+#: src/views/domain/DomainList.vue:59
 msgid "Enabled successfully"
 msgstr "啟用成功"
 
@@ -495,7 +511,7 @@ msgstr "用 Let's Encrypt 對網站進行加密"
 msgid "Error"
 msgstr "錯誤"
 
-#: src/routes/index.ts:115 src/views/domain/ngx_conf/LogEntry.vue:68
+#: src/routes/index.ts:127 src/views/domain/ngx_conf/LogEntry.vue:68
 msgid "Error Logs"
 msgstr "錯誤日志"
 
@@ -516,11 +532,11 @@ msgstr "過期時間: %{date}"
 msgid "Export"
 msgstr "導出"
 
-#: src/views/domain/DomainEdit.vue:162 src/views/domain/DomainList.vue:74
+#: src/views/domain/DomainEdit.vue:162 src/views/domain/DomainList.vue:73
 msgid "Failed to disable %{msg}"
 msgstr "禁用失敗 %{msg}"
 
-#: src/views/domain/DomainEdit.vue:153 src/views/domain/DomainList.vue:64
+#: src/views/domain/DomainEdit.vue:153 src/views/domain/DomainList.vue:63
 msgid "Failed to enable %{msg}"
 msgstr "啟用失敗 %{msg}"
 
@@ -532,7 +548,7 @@ msgstr "獲取證書信息失敗"
 msgid "Failed to save, syntax error(s) was detected in the configuration."
 msgstr "保存失敗,在配置中檢測到語法錯誤。"
 
-#: src/views/config/config.ts:22
+#: src/views/config/config.ts:21
 msgid "File"
 msgstr "文件"
 
@@ -615,9 +631,9 @@ msgstr "HTTP 挑戰端口"
 msgid "HTTP Port"
 msgstr "HTTP 監聽埠"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:29
-#: src/views/domain/cert/components/AutoCertStepOne.vue:40
-#: src/views/domain/cert/components/AutoCertStepOne.vue:45
+#: src/views/domain/cert/components/AutoCertStepOne.vue:27
+#: src/views/domain/cert/components/AutoCertStepOne.vue:38
+#: src/views/domain/cert/components/AutoCertStepOne.vue:43
 msgid "HTTP01"
 msgstr "HTTP01"
 
@@ -629,7 +645,7 @@ msgstr "初始核心升級程序錯誤"
 msgid "Initialing core upgrader"
 msgstr "正在初始化核心升級程序"
 
-#: src/routes/index.ts:155 src/views/other/Install.vue:128
+#: src/routes/index.ts:167 src/views/other/Install.vue:128
 msgid "Install"
 msgstr "安裝"
 
@@ -682,11 +698,11 @@ msgstr "Location"
 msgid "Locations"
 msgstr "Locations"
 
-#: src/routes/index.ts:161 src/views/other/Login.vue:105
+#: src/routes/index.ts:173 src/views/other/Login.vue:104
 msgid "Login"
 msgstr "登入"
 
-#: src/views/other/Login.vue:53
+#: src/views/other/Login.vue:52
 msgid "Login successful"
 msgstr "登入成功"
 
@@ -733,7 +749,7 @@ msgstr "記憶體和存儲"
 msgid "Modify"
 msgstr "修改"
 
-#: src/views/domain/DomainAdd.vue:146
+#: src/views/domain/DomainAdd.vue:145
 msgid "Modify Config"
 msgstr "修改配置"
 
@@ -742,9 +758,10 @@ msgstr "修改配置"
 msgid "Multi-line Directive"
 msgstr "多行指令"
 
-#: src/views/cert/Cert.vue:16 src/views/config/config.ts:9
-#: src/views/domain/cert/ChangeCert.vue:19 src/views/domain/DomainEdit.vue:32
-#: src/views/domain/DomainList.vue:16 src/views/domain/SiteDuplicate.vue:5
+#: src/views/cert/Cert.vue:16 src/views/cert/DNSCredential.vue:13
+#: src/views/config/config.ts:8 src/views/domain/cert/ChangeCert.vue:19
+#: src/views/domain/DomainEdit.vue:32 src/views/domain/DomainList.vue:15
+#: src/views/domain/SiteDuplicate.vue:5
 msgid "Name"
 msgstr "名稱"
 
@@ -771,7 +788,7 @@ msgstr "新版本發布"
 #: src/views/domain/cert/components/ObtainCert.vue:12
 #: src/views/domain/cert/components/ObtainCert.vue:13
 #: src/views/domain/cert/components/ObtainCert.vue:21
-#: src/views/domain/DomainAdd.vue:136
+#: src/views/domain/DomainAdd.vue:135
 msgid "Next"
 msgstr "下一步"
 
@@ -793,7 +810,7 @@ msgstr "Nginx 控件"
 msgid "Nginx Error Log Path"
 msgstr "Nginx 錯誤日誌路徑"
 
-#: src/routes/index.ts:105 src/views/nginx_log/NginxLog.vue:2
+#: src/routes/index.ts:117 src/views/nginx_log/NginxLog.vue:2
 #: src/views/preference/Preference.vue:8
 msgid "Nginx Log"
 msgstr "Nginx 日誌"
@@ -814,7 +831,7 @@ msgstr "Nginx 重啟成功"
 msgid "No"
 msgstr "取消"
 
-#: src/routes/index.ts:167 src/routes/index.ts:169
+#: src/routes/index.ts:179 src/routes/index.ts:181
 msgid "Not Found"
 msgstr "找不到頁面"
 
@@ -822,6 +839,7 @@ msgstr "找不到頁面"
 msgid "Not Valid Before: %{date}"
 msgstr "此前無效: %{date}"
 
+#: src/views/cert/DNSCredential.vue:6
 #: src/views/domain/cert/components/AutoCertStepOne.vue:17
 msgid "Note"
 msgstr "備註"
@@ -882,17 +900,25 @@ msgstr "執行核心升級錯誤"
 msgid "Performing core upgrade"
 msgstr "正在執行核心升級"
 
-#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+#: src/views/cert/DNSCredential.vue:44
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
-"provider. We will add a TXT record to the DNS records of your domain for "
-"ownership verification. Once the verification is complete, the record will "
-"be removed. Please note that the time configurations below are all in "
-"seconds."
+"provider. We will add one or more TXT records to the DNS records of your "
+"domain for ownership verification. Once the verification is complete, the "
+"records will be removed. Please note that the time configurations below are "
+"all in seconds."
+msgstr ""
+"請填寫您的 DNS 提供商提供的 API 身份驗證憑據。我們會將一個或多個 TXT 記錄添加"
+"到您域的 DNS 記錄中以進行所有權驗證。驗證完成後,記錄將被刪除。請注意,以下時"
+"間配置均以秒為單位。"
+
+#: src/views/domain/cert/components/AutoCertStepOne.vue:42
+msgid ""
+"Please first add credentials in Certification > DNS Credentials, and then "
+"select one of the credentials below to request the API of the DNS provider."
 msgstr ""
-"請填寫您的 DNS 提供商提供的 API 身份驗證憑據。我們會將 TXT 記錄添加到您域的 "
-"DNS 記錄中以進行所有權驗證。驗證完成後,記錄將被刪除。請注意,以下時間配置均"
-"以秒為單位。"
+"請先在 Certification > DNS Credentials 中添加憑據,然後選擇以下憑據之一以請"
+"求 DNS 提供商的 API。"
 
 #: src/views/domain/SiteDuplicate.vue:28
 msgid ""
@@ -904,15 +930,15 @@ msgstr "請輸入名稱,這將作為新配置的文件名!"
 msgid "Please input your E-mail!"
 msgstr "請輸入您的郵箱!"
 
-#: src/views/other/Install.vue:48 src/views/other/Login.vue:42
+#: src/views/other/Install.vue:48 src/views/other/Login.vue:41
 msgid "Please input your password!"
 msgstr "請輸入您的密碼!"
 
-#: src/views/other/Install.vue:42 src/views/other/Login.vue:36
+#: src/views/other/Install.vue:42 src/views/other/Login.vue:35
 msgid "Please input your username!"
 msgstr "請輸入您的使用者名稱!"
 
-#: src/routes/index.ts:128 src/views/preference/Preference.vue:2
+#: src/routes/index.ts:140 src/views/preference/Preference.vue:2
 msgid "Preference"
 msgstr "設定"
 
@@ -932,6 +958,10 @@ msgstr "禁止刪除默認用戶"
 msgid "Project Team"
 msgstr "專案團隊"
 
+#: src/views/cert/DNSCredential.vue:21
+msgid "Provider"
+msgstr "供應者"
+
 #: src/views/dashboard/DashBoard.vue:109
 msgid "Reads"
 msgstr "讀"
@@ -1024,23 +1054,23 @@ msgstr "儲存"
 msgid "Save Directive"
 msgstr "儲存指令"
 
-#: src/views/config/ConfigEdit.vue:53 src/views/domain/DomainAdd.vue:55
-#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:37
+#: src/views/config/ConfigEdit.vue:53 src/views/domain/DomainAdd.vue:54
+#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:36
 msgid "Save error %{msg}"
 msgstr "儲存錯誤 %{msg}"
 
-#: src/components/StdDataDisplay/StdBatchEdit.vue:40
+#: src/components/StdDataDisplay/StdBatchEdit.vue:39
 #: src/views/preference/Preference.vue:60
 msgid "Save successfully"
 msgstr "保存成功"
 
-#: src/components/StdDataDisplay/StdCurd.vue:108
+#: src/components/StdDataDisplay/StdCurd.vue:109
 msgid "Save Successfully"
 msgstr "保存成功"
 
-#: src/views/config/ConfigEdit.vue:51 src/views/domain/DomainAdd.vue:44
+#: src/views/config/ConfigEdit.vue:51 src/views/domain/DomainAdd.vue:43
 #: src/views/domain/DomainEdit.vue:142
-#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:35
+#: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:34
 msgid "Saved successfully"
 msgstr "儲存成功"
 
@@ -1054,11 +1084,11 @@ msgstr "上傳"
 
 #: src/components/NginxControl/NginxControl.vue:33
 #: src/components/NginxControl/NginxControl.vue:50
-#: src/components/StdDataDisplay/StdBatchEdit.vue:43
+#: src/components/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDataDisplay/StdTable.vue:168
 #: src/components/StdDataDisplay/StdTable.vue:343
 #: src/components/StdDataDisplay/StdTable.vue:463
-#: src/views/config/ConfigEdit.vue:37 src/views/domain/DomainList.vue:84
+#: src/views/config/ConfigEdit.vue:37 src/views/domain/DomainList.vue:83
 #: src/views/other/Install.vue:71 src/views/preference/Preference.vue:62
 #: src/views/system/Upgrade.vue:40
 msgid "Server error"
@@ -1075,7 +1105,7 @@ msgstr "未在指令集合中找到 server_name"
 #: src/views/domain/cert/components/AutoCertStepOne.vue:10
 #: src/views/domain/cert/components/AutoCertStepOne.vue:5
 #: src/views/domain/cert/components/AutoCertStepOne.vue:6
-#: src/views/domain/DomainAdd.vue:111
+#: src/views/domain/DomainAdd.vue:110
 msgid "server_name parameter is required"
 msgstr "必須為 server_name 指令指明參數"
 
@@ -1088,7 +1118,7 @@ msgstr "設置環境變量"
 msgid "Single Directive"
 msgstr "單行指令"
 
-#: src/routes/index.ts:119
+#: src/routes/index.ts:131
 msgid "Site Logs"
 msgstr "網站日誌"
 
@@ -1112,7 +1142,7 @@ msgstr "SSL認證內容"
 msgid "SSL Certification Key Content"
 msgstr "SSL 證書密鑰內容"
 
-#: src/views/domain/DomainList.vue:25
+#: src/views/domain/DomainList.vue:24
 msgid "Status"
 msgstr "狀態"
 
@@ -1132,7 +1162,7 @@ msgstr "主體名稱: %{name}"
 msgid "Swap"
 msgstr "交換空間"
 
-#: src/routes/index.ts:136
+#: src/routes/index.ts:148
 msgid "System"
 msgstr "系統"
 
@@ -1140,7 +1170,7 @@ msgstr "系統"
 msgid "Table"
 msgstr "表格"
 
-#: src/routes/index.ts:97 src/views/pty/Terminal.vue:2
+#: src/routes/index.ts:109 src/views/pty/Terminal.vue:2
 msgid "Terminal"
 msgstr "終端"
 
@@ -1178,7 +1208,7 @@ msgstr "外觀樣式"
 msgid "This auto-cert item is invalid, please remove it."
 msgstr "此自動證書項無效,請將其刪除。"
 
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:32
+#: src/views/domain/ngx_conf/NgxConfigEditor.vue:31
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
 "add a location which can proxy the request from authority to backend, and we "
@@ -1188,12 +1218,13 @@ msgstr ""
 "為了保證證書自動續期能夠正常進行,我們需要添加一個 Location 來代理從權限到後"
 "端的請求,我們需要保存這個文件並重新加載Nginx。你確定你要繼續嗎?"
 
-#: src/views/config/config.ts:14
+#: src/views/config/config.ts:13
 msgid "Type"
 msgstr "類型"
 
-#: src/views/cert/Cert.vue:68 src/views/config/config.ts:29
-#: src/views/domain/DomainList.vue:42 src/views/user/User.vue:37
+#: src/views/cert/Cert.vue:68 src/views/cert/DNSCredential.vue:26
+#: src/views/config/config.ts:28 src/views/domain/DomainList.vue:41
+#: src/views/user/User.vue:37
 msgid "Updated at"
 msgstr "修改時間"
 
@@ -1201,7 +1232,7 @@ msgstr "修改時間"
 msgid "Updated successfully"
 msgstr "已成功更新"
 
-#: src/routes/index.ts:147 src/views/system/Upgrade.vue:2
+#: src/routes/index.ts:159 src/views/system/Upgrade.vue:2
 #: src/views/system/Upgrade.vue:28 src/views/system/Upgrade.vue:29
 #: src/views/system/Upgrade.vue:33 src/views/system/Upgrade.vue:37
 #: src/views/system/Upgrade.vue:41 src/views/system/Upgrade.vue:44
@@ -1250,7 +1281,7 @@ msgstr "查看"
 msgid "Warning"
 msgstr "警告"
 
-#: src/views/domain/cert/components/ObtainCert.vue:181
+#: src/views/domain/cert/components/ObtainCert.vue:179
 msgid ""
 "We will remove the HTTPChallenge configuration from this file and reload the "
 "Nginx. Are you sure you want to continue?"

+ 88 - 0
frontend/src/views/cert/DNSChallenge.vue

@@ -0,0 +1,88 @@
+<script setup lang="ts">
+import {computed, inject, ref, watch} from 'vue'
+import auto_cert from '@/api/auto_cert'
+import {useGettext} from 'vue3-gettext'
+import {SelectProps} from 'ant-design-vue'
+
+const {$gettext} = useGettext()
+const providers: any = ref([])
+
+const data: any = inject('data')!
+
+const code = computed(() => {
+    return data.code
+})
+
+function init() {
+    providers.value?.forEach((v: any, k: number) => {
+        if (v.code === code.value) {
+            provider_idx.value = k
+        }
+    })
+}
+
+auto_cert.get_dns_providers().then(r => {
+    providers.value = r
+}).then(() => {
+    init()
+})
+
+const provider_idx = ref()
+
+const current: any = computed(() => {
+    return providers.value?.[provider_idx.value]
+})
+
+
+watch(code, init)
+
+watch(current, () => {
+    data.code = current.value.code
+    data.provider = current.value.name
+    auto_cert.get_dns_provider(current.value.code).then(r => {
+        Object.assign(current.value, r)
+    })
+})
+
+const options = computed<SelectProps['options']>(() => {
+    let list: SelectProps['options'] = []
+
+    providers.value.forEach((v: any, k: number) => {
+        list!.push({
+            value: k,
+            label: v.name
+        })
+    })
+
+    return list
+})
+
+const filterOption = (input: string, option: any) => {
+    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+}
+</script>
+
+<template>
+    <a-form layout="vertical">
+        <a-form-item :label="$gettext('DNS Provider')">
+            <a-select v-model:value="provider_idx" show-search :options="options" :filter-option="filterOption"/>
+        </a-form-item>
+        <template v-if="current?.configuration?.credentials">
+            <h4>{{ $gettext('Credentials') }}</h4>
+            <a-form-item :label="k" v-for="(v,k) in current?.configuration?.credentials"
+                         :extra="v" :rules="[{ required: true }]">
+                <a-input v-model:value="data.configuration.credentials[k]"/>
+            </a-form-item>
+        </template>
+        <template v-if="current?.configuration?.additional">
+            <h4>{{ $gettext('Additional') }}</h4>
+            <a-form-item :label="k" v-for="(v,k) in current?.configuration?.additional" :extra="v">
+                <a-input v-model:value="data.configuration.additional[k]"/>
+            </a-form-item>
+        </template>
+    </a-form>
+</template>
+
+<style lang="less" scoped>
+
+</style>

+ 1 - 1
frontend/src/views/cert/DNSCredential.vue

@@ -4,7 +4,7 @@ import {datetime} from '@/components/StdDataDisplay/StdTableTransformer'
 import dns_credential from '@/api/dns_credential'
 import StdCurd from '@/components/StdDataDisplay/StdCurd.vue'
 import Template from '@/views/template/Template.vue'
-import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'
+import DNSChallenge from './DNSChallenge.vue'
 import {input} from '@/components/StdDataEntry'
 
 const {$gettext, interpolate} = useGettext()

+ 2 - 4
frontend/src/views/domain/cert/components/AutoCertStepOne.vue

@@ -40,10 +40,8 @@ const data: Ref = inject('data')!
                 directory to HTTPChallengePort before obtaining the certificate.
             </p>
             <p v-else-if="data.challenge_method==='dns01'" v-translate>
-                Please fill in the API authentication credentials provided by your DNS provider.
-                We will add a TXT record to the DNS records of your domain for ownership verification.
-                Once the verification is complete, the record will be removed.
-                Please note that the time configurations below are all in seconds.
+                Please first add credentials in Certification > DNS Credentials, and then select one of the credentials
+                below to request the API of the DNS provider.
             </p>
         </template>
     </a-alert>

+ 16 - 15
frontend/src/views/domain/cert/components/DNSChallenge.vue

@@ -3,9 +3,11 @@ import {computed, inject, ref, watch} from 'vue'
 import auto_cert from '@/api/auto_cert'
 import {useGettext} from 'vue3-gettext'
 import {SelectProps} from 'ant-design-vue'
+import dns_credential from '@/api/dns_credential'
 
 const {$gettext} = useGettext()
 const providers: any = ref([])
+const credentials: any = ref([])
 
 const data: any = inject('data')!
 
@@ -37,10 +39,19 @@ const current: any = computed(() => {
 watch(code, init)
 
 watch(current, () => {
+    credentials.value = []
     data.code = current.value.code
     data.provider = current.value.name
-    auto_cert.get_dns_provider(current.value.code).then(r => {
-        Object.assign(current.value, r)
+    data.dns_credential_id = null
+
+    dns_credential.get_list({provider: data.provider}).then(r => {
+        r.data.forEach((v: any) => {
+            credentials.value.push({
+                value: v.id,
+                label: v.name
+            })
+        })
+
     })
 })
 
@@ -67,19 +78,9 @@ const filterOption = (input: string, option: any) => {
         <a-form-item :label="$gettext('DNS Provider')">
             <a-select v-model:value="provider_idx" show-search :options="options" :filter-option="filterOption"/>
         </a-form-item>
-        <template v-if="current?.configuration?.credentials">
-            <h4>{{ $gettext('Credentials') }}</h4>
-            <a-form-item :label="k" v-for="(v,k) in current?.configuration?.credentials"
-                         :extra="v" :rules="[{ required: true }]">
-                <a-input v-model:value="data.configuration.credentials[k]"/>
-            </a-form-item>
-        </template>
-        <template v-if="current?.configuration?.additional">
-            <h4>{{ $gettext('Additional') }}</h4>
-            <a-form-item :label="k" v-for="(v,k) in current?.configuration?.additional" :extra="v">
-                <a-input v-model:value="data.configuration.additional[k]"/>
-            </a-form-item>
-        </template>
+        <a-form-item v-if="provider_idx>-1" :label="$gettext('Credential')" :rules="[{ required: true }]">
+            <a-select :options="credentials" v-model:value="data.dns_credential_id"/>
+        </a-form-item>
     </a-form>
 </template>
 

+ 5 - 7
frontend/src/views/domain/cert/components/ObtainCert.vue

@@ -44,8 +44,8 @@ async function callback(ssl_certificate: string, ssl_certificate_key: string) {
     save_site_config()
 }
 
-function change_auto_cert(r: boolean) {
-    if (r) {
+function change_auto_cert(status: boolean) {
+    if (status) {
         domain.add_auto_cert(props.config_name, {domains: name.value.trim().split(' ')}).then(() => {
             message.success(interpolate($gettext('Auto-renewal enabled for %{name}'), {name: name.value}))
         }).catch(e => {
@@ -61,7 +61,6 @@ function change_auto_cert(r: boolean) {
 }
 
 async function onchange(r: boolean) {
-    change_auto_cert(r)
     if (r) {
         await template.get_block('letsencrypt.conf').then(r => {
             props.ngx_config.servers.forEach(async (v: any) => {
@@ -80,6 +79,7 @@ async function onchange(r: boolean) {
             v.locations = v.locations.filter((l: any) => l.path !== '/.well-known/acme-challenge')
         })
         save_site_config()
+        change_auto_cert(r)
     }
 }
 
@@ -138,10 +138,7 @@ const issue_cert = async (config_name: string, server_name: string, callback: Fu
     ws.onopen = () => {
         ws.send(JSON.stringify({
             server_name: server_name.trim().split(' '),
-            challenge_method: data.challenge_method,
-            config: {
-                ...data
-            }
+            ...data
         }))
     }
 
@@ -161,6 +158,7 @@ const issue_cert = async (config_name: string, server_name: string, callback: Fu
                     progressStatus.value = 'success'
                     progressPercent.value = 100
                     callback(r.ssl_certificate, r.ssl_certificate_key)
+                    change_auto_cert(true)
                 } else {
                     progressStatus.value = 'exception'
                 }

+ 1 - 0
frontend/src/views/domain/ngx_conf/LocationEditor.vue

@@ -3,6 +3,7 @@ import CodeEditor from '@/components/CodeEditor'
 import {useGettext} from 'vue3-gettext'
 import {reactive, ref} from 'vue'
 import {DeleteOutlined, HolderOutlined} from '@ant-design/icons-vue'
+import draggable from 'vuedraggable'
 
 const {$gettext} = useGettext()
 

+ 1 - 0
frontend/src/views/domain/ngx_conf/directive/DirectiveEditor.vue

@@ -3,6 +3,7 @@ import DirectiveAdd from '@/views/domain/ngx_conf/directive/DirectiveAdd'
 import {useGettext} from 'vue3-gettext'
 import {reactive, ref} from 'vue'
 import DirectiveEditorItem from '@/views/domain/ngx_conf/directive/DirectiveEditorItem.vue'
+import draggable from 'vuedraggable'
 
 const {$gettext} = useGettext()
 

+ 14 - 2
resources/development/nginx/sites-available/homework.jackyu.cn

@@ -4,13 +4,25 @@ server {
     server_name homework.jackyu.cn;
     # rewrite ^(.*)$  https://$host$1 permanent;
     return 307 https://$server_name$request_uri;
+    location /.well-known/acme-challenge {
+        proxy_set_header Host $host;
+        proxy_set_header X-Real_IP $remote_addr;
+        proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
+        proxy_pass http://127.0.0.1:5002;
+    }
 }
 server {
     listen 443 ssl http2;
     listen [::]:443 ssl http2;
-    ssl_certificate /etc/nginx/ssl/homework.jackyu.cn/fullchain.cer;
-    ssl_certificate_key /etc/nginx/ssl/homework.jackyu.cn/private.key;
+    ssl_certificate /etc/nginx/ssl/home.jackyu.cn/fullchain.cer;
+    ssl_certificate_key /etc/nginx/ssl/home.jackyu.cn/private.key;
     # rewrite ^(.*)$  https://$host$1 permanent;
     return 307 https://$server_name$request_uri;
     server_name home.jackyu.cn;
+    location /.well-known/acme-challenge {
+        proxy_set_header Host $host;
+        proxy_set_header X-Real_IP $remote_addr;
+        proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
+        proxy_pass http://127.0.0.1:5002;
+    }
 }

+ 93 - 0
resources/development/nginx/ssl/home.jackyu.cn/fullchain.cer

@@ -0,0 +1,93 @@
+-----BEGIN CERTIFICATE-----
+MIIFIjCCBAqgAwIBAgISA9cwhRyeHm9sWP3BzA7VdcKvMA0GCSqGSIb3DQEBCwUA
+MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
+EwJSMzAeFw0yMzA0MTMwNTQzMTJaFw0yMzA3MTIwNTQzMTFaMBkxFzAVBgNVBAMT
+DmhvbWUuamFja3l1LmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+wmvGGH/EeYiuR/XlorpccaPBS4mMRQHgwoudzv2h+V5N8ygnxfKPlmCG5xsgNrVu
+S9/CPg2Bj4jqZSkOH1MCCdPm7oWbkJZ125GW6vnRMvYFOIljkl5b0r6h9rYOFFvY
+Kg93RUgCG2qFHJxlTyzeBhcTfJKJdajB2BKxpgELqZfucxY0WB5VIIle3wlV1U7e
+QCjIk0FdvrJ3QxjRahtrvMstnuSgaaQGBEdGbQNM1kd+Iew3HW7sE9E07g38gkEN
+0tgD3057aW75heEuU0MAD+T9MvrHUiq08Hedr9erryje0MDkuBpYYqKIMzABX1n6
+tTq4N3AqA2H7NwnfIEMA8QIDAQABo4ICSTCCAkUwDgYDVR0PAQH/BAQDAgWgMB0G
+A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1Ud
+DgQWBBTR4VfaZbqf3ESlwy3wIkJvg5gDVzAfBgNVHSMEGDAWgBQULrMXt1hWy65Q
+CUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6Ly9y
+My5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iub3Jn
+LzAZBgNVHREEEjAQgg5ob21lLmphY2t5dS5jbjBMBgNVHSAERTBDMAgGBmeBDAEC
+ATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNl
+bmNyeXB0Lm9yZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB3AHoyjFTYty22IOo4
+4FIe6YQWcDIThU070ivBOlejUutSAAABh3lalJMAAAQDAEgwRgIhAMrMa1TWmJ6v
+u/zRN9YqWZGJcU+xSQyHDKgkM9V0s46iAiEA2qr2L39vvWJBu1Dnx+/0idNFj97a
+pjBXEZq35QTUbKcAdQC3Pvsk35xNunXyOcW6WPRsXfxCz3qfNcSeHQmBJe20mQAA
+AYd5WpTMAAAEAwBGMEQCIHKy+XtWSeGFiCj0M/Z8JvIsMAo0CETk9hmFrnfE6E1n
+AiBiWUOdFD3I77nl5RvY94bJDvMSl9HADmTj7NHhom5YYDANBgkqhkiG9w0BAQsF
+AAOCAQEAYLelbVG+VNZUOWQ6fWWLUFwIvw05ey3vVYVqazjsX0s6eMf/8aLREGV9
+lmUbftDooUqLW3wzRjk4aEnO8A4pdxQu7oPbdhLxjuCRreNMroH1LSgO1YWQ7BXP
+3ugihvxhHPAPbe0pfH/rqR3KOe/8tGXWYVeFoBmGHptaQVZt0d2ZceBHq6nMnetw
+K74et3/hAH0Ay3rWUy3uknfEDLymkKS+rMniGA8pybtcTyX0MAs6FbmiSgFvVct0
+0tNIEsjiCsl9y1Kp89r9t08MmJ3ZTxy3p+ce0gkbq8sIJRgo3o3cK9bUxag8UnhZ
+Tq/8hVY0nOsOZ3/SDXLW6rwHQAd5Uw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
+TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
+cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
+WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
+RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
+R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
+sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
+NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
+Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
+/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
+AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
+Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
+FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
+AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
+Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
+gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
+PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
+ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
+CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
+lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
+avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
+yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
+yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
+hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
+HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
+MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
+nLRbwHOoq7hHwg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
+TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
+cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC
+ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL
+wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D
+LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK
+4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5
+bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y
+sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ
+Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4
+FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc
+SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql
+PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND
+TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1
+c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx
++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB
+ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu
+b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E
+U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu
+MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC
+5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW
+9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG
+WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O
+he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC
+Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
+-----END CERTIFICATE-----

+ 27 - 0
resources/development/nginx/ssl/home.jackyu.cn/private.key

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAwmvGGH/EeYiuR/XlorpccaPBS4mMRQHgwoudzv2h+V5N8ygn
+xfKPlmCG5xsgNrVuS9/CPg2Bj4jqZSkOH1MCCdPm7oWbkJZ125GW6vnRMvYFOIlj
+kl5b0r6h9rYOFFvYKg93RUgCG2qFHJxlTyzeBhcTfJKJdajB2BKxpgELqZfucxY0
+WB5VIIle3wlV1U7eQCjIk0FdvrJ3QxjRahtrvMstnuSgaaQGBEdGbQNM1kd+Iew3
+HW7sE9E07g38gkEN0tgD3057aW75heEuU0MAD+T9MvrHUiq08Hedr9erryje0MDk
+uBpYYqKIMzABX1n6tTq4N3AqA2H7NwnfIEMA8QIDAQABAoIBAQCEDTGKeFWZepVt
+OP4UzeF2KhRi2vTT9heT68Ju0eSO/FeTfUWudDbEm6FlHQ5/OjHFBSDohsHmHMef
+mAgIjJfI1w12Gndz+E3qqXNI/A70PxeCtAZWZxKVDHfzmunrOAqVXtXSz7rmpi3t
+JejFoyLWHhxVMy58JPgsa14P84vZTrHF3HLbL5iXA9qdVNy9mYcYAqbhKD8PTLc7
+Cnk7nzVBRMQwSJZCuEoNDKvhU1nJpaIh/11dzebePUsXUf6VdQz+urJ2EwonIukr
+JHJKEdP0E4ZngfI4o4iFQY8PnQFkk/mBj4ByII2vgRJPVh0I2HSil1tcnQoEb966
+rw+1BBd1AoGBANJALAfjMKjQkXk/+ChDH8KSsRlY3fiOlqwSOnozQq/vGPKbaGaZ
+D3LHNyFZ3dgGXHmkHhErPNHOqv3hz19bLuzKDt7mMKXb+LvrMp7S0BUK+UFK+4P0
+vN3v8Vw5LaqgOuJ7ybkjZGNPC014G3FvrIw62RRQoC8Rz04cvkxmRiEDAoGBAOy5
+0s19jum8ll2eGpqL6HIdLczkvGj1IFQL0NF1rlBhlKNp37ec+mOCCbcow3NeYHfm
+xaJsK3wl0+Q3b2DVCe/UNHWa8dY1Cy0F/pFZxCEtm3ln3xfHj9KF6+HQxbr0Vw10
+p3iXNO6MdTZqQ1WEOe9DR6ayY3nPkTJ6zlzyf+H7AoGADqEIb0QPjq90b8tTqPmC
+rDcou2rDhxfkw/RAvV/zs+ofAkJt8TWVLZdO7rMiDHXk2VHiBa/Me4y1uRSNKUVe
+7nrgrgG2QNQdanXi/8oLUGuDDFf7SCMvQQIA+TnBQ64Cat/SGV+tDHvjfXBt+Gac
+yuUNVayGeL/0fKrjUs2K86ECgYBmLrwIyXbj++yoEnQHW/cFMwUvGVkesRi4TrVf
+hL2uosBnXW8dMdx/EYWiEy1y4j0f5HRQ7QJEP4vcSfWAxdTZOi8+yJg1T4Y4dArz
+sNzROX+QAz8wY4r4Y6hzPAvt7ESbYUxc6GAHzIdX6ryP8FiVp+QI153K2cciFBJ5
+2o9K+wKBgGFY5ipGubbXldPbJ5uKCZD6W4Y9L9GJZRmZtRK71+NdYiAHxhKehSlj
+cmOyh0LKhZkdyKWKFd+NBAYFhABOswWqppkzk/OOI+Bov8jaBuN+7/Va2RrrLXKz
+7kds4TarXHsrQ2gRpC9WNKpy89RLPUSa4TIcylerWaJcW9ZJyNRa
+-----END RSA PRIVATE KEY-----

+ 108 - 100
server/api/dns_credential.go

@@ -1,122 +1,130 @@
 package api
 
 import (
-	"github.com/0xJacky/Nginx-UI/server/model"
-	"github.com/0xJacky/Nginx-UI/server/pkg/cert/dns"
-	"github.com/0xJacky/Nginx-UI/server/query"
-	"github.com/gin-gonic/gin"
-	"github.com/spf13/cast"
-	"net/http"
+    "github.com/0xJacky/Nginx-UI/server/model"
+    "github.com/0xJacky/Nginx-UI/server/pkg/cert/dns"
+    "github.com/0xJacky/Nginx-UI/server/query"
+    "github.com/gin-gonic/gin"
+    "github.com/spf13/cast"
+    "net/http"
 )
 
 func GetDnsCredential(c *gin.Context) {
-	id := cast.ToInt(c.Param("id"))
-
-	d := query.DnsCredential
-
-	dnsCredential, err := d.FirstByID(id)
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
-	type apiDnsCredential struct {
-		model.Model
-		Name string `json:"name"`
-		dns.Config
-	}
-	c.JSON(http.StatusOK, apiDnsCredential{
-		Model:  dnsCredential.Model,
-		Name:   dnsCredential.Name,
-		Config: *dnsCredential.Config,
-	})
+    id := cast.ToInt(c.Param("id"))
+
+    d := query.DnsCredential
+
+    dnsCredential, err := d.FirstByID(id)
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
+    type apiDnsCredential struct {
+        model.Model
+        Name string `json:"name"`
+        dns.Config
+    }
+    c.JSON(http.StatusOK, apiDnsCredential{
+        Model:  dnsCredential.Model,
+        Name:   dnsCredential.Name,
+        Config: *dnsCredential.Config,
+    })
 }
 
 func GetDnsCredentialList(c *gin.Context) {
-	d := query.DnsCredential
-	data, err := d.Find()
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
-	c.JSON(http.StatusOK, gin.H{
-		"data": data,
-	})
+    d := query.DnsCredential
+    provider := c.Query("provider")
+    var data []*model.DnsCredential
+    var err error
+    if provider != "" {
+        data, err = d.Where(d.Provider.Eq(provider)).Find()
+    } else {
+        data, err = d.Find()
+    }
+
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
+    c.JSON(http.StatusOK, gin.H{
+        "data": data,
+    })
 }
 
 type DnsCredentialManageJson struct {
-	Name     string `json:"name" binding:"required"`
-	Provider string `json:"provider"`
-	dns.Config
+    Name     string `json:"name" binding:"required"`
+    Provider string `json:"provider"`
+    dns.Config
 }
 
 func AddDnsCredential(c *gin.Context) {
-	var json DnsCredentialManageJson
-	if !BindAndValid(c, &json) {
-		return
-	}
-
-	json.Config.Name = json.Provider
-	dnsCredential := model.DnsCredential{
-		Name:     json.Name,
-		Config:   &json.Config,
-		Provider: json.Provider,
-	}
-
-	d := query.DnsCredential
-
-	err := d.Create(&dnsCredential)
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, dnsCredential)
+    var json DnsCredentialManageJson
+    if !BindAndValid(c, &json) {
+        return
+    }
+
+    json.Config.Name = json.Provider
+    dnsCredential := model.DnsCredential{
+        Name:     json.Name,
+        Config:   &json.Config,
+        Provider: json.Provider,
+    }
+
+    d := query.DnsCredential
+
+    err := d.Create(&dnsCredential)
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
+
+    c.JSON(http.StatusOK, dnsCredential)
 }
 
 func EditDnsCredential(c *gin.Context) {
-	id := cast.ToInt(c.Param("id"))
-
-	var json DnsCredentialManageJson
-	if !BindAndValid(c, &json) {
-		return
-	}
-
-	d := query.DnsCredential
-
-	dnsCredential, err := d.FirstByID(id)
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
-
-	json.Config.Name = json.Provider
-	_, err = d.Where(d.ID.Eq(dnsCredential.ID)).Updates(&model.DnsCredential{
-		Name:     json.Name,
-		Config:   &json.Config,
-		Provider: json.Provider,
-	})
-
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
-
-	GetDnsCredential(c)
+    id := cast.ToInt(c.Param("id"))
+
+    var json DnsCredentialManageJson
+    if !BindAndValid(c, &json) {
+        return
+    }
+
+    d := query.DnsCredential
+
+    dnsCredential, err := d.FirstByID(id)
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
+
+    json.Config.Name = json.Provider
+    _, err = d.Where(d.ID.Eq(dnsCredential.ID)).Updates(&model.DnsCredential{
+        Name:     json.Name,
+        Config:   &json.Config,
+        Provider: json.Provider,
+    })
+
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
+
+    GetDnsCredential(c)
 }
 
 func DeleteDnsCredential(c *gin.Context) {
-	id := cast.ToInt(c.Param("id"))
-	d := query.DnsCredential
-
-	dnsCredential, err := d.FirstByID(id)
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
-	err = d.DeleteByID(dnsCredential.ID)
-	if err != nil {
-		ErrHandler(c, err)
-		return
-	}
-	c.JSON(http.StatusNoContent, nil)
+    id := cast.ToInt(c.Param("id"))
+    d := query.DnsCredential
+
+    dnsCredential, err := d.FirstByID(id)
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
+    err = d.DeleteByID(dnsCredential.ID)
+    if err != nil {
+        ErrHandler(c, err)
+        return
+    }
+    c.JSON(http.StatusNoContent, nil)
 }

+ 3 - 0
server/model/cert.go

@@ -21,6 +21,9 @@ type Cert struct {
 	SSLCertificatePath    string         `json:"ssl_certificate_path"`
 	SSLCertificateKeyPath string         `json:"ssl_certificate_key_path"`
 	AutoCert              int            `json:"auto_cert"`
+	ChallengeMethod       string         `json:"challenge_method"`
+	DnsCredentialID       int            `json:"dns_credential_id"`
+	DnsCredential         *DnsCredential `json:"dns_credential,omitempty"`
 	Log                   string         `json:"log"`
 }
 

+ 99 - 94
server/pkg/cert/auto_cert.go

@@ -1,123 +1,128 @@
 package cert
 
 import (
-	"fmt"
-	"github.com/0xJacky/Nginx-UI/server/model"
-	"github.com/pkg/errors"
-	"log"
-	"time"
+    "fmt"
+    "github.com/0xJacky/Nginx-UI/server/model"
+    "github.com/pkg/errors"
+    "log"
+    "time"
 )
 
 func handleIssueCertLogChan(logChan chan string) {
-	defer func() {
-		if err := recover(); err != nil {
-			log.Println("[Auto Cert] handleIssueCertLogChan", err)
-		}
-	}()
-
-	for logString := range logChan {
-		log.Println("[Auto Cert] Info", logString)
-	}
+    defer func() {
+        if err := recover(); err != nil {
+            log.Println("[Auto Cert] handleIssueCertLogChan", err)
+        }
+    }()
+
+    for logString := range logChan {
+        log.Println("[Auto Cert] Info", logString)
+    }
 }
 
 type AutoCertErrorLog struct {
-	buffer []string
-	cert   *model.Cert
+    buffer []string
+    cert   *model.Cert
 }
 
 func (t *AutoCertErrorLog) SetCertModel(cert *model.Cert) {
-	t.cert = cert
+    t.cert = cert
 }
 
 func (t *AutoCertErrorLog) Push(text string, err error) {
-	t.buffer = append(t.buffer, text+" "+err.Error())
-	log.Println("[AutoCert Error]", text, err)
+    t.buffer = append(t.buffer, text+" "+err.Error())
+    log.Println("[AutoCert Error]", text, err)
 }
 
 func (t *AutoCertErrorLog) Exit(text string, err error) {
-	t.buffer = append(t.buffer, text+" "+err.Error())
-	log.Println("[AutoCert Error]", text, err)
+    t.buffer = append(t.buffer, text+" "+err.Error())
+    log.Println("[AutoCert Error]", text, err)
 
-	if t.cert == nil {
-		return
-	}
+    if t.cert == nil {
+        return
+    }
 
-	_ = t.cert.Updates(&model.Cert{
-		Log: t.ToString(),
-	})
+    _ = t.cert.Updates(&model.Cert{
+        Log: t.ToString(),
+    })
 }
 
 func (t *AutoCertErrorLog) ToString() (content string) {
 
-	for _, v := range t.buffer {
-		content += fmt.Sprintf("[AutoCert Error] %s\n", v)
-	}
+    for _, v := range t.buffer {
+        content += fmt.Sprintf("[AutoCert Error] %s\n", v)
+    }
 
-	return
+    return
 }
 
 func AutoObtain() {
-	defer func() {
-		if err := recover(); err != nil {
-			log.Println("[AutoCert] Recover", err)
-		}
-	}()
-	log.Println("[AutoCert] Start")
-	autoCertList := model.GetAutoCertList()
-	for _, certModel := range autoCertList {
-		confName := certModel.Filename
-
-		errLog := &AutoCertErrorLog{}
-		errLog.SetCertModel(certModel)
-
-		if len(certModel.Filename) == 0 {
-			errLog.Exit("", errors.New("filename is empty"))
-			continue
-		}
-
-		if len(certModel.Domains) == 0 {
-			errLog.Exit(confName, errors.New("domains list is empty, "+
-				"try to reopen auto-cert for this config:"+confName))
-			continue
-		}
-
-		if certModel.SSLCertificatePath != "" {
-			cert, err := GetCertInfo(certModel.SSLCertificatePath)
-			if err != nil {
-				errLog.Push("get cert info", err)
-				// Get certificate info error, ignore this domain
-				continue
-			}
-			// every week
-			if time.Now().Sub(cert.NotBefore).Hours()/24 < 7 {
-				continue
-			}
-		}
-		// after 1 mo, reissue certificate
-		logChan := make(chan string, 1)
-		errChan := make(chan error, 1)
-
-		// support SAN certification
-		// go IssueCert(certModel.Domains, logChan, errChan)
-
-		go handleIssueCertLogChan(logChan)
-
-		// block, unless errChan closed
-		for err := range errChan {
-			errLog.Push("issue cert", err)
-		}
-
-		logStr := errLog.ToString()
-		if logStr != "" {
-			// store error log to db
-			_ = certModel.Updates(&model.Cert{
-				Log: errLog.ToString(),
-			})
-		} else {
-			certModel.ClearLog()
-		}
-
-		close(logChan)
-	}
-	log.Println("[AutoCert] End")
+    defer func() {
+        if err := recover(); err != nil {
+            log.Println("[AutoCert] Recover", err)
+        }
+    }()
+    log.Println("[AutoCert] Start")
+    autoCertList := model.GetAutoCertList()
+    for _, certModel := range autoCertList {
+        confName := certModel.Filename
+
+        errLog := &AutoCertErrorLog{}
+        errLog.SetCertModel(certModel)
+
+        if len(certModel.Filename) == 0 {
+            errLog.Exit("", errors.New("filename is empty"))
+            continue
+        }
+
+        if len(certModel.Domains) == 0 {
+            errLog.Exit(confName, errors.New("domains list is empty, "+
+                "try to reopen auto-cert for this config:"+confName))
+            continue
+        }
+
+        if certModel.SSLCertificatePath != "" {
+            cert, err := GetCertInfo(certModel.SSLCertificatePath)
+            if err != nil {
+                errLog.Push("get cert info", err)
+                // Get certificate info error, ignore this domain
+                continue
+            }
+            // every week
+            if time.Now().Sub(cert.NotBefore).Hours()/24 < 7 {
+                continue
+            }
+        }
+        // after 1 mo, reissue certificate
+        logChan := make(chan string, 1)
+        errChan := make(chan error, 1)
+
+        // support SAN certification
+        payload := &ConfigPayload{
+            ServerName:      certModel.Domains,
+            ChallengeMethod: certModel.ChallengeMethod,
+            DNSCredentialID: certModel.DnsCredentialID,
+        }
+        go IssueCert(payload, logChan, errChan)
+
+        go handleIssueCertLogChan(logChan)
+
+        // block, unless errChan closed
+        for err := range errChan {
+            errLog.Push("issue cert", err)
+        }
+
+        logStr := errLog.ToString()
+        if logStr != "" {
+            // store error log to db
+            _ = certModel.Updates(&model.Cert{
+                Log: errLog.ToString(),
+            })
+        } else {
+            certModel.ClearLog()
+        }
+
+        close(logChan)
+    }
+    log.Println("[AutoCert] End")
 }

+ 14 - 6
server/pkg/cert/cert.go

@@ -8,6 +8,7 @@ import (
 	"crypto/tls"
 	dns2 "github.com/0xJacky/Nginx-UI/server/pkg/cert/dns"
 	"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
+	"github.com/0xJacky/Nginx-UI/server/query"
 	"github.com/0xJacky/Nginx-UI/server/settings"
 	"github.com/go-acme/lego/v4/certcrypto"
 	"github.com/go-acme/lego/v4/certificate"
@@ -46,9 +47,9 @@ func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
 }
 
 type ConfigPayload struct {
-	ServerName      []string    `json:"server_name"`
-	ChallengeMethod string      `json:"challenge_method"`
-	Config          dns2.Config `json:"config"`
+	ServerName      []string `json:"server_name"`
+	ChallengeMethod string   `json:"challenge_method"`
+	DNSCredentialID int      `json:"dns_credential_id"`
 }
 
 func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error) {
@@ -108,16 +109,23 @@ func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error)
 			),
 		)
 	case DNS01:
+		d := query.DnsCredential
+		dnsCredential, err := d.FirstByID(payload.DNSCredentialID)
+		if err != nil {
+			errChan <- errors.Wrap(err, "get dns credential error")
+			return
+		}
+
 		logChan <- "Using DNS01 challenge provider"
-		code := payload.Config.Code
+		code := dnsCredential.Config.Code
 		pConfig, ok := dns2.GetProvider(code)
 
 		if !ok {
 			errChan <- errors.Wrap(err, "provider not found")
 		}
 		logChan <- "Setting environment variables"
-		if payload.Config.Configuration != nil {
-			err = pConfig.SetEnv(*payload.Config.Configuration)
+		if dnsCredential.Config.Configuration != nil {
+			err = pConfig.SetEnv(*dnsCredential.Config.Configuration)
 			if err != nil {
 				break
 			}

+ 82 - 1
server/query/certs.gen.go

@@ -38,7 +38,14 @@ func newCert(db *gorm.DB, opts ...gen.DOOption) cert {
 	_cert.SSLCertificatePath = field.NewString(tableName, "ssl_certificate_path")
 	_cert.SSLCertificateKeyPath = field.NewString(tableName, "ssl_certificate_key_path")
 	_cert.AutoCert = field.NewInt(tableName, "auto_cert")
+	_cert.ChallengeMethod = field.NewString(tableName, "challenge_method")
+	_cert.DnsCredentialID = field.NewInt(tableName, "dns_credential_id")
 	_cert.Log = field.NewString(tableName, "log")
+	_cert.DnsCredential = certBelongsToDnsCredential{
+		db: db.Session(&gorm.Session{}),
+
+		RelationField: field.NewRelation("DnsCredential", "model.DnsCredential"),
+	}
 
 	_cert.fillFieldMap()
 
@@ -59,7 +66,10 @@ type cert struct {
 	SSLCertificatePath    field.String
 	SSLCertificateKeyPath field.String
 	AutoCert              field.Int
+	ChallengeMethod       field.String
+	DnsCredentialID       field.Int
 	Log                   field.String
+	DnsCredential         certBelongsToDnsCredential
 
 	fieldMap map[string]field.Expr
 }
@@ -86,6 +96,8 @@ func (c *cert) updateTableName(table string) *cert {
 	c.SSLCertificatePath = field.NewString(table, "ssl_certificate_path")
 	c.SSLCertificateKeyPath = field.NewString(table, "ssl_certificate_key_path")
 	c.AutoCert = field.NewInt(table, "auto_cert")
+	c.ChallengeMethod = field.NewString(table, "challenge_method")
+	c.DnsCredentialID = field.NewInt(table, "dns_credential_id")
 	c.Log = field.NewString(table, "log")
 
 	c.fillFieldMap()
@@ -103,7 +115,7 @@ func (c *cert) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
 }
 
 func (c *cert) fillFieldMap() {
-	c.fieldMap = make(map[string]field.Expr, 11)
+	c.fieldMap = make(map[string]field.Expr, 14)
 	c.fieldMap["id"] = c.ID
 	c.fieldMap["created_at"] = c.CreatedAt
 	c.fieldMap["updated_at"] = c.UpdatedAt
@@ -114,7 +126,10 @@ func (c *cert) fillFieldMap() {
 	c.fieldMap["ssl_certificate_path"] = c.SSLCertificatePath
 	c.fieldMap["ssl_certificate_key_path"] = c.SSLCertificateKeyPath
 	c.fieldMap["auto_cert"] = c.AutoCert
+	c.fieldMap["challenge_method"] = c.ChallengeMethod
+	c.fieldMap["dns_credential_id"] = c.DnsCredentialID
 	c.fieldMap["log"] = c.Log
+
 }
 
 func (c cert) clone(db *gorm.DB) cert {
@@ -127,6 +142,72 @@ func (c cert) replaceDB(db *gorm.DB) cert {
 	return c
 }
 
+type certBelongsToDnsCredential struct {
+	db *gorm.DB
+
+	field.RelationField
+}
+
+func (a certBelongsToDnsCredential) Where(conds ...field.Expr) *certBelongsToDnsCredential {
+	if len(conds) == 0 {
+		return &a
+	}
+
+	exprs := make([]clause.Expression, 0, len(conds))
+	for _, cond := range conds {
+		exprs = append(exprs, cond.BeCond().(clause.Expression))
+	}
+	a.db = a.db.Clauses(clause.Where{Exprs: exprs})
+	return &a
+}
+
+func (a certBelongsToDnsCredential) WithContext(ctx context.Context) *certBelongsToDnsCredential {
+	a.db = a.db.WithContext(ctx)
+	return &a
+}
+
+func (a certBelongsToDnsCredential) Model(m *model.Cert) *certBelongsToDnsCredentialTx {
+	return &certBelongsToDnsCredentialTx{a.db.Model(m).Association(a.Name())}
+}
+
+type certBelongsToDnsCredentialTx struct{ tx *gorm.Association }
+
+func (a certBelongsToDnsCredentialTx) Find() (result *model.DnsCredential, err error) {
+	return result, a.tx.Find(&result)
+}
+
+func (a certBelongsToDnsCredentialTx) Append(values ...*model.DnsCredential) (err error) {
+	targetValues := make([]interface{}, len(values))
+	for i, v := range values {
+		targetValues[i] = v
+	}
+	return a.tx.Append(targetValues...)
+}
+
+func (a certBelongsToDnsCredentialTx) Replace(values ...*model.DnsCredential) (err error) {
+	targetValues := make([]interface{}, len(values))
+	for i, v := range values {
+		targetValues[i] = v
+	}
+	return a.tx.Replace(targetValues...)
+}
+
+func (a certBelongsToDnsCredentialTx) Delete(values ...*model.DnsCredential) (err error) {
+	targetValues := make([]interface{}, len(values))
+	for i, v := range values {
+		targetValues[i] = v
+	}
+	return a.tx.Delete(targetValues...)
+}
+
+func (a certBelongsToDnsCredentialTx) Clear() error {
+	return a.tx.Clear()
+}
+
+func (a certBelongsToDnsCredentialTx) Count() int64 {
+	return a.tx.Count()
+}
+
 type certDo struct{ gen.DO }
 
 // FirstByID Where("id=@id")

+ 5 - 1
server/query/dns_credentials.gen.go

@@ -34,6 +34,7 @@ func newDnsCredential(db *gorm.DB, opts ...gen.DOOption) dnsCredential {
 	_dnsCredential.DeletedAt = field.NewTime(tableName, "deleted_at")
 	_dnsCredential.Name = field.NewString(tableName, "name")
 	_dnsCredential.Config = field.NewField(tableName, "config")
+	_dnsCredential.Provider = field.NewString(tableName, "provider")
 
 	_dnsCredential.fillFieldMap()
 
@@ -50,6 +51,7 @@ type dnsCredential struct {
 	DeletedAt field.Time
 	Name      field.String
 	Config    field.Field
+	Provider  field.String
 
 	fieldMap map[string]field.Expr
 }
@@ -72,6 +74,7 @@ func (d *dnsCredential) updateTableName(table string) *dnsCredential {
 	d.DeletedAt = field.NewTime(table, "deleted_at")
 	d.Name = field.NewString(table, "name")
 	d.Config = field.NewField(table, "config")
+	d.Provider = field.NewString(table, "provider")
 
 	d.fillFieldMap()
 
@@ -88,13 +91,14 @@ func (d *dnsCredential) GetFieldByName(fieldName string) (field.OrderExpr, bool)
 }
 
 func (d *dnsCredential) fillFieldMap() {
-	d.fieldMap = make(map[string]field.Expr, 6)
+	d.fieldMap = make(map[string]field.Expr, 7)
 	d.fieldMap["id"] = d.ID
 	d.fieldMap["created_at"] = d.CreatedAt
 	d.fieldMap["updated_at"] = d.UpdatedAt
 	d.fieldMap["deleted_at"] = d.DeletedAt
 	d.fieldMap["name"] = d.Name
 	d.fieldMap["config"] = d.Config
+	d.fieldMap["provider"] = d.Provider
 }
 
 func (d dnsCredential) clone(db *gorm.DB) dnsCredential {

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio