diff --git a/packages/frontend/src/pages/auth.vue b/packages/frontend/src/pages/auth.vue index 124323a483..1454af63d2 100644 --- a/packages/frontend/src/pages/auth.vue +++ b/packages/frontend/src/pages/auth.vue @@ -55,12 +55,33 @@ const props = defineProps<{ token: string; }>(); +const getUrlParams = () => + window.location.search + .substring(1) + .split("&") + .reduce((result, query) => { + const [k, v] = query.split("="); + result[k] = decodeURI(v); + return result; + }, {}); + let state = $ref<'waiting' | 'accepted' | 'fetch-session-error' | 'denied' | null>(null); let session = $ref(null); function accepted() { state = 'accepted'; - if (session && session.app.callbackUrl) { + const isMastodon = !!getUrlParams().mastodon; + if (session && session.app.callbackUrl && isMastodon) { + const redirectUri = decodeURIComponent(getUrlParams().redirect_uri); + if (!session.app.callbackUrl.split("\n").includes(redirectUri)) { + state = "fetch-session-error"; + throw new Error("Callback URI doesn't match registered app"); + } + const callbackUrl = new URL(redirectUri); + callbackUrl.searchParams.append("code", session.token); + if (getUrlParams().state) callbackUrl.searchParams.append("state", getUrlParams().state); + location.href = callbackUrl.toString(); + } else if (session && session.app.callbackUrl) { const url = new URL(session.app.callbackUrl); if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(url.protocol)) throw new Error('invalid url'); location.href = `${session.app.callbackUrl}?token=${session.token}`;