keystatic icon indicating copy to clipboard operation
keystatic copied to clipboard

Prevent login for people without write access github repo

Open CapitaineToinon opened this issue 2 years ago • 2 comments

Hey there,

I've been trying to setup Keystatic with a Github repo. It works great until I want new people to contribute. I understand that people need write access to use Keystatic but why allow people to login at all? Right now, people can login but get a cryptic error when they try to edit anything:

image

It seems like keystatic cloud handles this, if I try to login to https://keystatic.com/keystatic I get an expected error message:

image

Could we have something similar for the Github integration?

CapitaineToinon avatar Dec 23 '23 16:12 CapitaineToinon

As a work around, I added some code before loading the keystatic admin using a different access token to verify that the current keystatic logged in user has access to my repo. If not, shows an error. For this, I stopped using the astro integration and just imported the UI and the API endpoints to install them manually, like we used to do before the integration.

---
import { Keystatic } from '@/components/keystatic'
import { Octokit } from '@octokit/core'
import { z } from 'astro:content'
import Layout from '@/layouts/default.astro'
import { ExclamationTriangleIcon } from '@radix-ui/react-icons'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import config from 'keystatic.config'

export const prerender = false

const accessToken = Astro.cookies.get('keystatic-gh-access-token')
let error: { title: string; message: string } | undefined = undefined

if (config.storage.kind === 'github' && accessToken) {
	const souls = new Octokit({
		auth: import.meta.env.SOULS_PERSONAL_ACCESS_TOKEN,
	})

	const keystatic = new Octokit({
		auth: accessToken.value,
	})

	try {
		const me = await keystatic.request('GET /user', {
			headers: {
				'X-GitHub-Api-Version': '2022-11-28',
			},
		})

		await souls.request('GET /repos/{owner}/{repo}/collaborators/{username}', {
			owner: 'soulsspeedruns',
			repo: 'website',
			username: me.data.login,
			headers: {
				'X-GitHub-Api-Version': '2022-11-28',
			},
		})
	} catch (e) {
		const result = z.object({ status: z.literal(404) }).safeParse(e)

		if (result.success) {
			error = {
				title: 'Forbidden',
				message: `The user is not a verified contributor.`,
			}

			Astro.response.status = 403
		} else {
			console.log(e)
			throw e
		}
	}
}
---

{
	error ? (
		<Layout title="Unauthorized">
			<main class="container mx-auto mt-20 grid grid-cols-10">
				<div class="col-span-6 col-start-3">
					<Alert
						variant="destructive"
						className="mb-6"
					>
						<ExclamationTriangleIcon className="h-4 w-4" />
						<AlertTitle>{error.title}</AlertTitle>
						<AlertDescription>{error.message}</AlertDescription>
					</Alert>
					<p class="prose max-w-none dark:prose-invert">
						Please check <a href="/contribute">how to contribute</a>.
					</p>
				</div>
			</main>
		</Layout>
	) : (
		<Keystatic client:only="react" />
	)
}

I had to use a different access token because for some reason I just couldn't get the correct api information using the keystatic token. Not really sure why, not that familiar with github scopes and stuff. Works for now though.

CapitaineToinon avatar Dec 27 '23 12:12 CapitaineToinon

+1

AliMejbar avatar Mar 22 '24 03:03 AliMejbar