From 783c49b578f08be23b7d51bd8ade14983d0e828b Mon Sep 17 00:00:00 2001 From: "Glenn Y. Rolland" Date: Tue, 21 Aug 2018 10:36:54 +0200 Subject: [PATCH] Support multiple types of ssl / auth --- .gitignore | 2 +- cmd/trello2mail/config.go | 102 +++++++++++++++++++++++++++++ cmd/trello2mail/mail.go | 91 +++++++++++++++++++++++++ cmd/trello2mail/main.go | 62 ++++++++++++++++++ cmd/trello2mail/smtp_login_auth.go | 41 ++++++++++++ 5 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 cmd/trello2mail/config.go create mode 100644 cmd/trello2mail/mail.go create mode 100644 cmd/trello2mail/main.go create mode 100644 cmd/trello2mail/smtp_login_auth.go diff --git a/.gitignore b/.gitignore index adc7657..fd5956a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ _*test.sh -trello2mail +/trello2mail diff --git a/cmd/trello2mail/config.go b/cmd/trello2mail/config.go new file mode 100644 index 0000000..bb5ffca --- /dev/null +++ b/cmd/trello2mail/config.go @@ -0,0 +1,102 @@ +package main + +import ( + "errors" + "fmt" + // "log" + "os" + "strconv" + // "net" + // "net/mail" + // "gopkg.in/russross/blackfriday.v2" +) + +type ConfigEntry struct { + Type string + Ptr interface{} + Values []string +} + +type Config struct { + EmailFrom string + EmailTo string + EmailSubject string + SmtpHostname string + SmtpPort uint16 + SmtpUsername string + SmtpPassword string + SmtpAuthType string + SmtpSecurityType string + TrelloUrl string + TrelloToken string +} + +func NewConfig() *Config { + return &Config{} +} + +func (config *Config) ParseEnv() (int, error) { + // map env variables to config pointers + dataMap := map[string](ConfigEntry){ + "EMAIL_FROM": ConfigEntry{"string", &(config.EmailFrom), nil}, + "EMAIL_TO": ConfigEntry{"string", &(config.EmailTo), nil}, + "EMAIL_SUBJECT": ConfigEntry{"string", &(config.EmailSubject), nil}, + "TRELLO_URL": ConfigEntry{"string", &(config.TrelloUrl), nil}, + "TRELLO_TOKEN": ConfigEntry{"string", &(config.TrelloToken), nil}, + + "SMTP_HOSTNAME": ConfigEntry{"string", &(config.SmtpHostname), nil}, + "SMTP_USERNAME": ConfigEntry{"string", &(config.SmtpUsername), nil}, + "SMTP_PASSWORD": ConfigEntry{"string", &(config.SmtpPassword), nil}, + "SMTP_PORT": ConfigEntry{"uint16", &(config.SmtpPort), nil}, + + "SMTP_AUTH_TYPE": ConfigEntry{"string", &(config.SmtpAuthType), []string{"none", "plain", "login"}}, + "SMTP_SECURITY_TYPE": ConfigEntry{"string", &(config.SmtpSecurityType), []string{"none", "tls", "starttls"}}, + } + + for envVar, mapEntry := range dataMap { + envValue := os.Getenv(envVar) + if len(envValue) == 0 { + return -1, errors.New(fmt.Sprintf( + "Empty environment variable. Please set %s value", envVar)) + } + + if mapEntry.Values != nil { + allowedValue := false + for _, v := range mapEntry.Values { + if v == envValue { + allowedValue = true + } + } + if !allowedValue { + return -1, errors.New(fmt.Sprintf( + "Wrong value for %s=%s. Value must be one of %v", envVar, envValue, mapEntry.Values)) + } + } + + switch mapEntry.Type { + case "string": + *(mapEntry.Ptr.(*string)) = envValue + + case "uint16": + u64, err := strconv.ParseUint(envValue, 10, 16) + if err != nil { + return -1, errors.New(fmt.Sprintf( + "Unable to convert %s=%s to unsigned int", envVar, envValue)) + } + *(mapEntry.Ptr.(*uint16)) = uint16(u64) + + case "bool": + b, err := strconv.ParseBool(envValue) + if err != nil { + return -1, errors.New(fmt.Sprintf( + "Unable to convert %s=%s to boolean", envVar, envValue)) + } + *(mapEntry.Ptr.(*bool)) = b + + default: + return -1, errors.New(fmt.Sprintf("Undefined parser for %s<%s>", envVar, mapEntry.Type)) + } + } + fmt.Printf("%#v\n", config) + return 0, nil +} diff --git a/cmd/trello2mail/mail.go b/cmd/trello2mail/mail.go new file mode 100644 index 0000000..9b3ad44 --- /dev/null +++ b/cmd/trello2mail/mail.go @@ -0,0 +1,91 @@ +package main + +import ( + "crypto/tls" + // "errors" + "fmt" + "log" + // "os" + // "strconv" + // "net" + // "net/mail" + "net/smtp" +) + +type MailHeaders map[string]string + +func (headers *MailHeaders) ParseConfig(config Config) (int, error) { + (*headers)["From"] = config.EmailFrom + (*headers)["To"] = config.EmailTo + (*headers)["Subject"] = config.EmailSubject + return 0, nil +} + +func NewAuth(config Config) *smtp.Auth { + + switch config.SmtpAuthType { + case "plain": + auth := smtp.PlainAuth( + "", + config.SmtpUsername, + config.SmtpPassword, + config.SmtpHostname, + ) + return &auth + + case "login": + auth := LoginAuth(config.SmtpUsername, config.SmtpPassword) + return &auth + + default: + } + return nil +} + +func NewTLS(config Config) *tls.Config { + // TLS config + return &tls.Config{ + InsecureSkipVerify: true, + ServerName: config.SmtpHostname, + } +} + +func NewSmtpClient(config Config) *smtp.Client { + address := fmt.Sprintf("%s:%d", config.SmtpHostname, config.SmtpPort) + tlsConfig := NewTLS(config) + switch config.SmtpSecurityType { + case "tls": + fmt.Printf("Creating TLS connection to %s...\n", address) + conn, err := tls.Dial("tcp", address, tlsConfig) + if err != nil { + log.Panic(err) + } + + fmt.Println("Creating SMTP client...") + c, err := smtp.NewClient(conn, config.SmtpHostname) + if err != nil { + log.Panic(err) + } + return c + + case "starttls": + fmt.Println("Creating SMTP client...") + c, err := smtp.Dial(address) + if err != nil { + log.Panic(err) + } + fmt.Printf("Creating StartTLS connection to %s...\n", address) + c.StartTLS(tlsConfig) + + return c + + default: + // no SSL/TLS + fmt.Println("Creating SMTP client...") + c, err := smtp.Dial(address) + if err != nil { + log.Panic(err) + } + return c + } +} diff --git a/cmd/trello2mail/main.go b/cmd/trello2mail/main.go new file mode 100644 index 0000000..4f227bc --- /dev/null +++ b/cmd/trello2mail/main.go @@ -0,0 +1,62 @@ +package main + +// Examples +// - Sending emails with SSL : https://gist.github.com/chrisgillis/10888032 +// - Project layout https://github.com/golang-standards/project-layout +// - Markdown rendering https://github.com/russross/blackfriday + +import ( + "fmt" + "log" + "os" + // "net" + // "net/mail" + // "gopkg.in/russross/blackfriday.v2" +) + +func BuildContent(config Config) []string { + // run taskell (download tasks from trello and export markdown) + // read file as an array + // insert trello board url + // convert to HTML + + // output := blackfriday.Run(input, blackfriday.WithNoExtensions()) + return []string{} +} + +func ImportFromTrello() { +} + +func main() { + // Setup config + config := NewConfig() + if _, err := config.ParseEnv(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) + os.Exit(1) + } + fmt.Printf("%#v\n", config) + + // Build headers + headers := make(MailHeaders) + headers.ParseConfig(*config) + + // Connect & authenticate + fmt.Println("Connecting...") + client := NewSmtpClient(*config) + + // Build auth + authConfig := NewAuth(*config) + fmt.Printf("Authenticating...\n") + + if err := client.Auth(*authConfig); err != nil { + log.Panic(err) + } + fmt.Println("Disconnecting...") + client.Quit() + + // Write email + // mdTasklist := ImportFromTrello(config) + // htmlTasklist := ConvertMarkdown(markdown) + // BuildEmail(config, htmlTasklist) + +} diff --git a/cmd/trello2mail/smtp_login_auth.go b/cmd/trello2mail/smtp_login_auth.go new file mode 100644 index 0000000..5fdefc1 --- /dev/null +++ b/cmd/trello2mail/smtp_login_auth.go @@ -0,0 +1,41 @@ +// MIT license (c) andelf 2013 + +package main + +import ( + "errors" + "net/smtp" +) + +type loginAuth struct { + username, password string +} + +func LoginAuth(username, password string) smtp.Auth { + return &loginAuth{username, password} +} + +func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) { + return "LOGIN", []byte(a.username), nil +} + +func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) { + if more { + switch string(fromServer) { + case "Username:": + return []byte(a.username), nil + case "Password:": + return []byte(a.password), nil + default: + return nil, errors.New("Unkown fromServer") + } + } + return nil, nil +} + +// usage: +// auth := LoginAuth("loginname", "password") +// err := smtp.SendMail(smtpServer + ":25", auth, fromAddress, toAddresses, []byte(message)) +// or +// client, err := smtp.Dial(smtpServer) +// client.Auth(LoginAuth("loginname", "password"))