summaryrefslogtreecommitdiff
path: root/lib/VNDB
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNDB')
-rw-r--r--lib/VNDB/DB/Users.pm98
-rw-r--r--lib/VNDB/Handler/Users.pm67
-rw-r--r--lib/VNDB/Util/Auth.pm140
3 files changed, 170 insertions, 135 deletions
diff --git a/lib/VNDB/DB/Users.pm b/lib/VNDB/DB/Users.pm
index d6776b2b..84ff10f2 100644
--- a/lib/VNDB/DB/Users.pm
+++ b/lib/VNDB/DB/Users.pm
@@ -6,15 +6,16 @@ use warnings;
use Exporter 'import';
our @EXPORT = qw|
- dbUserGet dbUserEdit dbUserAdd dbUserDel dbUserPrefSet
- dbSessionAdd dbSessionDel dbSessionUpdateLastUsed
+ dbUserGet dbUserEdit dbUserAdd dbUserDel dbUserPrefSet dbUserLogin dbUserLogout
+ dbUserUpdateLastUsed dbUserEmailExists dbUserGetMail dbUserSetMail dbUserSetPerm dbUserAdminSetPass
+ dbUserResetPass dbUserIsValidToken dbUserSetPass
dbNotifyGet dbNotifyMarkRead dbNotifyRemove
dbThrottleGet dbThrottleSet
|;
-# %options->{ username passwd mail session uid ip registered search results page what sort reverse notperm }
-# what: notifycount stats extended prefs hide_list
+# %options->{ username session uid ip registered search results page what sort reverse notperm }
+# what: notifycount stats scryptargs extended prefs hide_list
# sort: username registered votes changes tags
sub dbUserGet {
my $s = shift;
@@ -26,6 +27,7 @@ sub dbUserGet {
@_
);
+ my $token = unpack 'H*', $o{session}||'';
$o{search} =~ s/%// if $o{search};
my %where = (
$o{username} ? (
@@ -34,8 +36,6 @@ sub dbUserGet {
'SUBSTRING(username from 1 for 1) = ?' => $o{firstchar} ) : (),
!$o{firstchar} && defined $o{firstchar} ? (
'ASCII(username) < 97 OR ASCII(username) > 122' => 1 ) : (),
- $o{mail} ? (
- 'LOWER(mail) = LOWER(?)' => $o{mail} ) : (),
$o{uid} && !ref($o{uid}) ? (
'id = ?' => $o{uid} ) : (),
$o{uid} && ref($o{uid}) ? (
@@ -48,8 +48,8 @@ sub dbUserGet {
'registered > to_timestamp(?)' => $o{registered} ) : (),
$o{search} ? (
'username ILIKE ?' => "%$o{search}%") : (),
- $o{session} ? (
- q|s.token = decode(?, 'hex')| => unpack 'H*', $o{session} ) : (),
+ $token ? (
+ q|user_isloggedin(id, decode(?, 'hex')) IS NOT NULL| => $token ) : (),
$o{notperm} ? (
'perm & ~(?::smallint) > 0' => $o{notperm} ) : (),
);
@@ -57,8 +57,9 @@ sub dbUserGet {
my @select = (
qw|id username c_votes c_changes c_tags|,
q|extract('epoch' from registered) as registered|,
- $o{what} =~ /extended/ ? qw|mail perm ign_votes passwd| : (),
+ $o{what} =~ /extended/ ? qw|perm ign_votes| : (), # mail
$o{what} =~ /hide_list/ ? 'up.value AS hide_list' : (),
+ $o{what} =~ /scryptargs/ ? 'user_getscryptargs(id) AS scryptargs' : (),
$o{what} =~ /notifycount/ ?
'(SELECT COUNT(*) FROM notifications WHERE uid = u.id AND read IS NULL) AS notifycount' : (),
$o{what} =~ /stats/ ? (
@@ -69,11 +70,10 @@ sub dbUserGet {
'(SELECT COUNT(DISTINCT tag) FROM tags_vn WHERE uid = u.id) AS tagcount',
'(SELECT COUNT(DISTINCT vid) FROM tags_vn WHERE uid = u.id) AS tagvncount',
) : (),
- $o{session} ? q|extract('epoch' from s.lastused) as session_lastused| : (),
+ $token ? qq|extract('epoch' from user_isloggedin(id, decode('$token', 'hex'))) as session_lastused| : (),
);
my @join = (
- $o{session} ? 'JOIN sessions s ON s.uid = u.id' : (),
$o{what} =~ /hide_list/ || $o{sort} eq 'votes' ?
"LEFT JOIN users_prefs up ON up.uid = u.id AND up.key = 'hide_list'" : (),
);
@@ -119,10 +119,7 @@ sub dbUserEdit {
my %h;
defined $o{$_} && ($h{$_.' = ?'} = $o{$_})
- for (qw| username mail perm ign_votes email_confirmed |);
- $h{'passwd = decode(?, \'hex\')'} = unpack 'H*', $o{passwd}
- if defined $o{passwd};
-
+ for (qw| username ign_votes email_confirmed |);
return if scalar keys %h <= 0;
return $s->dbExec(q|
@@ -133,11 +130,9 @@ sub dbUserEdit {
}
-# username, pass(ecrypted), mail, [ip]
+# username, mail, [ip]
sub dbUserAdd {
- my($s, @o) = @_;
- $s->dbRow(q|INSERT INTO users (username, passwd, mail, ip) VALUES(?, decode(?, 'hex'), ?, ?) RETURNING id|,
- $o[0], unpack('H*', $o[1]), $o[2], $o[3]||$s->reqIP)->{id};
+ $_[0]->dbRow(q|INSERT INTO users (username, mail, ip) VALUES(?, ?, ?) RETURNING id|, $_[1], $_[2], $_[3]||$_[0]->reqIP)->{id};
}
@@ -156,27 +151,64 @@ sub dbUserPrefSet {
}
-# Adds a session to the database
-# uid, 40 character session token
-sub dbSessionAdd {
- $_[0]->dbExec(q|INSERT INTO sessions (uid, token) VALUES(?, decode(?, 'hex'))|, $_[1], unpack 'H*', $_[2]);
+# uid, encpass, token
+sub dbUserLogin {
+ $_[0]->dbRow(
+ q|SELECT user_login(?, decode(?, 'hex'), decode(?, 'hex')) AS r|,
+ $_[1], unpack('H*', $_[2]), unpack('H*', $_[3])
+ )->{r}||0;
}
-# Deletes session(s) from the database
-# If no token is supplied, all sessions for the uid are destroyed
-# uid, token (optional)
-sub dbSessionDel {
- my($s, @o) = @_;
- my %where = ('uid = ?' => $o[0]);
- $where{"token = decode(?, 'hex')"} = unpack 'H*', $o[1] if $o[1];
- $s->dbExec('DELETE FROM sessions !W', \%where);
+# uid, token
+sub dbUserLogout {
+ $_[0]->dbExec(q|SELECT user_logout(?, decode(?, 'hex'))|, $_[1], unpack 'H*', $_[2]);
}
# uid, token
-sub dbSessionUpdateLastUsed {
- $_[0]->dbExec(q|UPDATE sessions SET lastused = NOW() WHERE uid = ? AND token = decode(?, 'hex')|, $_[1], unpack 'H*', $_[2]);
+sub dbUserUpdateLastUsed {
+ $_[0]->dbExec(q|SELECT user_update_lastused(?, decode(?, 'hex'))|, $_[1], unpack 'H*', $_[2]);
+}
+
+
+sub dbUserEmailExists {
+ $_[0]->dbRow(q|SELECT user_emailexists(?) AS r|, $_[1])->{r};
+}
+
+
+sub dbUserIsValidToken {
+ $_[0]->dbRow(q|SELECT user_isvalidtoken(?, decode(?, 'hex')) AS r|, $_[1], unpack 'H*', $_[2])->{r};
+}
+
+
+sub dbUserResetPass {
+ $_[0]->dbRow(q|SELECT user_resetpass(?, decode(?, 'hex')) AS r|, $_[1], unpack 'H*', $_[2])->{r};
+}
+
+
+sub dbUserSetPass {
+ $_[0]->dbRow(q|SELECT user_setpass(?, decode(?, 'hex'), decode(?, 'hex')) AS r|, $_[1], unpack('H*', $_[2]), unpack('H*', $_[3]))->{r};
+}
+
+
+sub dbUserGetMail {
+ $_[0]->dbRow(q|SELECT user_getmail(?, ?, decode(?, 'hex')) AS r|, $_[1], $_[2], unpack 'H*', $_[3])->{r};
+}
+
+
+sub dbUserSetMail {
+ $_[0]->dbExec(q|SELECT user_setmail(?, ?, decode(?, 'hex'), ?)|, $_[1], $_[2], unpack('H*', $_[3]), $_[4]);
+}
+
+
+sub dbUserSetPerm {
+ $_[0]->dbExec(q|SELECT user_setperm(?, ?, decode(?, 'hex'), ?)|, $_[1], $_[2], unpack('H*', $_[3]), $_[4]);
+}
+
+
+sub dbUserAdminSetPass {
+ $_[0]->dbExec(q|SELECT user_admin_setpass(?, ?, decode(?, 'hex'), decode(?, 'hex'))|, $_[1], $_[2], unpack('H*', $_[3]), unpack('H*', $_[4]));
}
diff --git a/lib/VNDB/Handler/Users.pm b/lib/VNDB/Handler/Users.pm
index 5b6888cb..d1f0df93 100644
--- a/lib/VNDB/Handler/Users.pm
+++ b/lib/VNDB/Handler/Users.pm
@@ -145,7 +145,7 @@ sub userpage {
sub login {
my $self = shift;
- return $self->resRedirect('/') if $self->authInfo->{id};
+ return $self->resRedirect('/', 'temp') if $self->authInfo->{id};
my $tm = $self->dbThrottleGet(norm_ip($self->reqIP));
if($tm-time() > $self->{login_throttle}[1]) {
@@ -209,21 +209,18 @@ sub logout {
sub newpass {
my $self = shift;
- return $self->resRedirect('/') if $self->authInfo->{id};
+ return $self->resRedirect('/', 'temp') if $self->authInfo->{id};
- my($frm, $u);
+ my($frm, $uid, $token);
if($self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
$frm = $self->formValidate({ post => 'mail', template => 'email' });
if(!$frm->{_err}) {
- $u = $self->dbUserGet(mail => $frm->{mail})->[0];
- $frm->{_err} = [ 'No user found with that email address' ] if !$u || !$u->{id};
+ ($uid, $token) = $self->authResetPass($frm->{mail});
+ $frm->{_err} = [ 'No user found with that email address' ] if !$uid;
}
if(!$frm->{_err}) {
- my %o;
- my $token;
- ($token, $o{passwd}) = $self->authPrepareReset();
- $self->dbUserEdit($u->{id}, %o);
+ my $u = $self->dbUserGet(uid => $uid)->[0];
my $body = sprintf
"Hello %s,\n\nYour VNDB.org login has been disabled, you can now set a new password by following the link below:\n\n"
."%s\n\nNow don't forget your password again! :-)\n\nvndb.org",
@@ -253,7 +250,7 @@ sub newpass {
sub newpass_sent {
my $self = shift;
- return $self->resRedirect('/') if $self->authInfo->{id};
+ return $self->resRedirect('/', 'temp') if $self->authInfo->{id};
$self->htmlHeader(title => 'New password', noindex => 1);
div class => 'mainbox';
h1 'New password';
@@ -267,14 +264,14 @@ sub newpass_sent {
sub setpass {
my($self, $uid) = @_;
- return $self->resRedirect('/') if $self->authInfo->{id};
+ return $self->resRedirect('/', 'temp') if $self->authInfo->{id};
my $t = $self->formValidate({get => 't', regex => qr/^[a-f0-9]{40}$/i });
return $self->resNotFound if $t->{_err};
$t = $t->{t};
- my $u = $self->dbUserGet(uid => $uid, what => 'extended')->[0];
- return $self->resNotFound if !$u || !$self->authValidateReset($u->{passwd}, $t);
+ my $u = $self->dbUserGet(uid => $uid)->[0];
+ return $self->resNotFound if !$u || !$self->authIsValidToken($u->{id}, $t);
my $frm;
if($self->reqMethod eq 'POST') {
@@ -286,10 +283,8 @@ sub setpass {
push @{$frm->{_err}}, 'Passwords do not match' if $frm->{usrpass} ne $frm->{usrpass2};
if(!$frm->{_err}) {
- my %o = (email_confirmed => 1);
- $o{passwd} = $self->authPreparePass($frm->{usrpass});
- $self->dbUserEdit($uid, %o);
- return $self->authCreateSession($u->{username}, "/u$uid");
+ $self->dbUserEdit($uid, email_confirmed => 1);
+ return $self->authSetPass($uid, $frm->{usrpass}, "/u$uid", token => $t)
}
}
@@ -306,7 +301,7 @@ sub setpass {
sub register {
my $self = shift;
- return $self->resRedirect('/') if $self->authInfo->{id};
+ return $self->resRedirect('/', 'temp') if $self->authInfo->{id};
my $frm;
if($self->reqMethod eq 'POST') {
@@ -323,7 +318,7 @@ sub register {
push @{$frm->{_err}}, 'Someone already has this username, please choose another name'
if $frm->{usrname} eq 'anonymous' || !$frm->{_err} && $self->dbUserGet(username => $frm->{usrname})->[0]{id};
push @{$frm->{_err}}, 'Someone already registered with that email address'
- if !$frm->{_err} && $self->dbUserGet(mail => $frm->{mail})->[0]{id};
+ if !$frm->{_err} && $self->dbUserEmailExists($frm->{mail});
# Use /32 match for IPv4 and /48 for IPv6. The /48 is fairly broad, so some
# users may have to wait a bit before they can register...
@@ -332,8 +327,8 @@ sub register {
if !$frm->{_err} && $self->dbUserGet(ip => $ip =~ /:/ ? "$ip/48" : $ip, registered => time-24*3600)->[0]{id};
if(!$frm->{_err}) {
- my($token, $pass) = $self->authPrepareReset();
- my $uid = $self->dbUserAdd($frm->{usrname}, $pass, $frm->{mail});
+ my $uid = $self->dbUserAdd($frm->{usrname}, $frm->{mail});
+ my(undef, $token) = $self->authResetPass($frm->{mail});
my $body = sprintf "Hello %s,\n\n"
."Someone has registered an account on VNDB.org with your email address. To confirm your registration, follow the link below.\n\n"
."%s\n\n"
@@ -369,7 +364,7 @@ sub register {
sub register_done {
my $self = shift;
- return $self->resRedirect('/') if $self->authInfo->{id};
+ return $self->resRedirect('/', 'temp') if $self->authInfo->{id};
$self->htmlHeader(title => 'Account created', noindex => 1);
div class => 'mainbox';
h1 'Account created';
@@ -416,9 +411,6 @@ sub edit {
);
push @{$frm->{_err}}, 'Passwords do not match'
if ($frm->{usrpass} || $frm->{usrpass2}) && (!$frm->{usrpass} || !$frm->{usrpass2} || $frm->{usrpass} ne $frm->{usrpass2});
- push @{$frm->{_err}}, 'Invalid password'
- if !($self->authInfo->{id} != $u->{id} && $self->authCan('usermod'))
- && ($frm->{usrpass} || $frm->{usrpass2}) && !$self->authCheck($u->{username}, $frm->{curpass});
if(!$frm->{_err}) {
$frm->{skin} = '' if $frm->{skin} eq $self->{skin_default};
@@ -426,23 +418,34 @@ sub edit {
my $tags_cat = join(',', sort @{$frm->{tags_cat}}) || 'none';
$self->dbUserPrefSet($uid, tags_cat => $tags_cat eq $self->{default_tags_cat} ? '' : $tags_cat);
+
my %o;
if($self->authCan('usermod')) {
$o{username} = $frm->{usrname} if $frm->{usrname};
- $o{perm} = 0;
- $o{perm} |= $self->{permissions}{$_} for(@{ delete $frm->{perms} });
+ $o{ign_votes} = $frm->{ign_votes} ? 1 : 0;
+
+ my $perm = 0;
+ $perm |= $self->{permissions}{$_} for(@{ delete $frm->{perms} });
+ $self->dbUserSetPerm($u->{id}, $self->authInfo->{id}, $self->authInfo->{token}, $perm);
}
- $o{mail} = $frm->{mail};
- $o{passwd} = $self->authPreparePass($frm->{usrpass}) if $frm->{usrpass};
- $o{ign_votes} = $frm->{ign_votes} ? 1 : 0 if $self->authCan('usermod');
+ $self->dbUserSetMail($u->{id}, $self->authInfo->{id}, $self->authInfo->{token}, $frm->{mail});
$self->dbUserEdit($uid, %o);
- return $self->resRedirect("/u$uid/edit?d=1", 'post');
+ $self->authAdminSetPass($u->{id}, $frm->{usrpass}) if $frm->{usrpass} && $self->authInfo->{id} != $u->{id};
+
+ if($frm->{usrpass} && $self->authInfo->{id} == $u->{id}) {
+ # Bit ugly: On incorrect password, all other changes are still saved.
+ my $ok = $self->authSetPass($u->{id}, $frm->{usrpass}, "/u$uid/edit?d=1", pass => $frm->{curpass});
+ return if $ok;
+ push @{$frm->{_err}}, 'Invalid password';
+ } else {
+ return $self->resRedirect("/u$uid/edit?d=1", 'post');
+ }
}
}
# fill out default values
$frm->{usrname} ||= $u->{username};
- $frm->{mail} ||= $u->{mail};
+ $frm->{mail} ||= $self->dbUserGetMail($u->{id}, $self->authInfo->{id}, $self->authInfo->{token});
$frm->{perms} ||= [ grep $u->{perm} & $self->{permissions}{$_}, keys %{$self->{permissions}} ];
$frm->{$_} //= $u->{prefs}{$_} for(qw|skin customcss show_nsfw traits_sexual tags_all hide_list spoilers|);
$frm->{tags_cat} ||= [ split /,/, $u->{prefs}{tags_cat}||$self->{default_tags_cat} ];
diff --git a/lib/VNDB/Util/Auth.pm b/lib/VNDB/Util/Auth.pm
index 6e1dfa5d..e3ee20eb 100644
--- a/lib/VNDB/Util/Auth.pm
+++ b/lib/VNDB/Util/Auth.pm
@@ -14,8 +14,8 @@ use VNDB::Func;
our @EXPORT = qw|
- authInit authLogin authLogout authInfo authCan authPreparePass authCreateSession authCheck
- authPrepareReset authValidateReset authGetCode authCheckCode authPref
+ authInit authLogin authLogout authInfo authCan authSetPass authAdminSetPass
+ authResetPass authIsValidToken authGetCode authCheckCode authPref
|;
@@ -28,7 +28,7 @@ sub randomascii {
# Returns (uid, encrypted_token) on success, (0, '') on failure.
sub parsecookie {
# Earlier versions of the auth cookie didn't have the dot separator, so that's optional.
- return ($_[0]->reqCookie('auth')||'') =~ /^([a-zA-Z0-9]{40})\.?(\d+)$/ ? ($2, sha1 pack 'H*', $1) : (0, '');
+ return ($_[0]->reqCookie('auth')||'') =~ /^([a-fA-F0-9]{40})\.?(\d+)$/ ? ($2, sha1 pack 'H*', $1) : (0, '');
}
@@ -38,9 +38,10 @@ sub authInit {
my($uid, $token_e) = parsecookie($self);
$self->{_auth} = $uid && $self->dbUserGet(uid => $uid, session => $token_e, what => 'extended notifycount prefs')->[0];
+ $self->{_auth}{token} = $token_e if $self->{_auth};
# update the sessions.lastused column if lastused < now()-'6 hours'
- $self->dbSessionUpdateLastUsed($uid, $token_e) if $self->{_auth} && $self->{_auth}{session_lastused} < time()-6*3600;
+ $self->dbUserUpdateLastUsed($uid, $token_e) if $self->{_auth} && $self->{_auth}{session_lastused} < time()-6*3600;
# Drop the cookie if it's not valid
$self->resCookie(auth => undef) if !$self->{_auth} && $self->reqCookie('auth');
@@ -52,29 +53,39 @@ sub authInit {
sub authLogin {
my($self, $user, $pass, $to) = @_;
- if($self->authCheck($user, $pass)) {
- $self->authCreateSession($user, $to);
- return 1;
- }
+ return 0 if !$user || !$pass;
- return 0;
+ my $d = $self->dbUserGet(username => $user, what => 'scryptargs extended prefs notifycount')->[0];
+ return 0 if !$d->{id} || !$d->{scryptargs} || length($d->{scryptargs}) != 14;
+
+ my($N, $r, $p, $salt) = unpack 'NCCa8', $d->{scryptargs};
+ my $encpass = _preparepass($self, $pass, $salt, $N, $r, $p);
+
+ return _createsession($self, $d->{id}, $encpass, $to);
}
-# Args: user, url-to-redirect-to-on-success
-# Should only be called if the user is already authenticated (i.e. after authCheck or when the user just confirmed his email address).
-sub authCreateSession {
- my($self, $user, $to) = @_;
+# Prepares a plaintext password for database storage
+# Arguments: pass, optionally: salt, N, r, p
+# Returns: encrypted password (as a binary string)
+sub _preparepass {
+ my($self, $pass, $salt, $N, $r, $p) = @_;
+ ($N, $r, $p) = @{$self->{scrypt_args}} if !$N;
+ $salt ||= urandom(8);
+ return pack 'NCCa8a*', $N, $r, $p, $salt, scrypt_raw($pass, $self->{scrypt_salt} . $salt, $N, $r, $p, 32);
+}
+
- $self->{_auth} = $self->dbUserGet(username => $user, what => 'extended notifycount')->[0] if $user;
- die "No valid user!" if !$self->{_auth}{id};
+# self, uid, encpass, url-to-redirect-to
+sub _createsession {
+ my($self, $uid, $encpass, $url) = @_;
my $token = urandom(20);
- my $cookie = unpack('H*', $token).'.'.$self->{_auth}{id};
- $self->dbSessionAdd($self->{_auth}{id}, sha1 $token);
+ return 0 if !$self->dbUserLogin($uid, $encpass, sha1 $token);
- $self->resRedirect($to, 'post');
- $self->resCookie(auth => $cookie, httponly => 1, expires => time + 31536000); # keep the cookie for 1 year
+ $self->resRedirect($url, 'post');
+ $self->resCookie(auth => unpack('H*', $token).'.'.$uid, httponly => 1, expires => time + 31536000); # keep the cookie for 1 year
+ return 1;
}
@@ -83,82 +94,71 @@ sub authLogout {
my $self = shift;
my($uid, $token_e) = parsecookie($self);
- $self->dbSessionDel($uid, $token_e) if $uid;
+ $self->dbUserLogout($uid, $token_e) if $uid;
$self->resRedirect('/', 'temp');
$self->resCookie(auth => undef);
}
-# returns a hashref with information about the current loggedin user
-# the hash is identical to the hash returned by dbUserGet
-# returns empty hash if no user is logged in.
-sub authInfo {
- return shift->{_auth} || {};
+# Replaces the user's password with a random token that can be used to reset the password.
+sub authResetPass {
+ my $self = shift;
+ my $mail = shift;
+ my $token = unpack 'H*', urandom(20);
+ my $id = $self->dbUserResetPass($mail, sha1(lc($token)));
+ return $id ? ($id, $token) : ();
}
-# returns whether the currently loggedin or anonymous user can perform
-# a certain action. Argument is the action name as defined in global.pl
-sub authCan {
- my($self, $act) = @_;
- return $self->{_auth} ? $self->{_auth}{perm} & $self->{permissions}{$act} : 0;
+# uid, token
+sub authIsValidToken {
+ $_[0]->dbUserIsValidToken($_[1], sha1(lc($_[2])))
}
-# Checks for a valid login and writes information in _auth
-# Arguments: user, pass
-# Returns: 1 if login is valid, 0 otherwise
-sub authCheck {
- my($self, $user, $pass) = @_;
-
- return 0 if !$user || length($user) > 15 || length($user) < 2 || !$pass;
+# uid, new_pass, url_to_redir_to, 'token'|'pass', $token_or_pass
+# Changes the user's password, invalidates all existing sessions, creates a new
+# session and redirects.
+sub authSetPass {
+ my($self, $uid, $pass, $redir, $oldtype, $oldpass) = @_;
- my $d = $self->dbUserGet(username => $user, what => 'extended notifycount')->[0];
- return 0 if !$d->{id};
+ if($oldtype eq 'token') {
+ $oldpass = sha1(lc($oldpass));
- # scrypt format
- if(length $d->{passwd} == 46) {
- my($N, $r, $p, $salt) = unpack 'NCCa8', $d->{passwd};
- return 0 if $self->authPreparePass($pass, $salt, $N, $r, $p) ne $d->{passwd};
- $self->{_auth} = $d;
- return 1;
+ } elsif($oldtype eq 'pass') {
+ my $u = $self->dbUserGet(uid => $uid, what => 'scryptargs')->[0];
+ return 0 if !$u->{id} || !$u->{scryptargs} || length($u->{scryptargs}) != 14;
+ my($N, $r, $p, $salt) = unpack 'NCCa8', $u->{scryptargs};
+ $oldpass = _preparepass($self, $oldpass, $salt, $N, $r, $p);
}
- return 0;
+ $pass = _preparepass($self, $pass);
+ return 0 if !$self->dbUserSetPass($uid, $oldpass, $pass);
+ return _createsession($self, $uid, $pass, $redir);
}
-# Prepares a plaintext password for database storage
-# Arguments: pass, optionally: salt, N, r, p
-# Returns: encrypted password (as a binary string)
-sub authPreparePass {
- my($self, $pass, $salt, $N, $r, $p) = @_;
- ($N, $r, $p) = @{$self->{scrypt_args}} if !$N;
- $salt ||= urandom(8);
- return pack 'NCCa8a*', $N, $r, $p, $salt, scrypt_raw($pass, $self->{scrypt_salt} . $salt, $N, $r, $p, 32);
+sub authAdminSetPass {
+ my($self, $uid, $pass) = @_;
+ $pass = _preparepass($self, $pass);
+ $self->dbUserAdminSetPass($uid, $self->authInfo->{id}, $self->authInfo->{token}, $pass);
}
-# Generates a random token that can be used to reset the password.
-# Returns: token (hex string), token-encrypted (binary string)
-sub authPrepareReset {
- my $self = shift;
- my $token = unpack 'H*', urandom(20);
- my $salt = randomascii(9);
- my $token_e = encode_utf8($salt) . sha1(lc($token).$salt);
- return ($token, $token_e);
+# returns a hashref with information about the current loggedin user
+# the hash is identical to the hash returned by dbUserGet
+# returns empty hash if no user is logged in.
+sub authInfo {
+ return shift->{_auth} || {};
}
-# Checks whether the password reset token is valid.
-# Arguments: passwd (binary string), token (hex string)
-sub authValidateReset {
- my($self, $passwd, $token) = @_;
- return 0 if length $passwd != 29;
- my $salt = substr $passwd, 0, 9;
- return 0 if $salt.sha1(lc($token).$salt) ne $passwd;
- return 1;
+# returns whether the currently loggedin or anonymous user can perform
+# a certain action. Argument is the action name as defined in global.pl
+sub authCan {
+ my($self, $act) = @_;
+ return $self->{_auth} ? $self->{_auth}{perm} & $self->{permissions}{$act} : 0;
}