mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-25 03:17:38 -07:00
[backend] Stricter validation of activity identifiers
This resolves a security issue that was disclosed on 2024-03-24 & patched in coordination with other affected software on 2024-03-30. Huge thanks to Oneric for the detailed security disclosure.
This commit is contained in:
parent
74df0b3602
commit
ac57c58ecf
1 changed files with 24 additions and 10 deletions
|
@ -122,28 +122,42 @@ export default class Resolver {
|
||||||
apLogger.debug("Getting object from remote, authenticated as user:");
|
apLogger.debug("Getting object from remote, authenticated as user:");
|
||||||
apLogger.debug(JSON.stringify(this.user, null, 2));
|
apLogger.debug(JSON.stringify(this.user, null, 2));
|
||||||
|
|
||||||
const res = (
|
const {res, object} = await this.doFetch(value);
|
||||||
|
|
||||||
|
if (object.id == null) return object;
|
||||||
|
if (res.finalUrl === object.id) return object;
|
||||||
|
|
||||||
|
if (new URL(res.finalUrl).host !== new URL(object.id).host)
|
||||||
|
throw new Error("Object ID host doesn't match final url host");
|
||||||
|
|
||||||
|
const {res: finalRes, object: finalObject} = await this.doFetch(object.id);
|
||||||
|
|
||||||
|
if (finalRes.finalUrl !== finalObject.id)
|
||||||
|
throw new Error("Object ID still doesn't match final URL after second fetch attempt")
|
||||||
|
|
||||||
|
return finalObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async doFetch(uri: string) {
|
||||||
|
let res = (
|
||||||
this.user
|
this.user
|
||||||
? await signedGet(value, this.user)
|
? await signedGet(uri, this.user)
|
||||||
: await getJsonActivity(value)
|
: await getJsonActivity(uri)
|
||||||
);
|
);
|
||||||
const object = res.content as IObject;
|
let object = res.content as IObject;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
object == null ||
|
object == null ||
|
||||||
(Array.isArray(object["@context"])
|
(Array.isArray(object["@context"])
|
||||||
? !(object["@context"] as unknown[]).includes(
|
? !(object["@context"] as unknown[]).includes(
|
||||||
"https://www.w3.org/ns/activitystreams",
|
"https://www.w3.org/ns/activitystreams",
|
||||||
)
|
)
|
||||||
: object["@context"] !== "https://www.w3.org/ns/activitystreams")
|
: object["@context"] !== "https://www.w3.org/ns/activitystreams")
|
||||||
) {
|
) {
|
||||||
throw new Error("invalid response");
|
throw new Error("invalid response");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.id != null && new URL(res.finalUrl).host != new URL(object.id).host)
|
return {res, object};
|
||||||
throw new Error("Object ID host doesn't match final url host");
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveLocal(url: string): Promise<IObject> {
|
private resolveLocal(url: string): Promise<IObject> {
|
||||||
|
|
Loading…
Reference in a new issue