Skip to content

Commit

Permalink
fix(security): check event id, return giftwraps to receivers only. (#121
Browse files Browse the repository at this point in the history
)
  • Loading branch information
kehiy authored Feb 5, 2025
1 parent 4ed347c commit db8156e
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 8 deletions.
8 changes: 6 additions & 2 deletions delivery/websocket/req_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions documents/NIPs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion repository/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
6 changes: 5 additions & 1 deletion repository/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions repository/req.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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},
Expand Down
40 changes: 38 additions & 2 deletions types/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down

0 comments on commit db8156e

Please sign in to comment.