kopia lustrzana https://github.com/cloudflare/wildebeest
style authorization screen
rodzic
c4b26c6353
commit
65af6ca9bc
|
@ -1,9 +1,11 @@
|
|||
import { component$ } from '@builder.io/qwik'
|
||||
import type { Account } from '~/types'
|
||||
|
||||
type AvatarDetails = Pick<Account, 'display_name' | 'avatar' | 'url'>
|
||||
|
||||
type Props = {
|
||||
primary: Account
|
||||
secondary: Account | null
|
||||
primary: AvatarDetails
|
||||
secondary: AvatarDetails | null
|
||||
}
|
||||
|
||||
export const Avatar = component$<Props>(({ primary, secondary }) => {
|
||||
|
|
|
@ -4,6 +4,8 @@ import type { Client } from 'wildebeest/backend/src/mastodon/client'
|
|||
import { getClientById } from 'wildebeest/backend/src/mastodon/client'
|
||||
import { DocumentHead, loader$ } from '@builder.io/qwik-city'
|
||||
import { WildebeestLogo } from '~/components/MastodonLogo'
|
||||
import { Avatar } from '~/components/avatar'
|
||||
import { getPersonByEmail } from 'wildebeest/backend/src/activitypub/actors'
|
||||
|
||||
export const clientLoader = loader$<{ DATABASE: D1Database }, Promise<Client>>(async ({ platform, query }) => {
|
||||
const client_id = query.get('client_id') || ''
|
||||
|
@ -14,50 +16,103 @@ export const clientLoader = loader$<{ DATABASE: D1Database }, Promise<Client>>(a
|
|||
return client
|
||||
})
|
||||
|
||||
export const userLoader = loader$<{ DATABASE: D1Database; domain: string }, Promise<{ email: string }>>(
|
||||
async ({ cookie }) => {
|
||||
const jwt = cookie.get('CF_Authorization')
|
||||
if (jwt === null) {
|
||||
throw new Error('missing authorization')
|
||||
}
|
||||
try {
|
||||
// TODO: eventually, verify the JWT with Access, however this
|
||||
// is not critical.
|
||||
const payload = access.getPayload(jwt.value)
|
||||
return { email: payload.email }
|
||||
} catch (err: unknown) {
|
||||
console.warn(err.stack)
|
||||
throw new Error('failed to validate Access JWT')
|
||||
}
|
||||
export const userLoader = loader$<
|
||||
{ DATABASE: D1Database; domain: string },
|
||||
Promise<{ email: string; avatar: URL; name: string; url: URL }>
|
||||
>(async ({ cookie, platform }) => {
|
||||
const jwt = cookie.get('CF_Authorization')
|
||||
if (jwt === null) {
|
||||
throw new Error('missing authorization')
|
||||
}
|
||||
)
|
||||
let payload: access.JWTPayload
|
||||
try {
|
||||
// TODO: eventually, verify the JWT with Access, however this
|
||||
// is not critical.
|
||||
payload = access.getPayload(jwt.value)
|
||||
} catch (err: unknown) {
|
||||
console.warn((err as { stack: unknown }).stack)
|
||||
throw new Error('failed to validate Access JWT')
|
||||
}
|
||||
|
||||
if (!payload.email) {
|
||||
throw new Error("The Access JWT doesn't contain an email")
|
||||
}
|
||||
|
||||
const person = await getPersonByEmail(platform.DATABASE, payload.email)
|
||||
if (!person) {
|
||||
throw new Error(`Failed to fetch a person from the provided email (${payload.email})`)
|
||||
}
|
||||
|
||||
const name = person.name
|
||||
const avatar = person.icon?.url
|
||||
const url = person.url
|
||||
|
||||
if (!name || !avatar) {
|
||||
throw new Error(`The person associated with the Access JWT does't include a name or avatar`)
|
||||
}
|
||||
|
||||
return { email: payload.email, avatar, name, url }
|
||||
})
|
||||
|
||||
export default component$(() => {
|
||||
const client = clientLoader.use().value
|
||||
const user = userLoader.use().value
|
||||
const { email, avatar, name: display_name, url } = userLoader.use().value
|
||||
return (
|
||||
<div class="flex flex-col p-5 items-center">
|
||||
<h1 class="text-center mt-7 mb-9 flex items-center">
|
||||
<WildebeestLogo size="large" />
|
||||
<div class="flex flex-col p-4 items-center">
|
||||
<h1 class="text-center mt-3 mb-5 flex items-center">
|
||||
<WildebeestLogo size="medium" />
|
||||
</h1>
|
||||
<div class="text-left">
|
||||
<p>Signed in as: {user.email}.</p>
|
||||
<p>
|
||||
<a href="/cdn-cgi/access/logout">Click here to change account</a>.
|
||||
<hr class="border-t-0 border-b border-wildebeest-700 w-full mb-10" />
|
||||
<div class="max-w-lg text-left">
|
||||
<div class="border-b border-wildebeest-700 pb-10 mx-auto mt-5 mb-[5rem] flex flex-wrap justify-between gap-4 items-center">
|
||||
<div class="grid grid-rows-[repeat(2,_1fr)] grid-cols-[max-content,_1fr] items-center">
|
||||
<div class="row-span-2 mr-4">
|
||||
<Avatar
|
||||
primary={{
|
||||
avatar: avatar.toString(),
|
||||
display_name,
|
||||
url: url.toString(),
|
||||
}}
|
||||
secondary={null}
|
||||
/>
|
||||
</div>
|
||||
<p class="col-start-2">Signed in as:</p>
|
||||
<p class="col-start-2 font-bold">{email}</p>
|
||||
</div>
|
||||
<a
|
||||
class="no-underline col-start-3 row-span-full ml-auto"
|
||||
href="/cdn-cgi/access/logout"
|
||||
aria-label="Change Account"
|
||||
>
|
||||
<div class="text-wildebeest-500 opacity-40 hover:opacity-70 focus:opacity-70 flex items-baseline">
|
||||
<i class="fa fa-right-from-bracket text-[2.2rem]" />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<h2 class="text text-xl font-semibold mb-5">Authorization required</h2>
|
||||
<p class="mb-10">
|
||||
<strong class="text-[1rem]">{client.name}</strong>
|
||||
<span class="text-wildebeest-400">
|
||||
{' '}
|
||||
would like permission to access your account. It is a third-party application.
|
||||
</span>
|
||||
<strong class="text-[1rem]"> If you do not trust it, then you should not authorize it.</strong>
|
||||
</p>
|
||||
<h2 class="text text-xl font-semibold mb-5">Review permissions</h2>
|
||||
<div class="mb-5 grid grid-rows-[repeat(2,_1fr)] grid-cols-[max-content,_1fr] items-center bg-wildebeest-800 border border-wildebeest-600 p-4 rounded-md">
|
||||
<i class="fa-solid fa-check col-span-1 row-span-full text-[1.3rem] ml-2 mr-5 text-green-500 w-[1.5rem]"></i>
|
||||
<strong class="col-start-2">Everything</strong>
|
||||
<span class="col-start-2">Read and write access</span>
|
||||
</div>
|
||||
<form method="post" class="flex flex-col w-full">
|
||||
<button
|
||||
type="submit"
|
||||
class="mx-auto px-9 my-9 uppercase font-semibold bg-wildebeest-vibrant-600 hover:bg-wildebeest-vibrant-500 p-3 text-white text-uppercase border-wildebeest-vibrant-600 text-lg text-semi outline-none border rounded hover:border-wildebeest-vibrant-500 focus:border-wildebeest-vibrant-500"
|
||||
>
|
||||
Authorize
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<p class="text-left">
|
||||
<b>{client.name}</b> would like permission to access your account. It is a third-party application. If you do
|
||||
not trust it, then you should not authorize it.
|
||||
</p>
|
||||
<form method="post" class="flex flex-col w-full max-w-md">
|
||||
<button
|
||||
type="submit"
|
||||
class="mb-9 bg-wildebeest-vibrant-600 hover:bg-wildebeest-vibrant-500 p-3 text-white text-uppercase border-wildebeest-vibrant-600 text-lg text-semi outline-none border rounded hover:border-wildebeest-vibrant-500 focus:border-wildebeest-vibrant-500"
|
||||
>
|
||||
Authorize
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
Ładowanie…
Reference in New Issue