kopia lustrzana https://github.com/elk-zone/elk
fix: auto-recover from OAuth app deletion after token revocation (#3382)
rodzic
7b7334c27a
commit
37a91a0817
|
@ -1,6 +1,6 @@
|
||||||
import { stringifyQuery } from 'ufo'
|
import { stringifyQuery } from 'ufo'
|
||||||
|
|
||||||
import { defaultUserAgent } from '~~/server/utils/shared'
|
import { defaultUserAgent, invalidateApp } from '~~/server/utils/shared'
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
let { server, origin } = getRouterParams(event)
|
let { server, origin } = getRouterParams(event)
|
||||||
|
@ -43,7 +43,51 @@ export default defineEventHandler(async (event) => {
|
||||||
const url = `/signin/callback?${stringifyQuery({ server, token: result.access_token, vapid_key: app.vapid_key })}`
|
const url = `/signin/callback?${stringifyQuery({ server, token: result.access_token, vapid_key: app.vapid_key })}`
|
||||||
await sendRedirect(event, url, 302)
|
await sendRedirect(event, url, 302)
|
||||||
}
|
}
|
||||||
catch {
|
catch (error: any) {
|
||||||
|
// Check for invalid client error (OAuth app deleted)
|
||||||
|
if (error?.data?.error === 'invalid_client'
|
||||||
|
|| (error?.statusCode === 401 && error?.data?.error_description?.includes('Client authentication failed'))) {
|
||||||
|
// Invalidate cached app and retry once
|
||||||
|
await invalidateApp(origin, server)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const newApp = await getApp(origin, server)
|
||||||
|
if (!newApp) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
statusMessage: `Failed to re-register app for server: ${server}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const retryResult: any = await $fetch(`https://${server}/oauth/token`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'user-agent': defaultUserAgent,
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
client_id: newApp.client_id,
|
||||||
|
client_secret: newApp.client_secret,
|
||||||
|
redirect_uri: getRedirectURI(origin, server),
|
||||||
|
grant_type: 'authorization_code',
|
||||||
|
code,
|
||||||
|
scope: 'read write follow push',
|
||||||
|
},
|
||||||
|
retry: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
const url = `/signin/callback?${stringifyQuery({ server, token: retryResult.access_token, vapid_key: newApp.vapid_key })}`
|
||||||
|
await sendRedirect(event, url, 302)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
statusMessage: 'OAuth application recovery failed. Please try again.',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other errors (network, invalid code, etc.)
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
statusMessage: 'Could not complete log in.',
|
statusMessage: 'Could not complete log in.',
|
||||||
|
|
|
@ -111,6 +111,12 @@ export async function deleteApp(server: string) {
|
||||||
await storage.removeItem(key)
|
await storage.removeItem(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function invalidateApp(origin: string, server: string) {
|
||||||
|
const host = origin.replace(/^https?:\/\//, '').replace(/\W/g, '-').replace(/\?.*$/, '')
|
||||||
|
const key = `servers:v4:${server}:${host}.json`.toLowerCase()
|
||||||
|
await storage.removeItem(key)
|
||||||
|
}
|
||||||
|
|
||||||
export async function listServers() {
|
export async function listServers() {
|
||||||
const keys = await storage.getKeys('servers:v4:')
|
const keys = await storage.getKeys('servers:v4:')
|
||||||
const servers = new Set<string>()
|
const servers = new Set<string>()
|
||||||
|
|
Ładowanie…
Reference in New Issue