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
}