diff --git a/spindle/db/db.go b/spindle/db/db.go index eb7484cc..fb204c1c 100644 --- a/spindle/db/db.go +++ b/spindle/db/db.go @@ -270,6 +270,23 @@ func runMigrations(_ context.Context, conn *sql.Conn, logger *slog.Logger) error return err } + if err := orm.RunMigration(conn, logger, "member-acl-table", func(tx *sql.Tx) error { + _, err := tx.Exec(` + CREATE TABLE members ( + did TEXT PRIMARY KEY, + blocked INTEGER DEFAULT 0 + ); + + insert or ignore into members (did) select subject from spindle_members; + insert or ignore into members (did) select did from spindle_members; + + drop table spindle_members; + `) + return err + }); err != nil { + return err + } + return nil } diff --git a/spindle/db/known_dids.go b/spindle/db/known_dids.go deleted file mode 100644 index 2192e069..00000000 --- a/spindle/db/known_dids.go +++ /dev/null @@ -1,44 +0,0 @@ -package db - -func AddDid(q DBTX, did string) error { - _, err := q.Exec(`insert or ignore into known_dids (did) values (?)`, did) - return err -} - -func RemoveDid(q DBTX, did string) error { - _, err := q.Exec(`delete from known_dids where did = ?`, did) - return err -} - -func (d *DB) GetAllDids() ([]string, error) { - var dids []string - - rows, err := d.Query(`select did from known_dids`) - if err != nil { - return nil, err - } - defer rows.Close() - - for rows.Next() { - var did string - if err := rows.Scan(&did); err != nil { - return nil, err - } - dids = append(dids, did) - } - - if err := rows.Err(); err != nil { - return nil, err - } - - return dids, nil -} - -func (d *DB) HasKnownDids() bool { - var count int - err := d.QueryRow(`select count(*) from known_dids`).Scan(&count) - if err != nil { - return false - } - return count > 0 -} diff --git a/spindle/db/members.go b/spindle/db/members.go new file mode 100644 index 00000000..9f2d7c8d --- /dev/null +++ b/spindle/db/members.go @@ -0,0 +1,57 @@ +package db + +import ( + "context" + "database/sql" + "errors" + + "github.com/bluesky-social/indigo/atproto/syntax" +) + +func (d *DB) ListAllowedMembers() ([]syntax.DID, error) { + rows, err := d.Query(`select did from members where blocked = 0`) + if err != nil { + return nil, err + } + defer rows.Close() + + var dids []syntax.DID + for rows.Next() { + var did syntax.DID + if err := rows.Scan(&did); err != nil { + return nil, err + } + dids = append(dids, did) + } + + return dids, rows.Err() +} + +// IsAllowedMember reports whether did is known and unblocked. Unknown DIDs get fallback. +func (d *DB) IsAllowedMember(ctx context.Context, did syntax.DID, fallback bool) (bool, error) { + var blocked bool + err := d.QueryRowContext(ctx, `select blocked from members where did = ?`, did).Scan(&blocked) + if errors.Is(err, sql.ErrNoRows) { + return fallback, nil + } + if err != nil { + return false, err + } + return !blocked, nil +} + +func (d *DB) AllowMember(ctx context.Context, did syntax.DID) error { + return d.UpsertMember(ctx, did, false) +} + +func (d *DB) BlockMember(ctx context.Context, did syntax.DID) error { + return d.UpsertMember(ctx, did, true) +} + +func (d *DB) UpsertMember(ctx context.Context, did syntax.DID, block bool) error { + _, err := d.ExecContext(ctx, ` + insert into members (did, blocked) values (?, ?) + on conflict(did) do update set blocked = excluded.blocked + `, did, block) + return err +} diff --git a/spindle/server.go b/spindle/server.go index c1e6b080..d1ed0009 100644 --- a/spindle/server.go +++ b/spindle/server.go @@ -125,12 +125,12 @@ func New(ctx context.Context, cfg *config.Config, d *db.DB, engines map[string]m jc.ExemptCollection(tangled.RepoPullNSID) // Check if the spindle knows about any Dids; - dids, err := d.GetAllDids() + dids, err := d.ListAllowedMembers() if err != nil { return nil, fmt.Errorf("failed to get all dids: %w", err) } for _, d := range dids { - jc.AddDid(d) + jc.AddDid(d.String()) } knownRepos, err := d.AllRepos()