reworked templates so they're not read from disk each time
This commit is contained in:
parent
4fa86d82f0
commit
b093b46cea
7 changed files with 156 additions and 61 deletions
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
Version : "0.1.2"
|
Version : "0.1.3"
|
||||||
# Sample config.yaml file.
|
# Sample config.yaml file.
|
||||||
# Copy this file to "config/config.yaml" and adjust the
|
# Copy this file to "config/config.yaml" and adjust the
|
||||||
# settings to your requirements
|
# settings to your requirements
|
||||||
|
|
|
@ -6,18 +6,35 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"text/template"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
// "reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Global variables
|
// Global variables
|
||||||
var ThisSession Session
|
var ThisSession Session
|
||||||
var MainConfig Config
|
var MainConfig Config
|
||||||
|
|
||||||
|
// Template declaration
|
||||||
|
var templates []string = []string{"autodiscover.xml","autoconfig.xml"}
|
||||||
|
var Templates map[string]*template.Template = make(map[string]*template.Template)
|
||||||
|
|
||||||
const defaultConfigDir string = "default-config/"
|
const defaultConfigDir string = "default-config/"
|
||||||
const configDir string = "config/"
|
const configDir string = "config/"
|
||||||
|
|
||||||
|
func NewSessionID() string{
|
||||||
|
timecode := time.Now()
|
||||||
|
id := timecode.Format("20060102150405.000")
|
||||||
|
id = strings.Replace(id,".","",1)
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
func NewConfig() Config {
|
func NewConfig() Config {
|
||||||
MainConfig = loadConfig()
|
MainConfig = loadConfig()
|
||||||
|
loadXMLTemplates()
|
||||||
return MainConfig
|
return MainConfig
|
||||||
}
|
}
|
||||||
func loadConfig() Config {
|
func loadConfig() Config {
|
||||||
|
@ -37,7 +54,22 @@ func loadConfig() Config {
|
||||||
removeDisabledItems(&cfg)
|
removeDisabledItems(&cfg)
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
func loadXMLTemplates(){
|
||||||
|
for _, tmpl := range templates {
|
||||||
|
tmpl := fmt.Sprintf("templates/%s",tmpl)
|
||||||
|
name := path.Base(tmpl)
|
||||||
|
var fmap = template.FuncMap{
|
||||||
|
"lower": strings.ToLower,
|
||||||
|
"parseUsername": parseUsername,
|
||||||
|
"onoff": chooseOnOff,
|
||||||
|
}
|
||||||
|
t, err := template.New(name).Funcs(fmap).ParseFiles(tmpl)
|
||||||
|
if err != nil {
|
||||||
|
panic (err)
|
||||||
|
}
|
||||||
|
Templates[name] = t
|
||||||
|
}
|
||||||
|
}
|
||||||
func unmarshalConfig(file string, cfg *Config) {
|
func unmarshalConfig(file string, cfg *Config) {
|
||||||
if FileExists(file) {
|
if FileExists(file) {
|
||||||
content, err := ioutil.ReadFile(file)
|
content, err := ioutil.ReadFile(file)
|
||||||
|
@ -94,3 +126,40 @@ func JSONify(content interface{}) string {
|
||||||
}
|
}
|
||||||
return string(data)
|
return string(data)
|
||||||
}
|
}
|
||||||
|
func parseUsername(svc Service, email string) string {
|
||||||
|
if email == "" {
|
||||||
|
return "not-provided"
|
||||||
|
}
|
||||||
|
if svc.UsernameIsFQDN && !svc.RequireLocalDomain{
|
||||||
|
return email
|
||||||
|
} else if svc.UsernameIsFQDN && svc.RequireLocalDomain {
|
||||||
|
re := regexp.MustCompile(`[^@(%40)]+$`)
|
||||||
|
domain := re.FindString(email)
|
||||||
|
localemail := strings.Replace(email, domain,
|
||||||
|
MainConfig.LocalDomain,1)
|
||||||
|
return localemail
|
||||||
|
} else {
|
||||||
|
re := regexp.MustCompile(`^[^@(%40)]+`)
|
||||||
|
username := re.FindString(email)
|
||||||
|
return username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func chooseOnOff(value bool) string {
|
||||||
|
if value {
|
||||||
|
return "on"
|
||||||
|
} else {
|
||||||
|
return "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// GetIP gets a requests IP address by reading off the forwarded-for
|
||||||
|
// header (for proxies) and falls back to use the remote address.
|
||||||
|
func GetSessionIP() string {
|
||||||
|
r := ThisSession.Request
|
||||||
|
ip := r.RemoteAddr
|
||||||
|
forwarded := r.Header.Get("X-FORWARDED-FOR")
|
||||||
|
if forwarded != "" {
|
||||||
|
ip = forwarded
|
||||||
|
}
|
||||||
|
fmt.Printf("Session %s Connect From : %s\r\f",ThisSession.ID, ip)
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
|
@ -4,12 +4,15 @@ import "net/http"
|
||||||
|
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
|
ID string
|
||||||
|
IP string
|
||||||
ResponseWriter http.ResponseWriter
|
ResponseWriter http.ResponseWriter
|
||||||
Request *http.Request
|
Request *http.Request
|
||||||
Path string
|
Path string
|
||||||
WebContent string
|
WebContent string
|
||||||
ContentType string
|
ContentType string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Version string `yaml:"Version"`
|
Version string `yaml:"Version"`
|
||||||
BaseURL string `yaml:"BaseURL"`
|
BaseURL string `yaml:"BaseURL"`
|
||||||
|
@ -49,7 +52,7 @@ type Response struct {
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
ContentType string `json:"content_type"`
|
ContentType string `json:"content_type"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Content map[string]interface{} `json:"content"`
|
Content map[string]interface{} `json:"content"`
|
||||||
Config Config `json:"_"`
|
Config Config `json:"_"`
|
||||||
Email string `json:"_"`
|
Email string `json:"_"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<hostname>{{ .Server }}</hostname>
|
<hostname>{{ .Server }}</hostname>
|
||||||
<port>{{ .Port }}</port>
|
<port>{{ .Port }}</port>
|
||||||
<socketType>{{ .SocketType }}</socketType>
|
<socketType>{{ .SocketType }}</socketType>
|
||||||
<username>{{ . | parseUsername }}</username>
|
<username>{{ $.Email | parseUsername . }}</username>
|
||||||
<authentication>{{ .Authentication }}</authentication>
|
<authentication>{{ .Authentication }}</authentication>
|
||||||
</incomingServer>
|
</incomingServer>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<hostname>{{ .Server }}</hostname>
|
<hostname>{{ .Server }}</hostname>
|
||||||
<port>{{ .Port }}></port>
|
<port>{{ .Port }}></port>
|
||||||
<socketType>{{ .SocketType }}</socketType>
|
<socketType>{{ .SocketType }}</socketType>
|
||||||
<username>{{ . | parseUsername }}</username>
|
<username>{{ $.Email | parseUsername . }}</username>
|
||||||
<authentication>{{ .Authentication }}</authentication>
|
<authentication>{{ .Authentication }}</authentication>
|
||||||
</outgoingServer>
|
</outgoingServer>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
{{ with .Config.AddressBook }}
|
{{ with .Config.AddressBook }}
|
||||||
{{ if .Enabled }}
|
{{ if .Enabled }}
|
||||||
<addressBook type="{{ .Type | lower }}">
|
<addressBook type="{{ .Type | lower }}">
|
||||||
<username>{{ . | parseUsername }}</username>
|
<username>{{ $.Email | parseUsername . }}</username>
|
||||||
<authentication>{{ .Authentication }}</authentication>
|
<authentication>{{ .Authentication }}</authentication>
|
||||||
<serverURL>{{ .Server }}</serverURL>
|
<serverURL>{{ .Server }}</serverURL>
|
||||||
</addressBook>
|
</addressBook>
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
{{ with .Config.Calendar }}
|
{{ with .Config.Calendar }}
|
||||||
{{ if .Enabled }}
|
{{ if .Enabled }}
|
||||||
<calendar type="{{ .Type | lower }}">
|
<calendar type="{{ .Type | lower }}">
|
||||||
<username>{{ . | parseUsername }}</username>
|
<username>{{ $.Email | parseUsername . }}</username>
|
||||||
<authentication>{{ .Authentication }}</authentication>
|
<authentication>{{ .Authentication }}</authentication>
|
||||||
<serverURL>{{ .Server }}</serverURL>
|
<serverURL>{{ .Server }}</serverURL>
|
||||||
</calendar>
|
</calendar>
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
<webMail>
|
<webMail>
|
||||||
<loginPage url="{{ .Server }}" />
|
<loginPage url="{{ .Server }}" />
|
||||||
<loginPageInfo url="{{ .Server }}">
|
<loginPageInfo url="{{ .Server }}">
|
||||||
<username>{{ . | parseUsername }}</username>
|
<username>{{ $.Email | parseUsername . }}</username>
|
||||||
<usernameField id="{{ .UsernameDivID }}" name="{{ .UsernameDivID }}" />
|
<usernameField id="{{ .UsernameDivID }}" name="{{ .UsernameDivID }}" />
|
||||||
<passwordField name="{{ .PasswordDivName }}" />
|
<passwordField name="{{ .PasswordDivName }}" />
|
||||||
<loginButton id="{{ .SubmitButtonID }}" name="{{ .SubmitButtonName }}"/>
|
<loginButton id="{{ .SubmitButtonID }}" name="{{ .SubmitButtonName }}"/>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<Server>{{ .Server }}</Server>
|
<Server>{{ .Server }}</Server>
|
||||||
<Port>{{ .Port }}</Port>
|
<Port>{{ .Port }}</Port>
|
||||||
<DomainRequired>{{ .UsernameIsFQDN | onoff }}</DomainRequired>
|
<DomainRequired>{{ .UsernameIsFQDN | onoff }}</DomainRequired>
|
||||||
<LoginName>{{ . | parseUsername }}</LoginName>
|
<LoginName>{{ $.Email | parseUsername . }}</LoginName>
|
||||||
<SPA>{{ .SPA | onoff }}</SPA>
|
<SPA>{{ .SPA | onoff }}</SPA>
|
||||||
<SSL>{{ if eq .SocketType "SSL" }}on{{ else }}off{{ end }}</SSL>
|
<SSL>{{ if eq .SocketType "SSL" }}on{{ else }}off{{ end }}</SSL>
|
||||||
<AuthRequired>{{ not .NoAuthRequired | onoff }}</AuthRequired>
|
<AuthRequired>{{ not .NoAuthRequired | onoff }}</AuthRequired>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
<Server>{{ .Server }}</Server>
|
<Server>{{ .Server }}</Server>
|
||||||
<Port>{{ .Port }}</Port>
|
<Port>{{ .Port }}</Port>
|
||||||
<DomainRequired>{{ .UsernameIsFQDN | onoff }}</DomainRequired>
|
<DomainRequired>{{ .UsernameIsFQDN | onoff }}</DomainRequired>
|
||||||
<LoginName>{{ . | parseUsername }}</LoginName>
|
<LoginName>{{ $.Email | parseUsername . }}</LoginName>
|
||||||
<SPA>{{ .SPA | onoff }}</SPA>
|
<SPA>{{ .SPA | onoff }}</SPA>
|
||||||
<Encryption>{{ .SocketType }}</Encryption>
|
<Encryption>{{ .SocketType }}</Encryption>
|
||||||
<AuthRequired>{{ not .NoAuthRequired | onoff }}</AuthRequired>
|
<AuthRequired>{{ not .NoAuthRequired | onoff }}</AuthRequired>
|
||||||
|
|
|
@ -8,10 +8,16 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
func WebHandler(w http.ResponseWriter, r *http.Request) {
|
func WebHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Println("Request For :",r.URL)
|
|
||||||
|
|
||||||
ThisSession = Session{}
|
ThisSession = Session{}
|
||||||
ThisSession.ResponseWriter = w
|
ThisSession.ResponseWriter = w
|
||||||
ThisSession.Request = r
|
ThisSession.Request = r
|
||||||
|
|
||||||
|
ThisSession.ID = NewSessionID()
|
||||||
|
fmt.Printf("Session %s Request For : %s\r\f",ThisSession.ID, r.URL)
|
||||||
|
ThisSession.IP = GetSessionIP()
|
||||||
|
|
||||||
ThisSession.Path = strings.ToLower(r.URL.Path[1:])
|
ThisSession.Path = strings.ToLower(r.URL.Path[1:])
|
||||||
if ThisSession.Path == "" {
|
if ThisSession.Path == "" {
|
||||||
ThisSession.Path = "none"
|
ThisSession.Path = "none"
|
||||||
|
|
|
@ -2,42 +2,47 @@ package responses
|
||||||
import (
|
import (
|
||||||
"mailautoconf/global"
|
"mailautoconf/global"
|
||||||
. "mailautoconf/structs"
|
. "mailautoconf/structs"
|
||||||
"text/template"
|
// "text/template"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
// "path"
|
||||||
"strings"
|
"strings"
|
||||||
"bytes"
|
"bytes"
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
var email string
|
var email string
|
||||||
var fmap = template.FuncMap{
|
|
||||||
"lower": strings.ToLower,
|
|
||||||
"parseUsername": parseUsername,
|
|
||||||
"onoff": chooseOnOff,
|
|
||||||
}
|
|
||||||
func MozAutoconfig() string {
|
func MozAutoconfig() string {
|
||||||
// The below link has config-v1.1.xml information
|
// The below link has config-v1.1.xml information
|
||||||
// https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat
|
// https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat
|
||||||
tmpl := "templates/autoconfig.xml"
|
|
||||||
|
// parse the querystring
|
||||||
|
if err := global.ThisSession.Request.ParseForm(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the response
|
||||||
response := Response{}
|
response := Response{}
|
||||||
response.Email = global.ThisSession.Request.FormValue("emailaddress")
|
response.Email = global.ThisSession.Request.FormValue("emailaddress")
|
||||||
email = response.Email
|
email = response.Email
|
||||||
response.Config = global.MainConfig
|
response.Config = global.MainConfig
|
||||||
|
|
||||||
name := path.Base(tmpl)
|
// set content type to XML
|
||||||
t, err1 := template.New(name).Funcs(fmap).ParseFiles(tmpl)
|
|
||||||
if err1 != nil {
|
|
||||||
panic (err1)
|
|
||||||
}
|
|
||||||
global.ThisSession.ContentType = "application/xml"
|
global.ThisSession.ContentType = "application/xml"
|
||||||
|
|
||||||
|
// execute the template
|
||||||
var result bytes.Buffer
|
var result bytes.Buffer
|
||||||
err := t.Execute(&result, response)
|
template := global.Templates["autoconfig.xml"]
|
||||||
|
err := template.Execute(&result, response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return our string of xml
|
||||||
return result.String()
|
return result.String()
|
||||||
}
|
}
|
||||||
func MsAutoDiscoverXML() string {
|
func MsAutoDiscoverXML() string {
|
||||||
|
// MS Outlook Autodiscover.xml
|
||||||
|
//
|
||||||
// Example POST Request (sent from client) :
|
// Example POST Request (sent from client) :
|
||||||
// <?xml version="1.0" \?\>
|
// <?xml version="1.0" \?\>
|
||||||
// <Autodiscover xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
|
// <Autodiscover xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
|
||||||
|
@ -46,27 +51,64 @@ func MsAutoDiscoverXML() string {
|
||||||
// <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
|
// <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
|
||||||
// </Request>
|
// </Request>
|
||||||
// </Autodiscover>
|
// </Autodiscover>
|
||||||
tmpl := "templates/autodiscover.xml"
|
|
||||||
email = global.ThisSession.Request.FormValue("EMailAddress")
|
// Parse the form to get the values
|
||||||
response := Response{}
|
if err := global.ThisSession.Request.ParseForm(); err != nil {
|
||||||
response.Config = global.MainConfig
|
fmt.Println(err)
|
||||||
name := path.Base(tmpl)
|
|
||||||
t, err1 := template.New(name).Funcs(fmap).ParseFiles(tmpl)
|
|
||||||
if err1 != nil {
|
|
||||||
panic (err1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert the input to a string so we can extract the email address
|
||||||
|
form := fmt.Sprintf("%s",global.ThisSession.Request.Form)
|
||||||
|
|
||||||
|
// fine the EMailAddress section
|
||||||
|
find := regexp.MustCompile(`\<EMailAddress\>(.*?)\<\/EMailAddress\>`)
|
||||||
|
email = find.FindString(form)
|
||||||
|
|
||||||
|
// replace the tags
|
||||||
|
replace := regexp.MustCompile(`\<[\/]?EMailAddress\>`)
|
||||||
|
email = replace.ReplaceAllString(email,``)
|
||||||
|
|
||||||
|
fmt.Printf("Session %s Request for email : %s\r\f",global.ThisSession.ID,email)
|
||||||
|
// build the reponse
|
||||||
|
response := Response{}
|
||||||
|
response.Email = email
|
||||||
|
response.Config = global.MainConfig
|
||||||
|
|
||||||
|
// execute the template
|
||||||
|
template := global.Templates["autodiscover.xml"]
|
||||||
global.ThisSession.ContentType = "application/xml"
|
global.ThisSession.ContentType = "application/xml"
|
||||||
var result bytes.Buffer
|
var result bytes.Buffer
|
||||||
err := t.Execute(&result, response)
|
err := template.Execute(&result, response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return our string of xml
|
||||||
return result.String()
|
return result.String()
|
||||||
}
|
}
|
||||||
func MsAutoDiscoverJSON() string {
|
func MsAutoDiscoverJSON() string {
|
||||||
|
// MS Outlook Autodiscover.json - undocumented
|
||||||
|
//
|
||||||
// Example Request
|
// Example Request
|
||||||
// /autodiscover/autodiscover.json?Email=you@your.domain&Protocol=Autodiscoverv1&RedirectCount=1
|
// /autodiscover/autodiscover.json?Email=you@your.domain&Protocol=Autodiscoverv1&RedirectCount=1
|
||||||
return ""
|
email = global.ThisSession.Request.FormValue("Email")
|
||||||
|
protocol := global.ThisSession.Request.FormValue("Protocol")
|
||||||
|
fmt.Println(protocol)
|
||||||
|
global.ThisSession.ContentType = "application/json"
|
||||||
|
switch strings.ToLower(protocol) {
|
||||||
|
case "autodiscoverv1":
|
||||||
|
response := MSAutodiscoverJSONResponse{}
|
||||||
|
response.Protocol = "AutodiscoverV1"
|
||||||
|
response.Url = fmt.Sprintf("%s/Autodiscover/Autodiscover.xml", global.MainConfig.BaseURL)
|
||||||
|
return global.JSONify(response)
|
||||||
|
default:
|
||||||
|
|
||||||
|
response := MSAutodiscoverJSONError{}
|
||||||
|
response.ErrorCode = "InvalidProtocol";
|
||||||
|
response.ErrorMessage = fmt.Sprintf("The given protocol value '%s' is invalid. Supported values are 'AutodiscoverV1'", protocol)
|
||||||
|
return global.JSONify(response)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
func DefaultResponse() string {
|
func DefaultResponse() string {
|
||||||
response := Response{}
|
response := Response{}
|
||||||
|
@ -81,28 +123,3 @@ func OurConfig() string {
|
||||||
content := global.JSONify(global.MainConfig)
|
content := global.JSONify(global.MainConfig)
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
func parseUsername(svc Service) string {
|
|
||||||
if email == "" {
|
|
||||||
return "not-provided"
|
|
||||||
}
|
|
||||||
if svc.UsernameIsFQDN && !svc.RequireLocalDomain{
|
|
||||||
return email
|
|
||||||
} else if svc.UsernameIsFQDN && svc.RequireLocalDomain {
|
|
||||||
re := regexp.MustCompile(`[^@(%40)]+$`)
|
|
||||||
domain := re.FindString(email)
|
|
||||||
localemail := strings.Replace(email, domain,
|
|
||||||
global.MainConfig.LocalDomain,1)
|
|
||||||
return localemail
|
|
||||||
} else {
|
|
||||||
re := regexp.MustCompile(`^[^@(%40)]+`)
|
|
||||||
username := re.FindString(email)
|
|
||||||
return username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func chooseOnOff(value bool) string {
|
|
||||||
if value {
|
|
||||||
return "on"
|
|
||||||
} else {
|
|
||||||
return "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue