Add shared inbox support for ActivityPub delivery (#4755)
* feat(ap): add support for shared inboxes to reduce outbound load * feat(db): refactor ap followers db into followers repository * fix(ap): use the updated activity library to pull out the shared inbox endpoint * chore(deps): point at updated build of owncast/activity * fix(ap): typeless endpoints * feat(test): update ActivityPub test to support shared inboxes * chore(test): remove unused variable * fix: feedback from review. Guard against SSRF/non-HTTPS/local and handle transaction errors
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.15.0
|
||||
// sqlc v1.30.0
|
||||
|
||||
package db
|
||||
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.15.0
|
||||
// sqlc v1.30.0
|
||||
|
||||
package db
|
||||
|
||||
@@ -20,6 +20,7 @@ type ApAcceptedActivity struct {
|
||||
type ApFollower struct {
|
||||
Iri string
|
||||
Inbox string
|
||||
SharedInbox sql.NullString
|
||||
Name sql.NullString
|
||||
Username string
|
||||
Image sql.NullString
|
||||
|
||||
+8
-5
@@ -9,13 +9,13 @@ SElECT count(*) FROM ap_followers WHERE approved_at is not null;
|
||||
SElECT count(*) FROM ap_outbox;
|
||||
|
||||
-- name: GetFederationFollowersWithOffset :many
|
||||
SELECT iri, inbox, name, username, image, created_at FROM ap_followers WHERE approved_at is not null ORDER BY created_at DESC LIMIT $1 OFFSET $2;
|
||||
SELECT iri, inbox, shared_inbox, name, username, image, created_at FROM ap_followers WHERE approved_at is not null ORDER BY created_at DESC LIMIT $1 OFFSET $2;
|
||||
|
||||
-- name: GetRejectedAndBlockedFollowers :many
|
||||
SELECT iri, name, username, image, created_at, disabled_at FROM ap_followers WHERE disabled_at is not null;
|
||||
|
||||
-- name: GetFederationFollowerApprovalRequests :many
|
||||
SELECT iri, inbox, name, username, image, created_at FROM ap_followers WHERE approved_at IS null AND disabled_at is null;
|
||||
SELECT iri, inbox, shared_inbox, name, username, image, created_at FROM ap_followers WHERE approved_at IS null AND disabled_at is null;
|
||||
|
||||
-- name: ApproveFederationFollower :exec
|
||||
UPDATE ap_followers SET approved_at = $1, disabled_at = null WHERE iri = $2;
|
||||
@@ -24,7 +24,7 @@ UPDATE ap_followers SET approved_at = $1, disabled_at = null WHERE iri = $2;
|
||||
UPDATE ap_followers SET approved_at = null, disabled_at = $1 WHERE iri = $2;
|
||||
|
||||
-- name: GetFollowerByIRI :one
|
||||
SELECT iri, inbox, name, username, image, request, request_object, created_at, approved_at, disabled_at FROM ap_followers WHERE iri = $1;
|
||||
SELECT iri, inbox, shared_inbox, name, username, image, request, request_object, created_at, approved_at, disabled_at FROM ap_followers WHERE iri = $1;
|
||||
|
||||
-- name: GetOutboxWithOffset :many
|
||||
SELECT value FROM ap_outbox LIMIT $1 OFFSET $2;
|
||||
@@ -37,7 +37,7 @@ SELECT value, live_notification, created_at FROM ap_outbox WHERE iri = $1;
|
||||
DELETE FROM ap_followers WHERE iri = $1;
|
||||
|
||||
-- name: AddFollower :exec
|
||||
INSERT INTO ap_followers(iri, inbox, request, request_object, name, username, image, approved_at) values($1, $2, $3, $4, $5, $6, $7, $8);
|
||||
INSERT INTO ap_followers(iri, inbox, shared_inbox, request, request_object, name, username, image, approved_at) values($1, $2, $3, $4, $5, $6, $7, $8, $9);
|
||||
|
||||
-- name: AddToOutbox :exec
|
||||
INSERT INTO ap_outbox(iri, value, type, live_notification) values($1, $2, $3, $4);
|
||||
@@ -55,7 +55,10 @@ SELECT iri, actor, type, timestamp FROM ap_accepted_activities ORDER BY timestam
|
||||
SELECT count(*) FROM ap_accepted_activities WHERE iri = $1 AND actor = $2 AND TYPE = $3;
|
||||
|
||||
-- name: UpdateFollowerByIRI :exec
|
||||
UPDATE ap_followers SET inbox = $1, name = $2, username = $3, image = $4 WHERE iri = $5;
|
||||
UPDATE ap_followers SET inbox = $1, shared_inbox = $2, name = $3, username = $4, image = $5 WHERE iri = $6;
|
||||
|
||||
-- name: GetUniqueDeliveryInboxes :many
|
||||
SELECT COALESCE(shared_inbox, inbox) as delivery_inbox FROM ap_followers WHERE approved_at is not null GROUP BY delivery_inbox;
|
||||
|
||||
-- name: BanIPAddress :exec
|
||||
INSERT INTO ip_bans(ip_address, notes) values($1, $2);
|
||||
|
||||
+66
-30
@@ -1,6 +1,6 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.19.1
|
||||
// sqlc v1.30.0
|
||||
// source: query.sql
|
||||
|
||||
package db
|
||||
@@ -41,12 +41,13 @@ func (q *Queries) AddAuthForUser(ctx context.Context, arg AddAuthForUserParams)
|
||||
}
|
||||
|
||||
const addFollower = `-- name: AddFollower :exec
|
||||
INSERT INTO ap_followers(iri, inbox, request, request_object, name, username, image, approved_at) values($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
INSERT INTO ap_followers(iri, inbox, shared_inbox, request, request_object, name, username, image, approved_at) values($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
`
|
||||
|
||||
type AddFollowerParams struct {
|
||||
Iri string
|
||||
Inbox string
|
||||
SharedInbox sql.NullString
|
||||
Request string
|
||||
RequestObject []byte
|
||||
Name sql.NullString
|
||||
@@ -59,6 +60,7 @@ func (q *Queries) AddFollower(ctx context.Context, arg AddFollowerParams) error
|
||||
_, err := q.db.ExecContext(ctx, addFollower,
|
||||
arg.Iri,
|
||||
arg.Inbox,
|
||||
arg.SharedInbox,
|
||||
arg.Request,
|
||||
arg.RequestObject,
|
||||
arg.Name,
|
||||
@@ -158,7 +160,7 @@ UPDATE users SET display_color = $1 WHERE id = $2
|
||||
`
|
||||
|
||||
type ChangeDisplayColorParams struct {
|
||||
DisplayColor int
|
||||
DisplayColor int32
|
||||
ID string
|
||||
}
|
||||
|
||||
@@ -206,16 +208,17 @@ func (q *Queries) DoesInboundActivityExist(ctx context.Context, arg DoesInboundA
|
||||
}
|
||||
|
||||
const getFederationFollowerApprovalRequests = `-- name: GetFederationFollowerApprovalRequests :many
|
||||
SELECT iri, inbox, name, username, image, created_at FROM ap_followers WHERE approved_at IS null AND disabled_at is null
|
||||
SELECT iri, inbox, shared_inbox, name, username, image, created_at FROM ap_followers WHERE approved_at IS null AND disabled_at is null
|
||||
`
|
||||
|
||||
type GetFederationFollowerApprovalRequestsRow struct {
|
||||
Iri string
|
||||
Inbox string
|
||||
Name sql.NullString
|
||||
Username string
|
||||
Image sql.NullString
|
||||
CreatedAt sql.NullTime
|
||||
Iri string
|
||||
Inbox string
|
||||
SharedInbox sql.NullString
|
||||
Name sql.NullString
|
||||
Username string
|
||||
Image sql.NullString
|
||||
CreatedAt sql.NullTime
|
||||
}
|
||||
|
||||
func (q *Queries) GetFederationFollowerApprovalRequests(ctx context.Context) ([]GetFederationFollowerApprovalRequestsRow, error) {
|
||||
@@ -230,6 +233,7 @@ func (q *Queries) GetFederationFollowerApprovalRequests(ctx context.Context) ([]
|
||||
if err := rows.Scan(
|
||||
&i.Iri,
|
||||
&i.Inbox,
|
||||
&i.SharedInbox,
|
||||
&i.Name,
|
||||
&i.Username,
|
||||
&i.Image,
|
||||
@@ -249,21 +253,22 @@ func (q *Queries) GetFederationFollowerApprovalRequests(ctx context.Context) ([]
|
||||
}
|
||||
|
||||
const getFederationFollowersWithOffset = `-- name: GetFederationFollowersWithOffset :many
|
||||
SELECT iri, inbox, name, username, image, created_at FROM ap_followers WHERE approved_at is not null ORDER BY created_at DESC LIMIT $1 OFFSET $2
|
||||
SELECT iri, inbox, shared_inbox, name, username, image, created_at FROM ap_followers WHERE approved_at is not null ORDER BY created_at DESC LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type GetFederationFollowersWithOffsetParams struct {
|
||||
Limit int
|
||||
Offset int
|
||||
Limit int32
|
||||
Offset int32
|
||||
}
|
||||
|
||||
type GetFederationFollowersWithOffsetRow struct {
|
||||
Iri string
|
||||
Inbox string
|
||||
Name sql.NullString
|
||||
Username string
|
||||
Image sql.NullString
|
||||
CreatedAt sql.NullTime
|
||||
Iri string
|
||||
Inbox string
|
||||
SharedInbox sql.NullString
|
||||
Name sql.NullString
|
||||
Username string
|
||||
Image sql.NullString
|
||||
CreatedAt sql.NullTime
|
||||
}
|
||||
|
||||
func (q *Queries) GetFederationFollowersWithOffset(ctx context.Context, arg GetFederationFollowersWithOffsetParams) ([]GetFederationFollowersWithOffsetRow, error) {
|
||||
@@ -278,6 +283,7 @@ func (q *Queries) GetFederationFollowersWithOffset(ctx context.Context, arg GetF
|
||||
if err := rows.Scan(
|
||||
&i.Iri,
|
||||
&i.Inbox,
|
||||
&i.SharedInbox,
|
||||
&i.Name,
|
||||
&i.Username,
|
||||
&i.Image,
|
||||
@@ -297,7 +303,7 @@ func (q *Queries) GetFederationFollowersWithOffset(ctx context.Context, arg GetF
|
||||
}
|
||||
|
||||
const getFollowerByIRI = `-- name: GetFollowerByIRI :one
|
||||
SELECT iri, inbox, name, username, image, request, request_object, created_at, approved_at, disabled_at FROM ap_followers WHERE iri = $1
|
||||
SELECT iri, inbox, shared_inbox, name, username, image, request, request_object, created_at, approved_at, disabled_at FROM ap_followers WHERE iri = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetFollowerByIRI(ctx context.Context, iri string) (ApFollower, error) {
|
||||
@@ -306,6 +312,7 @@ func (q *Queries) GetFollowerByIRI(ctx context.Context, iri string) (ApFollower,
|
||||
err := row.Scan(
|
||||
&i.Iri,
|
||||
&i.Inbox,
|
||||
&i.SharedInbox,
|
||||
&i.Name,
|
||||
&i.Username,
|
||||
&i.Image,
|
||||
@@ -365,8 +372,8 @@ SELECT iri, actor, type, timestamp FROM ap_accepted_activities ORDER BY timestam
|
||||
`
|
||||
|
||||
type GetInboundActivitiesWithOffsetParams struct {
|
||||
Limit int
|
||||
Offset int
|
||||
Limit int32
|
||||
Offset int32
|
||||
}
|
||||
|
||||
type GetInboundActivitiesWithOffsetRow struct {
|
||||
@@ -514,8 +521,8 @@ SELECT value FROM ap_outbox LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type GetOutboxWithOffsetParams struct {
|
||||
Limit int
|
||||
Offset int
|
||||
Limit int32
|
||||
Offset int32
|
||||
}
|
||||
|
||||
func (q *Queries) GetOutboxWithOffset(ctx context.Context, arg GetOutboxWithOffsetParams) ([][]byte, error) {
|
||||
@@ -584,6 +591,33 @@ func (q *Queries) GetRejectedAndBlockedFollowers(ctx context.Context) ([]GetReje
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getUniqueDeliveryInboxes = `-- name: GetUniqueDeliveryInboxes :many
|
||||
SELECT COALESCE(shared_inbox, inbox) as delivery_inbox FROM ap_followers WHERE approved_at is not null GROUP BY delivery_inbox
|
||||
`
|
||||
|
||||
func (q *Queries) GetUniqueDeliveryInboxes(ctx context.Context) ([]string, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getUniqueDeliveryInboxes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []string
|
||||
for rows.Next() {
|
||||
var delivery_inbox string
|
||||
if err := rows.Scan(&delivery_inbox); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, delivery_inbox)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getUserByAccessToken = `-- name: GetUserByAccessToken :one
|
||||
SELECT users.id, display_name, display_color, users.created_at, disabled_at, previous_names, namechanged_at, authenticated_at, scopes FROM users, user_access_tokens WHERE token = $1 AND users.id = user_id
|
||||
`
|
||||
@@ -758,20 +792,22 @@ func (q *Queries) SetUserAsAuthenticated(ctx context.Context, id string) error {
|
||||
}
|
||||
|
||||
const updateFollowerByIRI = `-- name: UpdateFollowerByIRI :exec
|
||||
UPDATE ap_followers SET inbox = $1, name = $2, username = $3, image = $4 WHERE iri = $5
|
||||
UPDATE ap_followers SET inbox = $1, shared_inbox = $2, name = $3, username = $4, image = $5 WHERE iri = $6
|
||||
`
|
||||
|
||||
type UpdateFollowerByIRIParams struct {
|
||||
Inbox string
|
||||
Name sql.NullString
|
||||
Username string
|
||||
Image sql.NullString
|
||||
Iri string
|
||||
Inbox string
|
||||
SharedInbox sql.NullString
|
||||
Name sql.NullString
|
||||
Username string
|
||||
Image sql.NullString
|
||||
Iri string
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateFollowerByIRI(ctx context.Context, arg UpdateFollowerByIRIParams) error {
|
||||
_, err := q.db.ExecContext(ctx, updateFollowerByIRI,
|
||||
arg.Inbox,
|
||||
arg.SharedInbox,
|
||||
arg.Name,
|
||||
arg.Username,
|
||||
arg.Image,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
CREATE TABLE IF NOT EXISTS ap_followers (
|
||||
"iri" TEXT NOT NULL,
|
||||
"inbox" TEXT NOT NULL,
|
||||
"shared_inbox" TEXT,
|
||||
"name" TEXT,
|
||||
"username" TEXT NOT NULL,
|
||||
"image" TEXT,
|
||||
|
||||
Reference in New Issue
Block a user