88 lines
2.4 KiB
Go
88 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"slices"
|
|
|
|
"github.com/fiatjaf/khatru"
|
|
"github.com/nbd-wtf/go-nostr"
|
|
"github.com/nbd-wtf/go-nostr/nip29"
|
|
)
|
|
|
|
func requireKindAndSingleGroupIDOrSpecificEventReference(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
|
|
isMeta := false
|
|
isNormal := false
|
|
isReference := false
|
|
|
|
for _, kind := range filter.Kinds {
|
|
if slices.Contains(nip29.MetadataEventKinds, kind) {
|
|
isMeta = true
|
|
} else if isMeta {
|
|
// once we have one meta we can't have other stuff
|
|
return true, "it's not allowed to mix metadata kinds with others"
|
|
}
|
|
}
|
|
|
|
if !isMeta {
|
|
// we assume the caller wants normal events if the 'h' tag is specified
|
|
// or metadata events if the 'd' tag is specified
|
|
if hTags, hasHTags := filter.Tags["h"]; hasHTags && len(hTags) > 0 {
|
|
isNormal = true
|
|
} else if dTags, hasDTags := filter.Tags["d"]; hasDTags && len(dTags) > 0 {
|
|
isMeta = true
|
|
} else {
|
|
// this may be a request for "#e", "#a" or just "ids"
|
|
isReference = true
|
|
}
|
|
}
|
|
|
|
authed := khatru.GetAuthed(ctx)
|
|
|
|
switch {
|
|
case isNormal:
|
|
// access depends on whether a user is logged in and the groups are public or private
|
|
if tags, ok := filter.Tags["h"]; ok && len(tags) > 0 {
|
|
// "h" tags specified
|
|
for _, tag := range tags {
|
|
if group, _ := groups.Load(tag); group != nil {
|
|
if !group.Private {
|
|
continue // fine, this is public
|
|
}
|
|
|
|
// private,
|
|
if authed == "" {
|
|
return true, "auth-required: trying to read from a private group"
|
|
}
|
|
// check membership
|
|
group.mu.RLock()
|
|
if _, isMember := group.Members[authed]; isMember {
|
|
group.mu.Unlock()
|
|
continue // fine, this user is a member
|
|
}
|
|
group.mu.Unlock()
|
|
return true, "restricted: not a member"
|
|
}
|
|
}
|
|
}
|
|
case isReference:
|
|
if refE, ok := filter.Tags["e"]; ok && len(refE) > 0 {
|
|
// "#e" tags specified -- pablo's magic discovery trick
|
|
// we'll handle this while fetching the events so that we don't reveal private content
|
|
return false, ""
|
|
} else if refA, ok := filter.Tags["a"]; ok && len(refA) > 0 {
|
|
// "#a" tags specified -- idem
|
|
return false, ""
|
|
} else if len(filter.IDs) > 0 {
|
|
// "ids" specified -- idem
|
|
return false, ""
|
|
} else {
|
|
// other tags are not supported (unless they come together with "h")
|
|
return true, "invalid query, must have 'h', 'e' or 'a' tag"
|
|
}
|
|
case isMeta:
|
|
// should be fine
|
|
}
|
|
|
|
return false, ""
|
|
}
|