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.
|
||||
# Copy this file to "config/config.yaml" and adjust the
|
||||
# settings to your requirements
|
||||
|
|
|
@ -6,18 +6,35 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"encoding/json"
|
||||
|
||||
"text/template"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
// "reflect"
|
||||
)
|
||||
|
||||
// Global variables
|
||||
var ThisSession Session
|
||||
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 configDir string = "config/"
|
||||
|
||||
func NewSessionID() string{
|
||||
timecode := time.Now()
|
||||
id := timecode.Format("20060102150405.000")
|
||||
id = strings.Replace(id,".","",1)
|
||||
|
||||
return id
|
||||
}
|
||||
func NewConfig() Config {
|
||||
MainConfig = loadConfig()
|
||||
loadXMLTemplates()
|
||||
return MainConfig
|
||||
}
|
||||
func loadConfig() Config {
|
||||
|
@ -37,7 +54,22 @@ func loadConfig() Config {
|
|||
removeDisabledItems(&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) {
|
||||
if FileExists(file) {
|
||||
content, err := ioutil.ReadFile(file)
|
||||
|
@ -94,3 +126,40 @@ func JSONify(content interface{}) string {
|
|||
}
|
||||
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 {
|
||||
ID string
|
||||
IP string
|
||||
ResponseWriter http.ResponseWriter
|
||||
Request *http.Request
|
||||
Path string
|
||||
WebContent string
|
||||
ContentType string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Version string `yaml:"Version"`
|
||||
BaseURL string `yaml:"BaseURL"`
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<hostname>{{ .Server }}</hostname>
|
||||
<port>{{ .Port }}</port>
|
||||
<socketType>{{ .SocketType }}</socketType>
|
||||
<username>{{ . | parseUsername }}</username>
|
||||
<username>{{ $.Email | parseUsername . }}</username>
|
||||
<authentication>{{ .Authentication }}</authentication>
|
||||
</incomingServer>
|
||||
{{ end }}
|
||||
|
@ -20,7 +20,7 @@
|
|||
<hostname>{{ .Server }}</hostname>
|
||||
<port>{{ .Port }}></port>
|
||||
<socketType>{{ .SocketType }}</socketType>
|
||||
<username>{{ . | parseUsername }}</username>
|
||||
<username>{{ $.Email | parseUsername . }}</username>
|
||||
<authentication>{{ .Authentication }}</authentication>
|
||||
</outgoingServer>
|
||||
{{ end }}
|
||||
|
@ -28,7 +28,7 @@
|
|||
{{ with .Config.AddressBook }}
|
||||
{{ if .Enabled }}
|
||||
<addressBook type="{{ .Type | lower }}">
|
||||
<username>{{ . | parseUsername }}</username>
|
||||
<username>{{ $.Email | parseUsername . }}</username>
|
||||
<authentication>{{ .Authentication }}</authentication>
|
||||
<serverURL>{{ .Server }}</serverURL>
|
||||
</addressBook>
|
||||
|
@ -37,7 +37,7 @@
|
|||
{{ with .Config.Calendar }}
|
||||
{{ if .Enabled }}
|
||||
<calendar type="{{ .Type | lower }}">
|
||||
<username>{{ . | parseUsername }}</username>
|
||||
<username>{{ $.Email | parseUsername . }}</username>
|
||||
<authentication>{{ .Authentication }}</authentication>
|
||||
<serverURL>{{ .Server }}</serverURL>
|
||||
</calendar>
|
||||
|
@ -48,7 +48,7 @@
|
|||
<webMail>
|
||||
<loginPage url="{{ .Server }}" />
|
||||
<loginPageInfo url="{{ .Server }}">
|
||||
<username>{{ . | parseUsername }}</username>
|
||||
<username>{{ $.Email | parseUsername . }}</username>
|
||||
<usernameField id="{{ .UsernameDivID }}" name="{{ .UsernameDivID }}" />
|
||||
<passwordField name="{{ .PasswordDivName }}" />
|
||||
<loginButton id="{{ .SubmitButtonID }}" name="{{ .SubmitButtonName }}"/>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<Server>{{ .Server }}</Server>
|
||||
<Port>{{ .Port }}</Port>
|
||||
<DomainRequired>{{ .UsernameIsFQDN | onoff }}</DomainRequired>
|
||||
<LoginName>{{ . | parseUsername }}</LoginName>
|
||||
<LoginName>{{ $.Email | parseUsername . }}</LoginName>
|
||||
<SPA>{{ .SPA | onoff }}</SPA>
|
||||
<SSL>{{ if eq .SocketType "SSL" }}on{{ else }}off{{ end }}</SSL>
|
||||
<AuthRequired>{{ not .NoAuthRequired | onoff }}</AuthRequired>
|
||||
|
@ -25,7 +25,7 @@
|
|||
<Server>{{ .Server }}</Server>
|
||||
<Port>{{ .Port }}</Port>
|
||||
<DomainRequired>{{ .UsernameIsFQDN | onoff }}</DomainRequired>
|
||||
<LoginName>{{ . | parseUsername }}</LoginName>
|
||||
<LoginName>{{ $.Email | parseUsername . }}</LoginName>
|
||||
<SPA>{{ .SPA | onoff }}</SPA>
|
||||
<Encryption>{{ .SocketType }}</Encryption>
|
||||
<AuthRequired>{{ not .NoAuthRequired | onoff }}</AuthRequired>
|
||||
|
|
|
@ -8,10 +8,16 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
func WebHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("Request For :",r.URL)
|
||||
|
||||
|
||||
ThisSession = Session{}
|
||||
ThisSession.ResponseWriter = w
|
||||
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:])
|
||||
if ThisSession.Path == "" {
|
||||
ThisSession.Path = "none"
|
||||
|
|
|
@ -2,42 +2,47 @@ package responses
|
|||
import (
|
||||
"mailautoconf/global"
|
||||
. "mailautoconf/structs"
|
||||
"text/template"
|
||||
// "text/template"
|
||||
"fmt"
|
||||
"path"
|
||||
// "path"
|
||||
"strings"
|
||||
"bytes"
|
||||
"regexp"
|
||||
)
|
||||
var email string
|
||||
var fmap = template.FuncMap{
|
||||
"lower": strings.ToLower,
|
||||
"parseUsername": parseUsername,
|
||||
"onoff": chooseOnOff,
|
||||
}
|
||||
|
||||
func MozAutoconfig() string {
|
||||
// The below link has config-v1.1.xml information
|
||||
// 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.Email = global.ThisSession.Request.FormValue("emailaddress")
|
||||
email = response.Email
|
||||
response.Config = global.MainConfig
|
||||
|
||||
name := path.Base(tmpl)
|
||||
t, err1 := template.New(name).Funcs(fmap).ParseFiles(tmpl)
|
||||
if err1 != nil {
|
||||
panic (err1)
|
||||
}
|
||||
// set content type to XML
|
||||
global.ThisSession.ContentType = "application/xml"
|
||||
|
||||
// execute the template
|
||||
var result bytes.Buffer
|
||||
err := t.Execute(&result, response)
|
||||
template := global.Templates["autoconfig.xml"]
|
||||
err := template.Execute(&result, response)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// return our string of xml
|
||||
return result.String()
|
||||
}
|
||||
func MsAutoDiscoverXML() string {
|
||||
// MS Outlook Autodiscover.xml
|
||||
//
|
||||
// Example POST Request (sent from client) :
|
||||
// <?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">
|
||||
|
@ -46,27 +51,64 @@ func MsAutoDiscoverXML() string {
|
|||
// <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
|
||||
// </Request>
|
||||
// </Autodiscover>
|
||||
tmpl := "templates/autodiscover.xml"
|
||||
email = global.ThisSession.Request.FormValue("EMailAddress")
|
||||
response := Response{}
|
||||
response.Config = global.MainConfig
|
||||
name := path.Base(tmpl)
|
||||
t, err1 := template.New(name).Funcs(fmap).ParseFiles(tmpl)
|
||||
if err1 != nil {
|
||||
panic (err1)
|
||||
|
||||
// Parse the form to get the values
|
||||
if err := global.ThisSession.Request.ParseForm(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// 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"
|
||||
var result bytes.Buffer
|
||||
err := t.Execute(&result, response)
|
||||
err := template.Execute(&result, response)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// return our string of xml
|
||||
return result.String()
|
||||
}
|
||||
func MsAutoDiscoverJSON() string {
|
||||
// MS Outlook Autodiscover.json - undocumented
|
||||
//
|
||||
// Example Request
|
||||
// /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 {
|
||||
response := Response{}
|
||||
|
@ -81,28 +123,3 @@ func OurConfig() string {
|
|||
content := global.JSONify(global.MainConfig)
|
||||
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