Make authorized fetch configurable

This commit is contained in:
Jesse Wierzbinski 2023-10-15 20:07:39 -10:00
parent c0ff46559b
commit a8d8b70239
3 changed files with 48 additions and 27 deletions

View file

@ -101,6 +101,10 @@ force_sensitive = [] # NOT IMPLEMENTED
# Remove theses instances' media # Remove theses instances' media
remove_media = [] # NOT IMPLEMENTED remove_media = [] # NOT IMPLEMENTED
# Whether to verify HTTP signatures for every request (warning: can slow down your server
# significantly depending on processing power)
authorized_fetch = false
[filters] [filters]
# Drop notes with these regex filters (only applies to new activities) # Drop notes with these regex filters (only applies to new activities)

View file

@ -57,34 +57,49 @@ export default async (
const body: APActivity = await req.json(); const body: APActivity = await req.json();
// Verify HTTP signature // Verify HTTP signature
const signature = req.headers.get("Signature") ?? ""; if (config.activitypub.authorized_fetch) {
const signatureParams = signature // Check if date is older than 30 seconds
.split(",") const date = new Date(req.headers.get("Date") ?? "");
.reduce<Record<string, string>>((params, param) => {
const [key, value] = param.split("=");
params[key] = value.replace(/"/g, "");
return params;
}, {});
const signedString = `(request-target): post /users/${username}/inbox\nhost: ${ if (date.getTime() < Date.now() - 30000) {
config.http.base_url return errorResponse("Date is too old (max 30 seconds)", 401);
}\ndate: ${req.headers.get("Date")}`; }
const signatureBuffer = new TextEncoder().encode(signatureParams.signature);
const signatureBytes = new Uint8Array(signatureBuffer).buffer; const signature = req.headers.get("Signature") ?? "";
const publicKeyBuffer = (body.actor as any).publicKey.publicKeyPem; const signatureParams = signature
const publicKey = await crypto.subtle.importKey( .split(",")
"spki", .reduce<Record<string, string>>((params, param) => {
publicKeyBuffer, const [key, value] = param.split("=");
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, params[key] = value.replace(/"/g, "");
false, return params;
["verify"] }, {});
);
const verified = await crypto.subtle.verify( const signedString = `(request-target): post /users/${username}/inbox\nhost: ${
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, config.http.base_url
publicKey, }\ndate: ${req.headers.get("Date")}`;
signatureBytes, const signatureBuffer = new TextEncoder().encode(
new TextEncoder().encode(signedString) signatureParams.signature
); );
const signatureBytes = new Uint8Array(signatureBuffer).buffer;
const publicKeyBuffer = (body.actor as any).publicKey.publicKeyPem;
const publicKey = await crypto.subtle.importKey(
"spki",
publicKeyBuffer,
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
false,
["verify"]
);
const verified = await crypto.subtle.verify(
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
publicKey,
signatureBytes,
new TextEncoder().encode(signedString)
);
if (!verified) {
return errorResponse("Invalid signature", 401);
}
}
// Get the object's ActivityPub type // Get the object's ActivityPub type
const type = body.type; const type = body.type;

View file

@ -55,6 +55,7 @@ export interface ConfigType {
force_sensitive: string[]; force_sensitive: string[];
remove_media: string[]; remove_media: string[];
fetch_all_colletion_members: boolean; fetch_all_colletion_members: boolean;
authorized_fetch: boolean;
}; };
filters: { filters: {
@ -184,6 +185,7 @@ export const configDefaults: ConfigType = {
discard_follows: [], discard_follows: [],
remove_media: [], remove_media: [],
fetch_all_colletion_members: false, fetch_all_colletion_members: false,
authorized_fetch: false,
}, },
filters: { filters: {
note_filters: [], note_filters: [],