Merge branch 'emailauth'

master
Joey Hess 2015-05-13 23:38:56 -04:00
commit cfb2c22906
26 changed files with 781 additions and 383 deletions

View File

@ -165,7 +165,7 @@ sub getsetup () {
default_plugins => { default_plugins => {
type => "internal", type => "internal",
default => [qw{mdwn link inline meta htmlscrubber passwordauth default => [qw{mdwn link inline meta htmlscrubber passwordauth
openid signinedit lockedit conditional openid emailauth signinedit lockedit conditional
recentchanges parentlinks editpage recentchanges parentlinks editpage
templatebody}], templatebody}],
description => "plugins to enable by default", description => "plugins to enable by default",
@ -1464,6 +1464,14 @@ sub openiduser ($) {
return; return;
} }
sub emailuser ($) {
my $user=shift;
if (defined $user && $user =~ m/(.+)@/) {
return $1;
}
return;
}
sub htmlize ($$$$) { sub htmlize ($$$$) {
my $page=shift; my $page=shift;
my $destpage=shift; my $destpage=shift;

View File

@ -198,7 +198,6 @@ sub preprocess {
$commentuser = $params{username}; $commentuser = $params{username};
my $oiduser = eval { IkiWiki::openiduser($commentuser) }; my $oiduser = eval { IkiWiki::openiduser($commentuser) };
if (defined $oiduser) { if (defined $oiduser) {
# looks like an OpenID # looks like an OpenID
$commentauthorurl = $commentuser; $commentauthorurl = $commentuser;
@ -206,6 +205,11 @@ sub preprocess {
$commentopenid = $commentuser; $commentopenid = $commentuser;
} }
else { else {
my $emailuser = IkiWiki::emailuser($commentuser);
if (defined $emailuser) {
$commentuser=$emailuser;
}
if (length $config{cgiurl}) { if (length $config{cgiurl}) {
$commentauthorurl = IkiWiki::cgiurl( $commentauthorurl = IkiWiki::cgiurl(
do => 'goto', do => 'goto',

View File

@ -0,0 +1,193 @@
#!/usr/bin/perl
# Ikiwiki email address as login
package IkiWiki::Plugin::emailauth;
use warnings;
use strict;
use IkiWiki 3.00;
sub import {
hook(type => "getsetup", id => "emailauth", "call" => \&getsetup);
hook(type => "cgi", id => "emailauth", "call" => \&cgi);
hook(type => "formbuilder_setup", id => "emailauth", "call" => \&formbuilder_setup);
IkiWiki::loadplugin("loginselector");
IkiWiki::Plugin::loginselector::register_login_plugin(
"emailauth",
\&email_setup,
\&email_check_input,
\&email_auth,
);
}
sub getsetup () {
return
plugin => {
safe => 1,
rebuild => 0,
section => "auth",
},
}
sub email_setup ($$) {
my $q=shift;
my $template=shift;
return 1;
}
sub email_check_input ($) {
my $cgi=shift;
defined $cgi->param('do')
&& $cgi->param("do") eq "signin"
&& defined $cgi->param('Email_entry')
&& length $cgi->param('Email_entry');
}
# Send login link to email.
sub email_auth ($$$$) {
my $cgi=shift;
my $session=shift;
my $errordisplayer=shift;
my $infodisplayer=shift;
my $email=$cgi->param('Email_entry');
unless ($email =~ /.\@./) {
$errordisplayer->(gettext("Invalid email address."));
return;
}
# 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, $session);
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) {
my $token=gettoken($email);
if ($token eq $v) {
cleartoken($email);
my $session=getsession($email);
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();
}
}
}
sub formbuilder_setup (@) {
my %params=@_;
my $form=$params{form};
my $session=$params{session};
if ($form->title eq "preferences" &&
IkiWiki::emailuser($session->param("name"))) {
$form->field(name => "email", disabled => 1);
}
}
# 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.
#
# 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.
#
# The postsignin value from the session is also stored in the userinfo
# to allow resuming in a different browser session.
sub gentoken ($$) {
my $email=shift;
my $session=shift;
eval q{use CGI::Session};
error($@) if $@;
my $token = CGI::Session->new->id;
IkiWiki::userinfo_set($email, "emailauthexpire", time+(60*60*24));
IkiWiki::userinfo_set($email, "emailauth", $token);
IkiWiki::userinfo_set($email, "emailauthpostsignin", defined $session->param("postsignin") ? $session->param("postsignin") : "");
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;
}
# Generate a session to use after successful login.
sub getsession ($) {
my $email=shift;
IkiWiki::lockwiki();
IkiWiki::loadindex();
my $session=IkiWiki::cgi_getsession();
my $postsignin=IkiWiki::userinfo_get($email, "emailauthpostsignin");
IkiWiki::userinfo_set($email, "emailauthpostsignin", "");
if (defined $postsignin && length $postsignin) {
$session->param(postsignin => $postsignin);
}
$session->param(name => $email);
my $nickname=$email;
$nickname=~s/@.*//;
$session->param(nickname => Encode::decode_utf8($nickname));
IkiWiki::cgi_savesession($session);
return $session;
}
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

View File

@ -0,0 +1,132 @@
#!/usr/bin/perl
package IkiWiki::Plugin::loginselector;
use warnings;
use strict;
use IkiWiki 3.00;
# Plugins that provide login methods can register themselves here.
# Note that the template and js file also have be be modifed to add a new
# login method.
our %login_plugins;
sub register_login_plugin ($$$$) {
# Same as the name of the plugin that is registering itself as a
# login plugin. eg, "openid"
my $plugin_name=shift;
# This sub is passed a cgi object and a template object which it
# can manipulate. It should return true if the plugin can be used
# (it might load necessary modules for auth checking, for example).
my $plugin_setup=shift;
# This sub is passed a cgi object, and should return true
# if it looks like the user is logging in using the plugin.
my $plugin_check_input=shift;
# This sub is passed a cgi object, a session object, an error
# display callback, and an info display callback, and should
# handle the actual authentication. It can either exit w/o
# returning, if it is able to handle auth, or it can pass an
# error message to the error display callback to make the
# openid selector form be re-disiplayed with an error message
# on it.
my $plugin_auth=shift;
$login_plugins{$plugin_name}={
setup => $plugin_setup,
check_input => $plugin_check_input,
auth => $plugin_auth,
};
}
sub login_selector {
my $real_cgi_signin=shift;
my $otherform_label=shift;
my $q=shift;
my $session=shift;
my $template=IkiWiki::template("login-selector.tmpl");
foreach my $plugin (keys %login_plugins) {
if (! $login_plugins{$plugin}->{setup}->($template)) {
delete $login_plugins{$plugin};
}
else {
$template->param("login_selector_$plugin", 1);
}
}
foreach my $plugin (keys %login_plugins) {
if ($login_plugins{$plugin}->{check_input}->($q)) {
$login_plugins{$plugin}->{auth}->($q, $session, sub {
$template->param(login_error => shift());
}, sub {
$template->param(login_info => shift());
});
last;
}
}
$template->param(
cgiurl => IkiWiki::cgiurl(),
($real_cgi_signin ? (otherform => $real_cgi_signin->($q, $session, 1)) : ()),
otherform_label => $otherform_label,
);
IkiWiki::printheader($session);
print IkiWiki::cgitemplate($q, "signin", $template->output);
exit;
}
sub import {
add_underlay("login-selector");
add_underlay("jquery");
hook(type => "getsetup", id => "loginselector", call => \&getsetup);
hook(type => "checkconfig", id => "loginselector", call => \&checkconfig);
hook(type => "auth", id => "loginselector", call => \&authstub);
}
sub checkconfig () {
if ($config{cgi}) {
# Intercept normal signin form, so the login selector
# can be displayed.
#
# When other auth hooks are registered, give the selector
# a reference to the normal signin form.
require IkiWiki::CGI;
my $real_cgi_signin;
my $otherform_label=gettext("Other");
if (keys %{$IkiWiki::hooks{auth}} > 1) {
$real_cgi_signin=\&IkiWiki::cgi_signin;
# Special case to avoid labeling password auth as
# "Other" when it's the only auth plugin not
# integrated with the loginselector.
my %h=%{$IkiWiki::hooks{auth}};
foreach my $p (keys %login_plugins) {
delete $h{$p};
}
delete $h{loginselector};
if (keys %h == 1 && exists $h{passwordauth}) {
$otherform_label=gettext("Password");
}
}
inject(name => "IkiWiki::cgi_signin", call => sub ($$) {
login_selector($real_cgi_signin, $otherform_label, @_);
});
}
}
sub getsetup () {
return
plugin => {
# this plugin is safe but only makes sense as a
# dependency
safe => 0,
rebuild => 0,
},
}
sub authstub ($$) {
# While this hook is not currently used, it needs to exist
# so ikiwiki knows that the wiki supports logins, and will
# enable the Preferences page.
}
1

View File

@ -7,35 +7,17 @@ use strict;
use IkiWiki 3.00; use IkiWiki 3.00;
sub import { sub import {
add_underlay("openid-selector");
add_underlay("jquery");
hook(type => "checkconfig", id => "openid", call => \&checkconfig);
hook(type => "getsetup", id => "openid", call => \&getsetup); hook(type => "getsetup", id => "openid", call => \&getsetup);
hook(type => "auth", id => "openid", call => \&auth); hook(type => "auth", id => "openid", call => \&auth);
hook(type => "formbuilder_setup", id => "openid", hook(type => "formbuilder_setup", id => "openid",
call => \&formbuilder_setup, last => 1); call => \&formbuilder_setup, last => 1);
} IkiWiki::loadplugin("loginselector");
IkiWiki::Plugin::loginselector::register_login_plugin(
sub checkconfig () { "openid",
if ($config{cgi}) { \&openid_setup,
# Intercept normal signin form, so the openid selector \&openid_check_input,
# can be displayed. \&openid_auth,
# );
# When other auth hooks are registered, give the selector
# a reference to the normal signin form.
require IkiWiki::CGI;
my $real_cgi_signin;
my $nonopenidform_label=gettext("Other");
if (keys %{$IkiWiki::hooks{auth}} > 1) {
$real_cgi_signin=\&IkiWiki::cgi_signin;
if (keys %{$IkiWiki::hooks{auth}} == 2 && exists $IkiWiki::hooks{auth}->{passwordauth}) {
$nonopenidform_label=gettext("Password");
}
}
inject(name => "IkiWiki::cgi_signin", call => sub ($$) {
openid_selector($real_cgi_signin, $nonopenidform_label, @_);
});
}
} }
sub getsetup () { sub getsetup () {
@ -59,40 +41,34 @@ sub getsetup () {
}, },
} }
sub openid_selector { sub openid_setup ($$) {
my $real_cgi_signin=shift; my $q=shift;
my $nonopenidform_label=shift; my $template=shift;
if (load_openid_module()) {
my $openid_url=$q->param('openid_identifier');
if (defined $openid_url) {
$template->param(openid_url => $openid_url);
}
return 1;
}
else {
return 0;
}
}
sub openid_check_input ($) {
my $q=shift;
my $openid_url=$q->param('openid_identifier');
defined $q->param("action") && $q->param("action") eq "verify" && defined $openid_url && length $openid_url;
}
sub openid_auth ($$$$) {
my $q=shift; my $q=shift;
my $session=shift; my $session=shift;
my $errordisplayer=shift;
my $openid_url=$q->param('openid_identifier'); my $openid_url=$q->param('openid_identifier');
my $openid_error; validate($q, $session, $openid_url, $errordisplayer);
if (! load_openid_module()) {
if ($real_cgi_signin) {
$real_cgi_signin->($q, $session);
exit;
}
error(sprintf(gettext("failed to load openid module: "), @_));
}
elsif (defined $q->param("action") && $q->param("action") eq "verify") {
validate($q, $session, $openid_url, sub {
$openid_error=shift;
});
}
my $template=IkiWiki::template("openid-selector.tmpl");
$template->param(
cgiurl => IkiWiki::cgiurl(),
(defined $openid_error ? (openid_error => $openid_error) : ()),
(defined $openid_url ? (openid_url => $openid_url) : ()),
($real_cgi_signin ? (nonopenidform => $real_cgi_signin->($q, $session, 1)) : ()),
nonopenidform_label => $nonopenidform_label,
);
IkiWiki::printheader($session);
print IkiWiki::cgitemplate($q, "signin", $template->output);
exit;
} }
sub formbuilder_setup (@) { sub formbuilder_setup (@) {

View File

@ -277,7 +277,7 @@ sub formbuilder_setup (@) {
} }
elsif ($form->title eq "preferences") { elsif ($form->title eq "preferences") {
my $user=$session->param("name"); my $user=$session->param("name");
if (! IkiWiki::openiduser($user)) { if (! IkiWiki::openiduser($user) && ! IkiWiki::emailuser($user)) {
$form->field(name => "name", disabled => 1, $form->field(name => "name", disabled => 1,
value => $user, force => 1, value => $user, force => 1,
fieldset => "login"); fieldset => "login");

View File

@ -154,6 +154,7 @@ sub import (@) {
foreach my $admin (@{$config{adminuser}}) { foreach my $admin (@{$config{adminuser}}) {
next if defined IkiWiki::openiduser($admin); next if defined IkiWiki::openiduser($admin);
if (! defined IkiWiki::emailuser($admin)) {
# Prompt for password w/o echo. # Prompt for password w/o echo.
my ($password, $password2); my ($password, $password2);
system('stty -echo 2>/dev/null'); system('stty -echo 2>/dev/null');
@ -181,6 +182,7 @@ sub import (@) {
error("problem setting up $admin user"); error("problem setting up $admin user");
} }
} }
}
# Add wrappers, make live. # Add wrappers, make live.
if (system("ikiwiki", "--wrappers", "--setup", $config{dumpsetup}) != 0) { if (system("ikiwiki", "--wrappers", "--setup", $config{dumpsetup}) != 0) {

View File

@ -18,7 +18,7 @@ our $wikiname_short=IkiWiki::Setup::Automator::sanitize_wikiname($wikiname);
our $rcs=IkiWiki::Setup::Automator::ask( our $rcs=IkiWiki::Setup::Automator::ask(
gettext("What revision control system to use?"), "git"); gettext("What revision control system to use?"), "git");
our $admin=IkiWiki::Setup::Automator::ask( our $admin=IkiWiki::Setup::Automator::ask(
gettext("Which user (wiki account or openid) will be admin?"), $ENV{USER}); gettext("Which user (wiki account, openid, or email) will be admin?"), $ENV{USER});
use Net::Domain q{hostfqdn}; use Net::Domain q{hostfqdn};
our $domain=hostfqdn() || IkiWiki::Setup::Automator::ask( our $domain=hostfqdn() || IkiWiki::Setup::Automator::ask(
gettext("What is the domain name of the web server?"), ""); gettext("What is the domain name of the web server?"), "");

10
debian/changelog vendored
View File

@ -1,10 +1,14 @@
ikiwiki (3.20150330) UNRELEASED; urgency=medium ikiwiki (3.20150330) UNRELEASED; urgency=medium
* New emailauth plugin lets users log in, without any registration,
by simply clicking on a link in an email.
* Re-remove google from openid selector; their openid provider is * Re-remove google from openid selector; their openid provider is
gone for good. gone for good.
* When openid and passwordauth are the only enabled auth plugins, * Make the openid selector display "Password" instead of "Other"
make the openid selector display "Password" instead of "Other", when appropriate, so users are more likely to click on it when
so users are more likely to click on it when they don't have an openid. they don't have an openid.
* Converted openid-selector into a more generic loginselector helper
plugin.
-- Joey Hess <id@joeyh.name> Tue, 28 Apr 2015 12:24:08 -0400 -- Joey Hess <id@joeyh.name> Tue, 28 Apr 2015 12:24:08 -0400

11
debian/copyright vendored
View File

@ -201,20 +201,20 @@ Comment:
Republished with permission. Republished with permission.
License: GPL-2+ License: GPL-2+
Files: underlays/openid-selector/ikiwiki/openid/* Files: underlays/openid-selector/ikiwiki/login-selector/*
Copyright: © 2008-2010 andyjm, david.j.boden Copyright: © 2008-2010 andyjm, david.j.boden
Comment: Comment:
From http://code.google.com/p/openid-selector/ From http://code.google.com/p/openid-selector/
License: BSD-2-clause License: BSD-2-clause
Files: underlays/openid-selector/ikiwiki/openid/goa-* Files: underlays/openid-selector/ikiwiki/login-selector/goa-*
Copyright: Copyright:
© 2011 Red Hat, Inc. © 2011 Red Hat, Inc.
License: LGPL-2.1+ License: LGPL-2.1+
Comment: Comment:
taken from data/icons/16x16/ in gnome-online-accounts git taken from data/icons/16x16/ in gnome-online-accounts git
Files: underlays/openid-selector/ikiwiki/openid/wordpress.png Files: underlays/openid-selector/ikiwiki/login-selector/wordpress.png
Copyright: Copyright:
© 2003-2013 "the contributors" © 2003-2013 "the contributors"
License: GPL-2+ License: GPL-2+
@ -226,9 +226,8 @@ Files:
icons/aol.svg icons/aol.svg
icons/livejournal.svg icons/livejournal.svg
icons/verisign.svg icons/verisign.svg
underlays/openid-selector/ikiwiki/openid/aol.png underlays/openid-selector/ikiwiki/login-selector/aol.png
underlays/openid-selector/ikiwiki/openid/livejournal.png underlays/openid-selector/ikiwiki/login-selector/verisign.png
underlays/openid-selector/ikiwiki/openid/verisign.png
Copyright: Copyright:
© 2014 Simon McVittie © 2014 Simon McVittie
License: other License: other

View File

@ -10,7 +10,7 @@ It currently includes these pages:
* [[templates]] * [[templates]]
* [[ikiwiki/formatting]] * [[ikiwiki/formatting]]
* [[ikiwiki/markdown]] * [[ikiwiki/markdown]]
* [[ikiwiki/openid]] * [[ikiwiki/login-selector]]
* [[ikiwiki/pagespec]] * [[ikiwiki/pagespec]]
* [[ikiwiki/directive]] * [[ikiwiki/directive]]
* [[ikiwiki/subpage]] * [[ikiwiki/subpage]]

View File

@ -0,0 +1,17 @@
[[!template id=plugin name=emailauth core=1 author="[[Joey]]"]]
[[!tag type/auth]]
This plugin lets users log into ikiwiki using any email address. To complete
the login, a one-time-use link is emailed to the user, and they can simply
open that link in their browser.
It is enabled by default, but can be turned off if you want to only use
some other form of authentication, such as [[passwordauth]] or [[openid]].
Users who have logged in using emailauth will have their email address used as
their username. In places where the username is displayed, like the
RecentChanges page, the domain will be omitted, to avoid exposing the
user's email address.
This plugin needs the [[!cpan Mail::SendMail]] perl module installed,
and able to send outgoing email.

View File

@ -458,6 +458,9 @@ object's "name" parameter to the authenticated user's name. Note that
if the name is set to the name of a user who is not registered, if the name is set to the name of a user who is not registered,
a basic registration of the user will be automatically performed. a basic registration of the user will be automatically performed.
Auth plugins can use the loginselector helper plugin to let the user
select which authentication method to use.
### <a name="sessioncgi">sessioncgi</a> ### <a name="sessioncgi">sessioncgi</a>
hook(type => "sessioncgi", id => "foo", call => \&sessioncgi); hook(type => "sessioncgi", id => "foo", call => \&sessioncgi);

View File

@ -465,40 +465,40 @@ li.L8 { list-style: upper-alpha; }
display: none; display: none;
} }
/* openid selector */ /* login selector */
#openid_choice { #login_choice {
display: none; display: none;
} }
#openid_input_area { #login_input_area {
clear: both; clear: both;
padding: 10px; padding: 10px;
} }
#openid_btns, #openid_btns br { #login_btns, #login_btns br {
clear: both; clear: both;
} }
#openid_highlight { #login_highlight {
background-color: black; background-color: black;
float: left; float: left;
} }
.openid_large_btn { .login_large_btn {
padding: 1em 1.5em; padding: 1em 1.5em;
border: 1px solid #DDD; border: 1px solid #DDD;
margin: 3px; margin: 3px;
float: left; float: left;
} }
.openid_small_btn { .login_small_btn {
padding: 4px 4px; padding: 4px 4px;
border: 1px solid #DDD; border: 1px solid #DDD;
margin: 3px; margin: 3px;
float: left; float: left;
} }
a.openid_large_btn:focus { a.login_large_btn:focus {
outline: none; outline: none;
} }
a.openid_large_btn:focus { a.login_large_btn:focus {
outline-style: none; outline-style: none;
} }
.openid_selected { .login_selected {
border: 4px solid #DDD; border: 4px solid #DDD;
} }

View File

@ -92,8 +92,9 @@ Here is a full list of the template files used:
* `editpage.tmpl`, `editconflict.tmpl`, `editcreationconflict.tmpl`, * `editpage.tmpl`, `editconflict.tmpl`, `editcreationconflict.tmpl`,
`editfailedsave.tmpl`, `editpagegone.tmpl`, `pocreatepage.tmpl`, `editfailedsave.tmpl`, `editpagegone.tmpl`, `pocreatepage.tmpl`,
`editcomment.tmpl` `commentmoderation.tmpl`, `renamesummary.tmpl`, `editcomment.tmpl` `commentmoderation.tmpl`, `renamesummary.tmpl`,
`passwordmail.tmpl`, `openid-selector.tmpl`, `revert.tmpl` - Parts of ikiwiki's user `passwordmail.tmpl`, `emailauth.tmpl, `login-selector.tmpl`,
interface; do not normally need to be customised. `revert.tmpl` - Parts of ikiwiki's user interface; do not normally need
to be customised.
[[!meta robots="noindex, follow"]] [[!meta robots="noindex, follow"]]

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

View File

@ -0,0 +1,10 @@
To log into <TMPL_VAR WIKINAME>, just open the following link:
<TMPL_VAR AUTHURL>
This link can only be used once to log in, and will expire in one day.
(Please disregard this email if you were not trying to log in.)
--
ikiwiki

View File

@ -0,0 +1,65 @@
<script type="text/javascript" src="ikiwiki/jquery.min.js"></script>
<script type="text/javascript" src="ikiwiki/login-selector/login-selector.js"></script>
<script type="text/javascript">
$(document).ready(function() {
selector.init(
'openid_identifier',
{
<TMPL_IF LOGIN_SELECTOR_OPENID>'openid': 1,</TMPL_IF>
<TMPL_IF LOGIN_SELECTOR_EMAILAUTH>'email': 1,</TMPL_IF>
},
'<TMPL_IF OTHERFORM>otherform</TMPL_IF>',
'<TMPL_VAR OTHERFORM_LABEL>'
);
});
</script>
<form action="<TMPL_VAR CGIURL>" method="get" id="login_selector_form">
<div>
<script>
$('fieldset').append("<legend>Select login method</legend>");
</script>
<input type="hidden" name="do" value="signin" />
<input type="hidden" name="action" value="verify" />
<div id="login_choice">
<div id="login_btns"></div>
</div>
<div id="login_input_area">
<TMPL_IF LOGIN_SELECTOR_OPENID>
<div>
<h3>OpenId login:</h3>
<label for="openid_identifier" class="block">Enter your OpenID:</label>
<input id="openid_identifier" name="openid_identifier" type="text" value="<TMPL_VAR ESCAPE=HTML OPENID_URL>"/>
<input id="openid_submit" type="submit" value="Login"/>
</div>
</TMPL_IF>
<TMPL_IF LOGIN_SELECTOR_EMAILAUTH>
<div>
<h3>Email login:</h3>
<label for="email_address" class="block">Enter your email address:</label>
<input id="email_address" name="Email_entry" type="text" value="<TMPL_VAR ESCAPE=HTML EMAIL_ADDRESS>"/>
<input id="email_submit" type="submit" value="Login"/>
</div>
</TMPL_IF>
</div>
<TMPL_IF LOGIN_ERROR>
<div class="error"><TMPL_VAR LOGIN_ERROR></div>
</TMPL_IF>
<TMPL_IF LOGIN_INFO>
<TMPL_VAR LOGIN_INFO>
</TMPL_IF>
</div>
</form>
<div id="otherform">
<TMPL_IF OTHERFORM>
<br />
<noscript>
<h3><TMPL_VAR OTHERFORM_LABEL> login:</h3>
</noscript>
</TMPL_IF>
<TMPL_VAR OTHERFORM>
</div>

View File

@ -1,43 +0,0 @@
<script type="text/javascript" src="ikiwiki/jquery.min.js"></script>
<script type="text/javascript" src="ikiwiki/openid/openid-jquery.js"></script>
<script type="text/javascript">
$(document).ready(function() {
openid.init('openid_identifier','<TMPL_IF NONOPENIDFORM>nonopenidform</TMPL_IF>', '<TMPL_VAR NONOPENIDFORM_LABEL>');
});
</script>
<noscript>
<h2>OpenID:</h2>
</noscript>
<form action="<TMPL_VAR CGIURL>" method="get" id="openid_form">
<fieldset>
<script>
$('fieldset').append("<legend>Select login method</legend>");
</script>
<input type="hidden" name="do" value="signin" />
<input type="hidden" name="action" value="verify" />
<div id="openid_choice">
<div id="openid_btns"></div>
</div>
<div id="openid_input_area">
<label for="openid_identifier" class="block">Enter your OpenID:</label>
<input id="openid_identifier" name="openid_identifier" type="text" value="<TMPL_VAR ESCAPE=HTML OPENID_URL>"/>
<input id="openid_submit" type="submit" value="Login"/>
</div>
<TMPL_IF OPENID_ERROR>
<div class="error"><TMPL_VAR OPENID_ERROR></div>
</TMPL_IF>
</fieldset>
</form>
<div id="nonopenidform">
<TMPL_IF NONOPENIDFORM>
<br />
<noscript>
<h2><TMPL_VAR NONOPENIDFORM_LABEL>:</h2>
</noscript>
</TMPL_IF>
<TMPL_VAR NONOPENIDFORM>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

View File

Before

Width:  |  Height:  |  Size: 741 B

After

Width:  |  Height:  |  Size: 741 B

View File

@ -0,0 +1,264 @@
/*
Based on the Simple OpenID Plugin
http://code.google.com/p/openid-selector/
This code is licenced under the New BSD License.
*/
var selections_email_large = {
email: {
name: 'Email',
icon: 'wikiicons/email.png',
label: 'Enter your email address:',
url: null
}
};
var selections_openid_large = {
openid: {
name: 'OpenID',
icon: 'wikiicons/openidlogin-bg.gif',
label: 'Enter your OpenID:',
url: null
}
};
var selections_openid_small = {
verisign: {
name: 'Verisign',
icon: 'ikiwiki/login-selector/verisign.png',
label: 'Enter your Verisign username:',
url: 'http://{username}.pip.verisignlabs.com/'
},
yahoo: {
name: 'Yahoo',
icon: 'ikiwiki/login-selector/goa-account-yahoo.png',
url: 'http://me.yahoo.com/'
},
flickr: {
name: 'Flickr',
icon: 'ikiwiki/login-selector/goa-account-flickr.png',
label: 'Enter your Flickr username:',
url: 'http://flickr.com/photos/{username}/'
},
wordpress: {
name: 'Wordpress',
icon: 'ikiwiki/login-selector/wordpress.png',
label: 'Enter your Wordpress.com username:',
url: 'http://{username}.wordpress.com/'
},
aol: {
name: 'AOL',
icon: 'ikiwiki/login-selector/aol.png',
label: 'Enter your AOL username:',
url: 'http://openid.aol.com/{username}'
}
};
var selections = $.extend({}, selections_email_large, selections_openid_large, selections_openid_small);
var selector = {
ajaxHandler: null,
cookie_expires: 6*30, // 6 months.
cookie_name: 'openid_selection', // historical name
cookie_path: '/',
img_path: 'images/',
input_id: null,
selection_url: null,
selection_id: null,
othersignin_id: null,
init: function(input_id, login_methods, othersignin_id, othersignin_label) {
var selector_btns = $('#login_btns');
this.input_id = input_id;
$('#login_choice').show();
$('#login_input_area').empty();
// add box for each selection
if (login_methods['openid']) {
for (id in selections_openid_large) {
selector_btns.append(this.getBoxHTML(selections_openid_large[id], 'large'));
}
}
if (login_methods['email']) {
for (id in selections_email_large) {
selector_btns.prepend(this.getBoxHTML(selections_email_large[id], 'large'));
}
}
if (othersignin_label != "") {
this.othersignin_label=othersignin_label;
}
else {
this.othersignin_label="other";
}
if (othersignin_id != "") {
this.othersignin_id=othersignin_id;
selector_btns.prepend(
'<a href="javascript: selector.signin(\'othersignin\');"' +
' style="background: #FFF" ' +
'class="othersignin login_large_btn">' +
'<img alt="" width="16" height="16" src="favicon.ico" />' +
' ' + this.othersignin_label +
'</a>'
);
$('#'+this.othersignin_id).hide();
}
if (login_methods['openid'] && selections_openid_small) {
selector_btns.append('<br/>');
for (id in selections_openid_small) {
selector_btns.append(this.getBoxHTML(selections_openid_small[id], 'small'));
}
}
$('#login_selector_form').submit(this.submit);
var box_id = this.readCookie();
if (box_id) {
this.signin(box_id, true);
}
},
getBoxHTML: function(selection, box_size) {
var label="";
var title=""
if (box_size == 'large') {
label=' ' + selection["name"];
}
else {
title=' title="'+selection["name"]+'"';
}
var box_id = selection["name"].toLowerCase();
return '<a' + title +' href="javascript: selector.signin(\''+ box_id +'\');"' +
' style="background: #FFF" ' +
'class="' + box_id + ' login_' + box_size + '_btn">' +
'<img alt="" width="16" height="16" src="' + selection["icon"] + '" />' +
label +
'</a>';
},
/* selection image click */
signin: function(box_id, onload) {
if (box_id == 'othersignin') {
this.highlight(box_id);
$('#login_input_area').empty();
$('#'+this.othersignin_id).show();
this.setCookie(box_id);
return;
}
else {
if (this.othersignin_id) {
$('#'+this.othersignin_id).hide();
}
}
var selection = selections[box_id];
if (! selection) {
return;
}
this.highlight(box_id);
this.selection_id = box_id;
this.selection_url = selection['url'];
// prompt user for input?
if (selection['label']) {
this.setCookie(box_id);
this.useInputBox(selection);
} else {
this.setCookie('');
$('#login_input_area').empty();
if (! onload) {
$('#login_selector_form').submit();
}
}
},
/* Sign-in button click */
submit: function() {
var url = selector.selection_url;
if (url) {
url = url.replace('{username}', $('#entry').val());
selector.setOpenIdUrl(url);
}
else {
selector.setOpenIdUrl("");
}
if (selector.ajaxHandler) {
selector.ajaxHandler(selector.selection_id, document.getElementById(selector.input_id).value);
return false;
}
return true;
},
setOpenIdUrl: function (url) {
var hidden = $('#'+this.input_id);
if (hidden.length > 0) {
hidden.value = url;
} else {
$('#login_selector_form').append('<input style="display:none" id="' + this.input_id + '" name="' + this.input_id + '" value="'+url+'"/>');
}
},
highlight: function (box_id) {
// remove previous highlight.
var highlight = $('#login_highlight');
if (highlight) {
highlight.replaceWith($('#login_highlight a')[0]);
}
// add new highlight.
$('.'+box_id).wrap('<div id="login_highlight"></div>');
},
setCookie: function (value) {
var date = new Date();
date.setTime(date.getTime()+(this.cookie_expires*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
document.cookie = this.cookie_name+"="+value+expires+"; path=" + this.cookie_path;
},
readCookie: function () {
var nameEQ = this.cookie_name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
},
useInputBox: function (selection) {
var input_area = $('#login_input_area');
var html = '';
var id = selection['name']+'_entry';
var value = '';
var label = selection['label'];
var style = '';
if (selection['name'] == 'OpenID') {
id = this.input_id;
value = '';
style = 'background:#FFF url(wikiicons/openidlogin-bg.gif) no-repeat scroll 0 50%; padding-left:18px;';
}
if (label) {
html = '<label for="'+ id +'" class="block">' + label + '</label>';
}
html += '<input id="'+id+'" type="text" style="'+style+'" name="'+id+'" value="'+value+'" />' +
'<input id="selector_submit" type="submit" value="Login"/>';
input_area.empty();
input_area.append(html);
$('#'+id).focus();
},
setAjaxHandler: function (ajaxFunction) {
this.ajaxHandler = ajaxFunction;
}
};

View File

Before

Width:  |  Height:  |  Size: 714 B

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

View File

@ -1,237 +0,0 @@
/*
Simple OpenID Plugin
http://code.google.com/p/openid-selector/
This code is licenced under the New BSD License.
*/
var providers_large = {
verisign: {
name: 'Verisign',
icon: 'ikiwiki/openid/verisign.png',
label: 'Enter your Verisign username:',
url: 'http://{username}.pip.verisignlabs.com/'
},
yahoo: {
name: 'Yahoo',
icon: 'ikiwiki/openid/goa-account-yahoo.png',
url: 'http://me.yahoo.com/'
},
openid: {
name: 'OpenID',
icon: 'wikiicons/openidlogin-bg.gif',
label: 'Enter your OpenID:',
url: null
}
};
var providers_small = {
};
var providers = $.extend({}, providers_large, providers_small);
var openid = {
demo: false,
ajaxHandler: null,
cookie_expires: 6*30, // 6 months.
cookie_name: 'openid_provider',
cookie_path: '/',
img_path: 'images/',
input_id: null,
provider_url: null,
provider_id: null,
localsignin_id: null,
init: function(input_id, localsignin_id, localsignin_label) {
var openid_btns = $('#openid_btns');
this.input_id = input_id;
$('#openid_choice').show();
$('#openid_input_area').empty();
// add box for each provider
for (id in providers_large) {
openid_btns.append(this.getBoxHTML(providers_large[id], 'large'));
}
if (localsignin_label != "") {
this.localsignin_label=localsignin_label;
}
else {
this.localsignin_label="other";
}
if (localsignin_id != "") {
this.localsignin_id=localsignin_id;
openid_btns.append(
'<a href="javascript: openid.signin(\'localsignin\');"' +
' style="background: #FFF" ' +
'class="localsignin openid_large_btn">' +
'<img alt="" width="16" height="16" src="favicon.ico" />' +
' ' + this.localsignin_label +
'</a>'
);
$('#'+this.localsignin_id).hide();
}
if (providers_small) {
openid_btns.append('<br/>');
for (id in providers_small) {
openid_btns.append(this.getBoxHTML(providers_small[id], 'small'));
}
}
$('#openid_form').submit(this.submit);
var box_id = this.readCookie();
if (box_id) {
this.signin(box_id, true);
}
},
getBoxHTML: function(provider, box_size) {
var label="";
var title=""
if (box_size == 'large') {
label=' ' + provider["name"];
}
else {
title=' title="'+provider["name"]+'"';
}
var box_id = provider["name"].toLowerCase();
return '<a' + title +' href="javascript: openid.signin(\''+ box_id +'\');"' +
' style="background: #FFF" ' +
'class="' + box_id + ' openid_' + box_size + '_btn">' +
'<img alt="" width="16" height="16" src="' + provider["icon"] + '" />' +
label +
'</a>';
},
/* Provider image click */
signin: function(box_id, onload) {
if (box_id == 'localsignin') {
this.highlight(box_id);
$('#openid_input_area').empty();
$('#'+this.localsignin_id).show();
this.setCookie(box_id);
return;
}
else {
if (this.localsignin_id) {
$('#'+this.localsignin_id).hide();
}
}
var provider = providers[box_id];
if (! provider) {
return;
}
this.highlight(box_id);
this.provider_id = box_id;
this.provider_url = provider['url'];
// prompt user for input?
if (provider['label']) {
this.setCookie(box_id);
this.useInputBox(provider);
} else {
this.setCookie('');
$('#openid_input_area').empty();
if (! onload) {
$('#openid_form').submit();
}
}
},
/* Sign-in button click */
submit: function() {
var url = openid.provider_url;
if (url) {
url = url.replace('{username}', $('#openid_username').val());
openid.setOpenIdUrl(url);
}
if(openid.ajaxHandler) {
openid.ajaxHandler(openid.provider_id, document.getElementById(openid.input_id).value);
return false;
}
if(openid.demo) {
alert("In client demo mode. Normally would have submitted OpenID:\r\n" + document.getElementById(openid.input_id).value);
return false;
}
return true;
},
setOpenIdUrl: function (url) {
var hidden = $('#'+this.input_id);
if (hidden.length > 0) {
hidden.value = url;
} else {
$('#openid_form').append('<input style="display:none" id="' + this.input_id + '" name="' + this.input_id + '" value="'+url+'"/>');
}
},
highlight: function (box_id) {
// remove previous highlight.
var highlight = $('#openid_highlight');
if (highlight) {
highlight.replaceWith($('#openid_highlight a')[0]);
}
// add new highlight.
$('.'+box_id).wrap('<div id="openid_highlight"></div>');
},
setCookie: function (value) {
var date = new Date();
date.setTime(date.getTime()+(this.cookie_expires*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
document.cookie = this.cookie_name+"="+value+expires+"; path=" + this.cookie_path;
},
readCookie: function () {
var nameEQ = this.cookie_name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
},
useInputBox: function (provider) {
var input_area = $('#openid_input_area');
var html = '';
var id = 'openid_username';
var value = '';
var label = provider['label'];
var style = '';
if (provider['name'] == 'OpenID') {
id = this.input_id;
value = '';
style = 'background:#FFF url(wikiicons/openidlogin-bg.gif) no-repeat scroll 0 50%; padding-left:18px;';
}
if (label) {
html = '<label for="'+ id +'" class="block">' + label + '</label>';
}
html += '<input id="'+id+'" type="text" style="'+style+'" name="'+id+'" value="'+value+'" />' +
'<input id="openid_submit" type="submit" value="Login"/>';
input_area.empty();
input_area.append(html);
$('#'+id).focus();
},
setDemoMode: function (demoMode) {
this.demo = demoMode;
},
setAjaxHandler: function (ajaxFunction) {
this.ajaxHandler = ajaxFunction;
}
};