summaryrefslogtreecommitdiff
path: root/lib/VNWeb/User/Login.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNWeb/User/Login.pm')
-rw-r--r--lib/VNWeb/User/Login.pm55
1 files changed, 37 insertions, 18 deletions
diff --git a/lib/VNWeb/User/Login.pm b/lib/VNWeb/User/Login.pm
index fa679325..b4ac76da 100644
--- a/lib/VNWeb/User/Login.pm
+++ b/lib/VNWeb/User/Login.pm
@@ -4,19 +4,19 @@ use VNWeb::Prelude;
TUWF::get '/u/login' => sub {
- return tuwf->resRedirect('/', 'temp') if auth;
+ return tuwf->resRedirect('/', 'temp') if auth || config->{read_only};
my $ref = tuwf->reqGet('ref');
$ref = '/' if !$ref || $ref !~ /^\//;
framework_ title => 'Login', sub {
- elm_ 'User.Login' => tuwf->compile({}), $ref;
+ div_ widget(UserLogin => {ref => $ref}), '';
};
};
-elm_api UserLogin => undef, {
- username => { username => 1 },
+js_api UserLogin => {
+ username => {},
password => { password => 1 }
}, sub {
my $data = shift;
@@ -25,37 +25,56 @@ elm_api UserLogin => undef, {
my $tm = tuwf->dbVali(
'SELECT', sql_totime('greatest(timeout, now())'), 'FROM login_throttle WHERE ip =', \$ip
) || time;
- return elm_LoginThrottle if $tm-time() > config->{login_throttle}[1];
+ return +{ _err => 'Too many failed login attempts, please use the password reset form or try again later.' }
+ if $tm-time() > config->{login_throttle}[1];
+
+ my $ismail = $data->{username} =~ /@/;
+ my $mailmsg = 'Invalid username or password.';
+
+ my $u = tuwf->dbRowi('SELECT id, user_getscryptargs(id) x FROM users WHERE',
+ $ismail ? sql('id IN(SELECT uid FROM user_emailtoid(', \$data->{username}, '))')
+ : sql('lower(username) = lower(', \$data->{username}, ')')
+ );
+ # When logging in with an email, make sure we don't disclose whether or not an account with that email exists.
+ if ($ismail && !$u->{id}) {
+ auth->wasteTime; # make timing attacks a bit harder (not 100% perfect, DB lookups & different scrypt args can still influence timing)
+ return +{ _err => $mailmsg };
+ }
+ return +{ _err => 'No user with that name.' } if !$u->{id};
+ return +{ _err => 'Account disabled, please use the password reset form to re-activate your account.' } if !$u->{x};
my $insecure = is_insecurepass $data->{password};
- if(auth->login($data->{username}, $data->{password}, $insecure)) {
- auth->audit(auth->uid, 'login') if !$insecure;
- return $insecure ? elm_InsecurePass : elm_Success
+ my $ret = auth->login($u->{id}, $data->{password}, $insecure);
+ if($ret && $insecure) {
+ return +{ insecurepass => 1, uid => $u->{id} };
+ } elsif (40 == length $ret) {
+ return +{ _redir => "/$u->{id}/del/$ret" };
+ } else {
+ auth->audit(auth->uid, 'login');
+ return +{ ok => 1 };
}
# Failed login, log and update throttle.
- auth->audit(tuwf->dbVali('SELECT id FROM users WHERE username =', \$data->{username}), 'bad password', 'failed login attempt');
+ auth->audit($u->{id}, 'bad password', 'failed login attempt');
my $upd = {
ip => \$ip,
timeout => sql_fromtime $tm + config->{login_throttle}[0]
};
tuwf->dbExeci('INSERT INTO login_throttle', $upd, 'ON CONFLICT (ip) DO UPDATE SET', $upd);
- elm_BadLogin
+ +{ _err => $ismail ? $mailmsg : 'Incorrect password.' }
};
-elm_api UserChangePass => undef, {
- username => { username => 1 },
+js_api UserChangePass => {
+ uid => { vndbid => 'u' },
oldpass => { password => 1 },
newpass => { password => 1 },
}, sub {
my $data = shift;
- my $uid = tuwf->dbVali('SELECT id FROM users WHERE username =', \$data->{username});
- die if !$uid;
- return elm_InsecurePass if is_insecurepass $data->{newpass};
- auth->audit($uid, 'password change', 'after login with an insecure password');
- die if !auth->setpass($uid, undef, $data->{oldpass}, $data->{newpass}); # oldpass should already have been verified.
- elm_Success
+ return +{ _err => 'Your new password has also been leaked.' } if is_insecurepass $data->{newpass};
+ die if !auth->setpass($data->{uid}, undef, $data->{oldpass}, $data->{newpass}); # oldpass should already have been verified.
+ auth->audit($data->{uid}, 'password change', 'after login with an insecure password');
+ {}
};