plugins: finalizingLogin #328
Massimo Melina committed
Feb 21, 2025 at 19:39 UTC
ad1b063d7db30c2aa789c6f850f063846debfe08
4 files changed
+34
-15
dev-plugins.md
+7
@@ -561,6 +561,11 @@ This section is still partially documented, and you may need to have a look at t
561
- async supported
562
- preventable
563
- `failedLogin`
564
+- `finalizingLogin`
565
+ - parameters: { ctx, username, inputs }
566
+ - inputs: object
567
+ - merge of all inputs both from body and URL
568
+ - async supported
569
- `config ready`
570
- `config.KEY` where KEY is the key of a config that has changed
571
- `connectionClosed`
@@ -772,6 +777,8 @@ If you want to override a text regardless of the language, use the special langu
777
778
## API version history
779
780
+- 12.0 (v0.57.0)
781
+ - backend event: finalizingLogin
782
- 11.6 (v0.56.0)
783
- api.setError
784
- frontend events: afterBreadcrumbs, afterFolderStats, afterFilter
frontend/src/login.ts
+17
-12
@@ -26,9 +26,10 @@ async function login(username:string, password:string, extra?: object) {
26
return res
27
}, err => {
28
throw Error(err.message === 'trust' ? t('login_untrusted', "Login aborted: server identity cannot be trusted")
29
- : err.code === HTTP_UNAUTHORIZED ? t('login_bad_credentials', "Invalid credentials")
30
- : err.code === HTTP_CONFLICT ? t('login_bad_cookies', "Cookies not working - login failed")
31
- : t(err.message || String(err)))
29
+ : err.message === 'wrong' ? t('login_bad_credentials', "Invalid credentials")
30
+ : err.code === HTTP_UNAUTHORIZED ? t(err.message) // plugin's custom error
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
@@ -75,7 +76,7 @@ export async function loginDialog(closable=true, reloadAfter=true) {
76
return h('form', {
77
onSubmit(ev:any) {
78
ev.preventDefault()
78
- go()
79
+ go(ev)
80
}
81
},
82
h(CustomCode, { name: 'beforeLogin' }),
@@ -115,18 +116,22 @@ export async function loginDialog(closable=true, reloadAfter=true) {
116
if (key === 'Escape')
117
return close(null)
118
if (key === 'Enter')
118
- return go()
119
+ return go(ev)
120
}
121
121
- async function go(ev?: Event) {
122
- ev?.stopPropagation()
123
- const usr = usrRef.current?.value.trim()
124
- const pwd = pwdRef.current?.value
125
- if (going || !usr || !pwd) return
122
+ async function go(ev: Event) {
123
+ const form = ev.target instanceof HTMLElement && ev.target.closest('form')
124
+ if (!form) return
125
+ ev.stopPropagation()
126
+ const { username, password, ...rest } = Object.fromEntries(Array.from(form.querySelectorAll('[name]'))
127
+ .map(el => el instanceof HTMLInputElement ? [el.name, el.value] : []))
128
+ const u = username.trim()
129
+ if (going || !u || !password) return
130
going = true
131
try {
128
- const res = await login(usr, pwd, {
129
- [CFG.allow_session_ip_change]: ipRef.current?.checked
132
+ const res = await login(u, password, {
133
+ [CFG.allow_session_ip_change]: ipRef.current?.checked,
134
+ ...rest
135
})
136
await close(true)
137
toast(t`Logged in`, 'success')
src/api.auth.ts
+9
-3
@@ -21,9 +21,14 @@ export const login: ApiHandler = async ({ username, password }, ctx) => {
21
return new ApiError(HTTP_BAD_REQUEST)
22
if (!ctx.session)
23
return new ApiError(HTTP_SERVER_ERROR)
24
- const account = await clearTextLogin(ctx, username, password, 'api')
25
- if (!account)
26
- return new ApiError(HTTP_UNAUTHORIZED)
24
+ try {
25
+ const account = await clearTextLogin(ctx, username, password, 'api')
26
+ if (!account)
27
+ return new ApiError(HTTP_UNAUTHORIZED, 'wrong')
28
+ }
29
+ catch (e) {
30
+ return new ApiError(HTTP_UNAUTHORIZED, String(e))
31
+ }
32
return {
33
redirect: ctx.state.account?.redirect,
34
...await refresh_session({},ctx)
@@ -71,6 +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' })
80
await setLoggedIn(ctx, username)
81
return {
82
proof: String(M2),
src/auth.ts
+1
@@ -64,6 +64,7 @@ export async function setLoggedIn(ctx: Context, username: string | false) {
64
}
65
const a = ctx.state.account = getAccount(username)
66
if (!a) return
67
+ await events.emitAsync('finalizingLogin', { ctx, username, inputs: { ...ctx.state.params, ...ctx.query } })
68
s.username = normalizeUsername(username)
69
s.ts = Date.now()
70
const k = CFG.allow_session_ip_change