fix: (regression beta) wrong message failing login
Massimo Melina committed
Apr 21, 2025 at 17:47 UTC
a2f0f693d43c5e6aa1c7f88d21a1af0c7db452f4
4 files changed
+15
-10
e2e/frontend.spec.ts
+7
-1
@@ -15,10 +15,16 @@ test('around1', async ({ page }) => {
15
await page.getByRole('button', { name: 'Login' }).click();
16
await expect(page.getByRole('dialog', {})).toBeVisible();
17
await screenshot(page);
18
- await page.getByRole('textbox', { name: 'Username' }).fill(username);
18
+
19
+ await page.getByRole('textbox', { name: 'Username' }).fill(username + '!'); // wrong username
20
await page.getByRole('textbox', { name: 'Username' }).press('Tab');
21
await page.getByRole('textbox', { name: 'Password' }).fill(password);
22
await page.getByRole('button', { name: 'Continue' }).click();
23
+ await expect(page.getByText('x!ErrorInvalid credentials')).toBeVisible();
24
+ await page.getByRole('alertdialog').getByRole('button', { name: 'Close' }).click();
25
+
26
+ await page.getByRole('textbox', { name: 'Username' }).fill(username);
27
+ await page.getByRole('button', { name: 'Continue' }).click();
28
await page.locator('div').filter({ hasText: 'Logged in' }).nth(3).click();
29
await screenshot(page);
30
await page.getByRole('button', { name: username }).click();
frontend/src/login.ts
+4
-5
@@ -26,11 +26,10 @@ async function login(username:string, password:string, extra?: object) {
26
state.loginRequired = false
27
return res
28
}, err => {
29
- throw Error(err.message === 'trust' ? t('login_untrusted', "Login aborted: server identity cannot be trusted")
30
- : err.message === 'wrong' ? t('login_bad_credentials', "Invalid credentials")
31
- : err.code === HTTP_UNAUTHORIZED ? t(err.message) // plugin's custom error
32
- : err.code === HTTP_CONFLICT ? t('login_bad_cookies', "Cookies not working - login failed")
33
- : t(err.message || String(err)) )
29
+ throw Error(err.data === 'trust' ? t('login_untrusted', "Login aborted: server identity cannot be trusted")
30
+ : err.code === HTTP_UNAUTHORIZED && !err.data ? t('login_bad_credentials', "Invalid credentials") // err.data is empty on standard errors, but a plugin may want to show differently
31
+ : err.code === HTTP_CONFLICT ? t('login_bad_cookies', "Cookies not working - login failed")
32
+ : t(err.message || String(err)) )
33
}).finally(stopWorking)
34
}
35
shared/api.ts
+1
-1
@@ -57,7 +57,7 @@ export function apiCall<T=any>(cmd: string, params?: Dict, options: ApiCallOptio
57
console.debug(res.ok ? 'API' : 'API FAILED', cmd, params??'', '>>', data)
58
await options.onResponse?.(res, data)
59
if (!res.ok)
60
- throw new ApiError(res.status, data === undefined ? body : `Failed API ${cmd}: ${res.statusText}`, data)
60
+ throw new ApiError(res.status, data === body ? body : `Failed API ${cmd}: ${res.statusText}`, data)
61
return data as Awaited<T extends (...args: any[]) => infer R ? Awaited<R> : T>
62
}, err => {
63
stop?.()
src/api.auth.ts
+3
-3
@@ -24,7 +24,7 @@ export const login: ApiHandler = async ({ username, password }, ctx) => {
24
try {
25
const account = await clearTextLogin(ctx, username, password, 'api')
26
if (!account)
27
- return new ApiError(HTTP_UNAUTHORIZED, 'wrong')
27
+ return new ApiError(HTTP_UNAUTHORIZED)
28
}
29
catch (e) {
30
return new ApiError(HTTP_UNAUTHORIZED, String(e))
@@ -76,7 +76,7 @@ export const loginSrp2: ApiHandler = async ({ pubKey, proof }, ctx) => {
76
return new ApiError(HTTP_NOT_FOUND)
77
try {
78
const M2 = await step1.step2(BigInt(pubKey), BigInt(proof))
79
- .catch(() => { throw 'wrong' })
79
+ .catch(() => { throw '' })
80
await setLoggedIn(ctx, username)
81
return {
82
proof: String(M2),
@@ -88,7 +88,7 @@ export const loginSrp2: ApiHandler = async ({ pubKey, proof }, ctx) => {
88
ctx.logExtra({ u: username })
89
ctx.state.dontLog = false // log even if log_api is false
90
events.emit('failedLogin', ctx, { username })
91
- return new ApiError(HTTP_UNAUTHORIZED, String(e))
91
+ return new ApiError(HTTP_UNAUTHORIZED, e ? String(e) : undefined)
92
}
93
finally {
94
delete ongoingLogins[sid]