From 049ac5d60195a65337d65bf3c6da0fe22054511c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Faikl=20=28astro=29?= Date: Wed, 26 Jul 2023 10:51:45 +0200 Subject: [PATCH 1/4] add support for oauth2 with preregistered token --- README.md | 1 + bin/mw | 58 +++++++++++++++++++++++++++++++++++++---------- mw.1 | 29 ++++++++++++++++++++++++ share/mbsync-temp | 2 +- share/msmtp-temp | 4 ++-- 5 files changed, 79 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 76e2461..f8c9b38 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ A user of Arch-based distros can also install the current mutt-wizard release fr ### Optional Dependencies +- `cyrus-sasl-xoauth2-git` - Support for OAUTH2. - `pam-gnupg` - Automatically logs you into your GPG key on login so you will never need to input your password once logged on to your system. Check the repo and directions out [here](https://github.com/cruegge/pam-gnupg). diff --git a/bin/mw b/bin/mw index cdb7856..b554401 100755 --- a/bin/mw +++ b/bin/mw @@ -88,6 +88,7 @@ prepmutt() { } getprofiles() { + # TODO: oauth2 only for mbsync right now safename="$(echo $fulladdr | sed 's/@/_/g')" case "$type" in online) @@ -173,11 +174,24 @@ askinfo() { [ -z "$passprefix" ] && passprefix="" hostname="${fulladdr#*@}" login="${login:-$fulladdr}" - if [ -n "${password+x}" ]; then - insertpass - else - getpass - fi + [ -f "$oauthtokenfile" ] || + printf "If you want to use OAUTH2 (for Microsoft or Google), input path to pre-created token file (see help). Otherwise, leave empty: " && + read -r oauthtokenfile + + if [ -f "$oauthtokenfile" ]; then + authtype_msmtp=xoauth2 + authtype_mbsync=XOAUTH2 + else + [ -n "$oauthtokenfile" ] && echo "Token file not found" + authtype_msmtp=on + authtype_mbsync=LOGIN + if [ -n "${password+x}" ]; then + insertpass + else + getpass + fi + fi + pass_cmdline="$(pass_cmdline)" } insertpass() { @@ -187,10 +201,6 @@ insertpass() { errorexit() { echo "Log-on not successful." case "$imap" in - imap.gmail.com) - echo "This account with $service is using Google's Gmail servers, which disable all third-party applications without an application-specific password. -Please be sure you are using OAUTH with your Gmail account, or better yet, stop using Gmail." - ;; imap.mail.me.com) echo "This account with $service is using Apple's iCloud servers, which disable all non-Apple applications by default. Please be sure you either enable third-party applications, or create an app-specific password, or best of all, stop using Apple." @@ -199,16 +209,35 @@ Please be sure you either enable third-party applications, or create an app-spec exit 1 } +pass_cmdline() { + if [ -f "$oauthtokenfile" ]; then + # do not use pass insert to not clutter pass git history with token updates + encrypt_pipe="$GPG -qe $(printf -- " -r %s" $(cat "$PASSWORD_STORE_DIR/.gpg-id"))" + printf '%s ' /usr/share/neomutt/oauth2/mutt_oauth2.py --encryption-pipe "$encrypt_pipe" "$passprefix$fulladdr.tokens" + else + printf '%s ' pass "$passprefix$fulladdr" + fi +} + getpass() { while :; do pass rm -f "$passprefix$fulladdr" >/dev/null 2>&1 pass insert -f "$passprefix$fulladdr" && break done; } getboxes() { - if [ -n "${force+x}" ]; then + # TODO: add oauth2 curl + # in the meantime, get box names after syncing from folder structure: + #for d in "$maildir"/* + #do + # echo "$(basename "$d"):" + # mailboxes="$(find "$d" -mindepth 1 -type d -not -name 'cur' -not -name 'new' -not -name 'tmp' -printf '="%P" ')" + # printf "\tmailboxes %s\n\n" "$mailboxes" + #done + + if [ -f "$oauthtokenfile" ] || [ -n "${force+x}" ]; then mailboxes="$(printf "INBOX\\nDrafts\\nJunk\\nTrash\\nSent\\nArchive")" else - info="$(curl --location-trusted -s -m 5 --user "$login:$(pass "$passprefix$fulladdr")" --url "${protocol:-imaps}://$imap:${iport:-993}")" + info="$(curl --location-trusted -s -m 5 --user "$login:$(pass show "$prefix$fulladdr")" --url "${protocol:-imaps}://$imap:${iport:-993}")" [ -z "$info" ] && errorexit mailboxes="$(echo "$info" | grep -v HasChildren | sed "s/.*\" //;s/\"//g" | tr -d '\r')" fi @@ -283,6 +312,7 @@ Options allowed with -a: -s SMTP server address -S SMTP server port -x Password for account (recommended to be in double quotes) + -o Registered OAUTH2 token file path. See mw(1) for more info. -p Add for a POP server instead of IMAP. -P Pass Prefix (prefix of the file where password is stored) -X Delete an account's local email too when deleting. @@ -320,7 +350,7 @@ reorder() { ' "$tempfile" >>"$muttrc" } -while getopts "rfpXlhodTYD:y:i:I:s:S:u:a:n:P:x:m:t:" o; do case "${o}" in +while getopts "rfpXlhodTYD:y:i:I:s:S:u:a:n:P:x:O:m:t:" o; do case "${o}" in l) setact list ;; r) setact reorder ;; d) setact delete ;; @@ -387,6 +417,10 @@ while getopts "rfpXlhodTYD:y:i:I:s:S:u:a:n:P:x:m:t:" o; do case "${o}" in setact add password="$OPTARG" ;; + O) + setact add + oauthtokenfile="$OPTARG" + ;; X) setact delete purge=True diff --git a/mw.1 b/mw.1 index 4a136ee..f6c1068 100644 --- a/mw.1 +++ b/mw.1 @@ -67,6 +67,35 @@ SMTP server address .TP .B -S SMTP server port (assumed to be 465 if not specified) +.TP +.B -O path +Path to registered OAUTH2 token file. The file has to be first created using external scripts, see for example +.I https://wiki.archlinux.org/title/Isync#mutt_oauth2.py +for more information. If you already have +.B neomutt +installed, the script should be located in +.I /usr/share/neomutt/oauth2/mutt_oauth2.py +and you need to first create the token by specifying your authorization credentials. If your organization does not permit any new registrations, use Mozilla Thunderbird Client ID, for example, from +.I https://hg.mozilla.org/comm-central/file/tip/mailnews/base/src/OAuth2Providers.jsm +and pick your provider (Google or Microsoft). +Then you can use the script as +.IP +.EX +\&$ /usr/share/neomutt/oauth2/mutt_oauth2.py -v -t \\ +\& --authorize --client-id "9e5f94bc-e8a4-4e73-b8be-63364c29d753" --client-secret "" \\ +\& --email "" --provider microsoft \\ +\& --encryption-pipe "gpg --encrypt --recipient " \\ +\& token_path +.EE +. +.XP + +The token file is then decrypted by +.B mw +and saved to password store as +.I .tokens +encrypted using gpg. The file will not be tracked by git history by default. + .TP .B -x Account password. You will be prompted for the password interactively if this option is not given. diff --git a/share/mbsync-temp b/share/mbsync-temp index 4e77b09..1817ffb 100644 --- a/share/mbsync-temp +++ b/share/mbsync-temp @@ -3,7 +3,7 @@ Host $imap Port $iport User $login PassCmd "pass $passprefix$fulladdr" -AuthMechs LOGIN +AuthMechs $authtype_mbsync SSLType $imapssl CertificateFile $sslcert diff --git a/share/msmtp-temp b/share/msmtp-temp index 7333437..e61d587 100644 --- a/share/msmtp-temp +++ b/share/msmtp-temp @@ -3,8 +3,8 @@ host $smtp port $sport from $fulladdr user $login -passwordeval "pass $passprefix$fulladdr" -auth on +passwordeval "$pass_cmdline" +auth $authtype_msmtp tls on tls_trust_file $sslcert logfile $msmtplog From 451d9451b6c1631ba2b83dc70733fc82eec37a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Faikl=20=28astro=29?= Date: Wed, 26 Jul 2023 14:43:26 +0200 Subject: [PATCH 2/4] move oauth token file to pass store --- bin/mw | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/mw b/bin/mw index b554401..191b20e 100755 --- a/bin/mw +++ b/bin/mw @@ -181,6 +181,12 @@ askinfo() { if [ -f "$oauthtokenfile" ]; then authtype_msmtp=xoauth2 authtype_mbsync=XOAUTH2 + printf "Token will be moved to '%s', do you want to remove the original token file [y/N]? " "$PASSWORD_STORE_DIR/$prefix$fulladdr.tokens" + read -r prompt + case "$prompt" in + y|Y) mv "$oauthtokenfile" "$PASSWORD_STORE_DIR/$prefix$fulladdr.tokens" ;; + *) cp "$oauthtokenfile" "$PASSWORD_STORE_DIR/$prefix$fulladdr.tokens" ;; + esac else [ -n "$oauthtokenfile" ] && echo "Token file not found" authtype_msmtp=on From f259c52c17ae9ed72601a53b42b258e29bdd3e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Faikl=20=28astro=29?= Date: Sun, 30 Jul 2023 17:39:16 +0200 Subject: [PATCH 3/4] fix typo $prefix -> $passprefix --- bin/mw | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/mw b/bin/mw index 191b20e..b2eff48 100755 --- a/bin/mw +++ b/bin/mw @@ -181,11 +181,11 @@ askinfo() { if [ -f "$oauthtokenfile" ]; then authtype_msmtp=xoauth2 authtype_mbsync=XOAUTH2 - printf "Token will be moved to '%s', do you want to remove the original token file [y/N]? " "$PASSWORD_STORE_DIR/$prefix$fulladdr.tokens" + printf "Token will be moved to '%s', do you want to remove the original token file [y/N]? " "$PASSWORD_STORE_DIR/$passprefix$fulladdr.tokens" read -r prompt case "$prompt" in - y|Y) mv "$oauthtokenfile" "$PASSWORD_STORE_DIR/$prefix$fulladdr.tokens" ;; - *) cp "$oauthtokenfile" "$PASSWORD_STORE_DIR/$prefix$fulladdr.tokens" ;; + y|Y) mv "$oauthtokenfile" "$PASSWORD_STORE_DIR/$passprefix$fulladdr.tokens" ;; + *) cp "$oauthtokenfile" "$PASSWORD_STORE_DIR/$passprefix$fulladdr.tokens" ;; esac else [ -n "$oauthtokenfile" ] && echo "Token file not found" @@ -243,7 +243,7 @@ getboxes() { if [ -f "$oauthtokenfile" ] || [ -n "${force+x}" ]; then mailboxes="$(printf "INBOX\\nDrafts\\nJunk\\nTrash\\nSent\\nArchive")" else - info="$(curl --location-trusted -s -m 5 --user "$login:$(pass show "$prefix$fulladdr")" --url "${protocol:-imaps}://$imap:${iport:-993}")" + info="$(curl --location-trusted -s -m 5 --user "$login:$(pass show "$passprefix$fulladdr")" --url "${protocol:-imaps}://$imap:${iport:-993}")" [ -z "$info" ] && errorexit mailboxes="$(echo "$info" | grep -v HasChildren | sed "s/.*\" //;s/\"//g" | tr -d '\r')" fi From b809548d56c6369b2c2af9a293559383047c94e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Faikl=20=28astro=29?= Date: Mon, 9 Oct 2023 08:43:25 +0200 Subject: [PATCH 4/4] add oauth support for mbsync - my mistake, I have forgotten to update password request line for mbsync --- share/mbsync-temp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/mbsync-temp b/share/mbsync-temp index 1817ffb..1e38fa0 100644 --- a/share/mbsync-temp +++ b/share/mbsync-temp @@ -2,7 +2,7 @@ IMAPStore $fulladdr-remote Host $imap Port $iport User $login -PassCmd "pass $passprefix$fulladdr" +PassCmd "$pass_cmdline" AuthMechs $authtype_mbsync SSLType $imapssl CertificateFile $sslcert