Another attempt to fix the cors issue

This commit is contained in:
Gordon Pedersen 2023-10-17 11:44:14 +11:00
parent cf71ed823e
commit 4c244e9108
4 changed files with 41 additions and 26 deletions

View file

@ -1,4 +1,4 @@
import { authorized, verify } from "./request" import { authorized, defaultHeaders, verify } from "./request"
import outbox from "./outbox" import outbox from "./outbox"
import inbox from "./inbox" import inbox from "./inbox"
import ACTOR from "../actor" import ACTOR from "../actor"
@ -34,15 +34,15 @@ export function reqIsActivityPub(req:Request) {
const postOutbox = async (req:Request):Promise<Response> => { const postOutbox = async (req:Request):Promise<Response> => {
console.log("PostOutbox") console.log("PostOutbox")
if(!authorized(req)) return new Response('', { status: 401 }) if(!authorized(req)) return new Response('', { status: 401, headers: defaultHeaders(req) })
const bodyText = await req.text() const bodyText = await req.text()
const body = JSON.parse(bodyText) const body = JSON.parse(bodyText)
// ensure that the verified actor matches the actor in the request body // ensure that the verified actor matches the actor in the request body
if (ACTOR.id !== body.actor) return new Response("", { status: 401 }) if (ACTOR.id !== body.actor) return new Response("", { status: 401, headers: defaultHeaders(req) })
return await outbox(body, db) return await outbox(body, req, db)
} }
const postInbox = async (req:Request):Promise<Response> => { const postInbox = async (req:Request):Promise<Response> => {
@ -56,15 +56,15 @@ const postInbox = async (req:Request):Promise<Response> => {
// verify the signed HTTP request // verify the signed HTTP request
from = await verify(req, bodyText); from = await verify(req, bodyText);
} catch (err) { } catch (err) {
return new Response("", { status: 401 }) return new Response("", { status: 401, headers: defaultHeaders(req) })
} }
const body = JSON.parse(bodyText) const body = JSON.parse(bodyText)
// ensure that the verified actor matches the actor in the request body // ensure that the verified actor matches the actor in the request body
if (from !== body.actor) return new Response("", { status: 401 }) if (from !== body.actor) return new Response("", { status: 401, headers: defaultHeaders(req) })
return await inbox(body, db) return await inbox(body, req, db)
} }
const getOutbox = async (req:Request):Promise<Response> => { const getOutbox = async (req:Request):Promise<Response> => {
@ -82,7 +82,7 @@ const getOutbox = async (req:Request):Promise<Response> => {
...post, ...post,
actor: ACTOR.id actor: ACTOR.id
})).sort( (a,b) => new Date(b.published).getTime() - new Date(a.published).getTime()) })).sort( (a,b) => new Date(b.published).getTime() - new Date(a.published).getTime())
}, { headers: { "Content-Type": "application/activity+json"} }) }, { status:200, headers: defaultHeaders(req) })
} }
const getFollowers = async (req:Request):Promise<Response> => { const getFollowers = async (req:Request):Promise<Response> => {
@ -98,7 +98,7 @@ const getFollowers = async (req:Request):Promise<Response> => {
type: "OrderedCollection", type: "OrderedCollection",
totalItems: followers?.length, totalItems: followers?.length,
first: `${ACTOR.followers}?page=1`, first: `${ACTOR.followers}?page=1`,
}) }, { status:200, headers: defaultHeaders(req) })
else return Response.json({ else return Response.json({
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
id: `${ACTOR.followers}?page=${page}`, id: `${ACTOR.followers}?page=${page}`,
@ -106,7 +106,7 @@ const getFollowers = async (req:Request):Promise<Response> => {
partOf: ACTOR.followers, partOf: ACTOR.followers,
totalItems: followers?.length, totalItems: followers?.length,
orderedItems: followers?.map(follower => follower?.id) orderedItems: followers?.map(follower => follower?.id)
}) }, { status:200, headers: defaultHeaders(req) })
} }
const getFollowing = async (req:Request):Promise<Response> => { const getFollowing = async (req:Request):Promise<Response> => {
@ -122,7 +122,7 @@ const getFollowing = async (req:Request):Promise<Response> => {
type: "OrderedCollection", type: "OrderedCollection",
totalItems: following?.length, totalItems: following?.length,
first: `${ACTOR.following}?page=1`, first: `${ACTOR.following}?page=1`,
}) }, { status:200, headers: defaultHeaders(req) })
else return Response.json({ else return Response.json({
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
id: `${ACTOR.following}?page=${page}`, id: `${ACTOR.following}?page=${page}`,
@ -130,25 +130,25 @@ const getFollowing = async (req:Request):Promise<Response> => {
partOf: ACTOR.following, partOf: ACTOR.following,
totalItems: following?.length, totalItems: following?.length,
orderedItems: following?.map(follow => follow.id) orderedItems: following?.map(follow => follow.id)
}) }, { status:200, headers: defaultHeaders(req) })
} }
const getActor = async (req:Request):Promise<Response> => { const getActor = async (req:Request):Promise<Response> => {
console.log("GetActor") console.log("GetActor")
if(reqIsActivityPub(req)) return Response.json(ACTOR, { headers: { "Content-Type": "application/activity+json"}}) if(reqIsActivityPub(req)) return Response.json(ACTOR, { status:200, headers: defaultHeaders(req) })
else return Response.json(db.listPosts()) else return Response.json(db.listPosts(), { status:200, headers: defaultHeaders(req) })
} }
const getPost = async (req:Request, id:string):Promise<Response> => { const getPost = async (req:Request, id:string):Promise<Response> => {
console.log("GetPost", id) console.log("GetPost", id)
if(reqIsActivityPub(req)) return Response.json((db.getOutboxActivity(id))?.object, { headers: { "Content-Type": "application/activity+json"}}) if(reqIsActivityPub(req)) return Response.json((db.getOutboxActivity(id))?.object, { status:200, headers: defaultHeaders(req) })
else return Response.json(db.getPost(id)) else return Response.json(db.getPost(id), { status:200, headers: defaultHeaders(req) })
} }
const getOutboxActivity = async (req:Request, id:string):Promise<Response> => { const getOutboxActivity = async (req:Request, id:string):Promise<Response> => {
console.log("GetOutboxActivity", id) console.log("GetOutboxActivity", id)
return Response.json((db.getOutboxActivity(id)), { headers: { "Content-Type": "application/activity+json"}}) return Response.json((db.getOutboxActivity(id)), { status:200, headers: defaultHeaders(req) })
} }

