Fix federation issues caused by Delete actor activities

This commit is contained in:
Shadowfacts 2019-06-30 14:59:39 -04:00
parent b44a37de5a
commit 4743d69f95
Signed by untrusted user: shadowfacts
GPG Key ID: 94A5AB95422746E5
3 changed files with 25 additions and 8 deletions

View File

@ -24,7 +24,7 @@ function createActivity(article: Article): Create {
return createObject;
}
export async function getActor(url: string, db: Database, forceUpdate: boolean = false): Promise<Actor> {
export async function getActor(url: string, db: Database, forceUpdate: boolean = false): Promise<Actor | null> {
if (!forceUpdate) {
try {
const cached = await getCachedActor(url, db);
@ -34,7 +34,7 @@ export async function getActor(url: string, db: Database, forceUpdate: boolean =
}
}
const remote = await fetchActor(url);
cacheActor(remote, db);
if (remote) cacheActor(remote, db);
return remote;
}
@ -80,7 +80,7 @@ async function cacheActor(actor: Actor, db: Database) {
});
}
async function fetchActor(url: string): Promise<Actor> {
async function fetchActor(url: string): Promise<Actor | null> {
return new Promise((resolve, reject) => {
request({
url,
@ -91,7 +91,7 @@ async function fetchActor(url: string): Promise<Actor> {
json: true
}, (err, res) => {
if (err) reject(err);
else resolve(res.body as Actor);
else resolve(res.body ? res.body as Actor : null);
});
});
}

View File

@ -41,6 +41,11 @@ async function handleFollow(activity: Activity, req: Request, res: Response) {
}
const db = req.app.get("db") as Database;
const actor = await getActor(follow.actor, db, true); // always force re-fetch the actor on follow
if (!actor) {
// if the actor ceases existing between the time the Follow is sent and when receive it, ignore it and end the request
res.end();
return;
}
const acceptObject = <Accept>{
"@context": [
"https://www.w3.org/ns/activitystreams",

View File

@ -11,16 +11,28 @@ export = async (req: Request, res: Response, next: NextFunction) => {
}
const db = req.app.get("db") as Database;
const actor = await getActor(req.body.actor as string, db);
if (validate(req, actor.publicKey.publicKeyPem)) {
if (actor && validate(req, actor.publicKey.publicKeyPem)) {
next();
} else {
// if the first check fails, force re-fetch the actor and try again
const actor = await getActor(req.body.actor as string, db, true);
if (validate(req, actor.publicKey.publicKeyPem)) {
next();
if (!actor) {
// probably caused by Delete activity for an actor
if (req.body.type === "Delete") {
// if we don't have a cached copy of the key, we have had no interaction with actor
// so the Delete can be safely ignored
// we still send a 200 OK status, so that the originating instances knows it has successfully
// delivered the Delete (we just can't act on it)
res.status(200).end();
} else {
console.log(`Could not retrieve actor ${req.body.actor} to validate HTTP signature for`, req.body);
res.status(401).end("Could not retrieve actor to validate HTTP signature");
}
} else if (!validate(req, actor.publicKey.publicKeyPem)) {
console.log(`Could not validate HTTP signature for ${req.body.actor}`);
res.status(401).end("Could not validate HTTP signature");
} else {
next();
}
}
};