Skip to content

Commit

Permalink
Improvements to config and logging
Browse files Browse the repository at this point in the history
Added log-level option to CLI
  • Loading branch information
BenjaminGuzman committed Apr 22, 2022
1 parent 3f200ad commit 0a5e005
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 23 deletions.
52 changes: 35 additions & 17 deletions email-strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"errors"
"fmt"
log "github.com/sirupsen/logrus"
"io"
"io/fs"
"mime/multipart"
Expand Down Expand Up @@ -154,10 +155,11 @@ func (e *Email) SetHtmlMessage(htmlMessage string) *Email {
}

func (e *Email) SetAttachments(attachments []string) *Email {
realAttachments := make([]string, len(attachments))
realAttachments := make([]string, 0, len(attachments))
for _, attachment := range attachments {
stat, err := os.Stat(attachment)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Error with attachment '%s'. Ignoring it. %s", attachment, err)
continue
}
if !stat.IsDir() {
Expand All @@ -166,8 +168,10 @@ func (e *Email) SetAttachments(attachments []string) *Email {
}

// add all files inside the directory
err = filepath.WalkDir(attachment, func(path string, d fs.DirEntry, err error) error {
log.Debugf("Attachment %s is a directory, walking the directory", attachment)
_ = filepath.WalkDir(attachment, func(path string, d fs.DirEntry, err error) error {
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Error with attachment '%s'. Ignoring it. %s", path, err)
return nil // just ignore the error and continue, but don't add the file
}
if d.IsDir() {
Expand All @@ -177,16 +181,17 @@ func (e *Email) SetAttachments(attachments []string) *Email {
realAttachments = append(realAttachments, path)
return nil
})
if err != nil {
continue
}
}
e.attachments = attachments
e.attachments = realAttachments
return e
}

// CCEmails Returns only the emails in Email.cc
func (e *Email) CCEmails() []string {
if e.cc == nil {
return nil
}

emails := make([]string, 0, len(e.cc))
for _, entity := range e.cc {
if entity.Email != "" {
Expand All @@ -198,6 +203,10 @@ func (e *Email) CCEmails() []string {

// CCPGPKeyIds Returns the values of Email.cc
func (e *Email) CCPGPKeyIds() []string {
if e.cc == nil {
return nil
}

keyIds := make([]string, 0, len(e.cc))
for _, entity := range e.cc {
if entity.PGPKeyId != "" {
Expand Down Expand Up @@ -232,15 +241,19 @@ func (e *Email) SendEmail() (interface{}, error) {
return nil, errors.New("strategy needs to be initiated")
}

log.Debugln("Creating email payload")
payload, err := e.CreatePayload()
if err != nil {
return nil, err
}
log.Debugln("Done creating email payload")

log.Debugln("Sending email payload")
res, err := e.strategy.SendEmail(payload, e.Sender().Email)
if err != nil {
return nil, err
}
log.Debugln("Done sending email payload")

return res, nil
}
Expand Down Expand Up @@ -285,6 +298,16 @@ func createBasicHeaders(from, to, subject string) string {
)
}

func (e *Email) createCCHeader() string {
strBuilder := strings.Builder{}
if ccEmails := e.CCEmails(); ccEmails != nil && len(ccEmails) > 0 {
strBuilder.WriteString("Cc: ")
strBuilder.WriteString(strings.Join(ccEmails, ","))
strBuilder.WriteString("\r\n")
}
return strBuilder.String()
}

// CreateMessagePayload creates a multipart/alternative payload with the text plain and html message specified in e
//
// This is a pure function, i.e. e is not modified
Expand Down Expand Up @@ -344,11 +367,7 @@ func (e *Email) CreatePayload() ([]byte, error) {
payload.WriteString(createBasicHeaders(e.Sender().Email, e.Recipient().Email, e.subject))

// write CC headers
if e.cc != nil && len(e.cc) > 0 {
payload.WriteString("Cc: ")
payload.WriteString(strings.Join(e.CCEmails(), ","))
payload.WriteString("\r\n")
}
payload.WriteString(e.createCCHeader())
payload.WriteString("\r\nThis is a multi-part message in MIME format.\r\n")

// write message
Expand Down Expand Up @@ -416,11 +435,8 @@ func (e *Email) CreatePGPPayload() ([]byte, error) {
payload.WriteString(fmt.Sprintf("Content-Type: multipart/encrypted; protocol=\"application/pgp-encrypted\"; boundary=\"%s\"\r\n", mpWriter.Boundary()))
payload.WriteString(createBasicHeaders(e.Sender().Email, e.Recipient().Email, e.subject))

if e.cc != nil && len(e.cc) > 0 {
payload.WriteString("Cc: ")
payload.WriteString(strings.Join(e.CCEmails(), ","))
payload.WriteString("\r\n")
}
// write CC headers
payload.WriteString(e.createCCHeader())
payload.WriteString("\r\nThis is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)\r\n")

// write PGP header for encrypted message and PGP version
Expand Down Expand Up @@ -531,6 +547,7 @@ func pgpEncrypt(data []byte, senderId string, recipientsIds ...string) ([]byte,
gpgArgs[i+1] = recipientsIds[(i-len(initialArgs))/2]
}

log.Debugln("Encrypting data. Executing gpg", gpgArgs)
encryptCmd := exec.Command("gpg", gpgArgs...)
stdin, err := encryptCmd.StdinPipe()
if err != nil {
Expand All @@ -557,7 +574,7 @@ func pgpEncrypt(data []byte, senderId string, recipientsIds ...string) ([]byte,
}

e, _ := io.ReadAll(stderr)
if err := encryptCmd.Wait(); err != nil { // if recipient's key doesn't exist, this will return an error
if err = encryptCmd.Wait(); err != nil { // if recipient's key doesn't exist, this will return an error
return nil, fmt.Errorf("error while encrypting PGP message, pgp stderr: \"%s\". %w", e, err)
}

Expand All @@ -578,6 +595,7 @@ func pgpSign(data []byte, senderId string, passphraseFile string) ([]byte, error
gpgArgs = append(gpgArgs, "--passphrase-file", passphraseFile)
}

log.Debugln("Signing data. Executing gpg", gpgArgs)
signCmd := exec.Command("gpg", gpgArgs...)
stdin, err := signCmd.StdinPipe()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ if [ ! -f "login-monitor" ]; then
go build
fi

./login-monitor --config example-config.json --gmail-oauth2-config client-secret.json --gmail-oauth2-token token.json
./login-monitor --config config-example.json --gmail-oauth2-config client-secret.json --gmail-oauth2-token token.json
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ go 1.16
require (
cloud.google.com/go/compute v1.6.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
google.golang.org/api v0.74.0
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4 // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
Expand Down Expand Up @@ -176,8 +177,11 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand Down Expand Up @@ -317,6 +321,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down Expand Up @@ -362,6 +367,8 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
36 changes: 32 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"encoding/json"
"flag"
"fmt"
"log"
log "github.com/sirupsen/logrus"
"os"
"strings"
)

func configFlags(configPath, gmailOAuth2Config, gmailOAuth2Token *string) {
func configFlags(configPath, gmailOAuth2Config, gmailOAuth2Token, logLevel *string) {
flag.StringVar(
configPath,
"config",
Expand All @@ -27,6 +28,13 @@ func configFlags(configPath, gmailOAuth2Config, gmailOAuth2Token *string) {
"token.json",
"Token file for the Gmail Oauth2 strategy",
)
flag.StringVar(
logLevel,
"log-level",
"error",
"Log level to use throughout the application. "+
"Valid values are: trace, debug, info, warn, error, fatal, panic",
)
}

// ensures permissions for the executable that started the process are set to 500 (r-x --- ---)
Expand Down Expand Up @@ -61,10 +69,30 @@ func main() {
fmt.Println("Error while checking permissions.", err)
}

var configFile, gmailOAuth2Config, gmailOAuth2Token string
configFlags(&configFile, &gmailOAuth2Config, &gmailOAuth2Token)
var configFile, gmailOAuth2Config, gmailOAuth2Token, logLevel string
configFlags(&configFile, &gmailOAuth2Config, &gmailOAuth2Token, &logLevel)
flag.Parse()

switch strings.TrimSpace(strings.ToLower(logLevel)) {
case "trace":
log.SetLevel(log.TraceLevel)
case "debug":
log.SetLevel(log.DebugLevel)
case "info":
log.SetLevel(log.InfoLevel)
case "warn":
log.SetLevel(log.WarnLevel)
case "error":
log.SetLevel(log.ErrorLevel)
case "fatal":
log.SetLevel(log.FatalLevel)
case "panic":
log.SetLevel(log.PanicLevel)
default:
fmt.Printf("%s is not recognized as a log level. Setting log level to error", logLevel)
log.SetLevel(log.ErrorLevel)
}

configReader, err := os.Open(configFile)
defer configReader.Close()
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions message-example.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<p>New login on <b>%h</b> at <b>%t RFC822Z t%</b></p><br/>
<p>Details are provided as attachments</p><br/>
<p><i>Remember this information is confidential and please, RESPECT THE PRIVACY of other users</i></p>
<pre>%f go.mod f%</pre>
</body>
</html>
1 change: 1 addition & 0 deletions message-example.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
New login on %h at %t RFC822Z t%.
Details are provided as attachments.
Remember this information is confidential and please, RESPECT THE PRIVACY of other users
%f go.mod f%

0 comments on commit 0a5e005

Please sign in to comment.