#11: implement MTA-STS, TLS-RPT & Autoconfig HTTP services
This commit is contained in:
1 parent
c0042ef207
commit
314eb67dda
20 files changed
+1177
-31
No files matched your search
@@ -0,0 +1,79 @@
|
||||
package valueobject
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// BuildThunderbirdAutoconfigXML generates Mozilla Thunderbird config-v1.1 XML payload.
|
||||
func BuildThunderbirdAutoconfigXML(domainName, mailHost string) string {
|
||||
if mailHost == "" {
|
||||
mailHost = fmt.Sprintf("mail.%s", domainName)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<clientConfig version="1.1">
|
||||
<emailProvider id="%s">
|
||||
<domain>%s</domain>
|
||||
<displayName>LambdaMail - %s</displayName>
|
||||
<displayShortName>%s</displayShortName>
|
||||
<incomingServer type="imap">
|
||||
<hostname>%s</hostname>
|
||||
<port>993</port>
|
||||
<socketType>SSL</socketType>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<username>%%EMAILADDRESS%%</username>
|
||||
</incomingServer>
|
||||
<incomingServer type="pop3">
|
||||
<hostname>%s</hostname>
|
||||
<port>995</port>
|
||||
<socketType>SSL</socketType>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<username>%%EMAILADDRESS%%</username>
|
||||
</incomingServer>
|
||||
<outgoingServer type="smtp">
|
||||
<hostname>%s</hostname>
|
||||
<port>587</port>
|
||||
<socketType>STARTTLS</socketType>
|
||||
<authentication>password-cleartext</authentication>
|
||||
<username>%%EMAILADDRESS%%</username>
|
||||
</outgoingServer>
|
||||
</emailProvider>
|
||||
</clientConfig>`, domainName, domainName, domainName, domainName, mailHost, mailHost, mailHost)
|
||||
}
|
||||
|
||||
// BuildOutlookAutodiscoverXML generates Microsoft POX Autodiscover response XML.
|
||||
func BuildOutlookAutodiscoverXML(domainName, mailHost, emailAddress string) string {
|
||||
if mailHost == "" {
|
||||
mailHost = fmt.Sprintf("mail.%s", domainName)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`<?xml version="1.0" encoding="utf-8"?>
|
||||
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
|
||||
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
|
||||
<User>
|
||||
<DisplayName>%s</DisplayName>
|
||||
</User>
|
||||
<Account>
|
||||
<AccountType>email</AccountType>
|
||||
<Action>settings</Action>
|
||||
<Protocol>
|
||||
<Type>IMAP</Type>
|
||||
<Server>%s</Server>
|
||||
<Port>993</Port>
|
||||
<SSL>on</SSL>
|
||||
<AuthRequired>on</AuthRequired>
|
||||
<LoginName>%s</LoginName>
|
||||
</Protocol>
|
||||
<Protocol>
|
||||
<Type>SMTP</Type>
|
||||
<Server>%s</Server>
|
||||
<Port>587</Port>
|
||||
<SSL>off</SSL>
|
||||
<Encryption>TLS</Encryption>
|
||||
<AuthRequired>on</AuthRequired>
|
||||
<LoginName>%s</LoginName>
|
||||
</Protocol>
|
||||
</Account>
|
||||
</Response>
|
||||
</Autodiscover>`, emailAddress, mailHost, emailAddress, mailHost, emailAddress)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package valueobject
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuildThunderbirdAutoconfigXML(t *testing.T) {
|
||||
xml := BuildThunderbirdAutoconfigXML("example.test", "mail.example.test")
|
||||
if !strings.Contains(xml, "<hostname>mail.example.test</hostname>") {
|
||||
t.Errorf("missing mail host: %s", xml)
|
||||
}
|
||||
if !strings.Contains(xml, "<port>993</port>") {
|
||||
t.Errorf("missing port 993: %s", xml)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildOutlookAutodiscoverXML(t *testing.T) {
|
||||
xml := BuildOutlookAutodiscoverXML("example.test", "mail.example.test", "user@example.test")
|
||||
if !strings.Contains(xml, "<Server>mail.example.test</Server>") {
|
||||
t.Errorf("missing Server: %s", xml)
|
||||
}
|
||||
if !strings.Contains(xml, "<LoginName>user@example.test</LoginName>") {
|
||||
t.Errorf("missing LoginName: %s", xml)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package valueobject
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MtaStsMode string
|
||||
|
||||
const (
|
||||
MtaStsModeTesting MtaStsMode = "testing"
|
||||
MtaStsModeEnforce MtaStsMode = "enforce"
|
||||
MtaStsModeNone MtaStsMode = "none"
|
||||
)
|
||||
|
||||
type MtaStsPolicy struct {
|
||||
Version string
|
||||
Mode MtaStsMode
|
||||
MX []string
|
||||
MaxAge int
|
||||
}
|
||||
|
||||
func NewMtaStsPolicy(mode MtaStsMode, mx []string, maxAgeSeconds int) MtaStsPolicy {
|
||||
if maxAgeSeconds <= 0 {
|
||||
maxAgeSeconds = 604800 // default 7 days
|
||||
}
|
||||
return MtaStsPolicy{
|
||||
Version: "STSv1",
|
||||
Mode: mode,
|
||||
MX: mx,
|
||||
MaxAge: maxAgeSeconds,
|
||||
}
|
||||
}
|
||||
|
||||
func (p MtaStsPolicy) Format() string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(fmt.Sprintf("version: %s\r\n", p.Version))
|
||||
sb.WriteString(fmt.Sprintf("mode: %s\r\n", p.Mode))
|
||||
for _, mxHost := range p.MX {
|
||||
sb.WriteString(fmt.Sprintf("mx: %s\r\n", mxHost))
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("max_age: %d\r\n", p.MaxAge))
|
||||
return sb.String()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package valueobject
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMtaStsPolicy_Format(t *testing.T) {
|
||||
policy := NewMtaStsPolicy(MtaStsModeEnforce, []string{"mail.example.test"}, 604800)
|
||||
formatted := policy.Format()
|
||||
|
||||
if !strings.Contains(formatted, "version: STSv1") {
|
||||
t.Errorf("missing version: %s", formatted)
|
||||
}
|
||||
if !strings.Contains(formatted, "mode: enforce") {
|
||||
t.Errorf("missing mode: %s", formatted)
|
||||
}
|
||||
if !strings.Contains(formatted, "mx: mail.example.test") {
|
||||
t.Errorf("missing mx: %s", formatted)
|
||||
}
|
||||
if !strings.Contains(formatted, "max_age: 604800") {
|
||||
t.Errorf("missing max_age: %s", formatted)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user