grain/server/handlers/event.go

136 lines
3.5 KiB
Go
Raw Normal View History

package handlers
import (
"context"
"encoding/json"
"fmt"
2024-07-30 15:27:38 +00:00
"grain/config"
"grain/server/db"
2024-09-02 00:51:02 +00:00
"grain/server/handlers/response"
"grain/server/utils"
2024-09-02 00:51:02 +00:00
nostr "grain/server/types"
"golang.org/x/net/websocket"
)
2024-07-25 13:57:24 +00:00
func HandleEvent(ws *websocket.Conn, message []interface{}) {
config.LimitedGoRoutine(func() {
if len(message) != 2 {
fmt.Println("Invalid EVENT message format")
response.SendNotice(ws, "", "Invalid EVENT message format")
return
}
eventData, ok := message[1].(map[string]interface{})
if !ok {
fmt.Println("Invalid event data format")
response.SendNotice(ws, "", "Invalid event data format")
return
}
eventBytes, err := json.Marshal(eventData)
if err != nil {
fmt.Println("Error marshaling event data:", err)
response.SendNotice(ws, "", "Error marshaling event data")
return
}
2024-09-02 00:51:02 +00:00
var evt nostr.Event
err = json.Unmarshal(eventBytes, &evt)
if err != nil {
fmt.Println("Error unmarshaling event data:", err)
response.SendNotice(ws, "", "Error unmarshaling event data")
return
}
// Signature check moved here
if !utils.CheckSignature(evt) {
response.SendOK(ws, evt.ID, false, "invalid: signature verification failed")
return
}
eventSize := len(eventBytes) // Calculate event size
2024-08-30 19:51:46 +00:00
if !handleBlacklistAndWhitelist(ws, evt) {
return
}
if !handleRateAndSizeLimits(ws, evt, eventSize) {
return
}
2024-09-02 00:51:02 +00:00
// This is where I'll handle storage for multiple database types in the future
db.StoreMongoEvent(context.TODO(), evt, ws)
fmt.Println("Event processed:", evt.ID)
})
}
2024-09-02 00:51:02 +00:00
func handleBlacklistAndWhitelist(ws *websocket.Conn, evt nostr.Event) bool {
2024-08-04 18:02:53 +00:00
if config.GetConfig().DomainWhitelist.Enabled {
domains := config.GetConfig().DomainWhitelist.Domains
pubkeys, err := utils.FetchPubkeysFromDomains(domains)
if err != nil {
fmt.Println("Error fetching pubkeys from domains:", err)
response.SendNotice(ws, "", "Error fetching pubkeys from domains")
2024-08-30 19:51:46 +00:00
return false
2024-08-04 18:02:53 +00:00
}
for _, pubkey := range pubkeys {
config.GetConfig().PubkeyWhitelist.Pubkeys = append(config.GetConfig().PubkeyWhitelist.Pubkeys, pubkey)
}
}
2024-09-02 00:51:02 +00:00
if blacklisted, msg := config.CheckBlacklist(evt.PubKey, evt.Content); blacklisted {
response.SendOK(ws, evt.ID, false, msg)
2024-08-30 19:51:46 +00:00
return false
}
2024-09-02 00:51:02 +00:00
if config.GetConfig().KindWhitelist.Enabled && !config.IsKindWhitelisted(evt.Kind) {
2024-08-03 20:18:34 +00:00
response.SendOK(ws, evt.ID, false, "not allowed: event kind is not whitelisted")
2024-08-30 19:51:46 +00:00
return false
2024-08-03 20:18:34 +00:00
}
2024-09-02 00:51:02 +00:00
if config.GetConfig().PubkeyWhitelist.Enabled && !config.IsPubKeyWhitelisted(evt.PubKey) {
2024-08-03 20:18:34 +00:00
response.SendOK(ws, evt.ID, false, "not allowed: pubkey or npub is not whitelisted")
2024-08-30 19:51:46 +00:00
return false
2024-08-03 18:27:58 +00:00
}
2024-08-30 19:51:46 +00:00
return true
}
2024-09-02 00:51:02 +00:00
func handleRateAndSizeLimits(ws *websocket.Conn, evt nostr.Event, eventSize int) bool {
2024-08-30 19:51:46 +00:00
rateLimiter := config.GetRateLimiter()
sizeLimiter := config.GetSizeLimiter()
2024-07-27 14:06:34 +00:00
category := determineCategory(evt.Kind)
2024-07-25 13:57:24 +00:00
2024-07-26 14:02:34 +00:00
if allowed, msg := rateLimiter.AllowEvent(evt.Kind, category); !allowed {
response.SendOK(ws, evt.ID, false, msg)
2024-08-30 19:51:46 +00:00
return false
2024-07-25 13:57:24 +00:00
}
2024-07-26 20:46:01 +00:00
if allowed, msg := sizeLimiter.AllowSize(evt.Kind, eventSize); !allowed {
response.SendOK(ws, evt.ID, false, msg)
2024-08-30 19:51:46 +00:00
return false
}
return true
}
2024-07-27 14:06:34 +00:00
func determineCategory(kind int) string {
switch {
case kind == 0, kind == 3, kind >= 10000 && kind < 20000:
return "replaceable"
case kind == 1, kind >= 4 && kind < 45, kind >= 1000 && kind < 10000:
return "regular"
case kind == 2:
return "deprecated"
case kind >= 20000 && kind < 30000:
return "ephemeral"
case kind >= 30000 && kind < 40000:
return "parameterized_replaceable"
default:
return "unknown"
}
}