fix: auto-recover from OAuth app deletion after token revocation (#3382)

pull/3387/head
abcb1122 2025-09-22 07:35:24 -05:00 zatwierdzone przez GitHub
rodzic 7b7334c27a
commit 37a91a0817
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
2 zmienionych plików z 52 dodań i 2 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
import { stringifyQuery } from 'ufo'
import { defaultUserAgent } from '~~/server/utils/shared'
import { defaultUserAgent, invalidateApp } from '~~/server/utils/shared'
export default defineEventHandler(async (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 })}`
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({
statusCode: 400,
statusMessage: 'Could not complete log in.',

Wyświetl plik

@ -111,6 +111,12 @@ export async function deleteApp(server: string) {
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() {
const keys = await storage.getKeys('servers:v4:')
const servers = new Set<string>()