diff options
author | 2023-09-21 12:12:04 +0200 | |
---|---|---|
committer | 2023-09-21 12:12:04 +0200 | |
commit | 183eaa5b298235acb8f25ba8f18b98e31471d965 (patch) | |
tree | 55f42887edeb5206122d92eb30e0eedf145a3615 /internal/cache | |
parent | [docs] Add a note on cluster support (#2214) (diff) | |
download | gotosocial-183eaa5b298235acb8f25ba8f18b98e31471d965.tar.xz |
[feature] Implement explicit domain allows + allowlist federation mode (#2200)
* love like winter! wohoah, wohoah
* domain allow side effects
* tests! logging! unallow!
* document federation modes
* linty linterson
* test
* further adventures in documentation
* finish up domain block documentation (i think)
* change wording a wee little bit
* docs, example
* consolidate shared domainPermission code
* call mode once
* fetch federation mode within domain blocked func
* read domain perm import in streaming manner
* don't use pointer to slice for domain perms
* don't bother copying blocks + allows before deleting
* admonish!
* change wording just a scooch
* update docs
Diffstat (limited to 'internal/cache')
-rw-r--r-- | internal/cache/domain/domain.go | 51 | ||||
-rw-r--r-- | internal/cache/domain/domain_test.go | 30 | ||||
-rw-r--r-- | internal/cache/gts.go | 17 |
3 files changed, 56 insertions, 42 deletions
diff --git a/internal/cache/domain/domain.go b/internal/cache/domain/domain.go index 37e97472a..051ec5c1b 100644 --- a/internal/cache/domain/domain.go +++ b/internal/cache/domain/domain.go @@ -26,23 +26,28 @@ import ( "golang.org/x/exp/slices" ) -// BlockCache provides a means of caching domain blocks in memory to reduce load -// on an underlying storage mechanism, e.g. a database. +// Cache provides a means of caching domains in memory to reduce +// load on an underlying storage mechanism, e.g. a database. // -// The in-memory block list is kept up-to-date by means of a passed loader function during every -// call to .IsBlocked(). In the case of a nil internal block list, the loader function is called to -// hydrate the cache with the latest list of domain blocks. The .Clear() function can be used to -// invalidate the cache, e.g. when a domain block is added / deleted from the database. -type BlockCache struct { +// The in-memory domain list is kept up-to-date by means of a passed +// loader function during every call to .Matches(). In the case of +// a nil internal domain list, the loader function is called to hydrate +// the cache with the latest list of domains. +// +// The .Clear() function can be used to invalidate the cache, +// e.g. when an entry is added / deleted from the database. +type Cache struct { // atomically updated ptr value to the - // current domain block cache radix trie. + // current domain cache radix trie. rootptr unsafe.Pointer } -// IsBlocked checks whether domain is blocked. If the cache is not currently loaded, then the provided load function is used to hydrate it. -func (b *BlockCache) IsBlocked(domain string, load func() ([]string, error)) (bool, error) { +// Matches checks whether domain matches an entry in the cache. +// If the cache is not currently loaded, then the provided load +// function is used to hydrate it. +func (c *Cache) Matches(domain string, load func() ([]string, error)) (bool, error) { // Load the current root pointer value. - ptr := atomic.LoadPointer(&b.rootptr) + ptr := atomic.LoadPointer(&c.rootptr) if ptr == nil { // Cache is not hydrated. @@ -67,7 +72,7 @@ func (b *BlockCache) IsBlocked(domain string, load func() ([]string, error)) (bo // Store the new node ptr. ptr = unsafe.Pointer(root) - atomic.StorePointer(&b.rootptr, ptr) + atomic.StorePointer(&c.rootptr, ptr) } // Look for a match in the trie node. @@ -75,22 +80,20 @@ func (b *BlockCache) IsBlocked(domain string, load func() ([]string, error)) (bo } // Clear will drop the currently loaded domain list, -// triggering a reload on next call to .IsBlocked(). -func (b *BlockCache) Clear() { - atomic.StorePointer(&b.rootptr, nil) +// triggering a reload on next call to .Matches(). +func (c *Cache) Clear() { + atomic.StorePointer(&c.rootptr, nil) } -// String returns a string representation of stored domains in block cache. -func (b *BlockCache) String() string { - if ptr := atomic.LoadPointer(&b.rootptr); ptr != nil { +// String returns a string representation of stored domains in cache. +func (c *Cache) String() string { + if ptr := atomic.LoadPointer(&c.rootptr); ptr != nil { return (*root)(ptr).String() } return "<empty>" } -// root is the root node in the domain -// block cache radix trie. this is the -// singular access point to the trie. +// root is the root node in the domain cache radix trie. this is the singular access point to the trie. type root struct{ root node } // Add will add the given domain to the radix trie. @@ -99,14 +102,14 @@ func (r *root) Add(domain string) { } // Match will return whether the given domain matches -// an existing stored domain block in this radix trie. +// an existing stored domain in this radix trie. func (r *root) Match(domain string) bool { return r.root.match(strings.Split(domain, ".")) } // Sort will sort the entire radix trie ensuring that // child nodes are stored in alphabetical order. This -// MUST be done to finalize the block cache in order +// MUST be done to finalize the domain cache in order // to speed up the binary search of node child parts. func (r *root) Sort() { r.root.sort() @@ -154,7 +157,7 @@ func (n *node) add(parts []string) { if len(parts) == 0 { // Drop all children here as - // this is a higher-level block + // this is a higher-level domain // than that we previously had. nn.child = nil return diff --git a/internal/cache/domain/domain_test.go b/internal/cache/domain/domain_test.go index 8f975497b..9e091e1d0 100644 --- a/internal/cache/domain/domain_test.go +++ b/internal/cache/domain/domain_test.go @@ -24,21 +24,21 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/cache/domain" ) -func TestBlockCache(t *testing.T) { - c := new(domain.BlockCache) +func TestCache(t *testing.T) { + c := new(domain.Cache) - blocks := []string{ + cachedDomains := []string{ "google.com", "google.co.uk", "pleroma.bad.host", } loader := func() ([]string, error) { - t.Log("load: returning blocked domains") - return blocks, nil + t.Log("load: returning cached domains") + return cachedDomains, nil } - // Check a list of known blocked domains. + // Check a list of known cached domains. for _, domain := range []string{ "google.com", "mail.google.com", @@ -47,13 +47,13 @@ func TestBlockCache(t *testing.T) { "pleroma.bad.host", "dev.pleroma.bad.host", } { - t.Logf("checking domain is blocked: %s", domain) - if b, _ := c.IsBlocked(domain, loader); !b { - t.Errorf("domain should be blocked: %s", domain) + t.Logf("checking domain matches: %s", domain) + if b, _ := c.Matches(domain, loader); !b { + t.Errorf("domain should be matched: %s", domain) } } - // Check a list of known unblocked domains. + // Check a list of known uncached domains. for _, domain := range []string{ "askjeeves.com", "ask-kim.co.uk", @@ -62,9 +62,9 @@ func TestBlockCache(t *testing.T) { "gts.bad.host", "mastodon.bad.host", } { - t.Logf("checking domain isn't blocked: %s", domain) - if b, _ := c.IsBlocked(domain, loader); b { - t.Errorf("domain should not be blocked: %s", domain) + t.Logf("checking domain isn't matched: %s", domain) + if b, _ := c.Matches(domain, loader); b { + t.Errorf("domain should not be matched: %s", domain) } } @@ -76,10 +76,10 @@ func TestBlockCache(t *testing.T) { knownErr := errors.New("known error") // Check that reload is actually performed and returns our error - if _, err := c.IsBlocked("", func() ([]string, error) { + if _, err := c.Matches("", func() ([]string, error) { t.Log("load: returning known error") return nil, knownErr }); !errors.Is(err, knownErr) { - t.Errorf("is blocked did not return expected error: %v", err) + t.Errorf("matches did not return expected error: %v", err) } } diff --git a/internal/cache/gts.go b/internal/cache/gts.go index 12e917919..16a1585f7 100644 --- a/internal/cache/gts.go +++ b/internal/cache/gts.go @@ -36,7 +36,8 @@ type GTSCaches struct { block *result.Cache[*gtsmodel.Block] blockIDs *SliceCache[string] boostOfIDs *SliceCache[string] - domainBlock *domain.BlockCache + domainAllow *domain.Cache + domainBlock *domain.Cache emoji *result.Cache[*gtsmodel.Emoji] emojiCategory *result.Cache[*gtsmodel.EmojiCategory] follow *result.Cache[*gtsmodel.Follow] @@ -72,6 +73,7 @@ func (c *GTSCaches) Init() { c.initBlock() c.initBlockIDs() c.initBoostOfIDs() + c.initDomainAllow() c.initDomainBlock() c.initEmoji() c.initEmojiCategory() @@ -139,8 +141,13 @@ func (c *GTSCaches) BoostOfIDs() *SliceCache[string] { return c.boostOfIDs } +// DomainAllow provides access to the domain allow database cache. +func (c *GTSCaches) DomainAllow() *domain.Cache { + return c.domainAllow +} + // DomainBlock provides access to the domain block database cache. -func (c *GTSCaches) DomainBlock() *domain.BlockCache { +func (c *GTSCaches) DomainBlock() *domain.Cache { return c.domainBlock } @@ -384,8 +391,12 @@ func (c *GTSCaches) initBoostOfIDs() { )} } +func (c *GTSCaches) initDomainAllow() { + c.domainAllow = new(domain.Cache) +} + func (c *GTSCaches) initDomainBlock() { - c.domainBlock = new(domain.BlockCache) + c.domainBlock = new(domain.Cache) } func (c *GTSCaches) initEmoji() { |