diff --git a/delivery/websocket/req_handler.go b/delivery/websocket/req_handler.go index e63fb32..0b43cea 100644 --- a/delivery/websocket/req_handler.go +++ b/delivery/websocket/req_handler.go @@ -2,8 +2,10 @@ package websocket import ( "fmt" + "slices" "github.com/dezh-tech/immortal/pkg/utils" + "github.com/dezh-tech/immortal/types" "github.com/dezh-tech/immortal/types/message" "github.com/gorilla/websocket" ) @@ -38,7 +40,9 @@ func (s *Server) handleReq(conn *websocket.Conn, m message.Message) { return } - if s.config.Limitation.AuthRequired && !*client.isKnown { + if (s.config.Limitation.AuthRequired || + slices.Contains(msg.Filter.Kinds, types.KindGiftWrap)) && + !*client.isKnown { client.challenge = utils.GenerateChallenge(10) authm := message.MakeAuth(client.challenge) @@ -73,7 +77,7 @@ func (s *Server) handleReq(conn *websocket.Conn, m message.Message) { return } - res, err := s.handler.HandleReq(&msg.Filter) + res, err := s.handler.HandleReq(&msg.Filter, *client.pubkey) if err != nil { _ = conn.WriteMessage(1, message.MakeNotice(fmt.Sprintf("error: can't process REQ message: %s", err.Error()))) status = databaseFail diff --git a/documents/NIPs.md b/documents/NIPs.md index 931cfeb..ba0f9e2 100644 --- a/documents/NIPs.md +++ b/documents/NIPs.md @@ -6,7 +6,9 @@ - [X] **NIP-13**: Proof of Work - [X] **NIP-40**: Expiration Timestamp - [X] **NIP-42**: Authentication of Clients to Relays +- [ ] **NIP-45**: Event Counts - [ ] **NIP-50**: Search Capability - [X] **NIP-56**: Reporting +- [X] **NIP-59**: Gift Wrap - [X] **NIP-62**: Right to Vanish - [X] **NIP-70**: Protected Events diff --git a/repository/delete.go b/repository/delete.go index dd0e5be..185a6eb 100644 --- a/repository/delete.go +++ b/repository/delete.go @@ -158,7 +158,7 @@ func (h *Handler) DeleteByFilter(f *filter.Filter) error { for kind, deleteFilter := range queryKinds { collectionName, isMultiKindColl := getCollectionName(kind) - query := filterToMongoQuery(deleteFilter, isMultiKindColl, kind) + query := filterToMongoQuery(deleteFilter, isMultiKindColl, kind, "") ctx, cancel := context.WithTimeout(context.Background(), h.db.QueryTimeout) diff --git a/repository/handler.go b/repository/handler.go index cb84ebd..5c68405 100644 --- a/repository/handler.go +++ b/repository/handler.go @@ -22,7 +22,7 @@ func New(cfg Config, db *database.Database, grpc grpcclient.IClient) *Handler { } } -func filterToMongoQuery(f *filter.Filter, isMultiKindColl bool, k types.Kind) bson.D { +func filterToMongoQuery(f *filter.Filter, isMultiKindColl bool, k types.Kind, pubkey string) bson.D { query := make(bson.D, 0) if isMultiKindColl { @@ -41,6 +41,10 @@ func filterToMongoQuery(f *filter.Filter, isMultiKindColl bool, k types.Kind) bs query = append(query, bson.E{Key: "pubkey", Value: bson.M{"$in": f.Authors}}) } + if k == types.KindGiftWrap && pubkey != "" { + f.Tags["p"] = []string{pubkey} + } + if len(f.Tags) > 0 { tagQueries := bson.A{} for tagKey, tagValues := range f.Tags { diff --git a/repository/req.go b/repository/req.go index bc8b88d..0818b79 100644 --- a/repository/req.go +++ b/repository/req.go @@ -11,7 +11,7 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) -func (h *Handler) HandleReq(f *filter.Filter) ([]event.Event, error) { +func (h *Handler) HandleReq(f *filter.Filter, pubkey string) ([]event.Event, error) { queryKinds := make(map[types.Kind]*filter.Filter) if len(f.Kinds) != 0 { @@ -30,7 +30,7 @@ func (h *Handler) HandleReq(f *filter.Filter) ([]event.Event, error) { for kind, filter := range queryKinds { collectionName, isMultiKindColl := getCollectionName(kind) - query := filterToMongoQuery(filter, isMultiKindColl, kind) + query := filterToMongoQuery(filter, isMultiKindColl, kind, pubkey) matchStage := bson.D{ {Key: "$match", Value: query}, diff --git a/types/event/event.go b/types/event/event.go index 9efed9e..5eebd9e 100644 --- a/types/event/event.go +++ b/types/event/event.go @@ -10,6 +10,8 @@ import ( "github.com/mailru/easyjson" ) +const hextable = "0123456789abcdef" + // Event represents an event structure defined on NIP-01. type Event struct { ID string `bson:"id" json:"id"` @@ -77,23 +79,43 @@ func (e *Event) GetRawID() [32]byte { return sha256.Sum256(e.Serialize()) } -// IsValid function validats an event Signature and ID. -func (e *Event) IsValid(id [32]byte) bool { +// checkID checks if the user provided id is valid. +func (e *Event) checkID(id [32]byte) bool { + for i := 0; i < 32; i++ { + b := hextable[id[i]>>4] + if b != e.ID[i*2] { + return false + } + + b = hextable[id[i]&0x0f] + if b != e.ID[i*2+1] { + return false + } + } + + return true +} + +func (e *Event) checkSig(id [32]byte) bool { + // turn pubkey hex to byte array. pk, err := hex.DecodeString(e.PublicKey) if err != nil { return false } + // construct the pubkey from byte array. pubkey, err := schnorr.ParsePubKey(pk) if err != nil { return false } + // turn signature hex to byte array. s, err := hex.DecodeString(e.Signature) if err != nil { return false } + // construct signature from byte array. sig, err := schnorr.ParseSignature(s) if err != nil { return false @@ -103,6 +125,20 @@ func (e *Event) IsValid(id [32]byte) bool { return sig.Verify(id[:], pubkey) } +// IsValid function validats an event Signature and ID. +func (e *Event) IsValid(id [32]byte) bool { + // make sure the user provided id is valid. + if !e.checkID(id) { + return false + } + + if !e.checkSig(id) { + return false + } + + return true +} + // IsProtected checks if ["-"] tag is present, check nip-70 for more. func (e *Event) IsProtected() bool { for _, t := range e.Tags {