Skip to content

Commit

Permalink
implemented signiture verification methods to Np2pEvent and Np2pEvent…
Browse files Browse the repository at this point in the history
…ForRest.
  • Loading branch information
ryogrid committed Apr 24, 2024
1 parent 1026fbf commit b9ba64a
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 178 deletions.
196 changes: 27 additions & 169 deletions api_server/api_server.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package api_server

import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/ant0ine/go-json-rest/rest"
"github.com/ryogrid/nostrp2p/core"
Expand All @@ -19,148 +17,8 @@ import (
type NoArgReq struct {
}

type Np2pEventForREST struct {
Id string `json:"id"` // string of ID (32bytes) in hex
Pubkey string `json:"pubkey"` // string of Pubkey(encoded 256bit uint (holiman/uint256)) in hex
Created_at int64 `json:"created_at"` // unix timestamp in seconds
Kind uint16 `json:"kind"` // integer between 0 and 65535
Tags [][]string `json:"tags"` // Key: tag string, Value: string
Content string `json:"content"`
Sig string `json:"sig"` // string of Sig(64-bytes integr of the signature) in hex
}

type Np2pReqForREST struct {
Ids []string `json:"ids"`
Tag []string `json:"tag"` // "#<single-letter (a-zA-Z)>": <a list of tag values, for #e — a list of event ids, for #p — a list of pubkeys, etc.>
Authors []string `json:"authors"`
Kinds []int `json:"kinds"` // list of kind numbers (ex: "1,2,3")
Since int64 `json:"since"`
Until int64 `json:"until"`
Limit int64 `json:"limit"`
}

func (p *Np2pReqForREST) UnmarshalJSON(data []byte) error {
type Np2pReqForREST2 struct {
Ids []string `json:"ids"`
Tag []string `json:"tag"` // "#<single-letter (a-zA-Z)>": <a list of tag values, for #e — a list of event ids, for #p — a list of pubkeys, etc.>
Authors []string `json:"authors"`
Kinds []int `json:"kinds"`
Since int64 `json:"since"`
Until int64 `json:"until"`
Limit int64 `json:"limit"`
}

var req Np2pReqForREST2
json.Unmarshal(data, &req)
*p = *(*Np2pReqForREST)(&req)

var tag map[string][]string
json.Unmarshal(data, &tag)

for k, v := range tag {
if k[0] == '#' && len(k) == 2 {
if v == nil {
continue
}
//fmt.Println(v)
//fmt.Println(reflect.TypeOf(v))
p.Tag = []string{k}
for _, val := range v {
p.Tag = append(p.Tag, val)
}
}
}

return nil
}

func NewNp2pEventForREST(evt *schema.Np2pEvent) *Np2pEventForREST {
//idStr := fmt.Sprintf("%x", evt.Id[:])
idStr := hex.EncodeToString(evt.Id[:])
pubkeyStr := hex.EncodeToString(evt.Pubkey[:])
sigStr := ""
if evt.Sig != nil {
sigStr = hex.EncodeToString(evt.Sig[:])
}

tagsArr := make([][]string, 0)
for k, v := range evt.Tags {
tmpArr := make([]string, 0)
r := []rune(k)
// remove duplicated tag suffix (ex: "p_0" -> "p")
tmpArr = append(tmpArr, string(r[0]))
for _, val := range v {
tmpArr = append(tmpArr, val.(string))
}
tagsArr = append(tagsArr, tmpArr)
}

return &Np2pEventForREST{
Id: idStr, // remove leading zeros
Pubkey: pubkeyStr, //fmt.Sprintf("%x", evt.Pubkey[:]),
Created_at: evt.Created_at,
Kind: evt.Kind,
Tags: tagsArr,
Content: evt.Content,
Sig: sigStr,
}
}

func NewNp2pEventFromREST(evt *Np2pEventForREST) *schema.Np2pEvent {
tagsMap := make(map[string][]interface{})
tagCntMap := make(map[string]int)
for _, tag := range evt.Tags {
vals := make([]interface{}, 0)
for _, val := range tag[1:] {
vals = append(vals, val)
}
if _, ok := tagCntMap[tag[0]]; ok {
tagCntMap[tag[0]]++
tag[0] = fmt.Sprintf("%s_%d", tag[0], tagCntMap[tag[0]])
tagsMap[tag[0]] = vals
} else {
tagCntMap[tag[0]] = 0
tagsMap[tag[0]] = vals
}

}

pkey, err := hex.DecodeString(evt.Pubkey)
if err != nil {
panic(err)
}
pkey32 := [32]byte{}
copy(pkey32[:], pkey)
evtId, err := hex.DecodeString(evt.Id)
if err != nil {
panic(err)
}
evtId32 := [32]byte{}
copy(evtId32[:], evtId)

allBytes, err := hex.DecodeString(evt.Sig)
if err != nil {
panic(err)
}

var sigBytes [64]byte
copy(sigBytes[:], allBytes)

retEvt := &schema.Np2pEvent{
Pubkey: pkey32, //pkey.Bytes32(),
Id: evtId32, //evtId.Bytes32(),
Created_at: evt.Created_at,
Kind: evt.Kind,
Tags: tagsMap,
Content: evt.Content,
Sig: &sigBytes,
}

return retEvt
}

type EventsResp struct {
Events []Np2pEventForREST `json:"results"`
Events []schema.Np2pEventForREST `json:"results"`
}
type GeneralResp struct {
Status string
Expand All @@ -175,7 +33,7 @@ func NewApiServer(peer *core.Np2pPeer) *ApiServer {
}

func (s *ApiServer) publishHandler(w rest.ResponseWriter, req *rest.Request) {
input := Np2pEventForREST{}
input := schema.Np2pEventForREST{}
err := req.DecodeJsonPayload(&input)

if glo_val.DenyWriteMode {
Expand Down Expand Up @@ -210,8 +68,8 @@ func (s *ApiServer) publishHandler(w rest.ResponseWriter, req *rest.Request) {
}
}

func (s *ApiServer) sendRePost(w rest.ResponseWriter, input *Np2pEventForREST) {
evt := NewNp2pEventFromREST(input)
func (s *ApiServer) sendRePost(w rest.ResponseWriter, input *schema.Np2pEventForREST) {
evt := schema.NewNp2pEventFromREST(input)
s.buzzPeer.MessageMan.BcastOwnPost(evt)

// store for myself
Expand All @@ -220,7 +78,7 @@ func (s *ApiServer) sendRePost(w rest.ResponseWriter, input *Np2pEventForREST) {
w.WriteJson(&EventsResp{})
}

func (s *ApiServer) sendPost(w rest.ResponseWriter, input *Np2pEventForREST) {
func (s *ApiServer) sendPost(w rest.ResponseWriter, input *schema.Np2pEventForREST) {
if input.Content == "" {
rest.Error(w, "Content is required", 400)
return
Expand All @@ -241,7 +99,7 @@ func (s *ApiServer) sendPost(w rest.ResponseWriter, input *Np2pEventForREST) {
}
}

evt := NewNp2pEventFromREST(input)
evt := schema.NewNp2pEventFromREST(input)
if len(sendDests) > 0 && !isQuoteRpost {
// send to specified users because post is mention or reply
resendDests := make([]uint64, 0)
Expand All @@ -267,13 +125,13 @@ func (s *ApiServer) sendPost(w rest.ResponseWriter, input *Np2pEventForREST) {
w.WriteJson(&EventsResp{})
}

func (s *ApiServer) updateProfile(w rest.ResponseWriter, input *Np2pEventForREST) {
func (s *ApiServer) updateProfile(w rest.ResponseWriter, input *schema.Np2pEventForREST) {
if input.Tags == nil {
rest.Error(w, "Tags is null", http.StatusBadRequest)
return
}

evt := NewNp2pEventFromREST(input)
evt := schema.NewNp2pEventFromREST(input)
if *glo_val.SelfPubkey == evt.Pubkey {
s.buzzPeer.MessageMan.BcastProfile(evt)
// update local profile
Expand All @@ -285,13 +143,13 @@ func (s *ApiServer) updateProfile(w rest.ResponseWriter, input *Np2pEventForREST
})
}

func (s *ApiServer) setOrUpdateFollowList(w rest.ResponseWriter, input *Np2pEventForREST) {
func (s *ApiServer) setOrUpdateFollowList(w rest.ResponseWriter, input *schema.Np2pEventForREST) {
if input.Tags == nil {
rest.Error(w, "Tags is null", http.StatusBadRequest)
return
}

evt := NewNp2pEventFromREST(input)
evt := schema.NewNp2pEventFromREST(input)
if *glo_val.SelfPubkey == evt.Pubkey {
s.buzzPeer.MessageMan.DataMan.StoreEvent(evt)
// update local profile
Expand All @@ -303,8 +161,8 @@ func (s *ApiServer) setOrUpdateFollowList(w rest.ResponseWriter, input *Np2pEven
})
}

func (s *ApiServer) sendReaction(w rest.ResponseWriter, input *Np2pEventForREST) {
evt := NewNp2pEventFromREST(input)
func (s *ApiServer) sendReaction(w rest.ResponseWriter, input *schema.Np2pEventForREST) {
evt := schema.NewNp2pEventFromREST(input)
err := s.buzzPeer.MessageMan.UnicastEventData(evt.Tags["p"][0].(string), evt)
if err != nil && evt.Tags["p"][0].(string) != glo_val.SelfPubkeyStr {
// destination server is offline
Expand All @@ -323,7 +181,7 @@ func (s *ApiServer) sendReaction(w rest.ResponseWriter, input *Np2pEventForREST)
}

func (s *ApiServer) reqHandler(w rest.ResponseWriter, req *rest.Request) {
input := Np2pReqForREST{}
input := schema.Np2pReqForREST{}
err := req.DecodeJsonPayload(&input)

//fmt.Println("reqHandler")
Expand All @@ -339,7 +197,7 @@ func (s *ApiServer) reqHandler(w rest.ResponseWriter, req *rest.Request) {

// for supporting Nostr clients
w.WriteJson(&EventsResp{
Events: []Np2pEventForREST{},
Events: []schema.Np2pEventForREST{},
})
return
}
Expand All @@ -361,14 +219,14 @@ func (s *ApiServer) reqHandler(w rest.ResponseWriter, req *rest.Request) {
} else {

w.WriteJson(&EventsResp{
Events: []Np2pEventForREST{},
Events: []schema.Np2pEventForREST{},
})
return
}
}

// RESTRICTION: only one ID and author is supported
func (s *ApiServer) getPost(w rest.ResponseWriter, input *Np2pReqForREST) {
func (s *ApiServer) getPost(w rest.ResponseWriter, input *schema.Np2pReqForREST) {
if input.Ids == nil || len(input.Ids) == 0 || input.Authors == nil || len(input.Authors) == 0 {
rest.Error(w, "Ids and Authors are needed", http.StatusBadRequest)
return
Expand All @@ -380,44 +238,44 @@ func (s *ApiServer) getPost(w rest.ResponseWriter, input *Np2pReqForREST) {

if ok {
// found at local
w.WriteJson(&EventsResp{Events: []Np2pEventForREST{*NewNp2pEventForREST(gotEvt)}})
w.WriteJson(&EventsResp{Events: []schema.Np2pEventForREST{*schema.NewNp2pEventForREST(gotEvt)}})
} else {
// post data will be included on response of "getEvents"
w.WriteJson(&EventsResp{Events: []Np2pEventForREST{}})
w.WriteJson(&EventsResp{Events: []schema.Np2pEventForREST{}})
// request post data for future
s.buzzPeer.MessageMan.UnicastPostReq(shortPkey, tgtEvtId)
}
}

func (s *ApiServer) getProfile(w rest.ResponseWriter, input *Np2pReqForREST) {
func (s *ApiServer) getProfile(w rest.ResponseWriter, input *schema.Np2pReqForREST) {
shortPkey := np2p_util.GetUint64FromHexPubKeyStr(input.Authors[0])
profEvt := s.buzzPeer.MessageMan.DataMan.GetProfileLocal(shortPkey)

if profEvt != nil {
w.WriteJson(&EventsResp{Events: []Np2pEventForREST{*NewNp2pEventForREST(profEvt)}})
w.WriteJson(&EventsResp{Events: []schema.Np2pEventForREST{*schema.NewNp2pEventForREST(profEvt)}})
} else {
// profile data will be included on response of "getEvents"
w.WriteJson(&EventsResp{Events: []Np2pEventForREST{}})
w.WriteJson(&EventsResp{Events: []schema.Np2pEventForREST{}})
// request profile data for future
s.buzzPeer.MessageMan.UnicastProfileReq(shortPkey)
}
}

func (s *ApiServer) getFollowList(w rest.ResponseWriter, input *Np2pReqForREST) {
func (s *ApiServer) getFollowList(w rest.ResponseWriter, input *schema.Np2pReqForREST) {
shortPkey := np2p_util.GetUint64FromHexPubKeyStr(input.Authors[0])
fListEvt := s.buzzPeer.MessageMan.DataMan.GetFollowListLocal(shortPkey)

if fListEvt != nil {
w.WriteJson(&EventsResp{Events: []Np2pEventForREST{*NewNp2pEventForREST(fListEvt)}})
w.WriteJson(&EventsResp{Events: []schema.Np2pEventForREST{*schema.NewNp2pEventForREST(fListEvt)}})
} else {
// follow list data will be included on response of "getEvents"
w.WriteJson(&EventsResp{Events: []Np2pEventForREST{}})
w.WriteJson(&EventsResp{Events: []schema.Np2pEventForREST{}})
// request profile data for future
s.buzzPeer.MessageMan.UnicastFollowListReq(shortPkey)
}
}

func (s *ApiServer) getEvents(w rest.ResponseWriter, input *Np2pReqForREST) {
func (s *ApiServer) getEvents(w rest.ResponseWriter, input *schema.Np2pReqForREST) {
// for supporting Nostr clients
isPeriodSpecified := true
if input.Since == 0 {
Expand All @@ -438,10 +296,10 @@ func (s *ApiServer) getEvents(w rest.ResponseWriter, input *Np2pReqForREST) {
*events = (*events)[len(*events)-50:]
}

retEvents := make([]Np2pEventForREST, 0)
retEvents := make([]schema.Np2pEventForREST, 0)

for _, evt := range *events {
retEvents = append(retEvents, *NewNp2pEventForREST(evt))
retEvents = append(retEvents, *schema.NewNp2pEventForREST(evt))
}

w.WriteJson(&EventsResp{
Expand Down
24 changes: 20 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
module github.com/ryogrid/nostrp2p

go 1.18
go 1.21

toolchain go1.21.2

require (
github.com/ant0ine/go-json-rest v3.3.2+incompatible
github.com/chenjiandongx/mandodb v0.0.0-20230824062318-5bc13c508bc1
github.com/holiman/uint256 v1.2.4
github.com/pavelkrolevets/uint512 v0.0.0-20221129063351-01a9c0c431b5
github.com/nbd-wtf/go-nostr v0.30.0
github.com/spf13/cobra v1.8.0
github.com/vmihailenco/msgpack/v5 v5.4.1
github.com/weaveworks/mesh v0.0.0-20191105120815-58dbcc3e8e63
)

require (
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.2.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/puzpuzpuz/xsync/v3 v3.0.2 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tidwall/gjson v1.14.4 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect
golang.org/x/sys v0.8.0 // indirect
)
Loading

0 comments on commit b9ba64a

Please sign in to comment.