From f4dc7e1f746582d42462ec56347dd354756203b0 Mon Sep 17 00:00:00 2001 From: R Chowdhury Date: Tue, 26 May 2020 07:29:58 -0400 Subject: [PATCH] Add `oauthbearer` support for SMTP This piggybacks on the existing IMAP support, and uses the same configuration format (my local testing example has the IMAP and SMTP lines almost copy-pasted from one another). It's a little clumsy in that a new token is negotiated for every `Send()` command, but it's a start... --- commands/compose/send.go | 31 +++++++++++++++++++++++++++++++ lib/oauthbearer.go | 4 ++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/commands/compose/send.go b/commands/compose/send.go index 40ac4ca..dd7ece9 100644 --- a/commands/compose/send.go +++ b/commands/compose/send.go @@ -16,9 +16,11 @@ import ( "github.com/miolini/datacounter" "github.com/pkg/errors" + "git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/widgets" "git.sr.ht/~sircmpwn/aerc/worker/types" + "golang.org/x/oauth2" ) type Send struct{} @@ -97,6 +99,35 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error { case "plain": password, _ := uri.User.Password() saslClient = sasl.NewPlainClient("", uri.User.Username(), password) + case "oauthbearer": + q := uri.Query() + + oauth2 := &oauth2.Config{} + if q.Get("token_endpoint") != "" { + oauth2.ClientID = q.Get("client_id") + oauth2.ClientSecret = q.Get("client_secret") + oauth2.Scopes = []string{q.Get("scope")} + oauth2.Endpoint.TokenURL = q.Get("token_endpoint") + } + + password, _ := uri.User.Password() + bearer := lib.OAuthBearer{ + OAuth2: oauth2, + Enabled: true, + } + if bearer.OAuth2.Endpoint.TokenURL == "" { + return fmt.Errorf("No 'TokenURL' configured for this account") + } + token, err := bearer.ExchangeRefreshToken(password) + if err != nil { + return err + } + password = token.AccessToken + + saslClient = sasl.NewOAuthBearerClient(&sasl.OAuthBearerOptions{ + Username: uri.User.Username(), + Token: password, + }) default: return fmt.Errorf("Unsupported auth mechanism %s", auth) } diff --git a/lib/oauthbearer.go b/lib/oauthbearer.go index 5bcba60..1030696 100644 --- a/lib/oauthbearer.go +++ b/lib/oauthbearer.go @@ -13,7 +13,7 @@ type OAuthBearer struct { Enabled bool } -func (c *OAuthBearer) exchangeRefreshToken(refreshToken string) (*oauth2.Token, error) { +func (c *OAuthBearer) ExchangeRefreshToken(refreshToken string) (*oauth2.Token, error) { token := new(oauth2.Token) token.RefreshToken = refreshToken token.TokenType = "Bearer" @@ -26,7 +26,7 @@ func (c *OAuthBearer) Authenticate(username string, password string, client *cli } if c.OAuth2.Endpoint.TokenURL != "" { - token, err := c.exchangeRefreshToken(password) + token, err := c.ExchangeRefreshToken(password) if err != nil { return err }