kopia lustrzana https://github.com/cloudflare/wildebeest
commit
a97dbfa814
|
@ -1,6 +1,7 @@
|
|||
import { component$ } from '@builder.io/qwik'
|
||||
import { Link, useLocation } from '@builder.io/qwik-city'
|
||||
import { WildebeestLogo } from '~/components/MastodonLogo'
|
||||
import { accessLoader } from '~/routes/layout'
|
||||
|
||||
type LinkConfig = {
|
||||
iconName: string
|
||||
|
@ -10,6 +11,7 @@ type LinkConfig = {
|
|||
}
|
||||
|
||||
export default component$(() => {
|
||||
const accessData = accessLoader.use().value
|
||||
const location = useLocation()
|
||||
|
||||
const renderNavLink = ({ iconName, linkText, linkTarget, linkActiveRegex }: LinkConfig) => {
|
||||
|
@ -52,6 +54,21 @@ export default component$(() => {
|
|||
<hr class="border-t border-wildebeest-700 my-3" />
|
||||
{renderNavLink(aboutLink)}
|
||||
</div> */}
|
||||
|
||||
{!accessData.isAuthorized && (
|
||||
<a
|
||||
class="w-full block mb-4 no-underline text-center bg-wildebeest-vibrant-600 hover:bg-wildebeest-vibrant-500 p-2 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"
|
||||
href={accessData.loginUrl}
|
||||
>
|
||||
Sign in
|
||||
</a>
|
||||
)}
|
||||
{accessData.isAuthorized && (
|
||||
<a class="text-semi no-underline" href="/settings/migration">
|
||||
<i class="fa fa-gear mx-3 w-4" />
|
||||
Preferences
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
import { component$, useStore, useSignal, $ } from '@builder.io/qwik'
|
||||
import { loader$ } from '@builder.io/qwik-city'
|
||||
import { WildebeestEnv } from '~/types'
|
||||
import { checkAuth } from '~/utils/checkAuth'
|
||||
|
||||
export const loader = loader$<WildebeestEnv, void>(async ({ request, platform, redirect }) => {
|
||||
const isAuthorized = await checkAuth(request, platform)
|
||||
|
||||
if (!isAuthorized) {
|
||||
redirect(303, '/explore')
|
||||
}
|
||||
})
|
||||
|
||||
export default component$(() => {
|
||||
const ref = useSignal<Element>()
|
||||
const state = useStore({ alias: '' })
|
||||
const toast = useSignal<'success' | 'failure' | null>(null)
|
||||
|
||||
const handleInput = $((event: Event) => {
|
||||
state.alias = (event.target as HTMLInputElement).value
|
||||
})
|
||||
|
||||
const handleSubmit = $(async () => {
|
||||
const res = await fetch('/api/wb/settings/account/alias', { method: 'POST', body: JSON.stringify(state) })
|
||||
if (res.status == 200) {
|
||||
toast.value = 'success'
|
||||
} else {
|
||||
toast.value = 'failure'
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<form ref={ref} class="login-form" preventdefault:submit onSubmit$={handleSubmit}>
|
||||
<div class="max-w-4xl py-14 px-8">
|
||||
<h2 class="text-2xl font-bold mb-6">Account Aliases</h2>
|
||||
|
||||
{toast.value === 'success' && (
|
||||
<div class="bg-green-800 border-green-700 text-green-100 border mb-5 p-5 text-center rounded">
|
||||
Successfully created a new alias. You can now initiate the move from the old account.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{toast.value === 'failure' && (
|
||||
<div class="bg-red-800 border-red-700 text-red-100 border mb-5 p-5 text-center rounded">
|
||||
Failed to create alias.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p class="text-sm text-wildebeest-400 mb-10">
|
||||
If you want to move from another account to this one, here you can create an alias, which is required before
|
||||
you can proceed with moving followers from the old account to this one. This action by itself is harmless and
|
||||
reversible. The account migration is initiated from the old account.
|
||||
</p>
|
||||
|
||||
<div class="my-5">
|
||||
<label class="font-semibold mb-3" for="alias">
|
||||
Handle of the old account
|
||||
<span class="ml-1 text-red-500">*</span>
|
||||
</label>
|
||||
<div class="text-sm text-wildebeest-400">
|
||||
Specify the username@domain of the account you want to move from
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
class="bg-black text-white p-3 rounded outline-none border border-black hover:border-wildebeest-vibrant-500 focus:border-wildebeest-vibrant-500 w-full mb-5"
|
||||
type="text"
|
||||
id="alias"
|
||||
name="alias"
|
||||
value={state.alias}
|
||||
onInput$={handleInput}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full uppercase mb-9 bg-wildebeest-vibrant-600 hover:bg-wildebeest-vibrant-500 p-2 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"
|
||||
>
|
||||
Create Alias
|
||||
</button>
|
||||
|
||||
{/* <table class="table-auto w-full">
|
||||
<thead class="border-gray-600 border-b-2">
|
||||
<th class="text-left py-2">Handle of the old account</th>
|
||||
<th></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-gray-600 border-t">
|
||||
<td class="py-2">test</td>
|
||||
<td class="py-2">
|
||||
<div class="text-wildebeest-400 hover:text-white cursor-pointer">
|
||||
<i class="fa fa-trash fa-fw fa-xs mr-1" />
|
||||
Unlink Alias
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="border-gray-600 border-t">
|
||||
<td class="py-2">test 2</td>
|
||||
<td class="py-2">
|
||||
<div class="text-wildebeest-400 hover:text-white cursor-pointer">
|
||||
<i class="fa fa-trash fa-fw fa-xs mr-1" />
|
||||
Unlink Alias
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table> */}
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
})
|
|
@ -0,0 +1,6 @@
|
|||
import { component$ } from '@builder.io/qwik'
|
||||
|
||||
export default component$(() => {
|
||||
// In the future, a settings homepage will be here
|
||||
return <div></div>
|
||||
})
|
|
@ -0,0 +1,42 @@
|
|||
import { component$, Slot } from '@builder.io/qwik'
|
||||
import { WildebeestLogo } from '~/components/MastodonLogo'
|
||||
|
||||
export default component$(() => {
|
||||
return (
|
||||
<div class="flex w-screen min-h-screen justify-center">
|
||||
<AccountSidebar />
|
||||
<div class="flex-auto">
|
||||
<Slot />
|
||||
</div>
|
||||
<div class="flex-auto" />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export const AccountSidebar = component$(() => {
|
||||
return (
|
||||
<div class="bg-wildebeest-800 min-h-full flex-auto">
|
||||
<div class="flex flex-col items-end">
|
||||
<div class="my-12 mr-6">
|
||||
<WildebeestLogo size="large" />
|
||||
</div>
|
||||
<a class="text-semi no-underline text-wildebeest-vibrant-400 bg-transparent p-4" href="/">
|
||||
<i class="fa fa-chevron-left mr-2 w-3 inline-block" />
|
||||
<span class="hover:underline">Back to Wildebeest</span>
|
||||
</a>
|
||||
<ul class="mr-5">
|
||||
{/* <li class="mb-3">
|
||||
<a class="no-underline text-right text-wildebeest-400 hover:text-wildebeest-200" href="/settings/migration">
|
||||
Account Migration
|
||||
</a>
|
||||
</li> */}
|
||||
<li class="mb-3">
|
||||
<a class="no-underline text-right text-wildebeest-400 hover:text-wildebeest-200" href="/settings/aliases">
|
||||
Account Aliases
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
|
@ -0,0 +1,98 @@
|
|||
import { component$ } from '@builder.io/qwik'
|
||||
import { loader$ } from '@builder.io/qwik-city'
|
||||
import { WildebeestEnv } from '~/types'
|
||||
// import { checkAuth } from '~/utils/checkAuth'
|
||||
|
||||
export const loader = loader$<WildebeestEnv, void>(async ({ redirect }) => {
|
||||
// Hiding this page for now
|
||||
redirect(303, '/explore')
|
||||
|
||||
// const isAuthorized = await checkAuth(request, platform)
|
||||
|
||||
// if (!isAuthorized) {
|
||||
// redirect(303, '/explore')
|
||||
// }
|
||||
})
|
||||
|
||||
export default component$(() => {
|
||||
return (
|
||||
<div class="max-w-4xl py-14 px-8">
|
||||
<h2 class="text-2xl font-bold mb-10">Account Migration</h2>
|
||||
|
||||
<div class="text-green-700 mb-10">Your account is not currently being redirected to any other account.</div>
|
||||
|
||||
<h3 class="text-xl mb-6">Move to a different account</h3>
|
||||
|
||||
<p class="text-sm text-wildebeest-400 mb-5">Before proceeding, please read these notes carefully:</p>
|
||||
|
||||
<ul class="list-disc list-inside text-sm text-yellow-500 mb-5">
|
||||
<li class="pb-1">This action will move all followers from the current account to the new account</li>
|
||||
<li class="pb-1">
|
||||
Your current account's profile will be updated with a redirect notice and be excluded from searches
|
||||
</li>
|
||||
<li class="pb-1">No other data will be moved automatically</li>
|
||||
<li class="pb-1">The new account must first be configured to back-reference this one</li>
|
||||
<li class="pb-1">After moving there is a waiting period during which you will not be able to move again</li>
|
||||
<li class="pb-1">
|
||||
Your current account will not be fully usable afterwards. However, you will have access to data export as well
|
||||
as re-activation.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="text-sm text-wildebeest-400 mb-10">
|
||||
Alternatively, you can <a href="/settings/aliases">only put up a redirect on your profile. </a>
|
||||
</p>
|
||||
|
||||
<div class="flex">
|
||||
<div class="pr-3">
|
||||
<div class="my-5">
|
||||
<label class="font-semibold mb-3" for="old-account">
|
||||
Handle of the new account
|
||||
<span class="ml-1 text-red-500">*</span>
|
||||
</label>
|
||||
<div class="text-sm text-wildebeest-400">
|
||||
Specify the username@domain of the account you want to move to
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
class="bg-black text-white p-3 rounded outline-none border border-black hover:border-wildebeest-vibrant-500 focus:border-wildebeest-vibrant-500 w-full mb-5"
|
||||
type="text"
|
||||
name="old-account"
|
||||
id="old-account"
|
||||
/>
|
||||
</div>
|
||||
<div class="pl-3">
|
||||
<div class="my-5">
|
||||
<label class="font-semibold mb-3" for="password">
|
||||
Current Password
|
||||
<span class="ml-1 text-red-500">*</span>
|
||||
</label>
|
||||
<div class="text-sm text-wildebeest-400">
|
||||
For security purposes please enter the password of the current account
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
class="bg-black text-white p-3 rounded outline-none border border-red-500 hover:border-wildebeest-vibrant-500 focus:border-wildebeest-vibrant-500 w-full mb-5"
|
||||
type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full mb-10 uppercase bg-wildebeest-vibrant-600 hover:bg-wildebeest-vibrant-500 p-2 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"
|
||||
>
|
||||
Create Alias
|
||||
</button>
|
||||
|
||||
<h3 class="text-xl mt-4 mb-8">Moving from a different account</h3>
|
||||
|
||||
<p class="text-sm text-wildebeest-400 mb-5">
|
||||
To move from another account to this one, first you need to{' '}
|
||||
<a href="/settings/aliases">create an account alias</a>.
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
})
|
|
@ -0,0 +1,31 @@
|
|||
import { component$, Slot } from '@builder.io/qwik'
|
||||
import { loader$ } from '@builder.io/qwik-city'
|
||||
import * as access from 'wildebeest/backend/src/access'
|
||||
import { WildebeestEnv } from '~/types'
|
||||
import { checkAuth } from '~/utils/checkAuth'
|
||||
|
||||
type AccessLoaderData = {
|
||||
loginUrl: string
|
||||
isAuthorized: boolean
|
||||
}
|
||||
|
||||
export const accessLoader = loader$<WildebeestEnv, Promise<AccessLoaderData>>(async ({ platform, request }) => {
|
||||
const isAuthorized = await checkAuth(request, platform)
|
||||
|
||||
return {
|
||||
isAuthorized,
|
||||
loginUrl: access.generateLoginURL({
|
||||
redirectURL: request.url,
|
||||
domain: platform.ACCESS_AUTH_DOMAIN,
|
||||
aud: platform.ACCESS_AUD,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
export default component$(() => {
|
||||
return (
|
||||
<>
|
||||
<Slot />
|
||||
</>
|
||||
)
|
||||
})
|
|
@ -216,3 +216,8 @@ export type History = {
|
|||
accounts: string
|
||||
uses: string
|
||||
}
|
||||
|
||||
export type WildebeestEnv = {
|
||||
ACCESS_AUTH_DOMAIN: string
|
||||
ACCESS_AUD: string
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { RequestContext } from '@builder.io/qwik-city/middleware/request-handler'
|
||||
import * as access from 'wildebeest/backend/src/access'
|
||||
|
||||
type Env = {
|
||||
ACCESS_AUTH_DOMAIN: string
|
||||
ACCESS_AUD: string
|
||||
}
|
||||
|
||||
export const checkAuth = async (request: RequestContext, platform: Env) => {
|
||||
const jwt = request.headers.get('Cf-Access-Jwt-Assertion') || ''
|
||||
if (!jwt) return false
|
||||
|
||||
try {
|
||||
const validate = access.generateValidator({
|
||||
jwt,
|
||||
domain: platform.ACCESS_AUTH_DOMAIN,
|
||||
aud: platform.ACCESS_AUD,
|
||||
})
|
||||
await validate(new Request(request.url))
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
||||
const identity = await access.getIdentity({ jwt, domain: platform.ACCESS_AUTH_DOMAIN })
|
||||
if (identity) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -38,8 +38,8 @@
|
|||
"pages": "NO_D1_WARNING=true wrangler pages",
|
||||
"database:migrate": "yarn d1 migrations apply DATABASE",
|
||||
"database:create-mock": "rm -f .wrangler/state/d1/DATABASE.sqlite3 && CI=true yarn database:migrate --local && node ./frontend/mock-db/run.mjs",
|
||||
"dev": "export COMMIT_HASH=$(git rev-parse HEAD) && yarn build && yarn database:migrate --local && yarn pages dev frontend/dist --d1 DATABASE --persist --compatibility-date=2022-12-20 --binding 'INSTANCE_TITLE=Test Wildebeest' 'INSTANCE_DESCR=My Wildebeest Instance' --live-reload",
|
||||
"ci-dev-test-ui": "yarn build && yarn database:create-mock && yarn pages dev frontend/dist --d1 DATABASE --persist --port 8788 --binding 'INSTANCE_TITLE=Test Wildebeest' 'INSTANCE_DESCR=My Wildebeest Instance' --compatibility-date=2022-12-20",
|
||||
"dev": "export COMMIT_HASH=$(git rev-parse HEAD) && yarn build && yarn database:migrate --local && yarn pages dev frontend/dist --d1 DATABASE --persist --compatibility-date=2022-12-20 --binding 'INSTANCE_TITLE=Test Wildebeest' 'INSTANCE_DESCR=My Wildebeest Instance' 'ACCESS_AUTH_DOMAIN=0.0.0.0.cloudflareaccess.com' 'ACCESS_AUD=DEV_AUD' --live-reload",
|
||||
"ci-dev-test-ui": "yarn build && yarn database:create-mock && yarn pages dev frontend/dist --d1 DATABASE --persist --port 8788 --binding 'INSTANCE_TITLE=Test Wildebeest' 'INSTANCE_DESCR=My Wildebeest Instance' 'ACCESS_AUTH_DOMAIN=0.0.0.0.cloudflareaccess.com' 'ACCESS_AUD=DEV_AUD' --compatibility-date=2022-12-20",
|
||||
"deploy:init": "yarn pages project create wildebeest && yarn d1 create wildebeest",
|
||||
"deploy": "yarn build && yarn database:migrate && yarn pages publish frontend/dist --project-name=wildebeest"
|
||||
},
|
||||
|
|
Ładowanie…
Reference in New Issue