diff --git a/Makefile b/Makefile
index 82c32f3..f5acc3a 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,7 @@ clean:
build_fe:
cd fe && yarn && yarn build
+ rm -rf server/http_server/dist
cd server && cp -rf ../fe/dist http_server
build_server:
diff --git a/fe/src/i18n/i18n.js b/fe/src/i18n/i18n.js
index d973653..acdc58a 100644
--- a/fe/src/i18n/i18n.js
+++ b/fe/src/i18n/i18n.js
@@ -63,7 +63,8 @@ var lang = {
"web_domain": "Web Domain",
"dns_desc": "Please add the following information to your DNS records",
"ssl_auto": "Automatically configure SSL certificates (recommended)",
- "wait_desc": "HTTP challenge mode completes in approximately 1 minute.",
+ "wait_desc": "Please Wait.",
+ "dns_challenge_wait": "DNS propagation and cache refreshes take a long time, and a wait of 10-30 minutes is possible here.",
"ssl_challenge_type":"Challenge Type",
"ssl_auto_http":"Http Request",
"ssl_auto_dns":"DNS Records",
@@ -176,7 +177,8 @@ var zhCN = {
"ssl_challenge_type":"验证方式",
"ssl_manuallyf": "手动配置SSL证书",
"challenge_typ_desc": "如果PMail直接使用80端口,建议使用HTTP验证方式。",
- "wait_desc": "HTTP验证模式大约1分钟完成",
+ "wait_desc": "请稍等",
+ "dns_challenge_wait": "DNS传播和缓存刷新时间较长,此处可能等待10-30分钟",
"ssl_key_path": "ssl key文件位置",
"ssl_crt_path": "ssl crt文件位置",
"group_settings": "分组",
diff --git a/fe/src/views/ListView.vue b/fe/src/views/ListView.vue
index 4ca3dcb..d314635 100644
--- a/fe/src/views/ListView.vue
+++ b/fe/src/views/ListView.vue
@@ -40,6 +40,14 @@
+
+
+ !
+
+
+
diff --git a/fe/src/views/SetupView.vue b/fe/src/views/SetupView.vue
index f43831d..c75e1fc 100644
--- a/fe/src/views/SetupView.vue
+++ b/fe/src/views/SetupView.vue
@@ -133,16 +133,17 @@
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -313,7 +170,30 @@
- {{
+
+
+
+
+
+
+
+
+
+ {{ scope.row.value }}
+
+ {{ scope.row.value }}
+
+
+
+
+
+
+
+
+
+
+ {{
lang.next }}
@@ -324,10 +204,11 @@ import { reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import lang from '../i18n/i18n';
import axios from 'axios'
-
import { getCurrentInstance } from 'vue'
const app = getCurrentInstance()
const $http = app.appContext.config.globalProperties.$http
+const waitDesc = ref(lang.wait_desc)
+
const adminSettings = reactive({
"account": "admin",
@@ -349,18 +230,16 @@ const domainSettings = reactive({
const sslSettings = reactive({
"type": "0",
- "provider": "",
"challenge": "http",
"key_path": "./config/ssl/private.key",
"crt_path": "./config/ssl/public.crt",
- "paramsList": {},
+ "paramsList": [],
})
-const dnsApiParams = reactive({})
const active = ref(0)
const fullscreenLoading = ref(false)
-
+const dnsChecking = ref(false)
const dnsInfos = ref([
])
@@ -455,9 +334,9 @@ const getSSLConfig = () => {
ElMessage.error(res.errorMsg)
} else {
sslSettings.type = res.data.type
- if (sslSettings.type == "2"){
+ if (sslSettings.type == "2") {
sslSettings.type = "0"
- sslSettings.challenge="dns"
+ sslSettings.challenge = "dns"
}
@@ -475,24 +354,6 @@ const setSSLConfig = () => {
sslType = "2"
}
- if (sslType == "2") {
-
- let params = { "action": "setParams", "step": "ssl", };
-
- params = Object.assign(params, dnsApiParams);
-
- // dns验证方式先提交DNS api Key
- $http.post("/api/setup", params).then((res) => {
- if (res.errorNo != 0) {
- fullscreenLoading.value = false;
- ElMessage.error(res.errorMsg);
- return;
- }
- })
-
-
- }
-
$http.post("/api/setup", {
@@ -500,15 +361,18 @@ const setSSLConfig = () => {
"step": "ssl",
"ssl_type": sslType,
"key_path": sslSettings.key_path,
- "crt_path": sslSettings.crt_path,
- "serviceName": sslSettings.provider
+ "crt_path": sslSettings.crt_path
}).then((res) => {
if (res.errorNo != 0) {
fullscreenLoading.value = false;
ElMessage.error(res.errorMsg)
} else {
+ if (sslType == 2) {
+ fullscreenLoading.value = false;
+ dnsChecking.value = true;
+ getSSLDNSParams();
+ }
checkStatus();
-
}
})
}
@@ -542,16 +406,23 @@ const setDomainConfig = () => {
})
}
-const provide_change = () => {
- console.log(sslSettings.provider)
- $http.post("/api/setup", { "action": "getParams", "step": "ssl", "serverName": sslSettings.provider }).then((res) => {
+const getSSLDNSParams = () => {
+ $http.post("/api/setup", { "action": "getParams", "step": "ssl" }).then((res) => {
if (res.errorNo != 0) {
ElMessage.error(res.errorMsg)
} else {
sslSettings.paramsList = res.data
+ console.log(sslSettings.paramsList)
}
})
+ if (sslSettings.paramsList.length == 0) {
+ setTimeout(function () {
+ getSSLDNSParams()
+ }, 1000);
+ }
+
+
}
@@ -576,8 +447,12 @@ const next = () => {
active.value++
break
case 5:
- setSSLConfig();
- active.value++
+ if (dnsChecking.value) {
+ fullscreenLoading.value = true;
+ waitDesc.value = lang.dns_challenge_wait;
+ } else {
+ setSSLConfig();
+ }
break
}
diff --git a/server/config/config.go b/server/config/config.go
index 3423073..df4ccec 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -1,7 +1,12 @@
package config
import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/x509"
"encoding/json"
+ "encoding/pem"
"os"
)
@@ -48,8 +53,8 @@ func (c *Config) SetSetupPort(setupPort int) {
const DBTypeMySQL = "mysql"
const DBTypeSQLite = "sqlite"
const SSLTypeAutoHTTP = "0" //自动生成证书
-// const SSLTypeAutoDNS = "2" //自动生成证书,DNS api验证
-const SSLTypeUser = "1" //用户上传证书
+const SSLTypeAutoDNS = "2" //自动生成证书,DNS api验证
+const SSLTypeUser = "1" //用户上传证书
var DBTypes []string = []string{DBTypeMySQL, DBTypeSQLite}
@@ -86,3 +91,33 @@ func Init() {
}
}
+
+func ReadPrivateKey() (*ecdsa.PrivateKey, bool) {
+ key, err := os.ReadFile("./config/ssl/account_private.pem")
+ if err != nil {
+ return createNewPrivateKey(), true
+ }
+
+ block, _ := pem.Decode(key)
+ x509Encoded := block.Bytes
+ privateKey, _ := x509.ParseECPrivateKey(x509Encoded)
+
+ return privateKey, false
+}
+
+func createNewPrivateKey() *ecdsa.PrivateKey {
+ // Create a user. New accounts need an email and private key to start.
+ privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+ x509Encoded, _ := x509.MarshalECPrivateKey(privateKey)
+
+ // 将ec 密钥写入到 pem文件里
+ keypem, _ := os.OpenFile("./config/ssl/account_private.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+ err = pem.Encode(keypem, &pem.Block{Type: "EC PRIVATE KEY", Bytes: x509Encoded})
+ if err != nil {
+ panic(err)
+ }
+ return privateKey
+}
diff --git a/server/config/config.json b/server/config/config.json
index 54b48a7..36ad3aa 100644
--- a/server/config/config.json
+++ b/server/config/config.json
@@ -1,16 +1,17 @@
{
- "logLevel": "debug",
- "domain": "domain.com",
- "webDomain": "mail.domain.com",
+ "logLevel": "",
+ "domain": "test.domain",
+ "domains": null,
+ "webDomain": "mail.test.domain",
"dkimPrivateKeyPath": "config/dkim/dkim.priv",
- "sslType": "0",
- "SSLPrivateKeyPath": "config/ssl/private.key",
- "SSLPublicKeyPath": "config/ssl/public.crt",
- "dbDSN": "./config/pmail.db",
+ "sslType": "1",
+ "SSLPrivateKeyPath": "./config/ssl/private.key",
+ "SSLPublicKeyPath": "./config/ssl/public.crt",
+ "dbDSN": "./config/pmail_temp.db",
"dbType": "sqlite",
- "spamFilterLevel": 1,
+ "httpsEnabled": 1,
+ "spamFilterLevel": 0,
"httpPort": 80,
"httpsPort": 443,
- "isInit": true,
- "httpsEnabled": 1
+ "isInit": true
}
\ No newline at end of file
diff --git a/server/config/ssl/private.key b/server/config/ssl/private.key
index 6e7bf48..6428258 100644
--- a/server/config/ssl/private.key
+++ b/server/config/ssl/private.key
@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
-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
+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
-----END RSA PRIVATE KEY-----
diff --git a/server/config/ssl/public.crt b/server/config/ssl/public.crt
index c2853d9..28db02a 100644
--- a/server/config/ssl/public.crt
+++ b/server/config/ssl/public.crt
@@ -1,61 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIFFDCCA/ygAwIBAgISBNoMwrAFQkkwJmbpDuLTLHLiMA0GCSqGSIb3DQEBCwUA
-MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
-EwJSMzAeFw0yNDA0MTUwNTQ3MzlaFw0yNDA3MTQwNTQ3MzhaMBwxGjAYBgNVBAMT
-EXNtdHAuamlhbmd3ZWkub25lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAycVukHU+lPXo01d0W8ok0pxfy8/+tHKqd6gd9g1J6EOpf2SUvR77+URpKNXx
-MokVX84VHnBGxDMvh5hM8oN5gqbJEwhTqOwZi19MQVfI5a1wrkYep1+hcAS/MsLg
-wqxFp7ABsH2oljQLLYsGZTs/+QooDcmE2K+Nnj2nM5VZ9ouGX2ANPFMvSm1yuADm
-P4962xXEN730UfEamRTGsuU9U1g51cAUasblIf2RU9nKdEQsEihpApS45X2qayWg
-o3YJ6BAaqbZKmnekeIWkjlhHNYudNVxIqvp5MzndMPCNjfz/+xEcVn3hS5vzJMZQ
-eOPJjSes6E2Cr0X2cvXnQGUfzQIDAQABo4ICODCCAjQwDgYDVR0PAQH/BAQDAgWg
-MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G
-A1UdDgQWBBS+FIEsLeo9FCo2y2tOmFUfhiv/LzAfBgNVHSMEGDAWgBQULrMXt1hW
-y65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6
-Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iu
-b3JnLzBBBgNVHREEOjA4ghFtYWlsLmppYW5nd2VpLm9uZYIQcG9wLmppYW5nd2Vp
-Lm9uZYIRc210cC5qaWFuZ3dlaS5vbmUwEwYDVR0gBAwwCjAIBgZngQwBAgEwggEE
-BgorBgEEAdZ5AgQCBIH1BIHyAPAAdgAZmBBxCfDWUi4wgNKeP2S7g24ozPkPUo7u
-385KPxa0ygAAAY7ggunqAAAEAwBHMEUCIFEMkK6C5zyorCJEM2nZqH75nkl6KQjI
-RUiwLpcoupL0AiEAtKRWHmGBfL+AtLkurTurZlFURZIsrTqrreOFzThnSHoAdgBI
-sONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAY7ggunmAAAEAwBHMEUC
-IGqaf3PAFZnvoKac1ASRb9eRpaGp7m+x/+Z1siJYegCnAiEAsLQJO7QvX/dXe+Bq
-oCH1QhEqDFNhQLCavqrUyTi1wQ0wDQYJKoZIhvcNAQELBQADggEBABlSBbOwICT5
-zE+U4vyaeU0ufVSyjT7ZbohpMAJh8WK7zG7xj/XgAA0EX2LB62NVk3/3u/GF3uz6
-HsuCYUTsKY3MmwWttmwqWIxkMJk57j18J5vsJXW/YwqOz+v6h3QcUhUZW7c8Kl9I
-t9t20uTssCWJ2OLe3TtumjxKX9iqeQ5CD3GDLTJlKP3UJ6eFGN5E42JjnIxk9GH5
-yvqcPd9OHwDXbrA13Q6Xn7tdV8rzerGi/gGo18QvCtvH8wda/T+AUxRxXM9Ggit8
-ITBsP3PWuIDvECTdQ+Zbft9Ut6PxOBLSH3Gqtghe+Fn7XQpchODw+0LbLi1fOgrW
-8O+lguPxZ9w=
------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==
+MIIDmTCCAoECFH0cnkhiRVka2ZAWxpjtD+JgCv2GMA0GCSqGSIb3DQEBCwUAMIGI
+MQswCQYDVQQGEwJDTjETMBEGA1UECAwKU29tZS1TdGF0ZTELMAkGA1UEBwwCQkox
+DjAMBgNVBAoMBVBNYWlsMQ4wDAYDVQQLDAVQTWFpbDEWMBQGA1UEAwwNKi50ZXN0
+LmRvbWFpbjEfMB0GCSqGSIb3DQEJARYQdGVzdEB0ZXN0LmRvbWFpbjAeFw0yNDA3
+MDUwODA5MTVaFw0zNDA3MDMwODA5MTVaMIGIMQswCQYDVQQGEwJDTjETMBEGA1UE
+CAwKU29tZS1TdGF0ZTELMAkGA1UEBwwCQkoxDjAMBgNVBAoMBVBNYWlsMQ4wDAYD
+VQQLDAVQTWFpbDEWMBQGA1UEAwwNKi50ZXN0LmRvbWFpbjEfMB0GCSqGSIb3DQEJ
+ARYQdGVzdEB0ZXN0LmRvbWFpbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAPbn/CpeOKV04CUs57Okr8kluCEV4fitVYvRReDUZNwcrDNJCADRVPlZh+3l
+f0JdReC68M2pbHrd0CLearARRQwPJnuNphdimF6iFVr3EoPtTDzzJFKW/YxDyQBD
+rTFVVij7uwJ7QnFnJjREoEjS1w7ezpO/4UPd44YlEM63r+juYzVb7H4skJ3HzLmh
+4t46EcaIxX6uOeHY7MDctAxrMGjfahfurhoAYHcHO7zgPNWM1Q5Yt9zQo8Kv0Y2L
+vHxSUmZVrb4GHQhKDnvaoZJy80AA98As3ZJJiCmT/4oIPHb4c+9S/uDVqg4WHtc5
+pAFy+mPArnKYltRawkWI6Q17ZOsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAIl8L
+nL+wICckIRTfO4K4+F+7UHgLI2iTYRic6Hsy3K0aPvZAdVJiOlz0qaEcce+bFzj7
+BZiHQWDgiPF4vNFqcmas4oFV+Au2K8AoYQFJrq+3dtiUaMStT7JkjNjci3C2NhPO
+U7Gjq2OJx6IrJr7ECr2SFW4Sstw/h+s/mBfNl2BbE7kmT1xu/lyxpIiT7bYgSk/l
+A3cJFE1JIoa7eUPpV4Kh0titwJnDYVfQmEeBNYivyeNwe4hiHtiZDamI6H7Wu95b
+ldRRiFELoVs0GCn/ttIaSFvGUPeahn9rTNUUkjp4Un0RxuQFx8umQYl50zt1GZ1X
+DICmWUwYYejqdXrrww==
-----END CERTIFICATE-----
diff --git a/server/config/ssl/server.csr b/server/config/ssl/server.csr
new file mode 100644
index 0000000..bbe4828
--- /dev/null
+++ b/server/config/ssl/server.csr
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICzjCCAbYCAQAwgYgxCzAJBgNVBAYTAkNOMRMwEQYDVQQIDApTb21lLVN0YXRl
+MQswCQYDVQQHDAJCSjEOMAwGA1UECgwFUE1haWwxDjAMBgNVBAsMBVBNYWlsMRYw
+FAYDVQQDDA0qLnRlc3QuZG9tYWluMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QHRlc3Qu
+ZG9tYWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9uf8Kl44pXTg
+JSzns6SvySW4IRXh+K1Vi9FF4NRk3BysM0kIANFU+VmH7eV/Ql1F4Lrwzalset3Q
+It5qsBFFDA8me42mF2KYXqIVWvcSg+1MPPMkUpb9jEPJAEOtMVVWKPu7AntCcWcm
+NESgSNLXDt7Ok7/hQ93jhiUQzrev6O5jNVvsfiyQncfMuaHi3joRxojFfq454djs
+wNy0DGswaN9qF+6uGgBgdwc7vOA81YzVDli33NCjwq/RjYu8fFJSZlWtvgYdCEoO
+e9qhknLzQAD3wCzdkkmIKZP/igg8dvhz71L+4NWqDhYe1zmkAXL6Y8CucpiW1FrC
+RYjpDXtk6wIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAPSNiDkAGFhMWFzQns+a
+6+ujoI8Lf7baN/LklEEMRV2xq5sonj72ZU4PJDAyNFVj+pCKDOH5mb0r5ceRKYx/
+HOlXxYvDhvk3t9mAGrRwG3UhzbCSbIIcvdKbU4FDGaRIzrSsvcv9fUDnw5fKTL61
+IRDNewABlCncsUYfHrXeuMtqdiWyZMfYjiHDunCCo/FbrG70q9LjMHT4zHl9LV8T
+jnrQzX0UaxBgLYDPEJX+2fqaXObv1HHSWlgZ6Ov9eRRKN2oRkb+KIbaTnlQ7Z7Y9
+kzwla/WOKJDL5FA7275tVpC553+rglq/0Jy9Hiq71Sis9gnG8eTYsghN5FHZSMFT
+a1s=
+-----END CERTIFICATE REQUEST-----
diff --git a/server/controllers/email/list.go b/server/controllers/email/list.go
index 5b5c7b2..2d66f02 100644
--- a/server/controllers/email/list.go
+++ b/server/controllers/email/list.go
@@ -27,6 +27,7 @@ type emilItem struct {
IsRead bool `json:"is_read"`
Sender User `json:"sender"`
Dangerous bool `json:"dangerous"`
+ Error string `json:"error"`
}
type User struct {
@@ -83,6 +84,7 @@ func EmailList(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
IsRead: email.IsRead == 1,
Sender: sender,
Dangerous: email.SPFCheck == 0 && email.DKIMCheck == 0,
+ Error: email.Error.String,
})
}
diff --git a/server/controllers/email/send.go b/server/controllers/email/send.go
index 8141b8e..14d6ce4 100644
--- a/server/controllers/email/send.go
+++ b/server/controllers/email/send.go
@@ -213,11 +213,28 @@ func Send(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
if err != nil {
log.WithContext(ctx).Errorf("sql Error :%+v", err)
}
+
+ ue := models.UserEmail{
+ UserID: ctx.UserID,
+ EmailID: modelEmail.Id,
+ Status: 2,
+ IsRead: 1,
+ }
+ db.Instance.Insert(&ue)
+
} else {
_, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =1 where id = ? "), modelEmail.Id)
if err != nil {
log.WithContext(ctx).Errorf("sql Error :%+v", err)
}
+
+ ue := models.UserEmail{
+ UserID: ctx.UserID,
+ EmailID: modelEmail.Id,
+ Status: 1,
+ IsRead: 1,
+ }
+ db.Instance.Insert(&ue)
}
}, nil)
diff --git a/server/controllers/group.go b/server/controllers/group.go
index 6ef9f81..d798a77 100644
--- a/server/controllers/group.go
+++ b/server/controllers/group.go
@@ -31,7 +31,7 @@ func GetUserGroup(ctx *context.Context, w http.ResponseWriter, req *http.Request
},
{
Label: i18n.GetText(ctx.Lang, "outbox"),
- Tag: dto.SearchTag{Type: 1, Status: 1}.ToString(),
+ Tag: dto.SearchTag{Type: 1, Status: -1}.ToString(),
},
{
Label: i18n.GetText(ctx.Lang, "sketch"),
diff --git a/server/controllers/setup.go b/server/controllers/setup.go
index daa4075..b1aadcd 100644
--- a/server/controllers/setup.go
+++ b/server/controllers/setup.go
@@ -5,6 +5,7 @@ import (
log "github.com/sirupsen/logrus"
"io"
"net/http"
+ "os"
"pmail/config"
"pmail/dto/response"
"pmail/services/setup"
@@ -134,40 +135,36 @@ func Setup(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
return
}
- //if reqData["step"] == "ssl" && reqData["action"] == "getParams" {
- // params, err := ssl.GetServerParamsList(reqData["serverName"])
- // if err != nil {
- // response.NewErrorResponse(response.ServerError, err.Error(), "").FPrint(w)
- // return
- // }
- // response.NewSuccessResponse(params).FPrint(w)
- // return
- //}
-
- //if reqData["step"] == "ssl" && reqData["action"] == "setParams" {
- // for key, v := range reqData {
- // if key != "step" && key != "action" {
- // ssl.SetDomainServerParams(key, v)
- // }
- // }
- // response.NewSuccessResponse("Succ").FPrint(w)
- // return
- //}
+ if reqData["step"] == "ssl" && reqData["action"] == "getParams" {
+ dnsChallenge := ssl.GetDnsChallengeInstance()
+
+ response.NewSuccessResponse(dnsChallenge.GetDNSSettings(ctx)).FPrint(w)
+ return
+ }
if reqData["step"] == "ssl" && reqData["action"] == "set" {
+ keyPath := reqData["key_path"]
+ crtPath := reqData["crt_path"]
+
+ _, err := os.Stat(keyPath)
+ if err != nil {
+ response.NewErrorResponse(response.ServerError, err.Error(), "").FPrint(w)
+ return
+ }
- serviceName, ok := reqData["serviceName"]
- if !ok {
- serviceName = ""
+ _, err = os.Stat(crtPath)
+ if err != nil {
+ response.NewErrorResponse(response.ServerError, err.Error(), "").FPrint(w)
+ return
}
- err := ssl.SetSSL(reqData["ssl_type"], reqData["key_path"], reqData["crt_path"], serviceName)
+
+ err = ssl.SetSSL(reqData["ssl_type"], reqData["key_path"], reqData["crt_path"])
if err != nil {
response.NewErrorResponse(response.ServerError, err.Error(), "").FPrint(w)
return
}
- //if reqData["ssl_type"] == config.SSLTypeAutoHTTP || reqData["ssl_type"] == config.SSLTypeAutoDNS {
- if reqData["ssl_type"] == config.SSLTypeAutoHTTP {
+ if reqData["ssl_type"] == config.SSLTypeAutoHTTP || reqData["ssl_type"] == config.SSLTypeAutoDNS {
err = ssl.GenSSL(false)
if err != nil {
response.NewErrorResponse(response.ServerError, err.Error(), "").FPrint(w)
diff --git a/server/cron_server/ssl_update.go b/server/cron_server/ssl_update.go
index 03a0359..a343219 100644
--- a/server/cron_server/ssl_update.go
+++ b/server/cron_server/ssl_update.go
@@ -22,7 +22,7 @@ func Start() {
}
}
- if config.Instance.SSLType == "0" {
+ if config.Instance.SSLType == config.SSLTypeAutoHTTP || config.Instance.SSLType == config.SSLTypeAutoDNS {
go sslUpdateLoop()
} else {
go sslCheck()
@@ -45,6 +45,7 @@ func sslCheck() {
log.Errorf("SSL Check Error! %+v", err)
}
if newExpTime != expiredTime {
+ expiredTime = newExpTime
log.Infoln("SSL certificate had update! restarting")
signal.RestartChan <- true
}
diff --git a/server/main_test.go b/server/main_test.go
index aa31f94..7267100 100644
--- a/server/main_test.go
+++ b/server/main_test.go
@@ -72,6 +72,7 @@ func TestMaster(t *testing.T) {
t.Run("testSendEmail", testSendEmail)
time.Sleep(8 * time.Second)
t.Run("testEmailList", testEmailList)
+ t.Run("testGetDetail", testGetEmailDetail)
t.Run("testDelEmail", testDelEmail)
t.Run("testSendEmail2User1", testSendEmail2User1)
@@ -108,6 +109,23 @@ func testCheckRule(t *testing.T) {
}
}
+func testGetEmailDetail(t *testing.T) {
+ ret, err := httpClient.Post(TestHost+"/api/email/detail", "application/json", strings.NewReader(`{
+ "id":1
+}`))
+ if err != nil {
+ t.Error(err)
+ }
+ data, err := readResponse(ret.Body)
+ if err != nil {
+ t.Error(err)
+ }
+ if data.ErrorNo != 0 {
+ t.Error("GetEmailDetail Error! ", data)
+ }
+
+}
+
func testCreateRule(t *testing.T) {
ret, err := httpClient.Post(TestHost+"/api/rule/add", "application/json", strings.NewReader(`{
"name":"Move Group",
@@ -703,6 +721,7 @@ func testSendEmail2User3(t *testing.T) {
t.Logf("testSendEmail2User3 Success! Response: %+v", data)
}
+
func testEmailList(t *testing.T) {
ret, err := httpClient.Post(TestHost+"/api/email/list", "application/json", strings.NewReader(`{}`))
if err != nil {
@@ -716,8 +735,9 @@ func testEmailList(t *testing.T) {
t.Error("Get Email List Api Error!")
}
dt := data.Data.(map[string]interface{})
- if len(dt["list"].([]interface{})) == 0 {
+ if dt["list"] == nil || len(dt["list"].([]interface{})) == 0 {
t.Error("Email List Is Empty!")
+ return
}
lst := dt["list"].([]interface{})
diff --git a/server/models/user_email.go b/server/models/user_email.go
index e1f5353..5c1c11b 100644
--- a/server/models/user_email.go
+++ b/server/models/user_email.go
@@ -2,8 +2,8 @@ package models
type UserEmail struct {
ID int `xorm:"id int unsigned not null pk autoincr"`
- UserID int `xorm:"user_id int not null unique('uid_eid') index comment('用户id')"`
- EmailID int `xorm:"email_id not null unique('uid_eid') index comment('信件id')"`
+ UserID int `xorm:"user_id int not null index('idx_eid') index comment('用户id')"`
+ EmailID int `xorm:"email_id not null index('idx_eid') index comment('信件id')"`
IsRead int8 `xorm:"is_read tinyint(1) comment('是否已读')" json:"is_read"`
GroupId int `xorm:"group_id int notnull default(0) comment('分组id')'" json:"group_id"`
Status int8 `xorm:"status tinyint(4) notnull default(0) comment('0未发送,1已发送,2发送失败,3删除')" json:"status"` // 0未发送,1已发送,2发送失败 3删除
diff --git a/server/services/detail/detail.go b/server/services/detail/detail.go
index 67cd8b5..a6b598b 100644
--- a/server/services/detail/detail.go
+++ b/server/services/detail/detail.go
@@ -27,7 +27,7 @@ func GetEmailDetail(ctx *context.Context, id int, markRead bool) (*response.Emai
//获取邮件内容
var email response.EmailResponseData
- _, err = db.Instance.ID(id).Get(&email)
+ _, err = db.Instance.Select("*,1 as is_read").Table("email").Where("id=?", id).Get(&email)
if err != nil {
log.WithContext(ctx).Errorf("SQL error:%+v", err)
return nil, err
@@ -37,7 +37,7 @@ func GetEmailDetail(ctx *context.Context, id int, markRead bool) (*response.Emai
if markRead && ue.IsRead == 0 {
ue.IsRead = 1
- _, err = db.Instance.Update(&ue)
+ _, err = db.Instance.Where("id=?", ue.ID).Update(&ue)
if err != nil {
log.WithContext(ctx).Errorf("SQL error:%+v", err)
}
diff --git a/server/services/setup/ssl/challenge.go b/server/services/setup/ssl/challenge.go
index f7aefac..5786619 100644
--- a/server/services/setup/ssl/challenge.go
+++ b/server/services/setup/ssl/challenge.go
@@ -1,5 +1,12 @@
package ssl
+import (
+ "github.com/go-acme/lego/v4/challenge/dns01"
+ log "github.com/sirupsen/logrus"
+ "pmail/utils/context"
+ "time"
+)
+
type authInfo struct {
Domain string
Token string
@@ -35,3 +42,61 @@ func GetHttpChallengeInstance() *HttpChallenge {
}
return instance
}
+
+type DNSChallenge struct {
+ AuthInfo map[string]*authInfo
+}
+
+var dnsInstance *DNSChallenge
+
+func GetDnsChallengeInstance() *DNSChallenge {
+ if dnsInstance == nil {
+ dnsInstance = &DNSChallenge{
+ AuthInfo: map[string]*authInfo{},
+ }
+ }
+ return dnsInstance
+}
+
+func (h *DNSChallenge) Present(domain, token, keyAuth string) error {
+ info := dns01.GetChallengeInfo(domain, keyAuth)
+ log.Infof("Presenting challenge Info : %+v", info)
+ h.AuthInfo[token] = &authInfo{
+ Domain: info.FQDN,
+ Token: token,
+ KeyAuth: info.Value,
+ }
+ log.Infof("SSL Log:%s %s %s", domain, token, keyAuth)
+ return nil
+}
+
+func (h *DNSChallenge) CleanUp(domain, token, keyAuth string) error {
+ delete(h.AuthInfo, token)
+ return nil
+}
+
+func (h *DNSChallenge) Timeout() (timeout, interval time.Duration) {
+ return 60 * time.Minute, 5 * time.Second
+}
+
+type DNSItem struct {
+ Type string `json:"type"`
+ Host string `json:"host"`
+ Value string `json:"value"`
+ TTL int `json:"ttl"`
+ Tips string `json:"tips"`
+}
+
+func (h *DNSChallenge) GetDNSSettings(ctx *context.Context) []*DNSItem {
+ ret := []*DNSItem{}
+ for _, info := range h.AuthInfo {
+ ret = append(ret, &DNSItem{
+ Type: "TXT",
+ Host: info.Domain,
+ Value: info.KeyAuth,
+ TTL: 3600,
+ })
+ }
+
+ return ret
+}
diff --git a/server/services/setup/ssl/ssl.go b/server/services/setup/ssl/ssl.go
index fa6c825..b6b7d3e 100644
--- a/server/services/setup/ssl/ssl.go
+++ b/server/services/setup/ssl/ssl.go
@@ -3,11 +3,10 @@ package ssl
import (
"crypto"
"crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
"crypto/tls"
"crypto/x509"
"github.com/go-acme/lego/v4/certificate"
+ "github.com/go-acme/lego/v4/challenge/dns01"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"os"
@@ -51,15 +50,13 @@ func GetSSL() string {
return cfg.SSLType
}
-func SetSSL(sslType, priKey, crtKey, serviceName string) error {
+func SetSSL(sslType, priKey, crtKey string) error {
cfg, err := setup.ReadConfig()
if err != nil {
panic(err)
}
- //if sslType == config.SSLTypeAutoHTTP || sslType == config.SSLTypeUser || sslType == config.SSLTypeAutoDNS {
- if sslType == config.SSLTypeAutoHTTP || sslType == config.SSLTypeUser {
+ if sslType == config.SSLTypeAutoHTTP || sslType == config.SSLTypeUser || sslType == config.SSLTypeAutoDNS {
cfg.SSLType = sslType
- //cfg.DomainServiceName = serviceName
} else {
return errors.New("SSL Type Error!")
}
@@ -67,6 +64,8 @@ func SetSSL(sslType, priKey, crtKey, serviceName string) error {
if cfg.SSLType == config.SSLTypeUser {
cfg.SSLPrivateKeyPath = priKey
cfg.SSLPublicKeyPath = crtKey
+ // 手动设置证书的情况下后台地址默认不启用https
+ cfg.HttpsEnabled = 2
}
err = setup.WriteConfig(cfg)
@@ -77,28 +76,62 @@ func SetSSL(sslType, priKey, crtKey, serviceName string) error {
return nil
}
-func GenSSL(update bool) error {
+func renewCertificate(privateKey *ecdsa.PrivateKey, cfg *config.Config) error {
- cfg, err := setup.ReadConfig()
+ myUser := MyUser{
+ Email: "i@" + cfg.Domain,
+ key: privateKey,
+ }
+
+ conf := lego.NewConfig(&myUser)
+ conf.UserAgent = "PMail"
+ conf.Certificate.KeyType = certcrypto.RSA2048
+
+ // A client facilitates communication with the CA server.
+ client, err := lego.NewClient(conf)
+ if err != nil {
+ return errors.Wrap(err)
+ }
+
+ var reg *registration.Resource
+
+ reg, err = client.Registration.ResolveAccountByKey()
+ if err != nil {
+ return errors.Wrap(err)
+ }
+
+ myUser.Registration = reg
+
+ request := certificate.ObtainRequest{
+ Domains: []string{"smtp." + cfg.Domain, cfg.WebDomain, "pop." + cfg.Domain},
+ Bundle: true,
+ }
+
+ log.Infof("wait ssl renew")
+ certificates, err := client.Certificate.Obtain(request)
+ if err != nil {
+ panic(err)
+ }
+ err = os.WriteFile("./config/ssl/private.key", certificates.PrivateKey, 0666)
if err != nil {
panic(err)
}
- if !update {
- privateFile, errpi := os.ReadFile(cfg.SSLPrivateKeyPath)
- public, errpu := os.ReadFile(cfg.SSLPublicKeyPath)
- // 当前存在证书数据,就不生成了
- if errpi == nil && errpu == nil && len(privateFile) > 0 && len(public) > 0 {
- return nil
- }
+ err = os.WriteFile("./config/ssl/public.crt", certificates.Certificate, 0666)
+ if err != nil {
+ panic(err)
}
- // Create a user. New accounts need an email and private key to start.
- privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ err = os.WriteFile("./config/ssl/issuerCert.crt", certificates.IssuerCertificate, 0666)
if err != nil {
- return errors.Wrap(err)
+ panic(err)
}
+ return nil
+}
+
+func generateCertificate(privateKey *ecdsa.PrivateKey, cfg *config.Config, newAccount bool) error {
+
myUser := MyUser{
Email: "i@" + cfg.Domain,
key: privateKey,
@@ -114,31 +147,32 @@ func GenSSL(update bool) error {
return errors.Wrap(err)
}
- if cfg.SSLType == "0" {
+ if cfg.SSLType == config.SSLTypeAutoHTTP {
err = client.Challenge.SetHTTP01Provider(GetHttpChallengeInstance())
if err != nil {
return errors.Wrap(err)
}
+ } else if cfg.SSLType == config.SSLTypeAutoDNS {
+ err = client.Challenge.SetDNS01Provider(GetDnsChallengeInstance(), dns01.AddDNSTimeout(60*time.Minute))
+ if err != nil {
+ return errors.Wrap(err)
+ }
}
- //else if cfg.SSLType == "2" {
- // err = os.Setenv(strings.ToUpper(cfg.DomainServiceName)+"_PROPAGATION_TIMEOUT", "900")
- // if err != nil {
- // log.Errorf("Set ENV Variable Error: %s", err.Error())
- // }
- // dnspodProvider, err := dns.NewDNSChallengeProviderByName(cfg.DomainServiceName)
- // if err != nil {
- // return errors.Wrap(err)
- // }
- // err = client.Challenge.SetDNS01Provider(dnspodProvider, dns01.AddDNSTimeout(15*time.Minute))
- // if err != nil {
- // return errors.Wrap(err)
- // }
- //}
-
- reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
- if err != nil {
- return errors.Wrap(err)
+
+ var reg *registration.Resource
+
+ if newAccount {
+ reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
+ if err != nil {
+ return errors.Wrap(err)
+ }
+ } else {
+ reg, err = client.Registration.ResolveAccountByKey()
+ if err != nil {
+ return errors.Wrap(err)
+ }
}
+
myUser.Registration = reg
request := certificate.ObtainRequest{
@@ -154,7 +188,7 @@ func GenSSL(update bool) error {
if err != nil {
panic(err)
}
-
+ log.Infof("证书校验通过!")
err = os.WriteFile("./config/ssl/private.key", certificates.PrivateKey, 0666)
if err != nil {
panic(err)
@@ -177,6 +211,31 @@ func GenSSL(update bool) error {
return nil
}
+func GenSSL(update bool) error {
+
+ cfg, err := setup.ReadConfig()
+ if err != nil {
+ panic(err)
+ }
+
+ if !update {
+ privateFile, errpi := os.ReadFile(cfg.SSLPrivateKeyPath)
+ public, errpu := os.ReadFile(cfg.SSLPublicKeyPath)
+ // 当前存在证书数据,就不生成了
+ if errpi == nil && errpu == nil && len(privateFile) > 0 && len(public) > 0 {
+ return nil
+ }
+ }
+
+ privateKey, newAccount := config.ReadPrivateKey()
+
+ if !update {
+ return generateCertificate(privateKey, cfg, newAccount)
+ }
+
+ return renewCertificate(privateKey, cfg)
+}
+
// CheckSSLCrtInfo 返回证书过期剩余天数
func CheckSSLCrtInfo() (int, time.Time, error) {
@@ -207,7 +266,7 @@ func CheckSSLCrtInfo() (int, time.Time, error) {
}
func Update(needRestart bool) {
- if config.Instance != nil && config.Instance.IsInit && config.Instance.SSLType == "0" {
+ if config.Instance != nil && config.Instance.IsInit && (config.Instance.SSLType == config.SSLTypeAutoHTTP || config.Instance.SSLType == config.SSLTypeAutoDNS) {
days, _, err := CheckSSLCrtInfo()
if days < 30 || err != nil {
if err != nil {
diff --git a/server/utils/send/send.go b/server/utils/send/send.go
index ee156d0..82ed62c 100644
--- a/server/utils/send/send.go
+++ b/server/utils/send/send.go
@@ -76,24 +76,28 @@ func Forward(ctx *context.Context, e *parsemail.Email, forwardAddress string) er
tos := tos
as.WaitProcess(func(p any) {
err := smtp.SendMail("", domain.mxHost+":25", nil, e.From.EmailAddress, buildAddress(tos), b)
- if err != nil {
- log.WithContext(ctx).Warnf("SMTP Send Error! Error:%+v", err)
- } else {
- log.WithContext(ctx).Infof("SMTP Send Success !")
- }
- // 重新选取证书域名
+ // 使用其他方式发送
if err != nil {
+ // EOF 表示未知错误,此时降级为非tls连接发送(目前仅139邮箱有这个问题)
+ if errors.Is(err, smtp.NoSupportSTARTTLSError) || err.Error() == "EOF" {
+ err = smtp.SendMailWithTls("", domain.mxHost+":465", nil, e.From.EmailAddress, buildAddress(tos), b)
+ if err != nil {
+ log.WithContext(ctx).Warnf("Unsafe! %s Server Not Support SMTPS & STARTTLS", domain.domain)
+ err = smtp.SendMailUnsafe("", domain.mxHost+":25", nil, e.From.EmailAddress, buildAddress(tos), b)
+ }
+ }
+
+ // 证书错误,从新选取证书发送
if certificateErr, ok := err.(*tls.CertificateVerificationError); ok {
- if hostnameErr, is := certificateErr.Err.(x509.HostnameError); is {
+ // 单测使用
+ if domain.domain == "localhost" {
+ err = smtp.SendMailUnsafe("", domain.mxHost+":25", nil, e.From.EmailAddress, buildAddress(tos), b)
+ } else if hostnameErr, is := certificateErr.Err.(x509.HostnameError); is {
if hostnameErr.Certificate != nil {
certificateHostName := hostnameErr.Certificate.DNSNames
+ // 重新选取证书发送
err = smtp.SendMail(domainMatch(domain.domain, certificateHostName), domain.mxHost+":25", nil, e.From.EmailAddress, buildAddress(tos), b)
- if err != nil {
- log.WithContext(ctx).Warnf("SMTP Send Error! Error:%+v", err)
- } else {
- log.WithContext(ctx).Infof("SMTP Send Success !")
- }
}
}
}
@@ -185,7 +189,10 @@ func Send(ctx *context.Context, e *parsemail.Email) (error, map[string]error) {
// 证书错误,从新选取证书发送
if certificateErr, ok := err.(*tls.CertificateVerificationError); ok {
- if hostnameErr, is := certificateErr.Err.(x509.HostnameError); is {
+ // 单测使用
+ if domain.domain == "localhost" {
+ err = smtp.SendMailUnsafe("", domain.mxHost+":25", nil, e.From.EmailAddress, buildAddress(tos), b)
+ } else if hostnameErr, is := certificateErr.Err.(x509.HostnameError); is {
if hostnameErr.Certificate != nil {
certificateHostName := hostnameErr.Certificate.DNSNames
// 重新选取证书发送