forked from coracle/zooid
Generate member lists
This commit is contained in:
+9
-9
@@ -79,6 +79,10 @@ func LoadConfig(filename string) (*Config, error) {
|
|||||||
return &config, nil
|
return &config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (config *Config) Sign(event *nostr.Event) error {
|
||||||
|
return event.Sign(config.secret)
|
||||||
|
}
|
||||||
|
|
||||||
func (config *Config) GetSelf() nostr.PubKey {
|
func (config *Config) GetSelf() nostr.PubKey {
|
||||||
return config.secret.Public()
|
return config.secret.Public()
|
||||||
}
|
}
|
||||||
@@ -87,16 +91,12 @@ func (config *Config) IsSelf(pubkey nostr.PubKey) bool {
|
|||||||
return pubkey == config.GetSelf()
|
return pubkey == config.GetSelf()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) Sign(event *nostr.Event) error {
|
func (config *Config) GetOwner() nostr.PubKey {
|
||||||
return event.Sign(config.secret)
|
return nostr.MustPubKeyFromHex(config.Info.Pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) IsOwner(pubkey nostr.PubKey) bool {
|
func (config *Config) IsOwner(pubkey nostr.PubKey) bool {
|
||||||
return pubkey.Hex() == config.Info.Pubkey
|
return pubkey == config.GetOwner()
|
||||||
}
|
|
||||||
|
|
||||||
func (config *Config) IsAdmin(pubkey nostr.PubKey) bool {
|
|
||||||
return config.IsOwner(pubkey) || config.IsSelf(pubkey)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) GetAssignedRoles(pubkey nostr.PubKey) []Role {
|
func (config *Config) GetAssignedRoles(pubkey nostr.PubKey) []Role {
|
||||||
@@ -124,7 +124,7 @@ func (config *Config) GetAllRoles(pubkey nostr.PubKey) []Role {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) CanInvite(pubkey nostr.PubKey) bool {
|
func (config *Config) CanInvite(pubkey nostr.PubKey) bool {
|
||||||
if config.IsAdmin(pubkey) {
|
if config.IsOwner(pubkey) || config.IsSelf(pubkey) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ func (config *Config) CanInvite(pubkey nostr.PubKey) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) CanManage(pubkey nostr.PubKey) bool {
|
func (config *Config) CanManage(pubkey nostr.PubKey) bool {
|
||||||
if config.IsAdmin(pubkey) {
|
if config.IsOwner(pubkey) || config.IsSelf(pubkey) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -387,7 +387,7 @@ func (events *EventStore) GetOrCreateApplicationSpecificData(d string) nostr.Eve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (events *EventStore) GetOrCreateMemberList() nostr.Event {
|
func (events *EventStore) GetOrCreateRelayMembersList() nostr.Event {
|
||||||
filter := nostr.Filter{
|
filter := nostr.Filter{
|
||||||
Kinds: []nostr.Kind{RELAY_MEMBERS},
|
Kinds: []nostr.Kind{RELAY_MEMBERS},
|
||||||
}
|
}
|
||||||
|
|||||||
+140
-44
@@ -4,6 +4,8 @@ import (
|
|||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
|
||||||
func GetGroupIDFromEvent(event nostr.Event) string {
|
func GetGroupIDFromEvent(event nostr.Event) string {
|
||||||
tag := event.Tags.Find("h")
|
tag := event.Tags.Find("h")
|
||||||
|
|
||||||
@@ -14,11 +16,16 @@ func GetGroupIDFromEvent(event nostr.Event) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Struct definition
|
||||||
|
|
||||||
type GroupStore struct {
|
type GroupStore struct {
|
||||||
Config *Config
|
Config *Config
|
||||||
Events *EventStore
|
Events *EventStore
|
||||||
|
Management *ManagementStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Metadata
|
||||||
|
|
||||||
func (g *GroupStore) GetMetadata(h string) nostr.Event {
|
func (g *GroupStore) GetMetadata(h string) nostr.Event {
|
||||||
filter := nostr.Filter{
|
filter := nostr.Filter{
|
||||||
Kinds: []nostr.Kind{nostr.KindSimpleGroupMetadata},
|
Kinds: []nostr.Kind{nostr.KindSimpleGroupMetadata},
|
||||||
@@ -34,6 +41,81 @@ func (g *GroupStore) GetMetadata(h string) nostr.Event {
|
|||||||
return nostr.Event{}
|
return nostr.Event{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GroupStore) SetMetadataFromEvent(event nostr.Event) error {
|
||||||
|
tags := nostr.Tags{}
|
||||||
|
|
||||||
|
for _, tag := range event.Tags {
|
||||||
|
if len(tag) >= 2 && tag[0] == "h" {
|
||||||
|
tags = append(tags, nostr.Tag{"d", tag[1]})
|
||||||
|
} else {
|
||||||
|
tags = append(tags, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metadataEvent := nostr.Event{
|
||||||
|
Kind: nostr.KindSimpleGroupMetadata,
|
||||||
|
CreatedAt: event.CreatedAt,
|
||||||
|
Tags: tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
return g.Events.SignAndStoreEvent(&metadataEvent, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletion
|
||||||
|
|
||||||
|
func (g *GroupStore) DeleteGroup(h string) {
|
||||||
|
filters := []nostr.Filter{
|
||||||
|
{
|
||||||
|
Tags: nostr.TagMap{
|
||||||
|
"d": []string{h},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Tags: nostr.TagMap{
|
||||||
|
"h": []string{h},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filter := range filters {
|
||||||
|
for event := range g.Events.QueryEvents(filter, 0) {
|
||||||
|
g.Events.DeleteEvent(event.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Admins
|
||||||
|
|
||||||
|
func (g *GroupStore) IsAdmin(h string, pubkey nostr.PubKey) bool {
|
||||||
|
return g.Management.IsAdmin(pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupStore) GetAdmins(h string) []nostr.PubKey {
|
||||||
|
return g.Management.GetAdmins()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupStore) GenerateAdminsEvent(h string) nostr.Event {
|
||||||
|
tags := nostr.Tags{
|
||||||
|
nostr.Tag{"-"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pubkey := range g.GetAdmins(h) {
|
||||||
|
tags = append(tags, nostr.Tag{"p", pubkey.Hex()})
|
||||||
|
}
|
||||||
|
|
||||||
|
event := nostr.Event{
|
||||||
|
Kind: nostr.KindSimpleGroupAdmins,
|
||||||
|
CreatedAt: nostr.Now(),
|
||||||
|
Tags: tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Config.Sign(&event)
|
||||||
|
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
// Membership
|
||||||
|
|
||||||
func (g *GroupStore) AddMember(h string, pubkey nostr.PubKey) error {
|
func (g *GroupStore) AddMember(h string, pubkey nostr.PubKey) error {
|
||||||
event := nostr.Event{
|
event := nostr.Event{
|
||||||
Kind: nostr.KindSimpleGroupPutUser,
|
Kind: nostr.KindSimpleGroupPutUser,
|
||||||
@@ -60,47 +142,6 @@ func (g *GroupStore) RemoveMember(h string, pubkey nostr.PubKey) error {
|
|||||||
return g.Events.SignAndStoreEvent(&event, true)
|
return g.Events.SignAndStoreEvent(&event, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupStore) SetMetadataFromEvent(event nostr.Event) error {
|
|
||||||
tags := nostr.Tags{}
|
|
||||||
|
|
||||||
for _, tag := range event.Tags {
|
|
||||||
if len(tag) >= 2 && tag[0] == "h" {
|
|
||||||
tags = append(tags, nostr.Tag{"d", tag[1]})
|
|
||||||
} else {
|
|
||||||
tags = append(tags, tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
metadataEvent := nostr.Event{
|
|
||||||
Kind: nostr.KindSimpleGroupMetadata,
|
|
||||||
CreatedAt: event.CreatedAt,
|
|
||||||
Tags: tags,
|
|
||||||
}
|
|
||||||
|
|
||||||
return g.Events.SignAndStoreEvent(&metadataEvent, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GroupStore) DeleteGroup(h string) {
|
|
||||||
filters := []nostr.Filter{
|
|
||||||
{
|
|
||||||
Tags: nostr.TagMap{
|
|
||||||
"d": []string{h},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Tags: nostr.TagMap{
|
|
||||||
"h": []string{h},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, filter := range filters {
|
|
||||||
for event := range g.Events.QueryEvents(filter, 0) {
|
|
||||||
g.Events.DeleteEvent(event.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *GroupStore) IsMember(h string, pubkey nostr.PubKey) bool {
|
func (g *GroupStore) IsMember(h string, pubkey nostr.PubKey) bool {
|
||||||
filter := nostr.Filter{
|
filter := nostr.Filter{
|
||||||
Kinds: []nostr.Kind{nostr.KindSimpleGroupPutUser, nostr.KindSimpleGroupRemoveUser},
|
Kinds: []nostr.Kind{nostr.KindSimpleGroupPutUser, nostr.KindSimpleGroupRemoveUser},
|
||||||
@@ -123,10 +164,65 @@ func (g *GroupStore) IsMember(h string, pubkey nostr.PubKey) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GroupStore) GetMembers(h string) []nostr.PubKey {
|
||||||
|
filter := nostr.Filter{
|
||||||
|
Kinds: []nostr.Kind{nostr.KindSimpleGroupPutUser, nostr.KindSimpleGroupRemoveUser},
|
||||||
|
Tags: nostr.TagMap{
|
||||||
|
"h": []string{h},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
members := make([]nostr.PubKey, 0)
|
||||||
|
|
||||||
|
for event := range g.Events.QueryEvents(filter, 0) {
|
||||||
|
for hex := range event.Tags.FindAll("p") {
|
||||||
|
if pubkey, err := nostr.PubKeyFromHex(hex[1]); err != nil {
|
||||||
|
if event.Kind == nostr.KindSimpleGroupPutUser {
|
||||||
|
members = append(members, pubkey)
|
||||||
|
} else {
|
||||||
|
members = Remove(members, pubkey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return members
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupStore) GenerateMembersEvent(h string) nostr.Event {
|
||||||
|
tags := nostr.Tags{
|
||||||
|
nostr.Tag{"-"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pubkey := range g.GetMembers(h) {
|
||||||
|
tags = append(tags, nostr.Tag{"p", pubkey.Hex()})
|
||||||
|
}
|
||||||
|
|
||||||
|
event := nostr.Event{
|
||||||
|
Kind: nostr.KindSimpleGroupMembers,
|
||||||
|
CreatedAt: nostr.Now(),
|
||||||
|
Tags: tags,
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Config.Sign(&event)
|
||||||
|
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other stuff
|
||||||
|
|
||||||
func (g *GroupStore) HasAccess(h string, pubkey nostr.PubKey) bool {
|
func (g *GroupStore) HasAccess(h string, pubkey nostr.PubKey) bool {
|
||||||
if !HasTag(g.GetMetadata(h).Tags, "closed") {
|
if !HasTag(g.GetMetadata(h).Tags, "closed") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return g.IsMember(h, pubkey)
|
if g.IsAdmin(h, pubkey) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.IsMember(h, pubkey) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -50,8 +50,9 @@ func MakeInstance(filename string) (*Instance, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
groups := &GroupStore{
|
groups := &GroupStore{
|
||||||
Config: config,
|
Config: config,
|
||||||
Events: events,
|
Events: events,
|
||||||
|
Management: management,
|
||||||
}
|
}
|
||||||
|
|
||||||
instance := &Instance{
|
instance := &Instance{
|
||||||
|
|||||||
+31
-7
@@ -120,11 +120,35 @@ func (m *ManagementStore) PubkeyIsBanned(pubkey nostr.PubKey) bool {
|
|||||||
return tag != nil
|
return tag != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Admins
|
||||||
|
|
||||||
|
func (m *ManagementStore) IsAdmin(pubkey nostr.PubKey) bool {
|
||||||
|
return m.Config.IsOwner(pubkey) || m.Config.IsSelf(pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ManagementStore) GetAdmins() []nostr.PubKey {
|
||||||
|
members := make([]nostr.PubKey, 0)
|
||||||
|
|
||||||
|
members = append(members, m.Config.GetOwner())
|
||||||
|
|
||||||
|
members = append(members, m.Config.GetSelf())
|
||||||
|
|
||||||
|
for _, role := range m.Config.Roles {
|
||||||
|
if role.CanManage {
|
||||||
|
for _, pubkey := range role.Pubkeys {
|
||||||
|
members = append(members, nostr.MustPubKeyFromHex(pubkey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return members
|
||||||
|
}
|
||||||
|
|
||||||
// Membership
|
// Membership
|
||||||
|
|
||||||
func (m *ManagementStore) GetMembers() []nostr.PubKey {
|
func (m *ManagementStore) GetMembers() []nostr.PubKey {
|
||||||
pubkeys := make([]nostr.PubKey, 0)
|
pubkeys := make([]nostr.PubKey, 0)
|
||||||
for tag := range m.Events.GetOrCreateMemberList().Tags.FindAll("member") {
|
for tag := range m.Events.GetOrCreateRelayMembersList().Tags.FindAll("member") {
|
||||||
pubkey, err := nostr.PubKeyFromHex(tag[1])
|
pubkey, err := nostr.PubKeyFromHex(tag[1])
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -136,11 +160,11 @@ func (m *ManagementStore) GetMembers() []nostr.PubKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *ManagementStore) IsMember(pubkey nostr.PubKey) bool {
|
func (m *ManagementStore) IsMember(pubkey nostr.PubKey) bool {
|
||||||
return m.Events.GetOrCreateMemberList().Tags.FindWithValue("member", pubkey.Hex()) != nil
|
return m.Events.GetOrCreateRelayMembersList().Tags.FindWithValue("member", pubkey.Hex()) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ManagementStore) AddMember(pubkey nostr.PubKey) error {
|
func (m *ManagementStore) AddMember(pubkey nostr.PubKey) error {
|
||||||
membersEvent := m.Events.GetOrCreateMemberList()
|
membersEvent := m.Events.GetOrCreateRelayMembersList()
|
||||||
|
|
||||||
if membersEvent.Tags.FindWithValue("member", pubkey.Hex()) == nil {
|
if membersEvent.Tags.FindWithValue("member", pubkey.Hex()) == nil {
|
||||||
addMemberEvent := nostr.Event{
|
addMemberEvent := nostr.Event{
|
||||||
@@ -167,7 +191,7 @@ func (m *ManagementStore) AddMember(pubkey nostr.PubKey) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *ManagementStore) RemoveMember(pubkey nostr.PubKey) error {
|
func (m *ManagementStore) RemoveMember(pubkey nostr.PubKey) error {
|
||||||
membersEvent := m.Events.GetOrCreateMemberList()
|
membersEvent := m.Events.GetOrCreateRelayMembersList()
|
||||||
|
|
||||||
if membersEvent.Tags.FindWithValue("member", pubkey.Hex()) != nil {
|
if membersEvent.Tags.FindWithValue("member", pubkey.Hex()) != nil {
|
||||||
removeMemberEvent := nostr.Event{
|
removeMemberEvent := nostr.Event{
|
||||||
@@ -224,7 +248,7 @@ func (m *ManagementStore) GetAllowedPubkeyItems() []nip86.PubKeyReason {
|
|||||||
reasons := make([]nip86.PubKeyReason, 0)
|
reasons := make([]nip86.PubKeyReason, 0)
|
||||||
|
|
||||||
reasons = append(reasons, nip86.PubKeyReason{
|
reasons = append(reasons, nip86.PubKeyReason{
|
||||||
PubKey: nostr.MustPubKeyFromHex(m.Config.Info.Pubkey),
|
PubKey: m.Config.GetOwner(),
|
||||||
Reason: "relay owner",
|
Reason: "relay owner",
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -242,7 +266,7 @@ func (m *ManagementStore) GetAllowedPubkeyItems() []nip86.PubKeyReason {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for tag := range m.Events.GetOrCreateMemberList().Tags.FindAll("member") {
|
for tag := range m.Events.GetOrCreateRelayMembersList().Tags.FindAll("member") {
|
||||||
pubkey, err := nostr.PubKeyFromHex(tag[1])
|
pubkey, err := nostr.PubKeyFromHex(tag[1])
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -276,7 +300,7 @@ func (m *ManagementStore) AllowPubkey(pubkey nostr.PubKey) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *ManagementStore) HasAccess(pubkey nostr.PubKey) bool {
|
func (m *ManagementStore) HasAccess(pubkey nostr.PubKey) bool {
|
||||||
if m.Config.IsAdmin(pubkey) {
|
if m.IsAdmin(pubkey) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,16 @@ func Filter[T any](ss []T, test func(T) bool) (ret []T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Remove[T comparable](slice []T, element T) []T {
|
||||||
|
for i, v := range slice {
|
||||||
|
if v == element {
|
||||||
|
return append(slice[:i], slice[i+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
func RandomString(n int) string {
|
func RandomString(n int) string {
|
||||||
|
|||||||
Reference in New Issue
Block a user