View file

@ -1,10 +1,10 @@
import outbox from "./outbox" import outbox from "./outbox"
import { idsFromValue, send } from "./request" import { defaultHeaders, idsFromValue, send } from "./request"
import ACTOR from "../actor" import ACTOR from "../actor"
import ActivityPubDB from "./db" import ActivityPubDB from "./db"
let db:ActivityPubDB let db:ActivityPubDB
export default async function inbox(activity:any, database:ActivityPubDB) { export default async function inbox(activity:any, req:Request, database:ActivityPubDB) {
db = database db = database
const date = new Date() const date = new Date()
// get the main recipients ([...new Set()] is to dedupe) // get the main recipients ([...new Set()] is to dedupe)
@ -22,16 +22,16 @@ export default async function inbox(activity:any, database:ActivityPubDB) {
// TODO: process the activity and update local data // TODO: process the activity and update local data
switch(activity.type) { switch(activity.type) {
case "Follow": follow(activity, activity_id); break; case "Follow": follow(activity, activity_id, req); break;
case "Accept": accept(activity); break; case "Accept": accept(activity); break;
case "Reject": reject(activity); break; case "Reject": reject(activity); break;
case "Undo": undo(activity); break; case "Undo": undo(activity); break;
} }
return new Response("", { status: 204 }) return new Response("", { status:204, headers: defaultHeaders(req) })
} }
const follow = async (activity:any, activity_id:string) => { const follow = async (activity:any, activity_id:string, req:Request) => {
// someone is following me // someone is following me
// save this follower locally // save this follower locally
db.createFollower(activity_id, activity.actor, activity.published || new Date().toISOString()) db.createFollower(activity_id, activity.actor, activity.published || new Date().toISOString())
@ -42,7 +42,7 @@ const follow = async (activity:any, activity_id:string) => {
actor: ACTOR.id, actor: ACTOR.id,
to: [activity.actor], to: [activity.actor],
object: activity, object: activity,
}, db); }, req, db);
} }
const undo = async (activity:any) => { const undo = async (activity:any) => {

View file

@ -1,10 +1,10 @@
import { fetchObject, idsFromValue, send } from "./request" import { defaultHeaders, fetchObject, idsFromValue, send } from "./request"
import ACTOR from "../actor" import ACTOR from "../actor"
import ActivityPubDB, { Activity } from "./db" import ActivityPubDB, { Activity } from "./db"
let db:ActivityPubDB let db:ActivityPubDB
export default async function outbox(activity:any, database:ActivityPubDB):Promise<Response> { export default async function outbox(activity:any, req:Request, database:ActivityPubDB):Promise<Response> {
db = database db = database
const date = new Date() const date = new Date()
const activity_id = `${date.getTime().toString(32)}` const activity_id = `${date.getTime().toString(32)}`
@ -60,7 +60,7 @@ export default async function outbox(activity:any, database:ActivityPubDB):Promi
else if (to) send(to, activity) else if (to) send(to, activity)
}) })
return new Response("", { status: 201, headers: { location: activity.id } }) return new Response("", { status: 201, headers: { ...defaultHeaders(req), location: activity.id } })
} }
async function outboxSideEffect(activity_id:string, activity:Activity) { async function outboxSideEffect(activity_id:string, activity:Activity) {

View file

@ -10,6 +10,21 @@ export function idsFromValue(value:any):string[] {
return [] return []
} }
export function defaultHeaders(req:Request) {
const headers:any = {
'Access-Control-Allow-Origin': req.headers.get('Origin') || '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, DELETE',
'Access-Control-Max-Age': '86400',
'Access-Control-Allow-Credentials': true,
'Content-Type': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
}
let h
if (h = req.headers.get('Access-Control-Request-Headers'))
headers['Access-Control-Allow-Headers'] = 'Accept, Content-Type, Authorization, Signature, Digest, Date, Host'
return headers
}
// this function adds / modifies the appropriate headers for signing a request, then calls fetch // this function adds / modifies the appropriate headers for signing a request, then calls fetch
export function signedFetch(url: string | URL | Request, init?: FetchRequestInit): Promise<Response> export function signedFetch(url: string | URL | Request, init?: FetchRequestInit): Promise<Response>
{ {