update dynamic LoginName
This commit is contained in:
109
caddy/autodiscover-handler.go
Normal file
109
caddy/autodiscover-handler.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const port = "8280"
|
||||
|
||||
var emailRegex = regexp.MustCompile(`(?i)<EMailAddress>([^<]+)</EMailAddress>`)
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, "OK")
|
||||
})
|
||||
|
||||
http.HandleFunc("/autodiscover/autodiscover.xml", handleAutodiscover)
|
||||
// Outlook sendet manchmal mit Großbuchstaben
|
||||
http.HandleFunc("/Autodiscover/Autodiscover.xml", handleAutodiscover)
|
||||
http.HandleFunc("/AutoDiscover/AutoDiscover.xml", handleAutodiscover)
|
||||
|
||||
log.Printf("[autodiscover] Listening on port %s", port)
|
||||
if err := http.ListenAndServe(":"+port, nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func handleAutodiscover(w http.ResponseWriter, r *http.Request) {
|
||||
var email string
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err == nil {
|
||||
if match := emailRegex.FindStringSubmatch(string(body)); len(match) > 1 {
|
||||
email = strings.TrimSpace(match[1])
|
||||
}
|
||||
}
|
||||
r.Body.Close()
|
||||
}
|
||||
|
||||
var domain string
|
||||
if email != "" {
|
||||
parts := strings.SplitN(email, "@", 2)
|
||||
if len(parts) == 2 {
|
||||
domain = parts[1]
|
||||
}
|
||||
}
|
||||
if domain == "" {
|
||||
domain = extractDomainFromHost(r.Host)
|
||||
}
|
||||
|
||||
log.Printf("[autodiscover] %s from %s - email=%q domain=%s", r.Method, r.RemoteAddr, email, domain)
|
||||
|
||||
w.Header().Set("Content-Type", "application/xml")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprint(w, buildResponse(domain, email))
|
||||
}
|
||||
|
||||
func extractDomainFromHost(host string) string {
|
||||
// Strip port
|
||||
if idx := strings.Index(host, ":"); idx >= 0 {
|
||||
host = host[:idx]
|
||||
}
|
||||
parts := strings.Split(host, ".")
|
||||
if len(parts) >= 3 && strings.EqualFold(parts[0], "autodiscover") {
|
||||
return strings.Join(parts[1:], ".")
|
||||
}
|
||||
if len(parts) >= 2 {
|
||||
return strings.Join(parts[len(parts)-2:], ".")
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
func buildResponse(domain, loginName string) string {
|
||||
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">
|
||||
<Account>
|
||||
<AccountType>email</AccountType>
|
||||
<Action>settings</Action>
|
||||
<Protocol>
|
||||
<Type>IMAP</Type>
|
||||
<Server>imap.%s</Server>
|
||||
<Port>993</Port>
|
||||
<DomainRequired>off</DomainRequired>
|
||||
<LoginName>%s</LoginName>
|
||||
<SPA>off</SPA>
|
||||
<SSL>on</SSL>
|
||||
<AuthRequired>on</AuthRequired>
|
||||
</Protocol>
|
||||
<Protocol>
|
||||
<Type>SMTP</Type>
|
||||
<Server>smtp.%s</Server>
|
||||
<Port>465</Port>
|
||||
<DomainRequired>off</DomainRequired>
|
||||
<LoginName>%s</LoginName>
|
||||
<SPA>off</SPA>
|
||||
<SSL>on</SSL>
|
||||
<AuthRequired>on</AuthRequired>
|
||||
</Protocol>
|
||||
</Account>
|
||||
</Response>
|
||||
</Autodiscover>`, domain, loginName, domain, loginName)
|
||||
}
|
||||
Reference in New Issue
Block a user