jaromail

a commandline tool to easily and privately handle your e-mail
git clone git://parazyd.org/jaromail.git
Log | Files | Refs | Submodules | README

commit 63ed8f2480c7e42f04a1a9edd4d6a2287074c9ad
parent b89665a20ce042d69e3834750e5b654eef7cbc90
Author: Jaromil <jaromil@dyne.org>
Date:   Sun, 22 Mar 2015 23:38:01 +0100

remember fingerprint of known smtp servers

Diffstat:
Msrc/jaro | 8++++++--
Msrc/zlibs/email | 40++++++++++++++++++++++++++++++++++++++++
Msrc/zlibs/helpers | 4++--
Msrc/zlibs/zuper | 43++++++++++++++++++++++---------------------
4 files changed, 70 insertions(+), 25 deletions(-)

diff --git a/src/jaro b/src/jaro @@ -63,6 +63,7 @@ fi WORKDIR=${JAROWORKDIR:-$WORKDIR} # load our zuper extension +zkv=1 source $WORKDIR/zlibs/zuper @@ -130,6 +131,9 @@ vars+=(name login imap imap_port smtp smtp_port protocol password auth accountop typeset -ah folders exclude vars+=(host port type) +# global for server fingerprints +vars+=(fingerprint) + # global variables for addressbook vars+=(hostname addressbook addressbook_tmp) @@ -826,5 +830,5 @@ main() { check_bin main $@ -endgame NOERRORS -#return $exitcode +# endgame NOERRORS +# return $exitcode diff --git a/src/zlibs/email b/src/zlibs/email @@ -263,6 +263,10 @@ fetch() { ################################################ # read an email from stdin and send it via msmtp smtp_send() { + fn smtp-send + req=(account) + ckreq + read_account ${account} { test $? != 0 } && { error "Invalid account: $account" @@ -279,6 +283,42 @@ smtp_send() { host=$smtp port=$smtp_port + # load known fingerprints + typeset -A smtp_fingerprints + [[ -s $MAILDIRS/smtp_fingerprints.zkv ]] && { + zkv.load $MAILDIRS/smtp_fingerprints.zkv } + known_fingerprint=${smtp_fingerprints[$smtp:$port]} + # get the server's fingerprint + print QUIT \ + | openssl s_client -starttls smtp \ + -connect $smtp:$smtp_port \ + -showcerts 2>/dev/null \ + | openssl x509 -fingerprint -md5 -noout \ + | awk -F '=' '/Fingerprint/ {print $2}' | sysread fingerprint + fingerprint=$(print $fingerprint | trim) + # force printing fingerprint to stderr + oldquiet=$QUIET + QUIET=0 + act "known fingerprint: $known_fingerprint" + act "server fingerprint: $fingerprint" + [[ "$known_fingerprint" = "$fingerprint" ]] || { + warning "fingerprint difference detected" + # not the same? + if [[ "$known_fingerprint" = "" ]]; then + # never knew before, save it + act "$smtp:$port new fingerprint acknowledged" + smtp_fingerprints[$smtp:$port]="$fingerprint" + else + error "Server fingerprint mismatch!" + warning "The known one was different, this may be a man in the middle!" + warning "To override and forget the old one, edit $MAILDIRS/smtp_fingerprints.zkv" + return 1 + fi + } + QUIET=$oldquiet + + zkv.save smtp_fingerprints $MAILDIRS/smtp_fingerprints.zkv + ask_password [[ $? = 0 ]] || { error "Error retrieving password for $login on $smtp" diff --git a/src/zlibs/helpers b/src/zlibs/helpers @@ -353,7 +353,7 @@ human_size() { # TODO: save fingeprints of servers and check connections -fingerprint() { +get-smtp-fingerprint() { # dyne.org one: # tls_fingerprint 6A:D4:DF:E4:20:32:F9:66:94:35:0C:33:9D:74:96:5C @@ -370,7 +370,7 @@ fingerprint() { -connect $smtp:$smtp_port \ -showcerts 2>/dev/null \ | openssl x509 -fingerprint -md5 -noout \ - | awk -F '=' '/^MD5 Fingerprint/ {print $2}' + | awk -F '=' '/Fingerprint/ {print $2}' | sysread fingerprint } diff --git a/src/zlibs/zuper b/src/zlibs/zuper @@ -24,11 +24,15 @@ ########################## typeset -aU vars typeset -aU arrs -vars=(debug quiet ztmpfile) -arrs=() +vars=(DEBUG QUIET ztmpfile) +arrs=(req freq) -debug=${debug:-0} -quiet=${quiet:-0} +# reset list of destructors +destruens=() + +# global execution flags +DEBUG=${DEBUG:-0} +QUIET=${QUIET:-0} vars+=(zuper_version) zuper_version=0.1 @@ -93,48 +97,39 @@ function _msg() { function _message say act() { local notice="message" [[ "$1" = "-n" ]] && shift && notice="inline" - [[ $quiet = 1 ]] || _msg "$notice" $@ + [[ $QUIET = 1 ]] || _msg "$notice" $@ return 0 } function _verbose xxx func() { - [[ $debug = 1 ]] && _msg verbose $@ + [[ $DEBUG = 1 ]] && _msg verbose $@ return 0 } function _success yes notice() { - [[ $quiet = 1 ]] || _msg success $@ + [[ $QUIET = 1 ]] || _msg success $@ return 0 } function _warning no warn warning() { - [[ $quiet = 1 ]] || _msg warning $@ + [[ $QUIET = 1 ]] || _msg warning $@ return 0 } function _failure fatal die error() { # typeset -i exitcode=${exitv:-1} - [[ $quiet = 1 ]] || _msg failure $@ + [[ $QUIET = 1 ]] || _msg failure $@ return 1 } function _print() { - [[ $quiet = 1 ]] || _msg print $@ + [[ $QUIET = 1 ]] || _msg print $@ return 0 } - fn() { - local msg="$1" - command -v gettext 1>/dev/null 2>/dev/null \ - && msg="$(gettext -s "$1")" - for i in $(seq 2 ${#}); do - msg=${(S)msg//::$(($i - 1))*::/$*[$i]} - done - - fun="$msg" - func "$fun" + fun="$@" req=() freq=() } @@ -181,7 +176,10 @@ zdump() { done } - +# handy wrappers for throw/catch execution of blocks where we need the +# program to exit on any error (non-zero) returned by any function +throw() { function TRAPZERR() { zerr; return 1 } } +catch() { function TRAPZERR() { } } ########################## # Endgame handling @@ -215,6 +213,9 @@ endgame() { return 0 } +# Register endgame() to be called at exit. +# unlike TRAPEXIT, the zshexit() hook is not called when functions exit. +zshexit() { endgame EXIT; return $? } ########################## # Temp file handling