fix: harden ActivityPub federation and fix N+1 follower fanout (#1056)

* initial commit

* improve activitypub recipient query

* small fixes

---------

Co-authored-by: Christian Beutel <>
Co-authored-by: slothful-vassal <89943360+slothful-vassal@users.noreply.github.com>
This commit is contained in:
Flomp
2026-06-18 16:36:57 +02:00
committed by GitHub
parent 6baeafe755
commit 64da36aa20
6 changed files with 86 additions and 92 deletions

View File

@@ -194,12 +194,21 @@ func assembleActor(app core.App, ctx context.Context, dbActor *core.Record, incl
dbActor.Set("last_fetched", time.Now())
// an empty privacy field is the default for users who never touched
// their privacy settings and is treated as public. A non-empty but
// corrupt value fails closed (private) so a broken setting can't
// silently expose a profile.
privacy := settings.GetString("privacy")
result := make(map[string]interface{})
json.Unmarshal([]byte(privacy), &result)
// check that it's not our own profile
private = result["account"] == "private" && dbActor.Id != strings.TrimPrefix(ctx.Value("actor").(string), "actor:")
if privacy != "" {
result := make(map[string]interface{})
if err := json.Unmarshal([]byte(privacy), &result); err != nil {
private = true
} else {
// check that it's not our own profile
actorVal, _ := ctx.Value("actor").(string)
private = result["account"] == "private" && dbActor.Id != strings.TrimPrefix(actorVal, "actor:")
}
}
} else {
@@ -279,6 +288,9 @@ func fetchRemoteActor(app core.App, ctx context.Context, iri string, includeFoll
client := util.SafeHTTPClient()
req, err := http.NewRequestWithContext(ctx, "GET", iri, nil)
if err != nil {
return nil, nil, nil, err
}
headers := map[string]string{
"Accept": "application/ld+json",
@@ -291,7 +303,8 @@ func fetchRemoteActor(app core.App, ctx context.Context, iri string, includeFoll
req.Header.Add(k, v)
}
userActorId := strings.TrimPrefix(ctx.Value("actor").(string), "actor:")
actorVal, _ := ctx.Value("actor").(string)
userActorId := strings.TrimPrefix(actorVal, "actor:")
userActor, err := app.FindRecordById("activitypub_actors", userActorId)
if userActor != nil && userActor.GetString("private_key") != "" {
dbPrivateKey := userActor.GetString("private_key")
@@ -332,7 +345,7 @@ func fetchRemoteActor(app core.App, ctx context.Context, iri string, includeFoll
defer resp.Body.Close()
var pubActor pub.Actor
if err := json.NewDecoder(resp.Body).Decode(&pubActor); err != nil {
if err := json.NewDecoder(io.LimitReader(resp.Body, 1<<20)).Decode(&pubActor); err != nil {
return nil, nil, nil, err
}
@@ -365,6 +378,9 @@ func FetchCollection(app core.App, ctx context.Context, collectionURL string) (*
}
req, err := http.NewRequestWithContext(ctx, "GET", collectionURL, nil)
if err != nil {
return nil, err
}
headers := map[string]string{
"Accept": "application/ld+json",
@@ -376,7 +392,8 @@ func FetchCollection(app core.App, ctx context.Context, collectionURL string) (*
for k, v := range headers {
req.Header.Add(k, v)
}
userActorId := strings.TrimPrefix(ctx.Value("actor").(string), "actor:")
actorVal, _ := ctx.Value("actor").(string)
userActorId := strings.TrimPrefix(actorVal, "actor:")
userActor, err := app.FindRecordById("activitypub_actors", userActorId)
if userActor != nil && userActor.GetString("private_key") != "" {
dbPrivateKey := userActor.GetString("private_key")