style authorization screen

pull/159/head
Dario Piotrowicz 2023-01-30 22:40:11 +00:00
rodzic c4b26c6353
commit 65af6ca9bc
2 zmienionych plików z 95 dodań i 38 usunięć

Wyświetl plik

@ -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 }) => {

Wyświetl plik

@ -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>
)
})