feat: 🎸 Show correct login error to user

This commit is contained in:
Jin 2025-03-26 00:13:56 +01:00
parent c1ed471403
commit 8f157e04d4
2 changed files with 42 additions and 42 deletions

View File

@ -18,7 +18,8 @@ function loginPage(req: Request, res: Response) {
res.redirect('/authenticate'); res.redirect('/authenticate');
} else { } else {
res.render('login', { res.render('login', {
failedAuth: false, wrongPassword: false,
wrongTotp: false,
totpEnabled: totp.isTotpEnabled(), totpEnabled: totp.isTotpEnabled(),
assetPath: assetPath, assetPath: assetPath,
appPath: appPath, appPath: appPath,
@ -69,38 +70,40 @@ function login(req: Request, res: Response) {
const submittedPassword = req.body.password; const submittedPassword = req.body.password;
const submittedTotp = req.body.token; const submittedTotp = req.body.token;
if (verifyPassword(submittedPassword)) { // 首先验证密码
if (totp.isTotpEnabled()) { if (!verifyPassword(submittedPassword)) {
if (!verifyTOTP(submittedTotp)) { sendLoginError(req, res, 'password');
sendLoginError(req, res); return;
return; }
}
// 如果密码正确且启用了 TOTP验证 TOTP
if (totp.isTotpEnabled()) {
if (!verifyTOTP(submittedTotp)) {
sendLoginError(req, res, 'totp');
return;
}
}
const rememberMe = req.body.rememberMe;
req.session.regenerate(() => {
if (rememberMe) {
req.session.cookie.maxAge = 21 * 24 * 3600000; // 3 weeks
} else {
// unset default maxAge set by sessionParser
// Cookie becomes non-persistent and expires after current browser session (e.g. when browser is closed)
req.session.cookie.maxAge = undefined;
} }
const rememberMe = req.body.rememberMe; // 记录当前的认证状态
req.session.lastAuthState = {
totpEnabled: totp.isTotpEnabled(),
ssoEnabled: open_id.isOpenIDEnabled()
};
req.session.regenerate(() => { req.session.loggedIn = true;
if (rememberMe) { res.redirect('.');
req.session.cookie.maxAge = 21 * 24 * 3600000; // 3 weeks });
} else {
// unset default maxAge set by sessionParser
// Cookie becomes non-persistent and expires after current browser session (e.g. when browser is closed)
req.session.cookie.maxAge = undefined;
}
// 记录当前的认证状态
req.session.lastAuthState = {
totpEnabled: totp.isTotpEnabled(),
ssoEnabled: open_id.isOpenIDEnabled()
};
req.session.loggedIn = true;
res.redirect('.');
});
}
else {
sendLoginError(req, res);
}
} }
function verifyTOTP(submittedToken: string) { function verifyTOTP(submittedToken: string) {
@ -119,17 +122,18 @@ function verifyPassword(submittedPassword: string) {
return guess_hashed.equals(hashed_password); return guess_hashed.equals(hashed_password);
} }
function sendLoginError(req: Request, res: Response) { function sendLoginError(req: Request, res: Response, errorType: 'password' | 'totp' = 'password') {
// note that logged IP address is usually meaningless since the traffic should come from a reverse proxy // note that logged IP address is usually meaningless since the traffic should come from a reverse proxy
if (totp.isTotpEnabled()) { if (totp.isTotpEnabled()) {
log.info(`WARNING: Wrong password or TOTP from ${req.ip}, rejecting.`); log.info(`WARNING: Wrong ${errorType} from ${req.ip}, rejecting.`);
} else { } else {
log.info(`WARNING: Wrong password from ${req.ip}, rejecting.`); log.info(`WARNING: Wrong password from ${req.ip}, rejecting.`);
} }
res.status(401).render('login', { res.render('login', {
failedAuth: true, wrongPassword: errorType === 'password',
totpEnabled: optionService.getOption('totpEnabled') && totp.checkForTotSecret(), wrongTotp: errorType === 'totp',
totpEnabled: totp.isTotpEnabled(),
assetPath: assetPath, assetPath: assetPath,
appPath: appPath, appPath: appPath,
}); });

View File

@ -41,20 +41,16 @@
</div> </div>
<% } %> <% } %>
<% if (failedAuth) { %> <% if ( wrongPassword ) { %>
<div class="alert alert-warning"> <div class="alert alert-warning">
<%= t("login.incorrect-password") %> <%= t("login.incorrect-password") %>
</div> </div>
<% } %> <% } %>
<% if (failedAuth) { %> <% if ( totpEnabled ) { %>
<% if( totpEnabled ) { %> <% if( wrongTotp ) { %>
<div class="alert alert-warning"> <div class="alert alert-warning">
<%= t("login.incorrect-totp") %> <%= t("login.incorrect-totp") %>
</div> </div>
<% }else{ %>
<div class="alert alert-warning">
<%= t("login.incorrect-password") %>
</div>
<% } %> <% } %>
<% } %> <% } %>