diff options
author | Joey Hess <joeyh@joeyh.name> | 2015-05-13 22:27:03 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2015-05-13 22:27:03 -0400 |
commit | 95e1e51caafbb3e4b179936b6d191ca87f47d4ae (patch) | |
tree | 00b33106e2a4030c1f5a237592b9a2f55a7020b0 /IkiWiki/Plugin/emailauth.pm | |
parent | f1d77f81933b4e4c38780a1934ac6daaaf0a9b80 (diff) | |
download | ikiwiki-95e1e51caafbb3e4b179936b6d191ca87f47d4ae.tar ikiwiki-95e1e51caafbb3e4b179936b6d191ca87f47d4ae.tar.gz |
emailauth link sent and verified; user login works
Still some work to do since the user name is an email address and should
not be leaked.
Diffstat (limited to 'IkiWiki/Plugin/emailauth.pm')
-rw-r--r-- | IkiWiki/Plugin/emailauth.pm | 113 |
1 files changed, 108 insertions, 5 deletions
diff --git a/IkiWiki/Plugin/emailauth.pm b/IkiWiki/Plugin/emailauth.pm index 3946ace03..3266e21ab 100644 --- a/IkiWiki/Plugin/emailauth.pm +++ b/IkiWiki/Plugin/emailauth.pm @@ -8,6 +8,7 @@ use IkiWiki 3.00; sub import { hook(type => "getsetup", id => "emailauth", "call" => \&getsetup); + hook(type => "cgi", id => "cgi", "call" => \&cgi); IkiWiki::loadplugin("loginselector"); IkiWiki::Plugin::loginselector::register_login_plugin( "emailauth", @@ -41,17 +42,119 @@ sub email_check_input ($) { && length $cgi->param('Email_entry'); } -sub email_auth ($$$) { +# Send login link to email. +sub email_auth ($$$$) { my $cgi=shift; my $session=shift; my $errordisplayer=shift; - - unless ($cgi->param('Email_entry') =~ /.\@./) { - $errordisplayer->("Invalid email address."); + my $infodisplayer=shift; + + my $email=$cgi->param('Email_entry'); + unless ($email =~ /.\@./) { + $errordisplayer->(gettext("Invalid email address.")); return; } - error "EMAIL AUTH"; + # Implicit account creation. + my $userinfo=IkiWiki::userinfo_retrieve(); + if (! exists $userinfo->{$email} || ! ref $userinfo->{$email}) { + IkiWiki::userinfo_setall($email, { + 'email' => $email, + 'regdate' => time, + }); + } + + my $token=gentoken($email); + my $template=template("emailauth.tmpl"); + $template->param( + wikiname => $config{wikiname}, + # Intentionally using short field names to keep link short. + authurl => IkiWiki::cgiurl_abs( + 'e' => $email, + 'v' => $token, + ), + ); + + eval q{use Mail::Sendmail}; + error($@) if $@; + sendmail( + To => $email, + From => "$config{wikiname} admin <". + (defined $config{adminemail} ? $config{adminemail} : "") + .">", + Subject => "$config{wikiname} login", + Message => $template->output, + ) or error(gettext("Failed to send mail")); + + $infodisplayer->(gettext("You have been sent an email, with a link you can open to complete the login process.")); +} + +# Finish login process. +sub cgi ($$) { + my $cgi=shift; + + my $email=$cgi->param('e'); + my $v=$cgi->param('v'); + if (defined $email && defined $v && length $email && length $v) { + # Need to lock the wiki before getting a session. + IkiWiki::lockwiki(); + IkiWiki::loadindex(); + my $session=IkiWiki::cgi_getsession(); + + my $token=gettoken($email); + if ($token eq $v) { + print STDERR "SUCCESS $email!!\n"; + cleartoken($email); + $session->param(name => $email); + my $nickname=$email; + $nickname=~s/@.*//; + $session->param(nickname => Encode::decode_utf8($nickname)); + IkiWiki::cgi_postsignin($cgi, $session); + } + elsif (length $token ne length $cgi->param('v')) { + error(gettext("Wrong login token length. Please check that you pasted in the complete login link from the email!")); + } + else { + loginfailure(); + } + } +} + +# Generates the token that will be used in the authurl to log the user in. +# This needs to be hard to guess, and relatively short. Generating a cgi +# session id will make it as hard to guess as any cgi session. +sub gentoken ($) { + my $email=shift; + eval q{use CGI::Session}; + error($@) if $@; + my $token = CGI::Session->new->id; + # Store token in userinfo; this allows the user to log in + # using a different browser session, if it takes a while for the + # email to get to them. + IkiWiki::userinfo_set($email, "emailauthexpire", time+(60*60*24)); + IkiWiki::userinfo_set($email, "emailauth", $token); + return $token; +} + +# Gets the token, checking for expiry. +sub gettoken ($) { + my $email=shift; + my $val=IkiWiki::userinfo_get($email, "emailauth"); + my $expire=IkiWiki::userinfo_get($email, "emailauthexpire"); + if (! length $val || time > $expire) { + loginfailure(); + } + return $val; +} + +sub cleartoken ($) { + my $email=shift; + IkiWiki::userinfo_set($email, "emailauthexpire", 0); + IkiWiki::userinfo_set($email, "emailauth", ""); +} + +sub loginfailure () { + error "Bad email authentication token. Please retry login."; } 1 |