khatru-pyramid/whitelist.go

103 lines
2.2 KiB
Go
Raw Normal View History

2023-09-06 20:49:18 +02:00
package main
import (
"encoding/json"
2023-10-28 21:40:54 -03:00
"fmt"
2023-09-06 20:49:18 +02:00
"os"
"github.com/nbd-wtf/go-nostr"
)
2023-10-29 13:45:46 -03:00
const WHITELIST_FILE = "users.json"
2023-09-06 20:49:18 +02:00
2023-10-29 13:45:46 -03:00
type Whitelist map[string]string // { [user_pubkey]: [invited_by] }
2023-09-06 20:49:18 +02:00
2023-10-29 13:45:46 -03:00
func addToWhitelist(pubkey string, inviter string) error {
if !isPublicKeyInWhitelist(inviter) {
return fmt.Errorf("pubkey %s doesn't have permission to invite", inviter)
2023-09-06 20:49:18 +02:00
}
if !nostr.IsValidPublicKeyHex(pubkey) {
return fmt.Errorf("pubkey invalid: %s", pubkey)
}
if isPublicKeyInWhitelist(pubkey) {
return fmt.Errorf("pubkey already in whitelist: %s", pubkey)
}
whitelist[pubkey] = inviter
2023-10-29 13:45:46 -03:00
return saveWhitelist()
}
2023-10-29 13:45:46 -03:00
func isPublicKeyInWhitelist(pubkey string) bool {
_, ok := whitelist[pubkey]
return ok
}
2023-09-06 20:49:18 +02:00
2023-11-02 21:08:57 -03:00
func isAncestorOf(ancestor string, target string) bool {
parent, ok := whitelist[target]
if !ok {
// parent is not in whitelist, this means this is a top-level user and can
// only be deleted by manually editing the users.json file
return false
2023-10-28 20:21:15 -03:00
}
2023-11-02 21:08:57 -03:00
if parent == ancestor {
// if the pubkey is the parent, that means it is an ancestor
return true
}
// otherwise we climb one degree up and test with the parent of the target
return isAncestorOf(ancestor, parent)
2023-10-28 20:21:15 -03:00
}
2023-10-29 13:45:46 -03:00
func removeFromWhitelist(target string, deleter string) error {
// check if this user is a descendant of the user who issued the delete command
if !isAncestorOf(deleter, target) {
return fmt.Errorf("insufficient permissions to delete this")
2023-10-28 21:40:54 -03:00
}
2023-10-28 20:21:15 -03:00
2023-10-29 13:45:46 -03:00
// if we got here that means we have permission to delete the target
delete(whitelist, target)
// delete all people who were invited by the target
removeDescendantsFromWhitelist(target)
2023-10-28 20:21:15 -03:00
return saveWhitelist()
}
2023-10-29 13:45:46 -03:00
func removeDescendantsFromWhitelist(ancestor string) {
for pubkey, inviter := range whitelist {
if inviter == ancestor {
delete(whitelist, pubkey)
removeDescendantsFromWhitelist(pubkey)
}
2023-09-06 20:49:18 +02:00
}
2023-10-29 13:45:46 -03:00
}
2023-10-29 13:45:46 -03:00
func loadWhitelist() error {
b, err := os.ReadFile(WHITELIST_FILE)
2023-09-06 20:49:18 +02:00
if err != nil {
return err
}
2023-10-29 13:45:46 -03:00
if err := json.Unmarshal(b, &whitelist); err != nil {
2023-09-06 20:49:18 +02:00
return err
}
2023-09-06 20:49:18 +02:00
return nil
}
func saveWhitelist() error {
2023-09-06 20:49:18 +02:00
jsonBytes, err := json.Marshal(whitelist)
if err != nil {
return err
}
2023-10-29 13:45:46 -03:00
if err := os.WriteFile(WHITELIST_FILE, jsonBytes, 0644); err != nil {
2023-09-06 20:49:18 +02:00
return err
}
2023-09-06 20:49:18 +02:00
return nil
}