diff options
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/fwdsms/config.go | 44 | ||||
| -rw-r--r-- | cmd/fwdsms/config_test.go | 36 | ||||
| -rw-r--r-- | cmd/fwdsms/mailer.go | 122 | ||||
| -rw-r--r-- | cmd/fwdsms/mailer_test.go | 52 | ||||
| -rw-r--r-- | cmd/fwdsms/main.go | 89 |
5 files changed, 0 insertions, 343 deletions
diff --git a/cmd/fwdsms/config.go b/cmd/fwdsms/config.go deleted file mode 100644 index 64a4a51..0000000 --- a/cmd/fwdsms/config.go +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: © 2020 Grégoire Duchêne <gduchene@awhk.org> -// SPDX-License-Identifier: ISC - -package main - -import ( - "io" - - "gopkg.in/yaml.v3" -) - -type Config struct { - Message Message `yaml:"message"` - SMTP SMTP `yaml:"smtp"` - Twilio Twilio `yaml:"twilio"` -} - -type Message struct { - From string `yaml:"from"` - To string `yaml:"to"` - Subject string `yaml:"subject"` - Template string `yaml:"template"` -} - -type SMTP struct { - Address string `yaml:"hostname"` - Username string `yaml:"username"` - Password string `yaml:"password"` -} - -type Twilio struct { - Address string `yaml:"address"` - AuthToken string `yaml:"authToken"` - Endpoint string `yaml:"endpoint"` -} - -func loadConfig(r io.Reader) (*Config, error) { - dec := yaml.NewDecoder(r) - cfg := &Config{} - if err := dec.Decode(cfg); err != nil { - return nil, err - } - return cfg, nil -} diff --git a/cmd/fwdsms/config_test.go b/cmd/fwdsms/config_test.go deleted file mode 100644 index a303719..0000000 --- a/cmd/fwdsms/config_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -const cfg string = ` -message: - from: foo@example.com - to: bar@example.com - subject: New SMS From {{.From}} For {{.To}} - template: | - From: {{.From}} - To: {{.To}} - Date: {{.DateReceived.UTC}} - - {{.Message}} - -smtp: - hostname: example.com:465 - username: bar - password: some password - -twilio: - address: /run/fwdsms/socket - authToken: some token - endpoint: / -` - -func TestConfig(t *testing.T) { - _, err := loadConfig(strings.NewReader(cfg)) - assert.NoError(t, err) -} diff --git a/cmd/fwdsms/mailer.go b/cmd/fwdsms/mailer.go deleted file mode 100644 index cb687c9..0000000 --- a/cmd/fwdsms/mailer.go +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-FileCopyrightText: © 2020 Grégoire Duchêne <gduchene@awhk.org> -// SPDX-License-Identifier: ISC - -package main - -import ( - "bytes" - "context" - "crypto/tls" - "fmt" - "log" - "net" - "net/smtp" - "text/template" - "time" - - "go.awhk.org/fwdsms/pkg/twilio" -) - -type email struct { - from, to string - body []byte -} - -type mailer struct { - auth smtp.Auth - hostname string - sms <-chan twilio.SMS - tmplFrom, tmplTo, tmplMsg *template.Template -} - -func (m *mailer) sendEmail(e email) error { - dialer := &net.Dialer{Timeout: time.Second} - conn, err := tls.DialWithDialer(dialer, "tcp", m.hostname, nil) - if err != nil { - return err - } - if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil { - log.Printf("Failed to set the SMTP connection deadline: %s.", err) - } - h, _, _ := net.SplitHostPort(m.hostname) - c, err := smtp.NewClient(conn, h) - if err != nil { - conn.Close() - return err - } - defer c.Close() - if err := c.Auth(m.auth); err != nil { - return err - } - - if err := c.Mail(e.from); err != nil { - return err - } - if err := c.Rcpt(e.to); err != nil { - return err - } - w, err := c.Data() - if err != nil { - return err - } - if _, err := w.Write(e.body); err != nil { - return err - } - if err = w.Close(); err != nil { - return nil - } - return c.Quit() -} - -func (m *mailer) newEmail(sms twilio.SMS) email { - var from, to, msg bytes.Buffer - if err := m.tmplFrom.Execute(&from, sms); err != nil { - log.Printf("Failed to apply a template: %v.", err) - } - if err := m.tmplTo.Execute(&to, sms); err != nil { - log.Printf("Failed to apply a template: %v.", err) - } - if err := m.tmplMsg.Execute(&msg, sms); err != nil { - log.Printf("Failed to apply a template: %v.", err) - } - return email{from.String(), to.String(), msg.Bytes()} -} - -func (m *mailer) start(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case sms := <-m.sms: - if err := m.sendEmail(m.newEmail(sms)); err != nil { - log.Printf("Failed to send email: %v.", err) - } - } - } -} - -func newMailer(cfg *Config, sms <-chan twilio.SMS) *mailer { - if cfg.Message.From == "" { - log.Fatal("Missing From field.") - } - if cfg.Message.To == "" { - log.Fatal("Missing To field.") - } - if cfg.Message.Subject == "" { - log.Fatal("Missing Subject field.") - } - if cfg.Message.Template == "" { - log.Fatal("Missing Template field.") - } - tmplMsg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s\r\n", - cfg.Message.From, cfg.Message.To, cfg.Message.Subject, cfg.Message.Template) - host, _, _ := net.SplitHostPort(cfg.SMTP.Address) - return &mailer{ - auth: smtp.PlainAuth("", cfg.SMTP.Username, cfg.SMTP.Password, host), - hostname: cfg.SMTP.Address, - sms: sms, - tmplFrom: template.Must(template.New("from").Parse(cfg.Message.From)), - tmplTo: template.Must(template.New("to").Parse(cfg.Message.To)), - tmplMsg: template.Must(template.New("message").Parse(tmplMsg)), - } -} diff --git a/cmd/fwdsms/mailer_test.go b/cmd/fwdsms/mailer_test.go deleted file mode 100644 index e1376c3..0000000 --- a/cmd/fwdsms/mailer_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-FileCopyrightText: © 2020 Grégoire Duchêne <gduchene@awhk.org> -// SPDX-License-Identifier: ISC - -package main - -import ( - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "go.awhk.org/fwdsms/pkg/twilio" -) - -func TestMailer_newEmail(t *testing.T) { - m := newMailer(&Config{ - Message: Message{ - From: "fwdsms@example.com", - To: "sms{{.To}}@example.com", - Subject: "New SMS From {{.From}}", - Template: `From: {{.From}} - To: {{.To}} -Date: {{.DateReceived.UTC}} - -{{.Body}}`, - }}, nil) - // Reserved phone numbers, see Ofcom's website. - sms := twilio.SMS{ - DateReceived: time.Unix(0, 0), - From: "+442079460123", - To: "+447700900123", - Body: "Hello World!", - } - wants := email{ - from: "fwdsms@example.com", - to: "sms+447700900123@example.com", - body: []byte(strings.Join([]string{ - "From: fwdsms@example.com", - "To: sms+447700900123@example.com", - "Subject: New SMS From +442079460123", - "", - `From: +442079460123 - To: +447700900123 -Date: 1970-01-01 00:00:00 +0000 UTC - -Hello World!`, - "", - }, "\r\n")), - } - assert.Equal(t, wants, m.newEmail(sms)) -} diff --git a/cmd/fwdsms/main.go b/cmd/fwdsms/main.go deleted file mode 100644 index 090331f..0000000 --- a/cmd/fwdsms/main.go +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-FileCopyrightText: © 2020 Grégoire Duchêne <gduchene@awhk.org> -// SPDX-License-Identifier: ISC - -package main - -import ( - "context" - "flag" - "log" - "net" - "net/http" - "os" - "os/signal" - "time" - - "github.com/gorilla/handlers" - "github.com/gorilla/mux" - "golang.org/x/sys/unix" - - "go.awhk.org/fwdsms/pkg/twilio" -) - -var cfgFilename = flag.String("c", "/etc/fwdsms.yaml", "configuration file") - -func main() { - flag.Parse() - log.SetFlags(0) - fd, err := os.Open(*cfgFilename) - if err != nil { - log.Fatalf("Could not open the configuration file: %v.", err) - } - cfg, err := loadConfig(fd) - if err != nil { - log.Fatalf("Could not load the configuration: %v.", err) - } - - done := make(chan os.Signal, 1) - signal.Notify(done, os.Interrupt, unix.SIGTERM) - - sms := make(chan twilio.SMS) - - r := mux.NewRouter() - r.Path(cfg.Twilio.Endpoint). - Methods(http.MethodPost). - Handler(handlers.ProxyHeaders(&twilio.Filter{ - AuthToken: []byte(cfg.Twilio.AuthToken), - Handler: &twilio.SMSTee{ - Chan: sms, - Handler: twilio.EmptyResponseHandler, - }, - })) - srv := http.Server{Handler: r} - go func() { - var ( - l net.Listener - err error - ) - if cfg.Twilio.Address != "" && cfg.Twilio.Address[0] == '/' { - if l, err = net.Listen("unix", cfg.Twilio.Address); err != nil { - log.Fatalf("Could not set up UNIX listener: %v.", err) - } - if err = os.Chmod(cfg.Twilio.Address, 0666); err != nil { - log.Fatalf("Could not set up permissions on UNIX socket: %v.", err) - } - } else { - if cfg.Twilio.Address == "" { - cfg.Twilio.Address = ":8080" - } - if l, err = net.Listen("tcp", cfg.Twilio.Address); err != nil { - log.Fatalf("Could not set up TCP listener: %v.", err) - } - } - if err = srv.Serve(l); err != nil && err != http.ErrServerClosed { - log.Fatalf("Failed to serve HTTP: %v.", err) - } - }() - - mailer := newMailer(cfg, sms) - ctx, cancel := context.WithCancel(context.Background()) - go mailer.start(ctx) - - <-done - cancel() - ctx, cancel = context.WithTimeout(context.Background(), time.Second) - defer cancel() - if err := srv.Shutdown(ctx); err != nil && err != http.ErrServerClosed { - log.Fatalf("Failed to properly shut down the HTTP server: %v.", err) - } -} |
