package db import ( "database/sql" "errors" "github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/core/spindle/config" ) func AddToAllowlist(q DBTX, did syntax.DID) error { _, err := q.Exec(`insert or ignore into instance_allowlist (did) values (?)`, did) return err } func RemoveFromAllowlist(q DBTX, did syntax.DID) error { _, err := q.Exec(`delete from instance_allowlist where did = ?`, did) return err } func AllowlistContains(q DBTX, did syntax.DID) (bool, error) { var one int err := q.QueryRow(`select 1 from instance_allowlist where did = ?`, did).Scan(&one) switch { case err == sql.ErrNoRows: return false, nil case err != nil: return false, err default: return true, nil } } func ListAllowlist(q DBTX) ([]syntax.DID, error) { rows, err := q.Query(`select did from instance_allowlist order by did asc`) if err != nil { return nil, err } defer rows.Close() dids := []syntax.DID{} for rows.Next() { var did string if err := rows.Scan(&did); err != nil { return nil, err } parsed, err := syntax.ParseDID(did) if err != nil { continue } dids = append(dids, parsed) } return dids, rows.Err() } // a ban beats everything, admins are served even when admission is closed func Enrolls(q DBTX, srv *config.Server, did syntax.DID) (bool, error) { var banned, listed bool err := q.QueryRow(` select exists(select 1 from bans where subject_did = ?), exists(select 1 from instance_allowlist where did = ?)`, did, did, ).Scan(&banned, &listed) if err != nil { return false, err } return !banned && (srv.OpenAdmission() || srv.IsAdmin(did.String()) || listed), nil } // a ban beats paused, and paused only means admission is closed type RepoGate struct { Served bool Banned bool Paused bool } // keep this in step with Enrolls, they answer the same question func (d *DB) Gate(srv *config.Server, repoDid syntax.DID) (RepoGate, error) { var owner string var banned, listed bool err := d.QueryRow(` select r.owner, exists(select 1 from bans where subject_did in (r.repo_did, r.owner)), exists(select 1 from instance_allowlist where did = r.owner) from repos r where r.repo_did = ? limit 1`, repoDid.String(), ).Scan(&owner, &banned, &listed) if errors.Is(err, sql.ErrNoRows) { return RepoGate{}, nil } if err != nil { return RepoGate{}, err } enrolled := srv.OpenAdmission() || srv.IsAdmin(owner) || listed return RepoGate{Served: true, Banned: banned, Paused: !banned && !enrolled}, nil }