summaryrefslogtreecommitdiff
path: root/lib/VNDB/Util/Auth.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNDB/Util/Auth.pm')
-rw-r--r--lib/VNDB/Util/Auth.pm140
1 files changed, 70 insertions, 70 deletions
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;
}