MOW-100: protect first-login behind Access

pull/144/head
Sven Sauleau 2023-01-20 15:03:52 +00:00
rodzic 87581e235d
commit e00f05cdf2
2 zmienionych plików z 56 dodań i 11 usunięć

Wyświetl plik

@ -104,12 +104,11 @@ describe('Mastodon APIs', () => {
assert.equal(count, 0)
})
test('first login creates the user and redirects', async () => {
test('first login is protected by Access', async () => {
const db = await makeDB()
const params = new URLSearchParams({
redirect_uri: 'https://redirect.com/a',
email: 'a@cloudflare.com',
})
const formData = new FormData()
@ -120,7 +119,29 @@ describe('Mastodon APIs', () => {
method: 'POST',
body: formData,
})
const res = await first_login.handlePostRequest(req, db, userKEK)
const res = await first_login.handlePostRequest(req, db, userKEK, accessDomain, accessAud)
assert.equal(res.status, 401)
})
test('first login creates the user and redirects', async () => {
const db = await makeDB()
const params = new URLSearchParams({
redirect_uri: 'https://redirect.com/a',
})
const formData = new FormData()
formData.set('username', 'username')
formData.set('name', 'name')
const req = new Request('https://example.com/first-login?' + params, {
method: 'POST',
body: formData,
headers: {
cookie: `CF_Authorization=${TEST_JWT}`,
},
})
const res = await first_login.handlePostRequest(req, db, userKEK, accessDomain, accessAud)
assert.equal(res.status, 302)
const location = res.headers.get('location')
@ -129,7 +150,7 @@ describe('Mastodon APIs', () => {
const actor = await db.prepare('SELECT * FROM actors').first()
const properties = JSON.parse(actor.properties)
assert.equal(actor.email, 'a@cloudflare.com')
assert.equal(actor.email, 'sven@cloudflare.com')
assert.equal(properties.preferredUsername, 'username')
assert.equal(properties.name, 'name')
assert(isUrlValid(actor.id))

Wyświetl plik

@ -3,17 +3,41 @@
import type { Env } from 'wildebeest/backend/src/types/env'
import type { ContextData } from 'wildebeest/backend/src/types/context'
import { createPerson } from 'wildebeest/backend/src/activitypub/actors'
import { parse } from 'cookie'
import * as errors from 'wildebeest/backend/src/errors'
import * as access from 'wildebeest/backend/src/access'
export const onRequestPost: PagesFunction<Env, any, ContextData> = async ({ request, env }) => {
return handlePostRequest(request, env.DATABASE, env.userKEK)
return handlePostRequest(request, env.DATABASE, env.userKEK, env.ACCESS_AUTH_DOMAIN, env.ACCESS_AUD)
}
// FIXME: move this behind Cloudflare Access. We can find the JWT in the cookies
export async function handlePostRequest(request: Request, db: D1Database, userKEK: string): Promise<Response> {
export async function handlePostRequest(
request: Request,
db: D1Database,
userKEK: string,
accessDomain: string,
accessAud: string
): Promise<Response> {
const url = new URL(request.url)
// TODO: email is in the JWT, should be parsed, verified and passed in the
// request context.
const email = url.searchParams.get('email') || ''
const cookie = parse(request.headers.get('Cookie') || '')
const jwt = cookie['CF_Authorization']
if (!jwt) {
return errors.notAuthorized('missing CF_Authorization')
}
const payload = access.getPayload(jwt)
if (!payload.email) {
return errors.notAuthorized('missing email')
}
const validatate = access.generateValidator({
jwt,
domain: accessDomain,
aud: accessAud,
})
await validatate(request)
const domain = url.hostname
const formData = await request.formData()
@ -27,7 +51,7 @@ export async function handlePostRequest(request: Request, db: D1Database, userKE
properties.name = formData.get('name') || ''
}
await createPerson(domain, db, userKEK, email, properties)
await createPerson(domain, db, userKEK, payload.email, properties)
if (!url.searchParams.has('redirect_uri')) {
return new Response('', { status: 400 })