about summary refs log tree commit diff stats
path: root/worker
diff options
context:
space:
mode:
authorFrode Aannevik <frode.aa@gmail.com>2019-07-10 21:00:28 +0200
committerDrew DeVault <sir@cmpwn.com>2019-07-11 19:36:14 -0400
commitb0eaf5191c9bc5b128e347625b7eef998ba63c41 (patch)
treeca9fe0155e4a01bb84d3aca248b37bf844145f8b /worker
parent217e85a55d0c1047bef1e2bc41783ccd4629bfc1 (diff)
downloadaerc-b0eaf5191c9bc5b128e347625b7eef998ba63c41.tar.gz
Support imaps with oauthbearer authentication (Gmail)
    imaps+oauthbearer://user:token@host?token_endpoint=...

 - the config Source password is used as access token if
   no token_endpoint parameter is set
 - the config Source password is used as refresh token if
   token_endpoint parameter is set, and used to exchange
   with an access token

The implementation has only been tested with Gmail.

    source = imaps+oauthbearer://{username}:{refersh_token}@imap.gmail.com:993? \
    client_id=XX&\
    client_secret=XX&\
    token_endpoint=https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Ftoken

client credentials created with

    https://console.developers.google.com/apis/credentials

refresh token created with

    https://github.com/google/gmail-oauth2-tools/blob/master/python/oauth2.py

rel: https://todo.sr.ht/~sircmpwn/aerc2/42
Diffstat (limited to 'worker')
-rw-r--r--worker/imap/worker.go34
1 files changed, 28 insertions, 6 deletions
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index 88f8b37..de86994 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -9,7 +9,9 @@ import (
 	"github.com/emersion/go-imap"
 	idle "github.com/emersion/go-imap-idle"
 	"github.com/emersion/go-imap/client"
+	"golang.org/x/oauth2"
 
+	"git.sr.ht/~sircmpwn/aerc/lib"
 	"git.sr.ht/~sircmpwn/aerc/models"
 	"git.sr.ht/~sircmpwn/aerc/worker/types"
 )
@@ -23,11 +25,12 @@ type imapClient struct {
 
 type IMAPWorker struct {
 	config struct {
-		scheme   string
-		insecure bool
-		addr     string
-		user     *url.Userinfo
-		folders  []string
+		scheme      string
+		insecure    bool
+		addr        string
+		user        *url.Userinfo
+		folders     []string
+		oauthBearer lib.OAuthBearer
 	}
 
 	client   *imapClient
@@ -71,6 +74,20 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
 			w.config.insecure = true
 		}
 
+		if strings.HasSuffix(w.config.scheme, "+oauthbearer") {
+			w.config.scheme = strings.TrimSuffix(w.config.scheme, "+oauthbearer")
+			w.config.oauthBearer.Enabled = true
+			q := u.Query()
+			if q.Get("token_endpoint") != "" {
+				w.config.oauthBearer.OAuth2 = &oauth2.Config{
+					ClientID:     q.Get("client_id"),
+					ClientSecret: q.Get("client_secret"),
+					Scopes:       []string{q.Get("scope")},
+				}
+				w.config.oauthBearer.OAuth2.Endpoint.TokenURL = q.Get("token_endpoint")
+			}
+		}
+
 		w.config.addr = u.Host
 		if !strings.ContainsRune(w.config.addr, ':') {
 			w.config.addr += ":" + w.config.scheme
@@ -110,7 +127,12 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
 			if !hasPassword {
 				// TODO: ask password
 			}
-			if err := c.Login(username, password); err != nil {
+
+			if w.config.oauthBearer.Enabled {
+				if err := w.config.oauthBearer.Authenticate(username, password, c); err != nil {
+					return err
+				}
+			} else if err := c.Login(username, password); err != nil {
 				return err
 			}
 		}