massive code cleanup
This commit is contained in:
@@ -410,14 +410,10 @@ func (f *T) Unmarshal(b []byte) (r []byte, err error) {
|
|||||||
}
|
}
|
||||||
if r[0] == '}' {
|
if r[0] == '}' {
|
||||||
state = afterClose
|
state = afterClose
|
||||||
// log.I.Ln("afterClose")
|
|
||||||
// rem = rem[1:]
|
|
||||||
} else if r[0] == ',' {
|
} else if r[0] == ',' {
|
||||||
state = openParen
|
state = openParen
|
||||||
// log.I.Ln("openParen")
|
|
||||||
} else if r[0] == '"' {
|
} else if r[0] == '"' {
|
||||||
state = inKey
|
state = inKey
|
||||||
// log.I.Ln("inKey")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(r) == 0 {
|
if len(r) == 0 {
|
||||||
@@ -436,30 +432,24 @@ invalid:
|
|||||||
// Matches checks a filter against an event and determines if the event matches the filter.
|
// Matches checks a filter against an event and determines if the event matches the filter.
|
||||||
func (f *T) Matches(ev *event.T) bool {
|
func (f *T) Matches(ev *event.T) bool {
|
||||||
if ev == nil {
|
if ev == nil {
|
||||||
// log.T.ToSliceOfBytes("nil event")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if f.IDs.Len() > 0 && !f.IDs.Contains(ev.Id) {
|
if f.IDs.Len() > 0 && !f.IDs.Contains(ev.Id) {
|
||||||
// log.T.ToSliceOfBytes("no ids in filter match event\nEVENT %s\nFILTER %s", ev.ToObject().String(), f.ToObject().String())
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if f.Kinds.Len() > 0 && !f.Kinds.Contains(ev.Kind) {
|
if f.Kinds.Len() > 0 && !f.Kinds.Contains(ev.Kind) {
|
||||||
// log.T.ToSliceOfBytes("no matching kinds in filter\nEVENT %s\nFILTER %s", ev.ToObject().String(), f.ToObject().String())
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if f.Authors.Len() > 0 && !f.Authors.Contains(ev.Pubkey) {
|
if f.Authors.Len() > 0 && !f.Authors.Contains(ev.Pubkey) {
|
||||||
// log.T.ToSliceOfBytes("no matching authors in filter\nEVENT %s\nFILTER %s", ev.ToObject().String(), f.ToObject().String())
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if f.Tags.Len() > 0 && !ev.Tags.Intersects(f.Tags) {
|
if f.Tags.Len() > 0 && !ev.Tags.Intersects(f.Tags) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if f.Since.Int() != 0 && ev.CreatedAt.I64() < f.Since.I64() {
|
if f.Since.Int() != 0 && ev.CreatedAt.I64() < f.Since.I64() {
|
||||||
// log.T.ToSliceOfBytes("event is older than since\nEVENT %s\nFILTER %s", ev.ToObject().String(), f.ToObject().String())
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if f.Until.Int() != 0 && ev.CreatedAt.I64() > f.Until.I64() {
|
if f.Until.Int() != 0 && ev.CreatedAt.I64() > f.Until.I64() {
|
||||||
// log.T.ToSliceOfBytes("event is newer than until\nEVENT %s\nFILTER %s", ev.ToObject().String(), f.ToObject().String())
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -535,7 +525,6 @@ func GenFilter() (f *T, err error) {
|
|||||||
id := make([]byte, sha256.Size)
|
id := make([]byte, sha256.Size)
|
||||||
frand.Read(id)
|
frand.Read(id)
|
||||||
f.IDs = f.IDs.Append(id)
|
f.IDs = f.IDs.Append(id)
|
||||||
// f.IDs.Field = append(f.IDs.Field, id)
|
|
||||||
}
|
}
|
||||||
n = frand.Intn(16)
|
n = frand.Intn(16)
|
||||||
for _ = range n {
|
for _ = range n {
|
||||||
@@ -549,7 +538,6 @@ func GenFilter() (f *T, err error) {
|
|||||||
}
|
}
|
||||||
pk := sk.PubKey()
|
pk := sk.PubKey()
|
||||||
f.Authors = f.Authors.Append(schnorr.SerializePubKey(pk))
|
f.Authors = f.Authors.Append(schnorr.SerializePubKey(pk))
|
||||||
// f.Authors.Field = append(f.Authors.Field, schnorr.SerializePubKey(pk))
|
|
||||||
}
|
}
|
||||||
a := frand.Intn(16)
|
a := frand.Intn(16)
|
||||||
if a < n {
|
if a < n {
|
||||||
@@ -570,7 +558,6 @@ func GenFilter() (f *T, err error) {
|
|||||||
}
|
}
|
||||||
idb = append([][]byte{{'#', byte(b)}}, idb...)
|
idb = append([][]byte{{'#', byte(b)}}, idb...)
|
||||||
f.Tags = f.Tags.AppendTags(tag.FromBytesSlice(idb...))
|
f.Tags = f.Tags.AppendTags(tag.FromBytesSlice(idb...))
|
||||||
// f.Tags.T = append(f.Tags.T, tag.FromBytesSlice(idb...))
|
|
||||||
} else {
|
} else {
|
||||||
var idb [][]byte
|
var idb [][]byte
|
||||||
for range l {
|
for range l {
|
||||||
@@ -582,7 +569,6 @@ func GenFilter() (f *T, err error) {
|
|||||||
}
|
}
|
||||||
idb = append([][]byte{{'#', byte(b)}}, idb...)
|
idb = append([][]byte{{'#', byte(b)}}, idb...)
|
||||||
f.Tags = f.Tags.AppendTags(tag.FromBytesSlice(idb...))
|
f.Tags = f.Tags.AppendTags(tag.FromBytesSlice(idb...))
|
||||||
// f.Tags.T = append(f.Tags.T, tag.FromBytesSlice(idb...))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tn := int(timestamp.Now().I64())
|
tn := int(timestamp.Now().I64())
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ package normalize
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"realy.mleku.dev/chk"
|
"realy.mleku.dev/chk"
|
||||||
@@ -91,42 +90,3 @@ func URL[V string | []byte](v V) (b []byte) {
|
|||||||
p.Path = string(bytes.TrimRight([]byte(p.Path), "/"))
|
p.Path = string(bytes.TrimRight([]byte(p.Path), "/"))
|
||||||
return []byte(p.String())
|
return []byte(p.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Msg constructs a properly formatted message with a machine-readable prefix for OK and CLOSED
|
|
||||||
// envelopes.
|
|
||||||
func Msg(prefix Reason, format string, params ...any) []byte {
|
|
||||||
if len(prefix) < 1 {
|
|
||||||
prefix = Error
|
|
||||||
}
|
|
||||||
return []byte(fmt.Sprintf(prefix.S()+": "+format, params...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reason is the machine-readable prefix before the colon in an OK or CLOSED envelope message.
|
|
||||||
// Below are the most common kinds that are mentioned in NIP-01.
|
|
||||||
type Reason []byte
|
|
||||||
|
|
||||||
var (
|
|
||||||
AuthRequired = Reason("auth-required")
|
|
||||||
PoW = Reason("pow")
|
|
||||||
Duplicate = Reason("duplicate")
|
|
||||||
Blocked = Reason("blocked")
|
|
||||||
RateLimited = Reason("rate-limited")
|
|
||||||
Invalid = Reason("invalid")
|
|
||||||
Error = Reason("error")
|
|
||||||
Unsupported = Reason("unsupported")
|
|
||||||
Restricted = Reason("restricted")
|
|
||||||
)
|
|
||||||
|
|
||||||
// S returns the Reason as a string
|
|
||||||
func (r Reason) S() string { return string(r) }
|
|
||||||
|
|
||||||
// B returns the Reason as a byte slice.
|
|
||||||
func (r Reason) B() []byte { return r }
|
|
||||||
|
|
||||||
// IsPrefix returns whether a text contains the same Reason prefix.
|
|
||||||
func (r Reason) IsPrefix(reason []byte) bool { return bytes.HasPrefix(reason, r.B()) }
|
|
||||||
|
|
||||||
// F allows creation of a full Reason text with a printf style format.
|
|
||||||
func (r Reason) F(format string, params ...any) []byte {
|
|
||||||
return Msg(r, format, params...)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -83,7 +83,10 @@ func (x *Operations) RegisterConfigurationSet(api huma.API) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.I.F("setting configuration")
|
log.I.F("setting configuration")
|
||||||
x.SetConfiguration(input.Body)
|
if err = x.SetConfiguration(input.Body); chk.E(err) {
|
||||||
|
err = huma.Error400BadRequest(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,7 +194,6 @@ func (r *T) QueryEvents(c context.T, f *filter.T) (evs event.Ts, err error) {
|
|||||||
// intent or the client is erroneous, if any limit greater is
|
// intent or the client is erroneous, if any limit greater is
|
||||||
// requested this will be used instead as the previous clause.
|
// requested this will be used instead as the previous clause.
|
||||||
if len(evMap) >= r.MaxLimit {
|
if len(evMap) >= r.MaxLimit {
|
||||||
// log.T.ToSliceOfBytes("found MaxLimit events: %d", len(evMap))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,17 +226,6 @@ func (r *T) QueryEvents(c context.T, f *filter.T) (evs event.Ts, err error) {
|
|||||||
if len(evs) > limit {
|
if len(evs) > limit {
|
||||||
evs = evs[:limit]
|
evs = evs[:limit]
|
||||||
}
|
}
|
||||||
// log.T.C(func() string {
|
|
||||||
// evIds := make([]string, len(evs))
|
|
||||||
// for i, ev := range evs {
|
|
||||||
// evIds[i] = hex.Enc(ev.Id)
|
|
||||||
// }
|
|
||||||
// heading := fmt.Sprintf("query complete,%d events found,%s", len(evs),
|
|
||||||
// f.Serialize())
|
|
||||||
// return fmt.Sprintf("%s\nevents,%v", heading, evIds)
|
|
||||||
// })
|
|
||||||
// bump the access times on all retrieved events. do this in a goroutine so the
|
|
||||||
// user's events are delivered immediately
|
|
||||||
go func() {
|
go func() {
|
||||||
for ser := range accessed {
|
for ser := range accessed {
|
||||||
seri := serial.New([]byte(ser))
|
seri := serial.New([]byte(ser))
|
||||||
@@ -252,7 +240,6 @@ func (r *T) QueryEvents(c context.T, f *filter.T) (evs event.Ts, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// log.T.Ln("last access for", seri.Uint64(), now.U64())
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -260,6 +247,5 @@ func (r *T) QueryEvents(c context.T, f *filter.T) (evs event.Ts, err error) {
|
|||||||
} else {
|
} else {
|
||||||
log.T.F("no events found,%s", f.Serialize())
|
log.T.F("no events found,%s", f.Serialize())
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"realy.mleku.dev/context"
|
"realy.mleku.dev/context"
|
||||||
"realy.mleku.dev/event"
|
"realy.mleku.dev/event"
|
||||||
"realy.mleku.dev/log"
|
"realy.mleku.dev/log"
|
||||||
"realy.mleku.dev/normalize"
|
|
||||||
"realy.mleku.dev/publish"
|
"realy.mleku.dev/publish"
|
||||||
|
"realy.mleku.dev/reason"
|
||||||
"realy.mleku.dev/store"
|
"realy.mleku.dev/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ func (s *Server) addEvent(c context.T, ev *event.T,
|
|||||||
|
|
||||||
if ev == nil {
|
if ev == nil {
|
||||||
log.I.F("empty event")
|
log.I.F("empty event")
|
||||||
return false, normalize.Invalid.F("empty event")
|
return false, reason.Invalid.F("empty event")
|
||||||
}
|
}
|
||||||
// don't allow storing event with protected marker as per nip-70 with auth enabled.
|
// don't allow storing event with protected marker as per nip-70 with auth enabled.
|
||||||
if (s.AuthRequired() || !s.PublicReadable()) && ev.Tags.ContainsProtectedMarker() {
|
if (s.AuthRequired() || !s.PublicReadable()) && ev.Tags.ContainsProtectedMarker() {
|
||||||
@@ -39,19 +39,19 @@ func (s *Server) addEvent(c context.T, ev *event.T,
|
|||||||
} else {
|
} else {
|
||||||
if saveErr := s.Publish(c, ev); saveErr != nil {
|
if saveErr := s.Publish(c, ev); saveErr != nil {
|
||||||
if errors.Is(saveErr, store.ErrDupEvent) {
|
if errors.Is(saveErr, store.ErrDupEvent) {
|
||||||
return false, normalize.Error.F(saveErr.Error())
|
return false, reason.Error.F(saveErr.Error())
|
||||||
}
|
}
|
||||||
errmsg := saveErr.Error()
|
errmsg := saveErr.Error()
|
||||||
if NIP20prefixmatcher.MatchString(errmsg) {
|
if NIP20prefixmatcher.MatchString(errmsg) {
|
||||||
if strings.Contains(errmsg, "tombstone") {
|
if strings.Contains(errmsg, "tombstone") {
|
||||||
return false, normalize.Blocked.F("event was deleted, not storing it again")
|
return false, reason.Blocked.F("event was deleted, not storing it again")
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(errmsg, string(normalize.Blocked)) {
|
if strings.HasPrefix(errmsg, string(reason.Blocked)) {
|
||||||
return false, []byte(errmsg)
|
return false, []byte(errmsg)
|
||||||
}
|
}
|
||||||
return false, normalize.Error.F(errmsg)
|
return false, reason.Error.F(errmsg)
|
||||||
} else {
|
} else {
|
||||||
return false, normalize.Error.F("failed to save (%s)", errmsg)
|
return false, reason.Error.F("failed to save (%s)", errmsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ type Server interface {
|
|||||||
OwnersFollowed(pubkey string) (ok bool)
|
OwnersFollowed(pubkey string) (ok bool)
|
||||||
PublicReadable() bool
|
PublicReadable() bool
|
||||||
ServiceURL(req *http.Request) (s string)
|
ServiceURL(req *http.Request) (s string)
|
||||||
SetConfiguration(*config.C)
|
SetConfiguration(cfg *config.C) (err error)
|
||||||
Shutdown()
|
Shutdown()
|
||||||
Storage() store.I
|
Storage() store.I
|
||||||
Unlock()
|
Unlock()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"realy.mleku.dev/chk"
|
"realy.mleku.dev/chk"
|
||||||
"realy.mleku.dev/context"
|
"realy.mleku.dev/context"
|
||||||
|
"realy.mleku.dev/errorf"
|
||||||
"realy.mleku.dev/event"
|
"realy.mleku.dev/event"
|
||||||
"realy.mleku.dev/log"
|
"realy.mleku.dev/log"
|
||||||
"realy.mleku.dev/realy/config"
|
"realy.mleku.dev/realy/config"
|
||||||
@@ -32,7 +33,11 @@ func (s *Server) Configuration() config.C {
|
|||||||
return *s.configuration
|
return *s.configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SetConfiguration(cfg *config.C) {
|
func (s *Server) SetConfiguration(cfg *config.C) (err error) {
|
||||||
|
if len(cfg.Admins) == 0 {
|
||||||
|
err = errorf.E("cannot set configuration without at least one admin")
|
||||||
|
return
|
||||||
|
}
|
||||||
s.configurationMx.Lock()
|
s.configurationMx.Lock()
|
||||||
s.configuration = cfg
|
s.configuration = cfg
|
||||||
s.configured = true
|
s.configured = true
|
||||||
@@ -41,6 +46,7 @@ func (s *Server) SetConfiguration(cfg *config.C) {
|
|||||||
chk.E(c.SetConfiguration(cfg))
|
chk.E(c.SetConfiguration(cfg))
|
||||||
chk.E(s.UpdateConfiguration())
|
chk.E(s.UpdateConfiguration())
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) AddEvent(
|
func (s *Server) AddEvent(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"realy.mleku.dev/filter"
|
"realy.mleku.dev/filter"
|
||||||
"realy.mleku.dev/kinds"
|
"realy.mleku.dev/kinds"
|
||||||
"realy.mleku.dev/log"
|
"realy.mleku.dev/log"
|
||||||
"realy.mleku.dev/normalize"
|
"realy.mleku.dev/reason"
|
||||||
"realy.mleku.dev/store"
|
"realy.mleku.dev/store"
|
||||||
"realy.mleku.dev/tag"
|
"realy.mleku.dev/tag"
|
||||||
)
|
)
|
||||||
@@ -42,7 +42,7 @@ func (s *Server) Publish(c context.T, evt *event.T) (err error) {
|
|||||||
}
|
}
|
||||||
if ev.CreatedAt.Int() > evt.CreatedAt.Int() {
|
if ev.CreatedAt.Int() > evt.CreatedAt.Int() {
|
||||||
log.I.F("not replacing newer replaceable event")
|
log.I.F("not replacing newer replaceable event")
|
||||||
return errorf.W(string(normalize.Invalid.F("not replacing newer replaceable event")))
|
return errorf.W(string(reason.Invalid.F("not replacing newer replaceable event")))
|
||||||
}
|
}
|
||||||
// not deleting these events because some clients are retarded and the query
|
// not deleting these events because some clients are retarded and the query
|
||||||
// will pull the new one but a backup can recover the data of old ones
|
// will pull the new one but a backup can recover the data of old ones
|
||||||
@@ -88,7 +88,7 @@ func (s *Server) Publish(c context.T, evt *event.T) (err error) {
|
|||||||
err = nil
|
err = nil
|
||||||
log.I.F("maybe replace %s", ev.Serialize())
|
log.I.F("maybe replace %s", ev.Serialize())
|
||||||
if ev.CreatedAt.Int() > evt.CreatedAt.Int() {
|
if ev.CreatedAt.Int() > evt.CreatedAt.Int() {
|
||||||
return errorf.D(string(normalize.Blocked.F("not replacing newer parameterized replaceable event")))
|
return errorf.D(string(reason.Blocked.F("not replacing newer parameterized replaceable event")))
|
||||||
}
|
}
|
||||||
// not deleting these events because some clients are retarded and the query
|
// not deleting these events because some clients are retarded and the query
|
||||||
// will pull the new one but a backup can recover the data of old ones
|
// will pull the new one but a backup can recover the data of old ones
|
||||||
|
|||||||
45
reason/reason.go
Normal file
45
reason/reason.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package reason
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// R is the machine-readable prefix before the colon in an OK or CLOSED envelope message.
|
||||||
|
// Below are the most common kinds that are mentioned in NIP-01.
|
||||||
|
type R []byte
|
||||||
|
|
||||||
|
var (
|
||||||
|
AuthRequired = R("auth-required")
|
||||||
|
PoW = R("pow")
|
||||||
|
Duplicate = R("duplicate")
|
||||||
|
Blocked = R("blocked")
|
||||||
|
RateLimited = R("rate-limited")
|
||||||
|
Invalid = R("invalid")
|
||||||
|
Error = R("error")
|
||||||
|
Unsupported = R("unsupported")
|
||||||
|
Restricted = R("restricted")
|
||||||
|
)
|
||||||
|
|
||||||
|
// S returns the R as a string
|
||||||
|
func (r R) S() string { return string(r) }
|
||||||
|
|
||||||
|
// B returns the R as a byte slice.
|
||||||
|
func (r R) B() []byte { return r }
|
||||||
|
|
||||||
|
// IsPrefix returns whether a text contains the same R prefix.
|
||||||
|
func (r R) IsPrefix(reason []byte) bool { return bytes.HasPrefix(reason, r.B()) }
|
||||||
|
|
||||||
|
// F allows creation of a full R text with a printf style format.
|
||||||
|
func (r R) F(format string, params ...any) []byte {
|
||||||
|
return Msg(r, format, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Msg constructs a properly formatted message with a machine-readable prefix for OK and CLOSED
|
||||||
|
// envelopes.
|
||||||
|
func Msg(prefix R, format string, params ...any) []byte {
|
||||||
|
if len(prefix) < 1 {
|
||||||
|
prefix = Error
|
||||||
|
}
|
||||||
|
return []byte(fmt.Sprintf(prefix.S()+": "+format, params...))
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"realy.mleku.dev/envelopes/authenvelope"
|
"realy.mleku.dev/envelopes/authenvelope"
|
||||||
"realy.mleku.dev/envelopes/okenvelope"
|
"realy.mleku.dev/envelopes/okenvelope"
|
||||||
"realy.mleku.dev/log"
|
"realy.mleku.dev/log"
|
||||||
"realy.mleku.dev/normalize"
|
|
||||||
"realy.mleku.dev/realy/interfaces"
|
"realy.mleku.dev/realy/interfaces"
|
||||||
|
"realy.mleku.dev/reason"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *A) HandleAuth(req []byte,
|
func (a *A) HandleAuth(req []byte,
|
||||||
@@ -33,16 +33,16 @@ func (a *A) HandleAuth(req []byte,
|
|||||||
svcUrl); chk.E(err) {
|
svcUrl); chk.E(err) {
|
||||||
e := err.Error()
|
e := err.Error()
|
||||||
if err = okenvelope.NewFrom(env.Event.Id, false,
|
if err = okenvelope.NewFrom(env.Event.Id, false,
|
||||||
normalize.Error.F(err.Error())).Write(a.Listener); chk.E(err) {
|
reason.Error.F(err.Error())).Write(a.Listener); chk.E(err) {
|
||||||
return []byte(err.Error())
|
return []byte(err.Error())
|
||||||
}
|
}
|
||||||
return normalize.Error.F(e)
|
return reason.Error.F(e)
|
||||||
} else if !valid {
|
} else if !valid {
|
||||||
if err = okenvelope.NewFrom(env.Event.Id, false,
|
if err = okenvelope.NewFrom(env.Event.Id, false,
|
||||||
normalize.Error.F("failed to authenticate")).Write(a.Listener); chk.E(err) {
|
reason.Error.F("failed to authenticate")).Write(a.Listener); chk.E(err) {
|
||||||
return []byte(err.Error())
|
return []byte(err.Error())
|
||||||
}
|
}
|
||||||
return normalize.Restricted.F("auth response does not validate")
|
return reason.Restricted.F("auth response does not validate")
|
||||||
} else {
|
} else {
|
||||||
if err = okenvelope.NewFrom(env.Event.Id, true,
|
if err = okenvelope.NewFrom(env.Event.Id, true,
|
||||||
[]byte{}).Write(a.Listener); chk.E(err) {
|
[]byte{}).Write(a.Listener); chk.E(err) {
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ import (
|
|||||||
"realy.mleku.dev/ints"
|
"realy.mleku.dev/ints"
|
||||||
"realy.mleku.dev/kind"
|
"realy.mleku.dev/kind"
|
||||||
"realy.mleku.dev/log"
|
"realy.mleku.dev/log"
|
||||||
"realy.mleku.dev/normalize"
|
|
||||||
"realy.mleku.dev/realy/interfaces"
|
"realy.mleku.dev/realy/interfaces"
|
||||||
|
"realy.mleku.dev/reason"
|
||||||
"realy.mleku.dev/sha256"
|
"realy.mleku.dev/sha256"
|
||||||
|
"realy.mleku.dev/store"
|
||||||
"realy.mleku.dev/tag"
|
"realy.mleku.dev/tag"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,57 +44,75 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server,
|
|||||||
a.Listener.AuthedBytes(), remote)
|
a.Listener.AuthedBytes(), remote)
|
||||||
log.T.F("%s accepted %v", remote, accept)
|
log.T.F("%s accepted %v", remote, accept)
|
||||||
if !accept {
|
if !accept {
|
||||||
|
if err = a.HandleRejectEvent(env, notice); chk.E(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = a.VerifyEvent(env); chk.E(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var reason []byte
|
||||||
|
ok, reason = srv.AddEvent(c, env.T, a.Listener.Req(), a.Listener.AuthedBytes(), remote)
|
||||||
|
log.T.F("event added %v", ok)
|
||||||
|
if err = okenvelope.NewFrom(env.Id, ok, reason).Write(a.Listener); chk.E(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if after != nil {
|
||||||
|
after()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) VerifyEvent(env *eventenvelope.Submission) (err error) {
|
||||||
|
if !bytes.Equal(env.GetIDBytes(), env.Id) {
|
||||||
|
if err = a.Invalid(env, "event id is computed incorrectly"); chk.E(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
if ok, err = env.Verify(); chk.T(err) {
|
||||||
|
if err = a.Error(env, "failed to verify signature", err); chk.T(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if !ok {
|
||||||
|
if err = a.Error(env, "signature is invalid", err); chk.T(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) HandleRejectEvent(env *eventenvelope.Submission, notice string) (err error) {
|
||||||
if strings.Contains(notice, "mute") {
|
if strings.Contains(notice, "mute") {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Blocked(env, notice); chk.E(err) {
|
||||||
normalize.Blocked.F(notice)).Write(a.Listener); chk.T(err) {
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !a.Listener.AuthRequested() {
|
if !a.Listener.AuthRequested() {
|
||||||
a.Listener.RequestAuth()
|
a.Listener.RequestAuth()
|
||||||
log.I.F("requesting auth from client %s", a.Listener.RealRemote())
|
log.I.F("requesting auth from client %s", a.Listener.RealRemote())
|
||||||
if err = authenvelope.NewChallengeWith(a.Listener.Challenge()).Write(a.Listener); chk.T(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
|
||||||
normalize.AuthRequired.F("auth required for storing events")).Write(a.Listener); chk.T(err) {
|
|
||||||
}
|
|
||||||
return
|
|
||||||
} else {
|
} else {
|
||||||
log.I.F("requesting auth again from client %s", a.Listener.RealRemote())
|
log.I.F("requesting auth again from client %s", a.Listener.RealRemote())
|
||||||
|
}
|
||||||
if err = authenvelope.NewChallengeWith(a.Listener.Challenge()).Write(a.Listener); chk.T(err) {
|
if err = authenvelope.NewChallengeWith(a.Listener.Challenge()).Write(a.Listener); chk.T(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.AuthRequired(env, "auth required for storing events"); chk.E(err) {
|
||||||
normalize.AuthRequired.F("auth required for storing events")).Write(a.Listener); chk.T(err) {
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
|
||||||
normalize.Invalid.F(notice)).Write(a.Listener); chk.T(err) {
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !bytes.Equal(env.GetIDBytes(), env.Id) {
|
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
|
||||||
normalize.Invalid.F("event id is computed incorrectly")).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ok, err = env.Verify(); chk.T(err) {
|
if err = a.Invalid(env, notice); chk.E(err) {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
|
||||||
normalize.Error.F("failed to verify signature")).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if !ok {
|
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
|
||||||
normalize.Error.F("signature is invalid")).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if env.T.Kind.K == kind.Deletion.K {
|
|
||||||
|
func (a *A) CheckDelete(c context.T, env *eventenvelope.Submission, sto store.I) (err error) {
|
||||||
log.I.F("delete event\n%s", env.T.Serialize())
|
log.I.F("delete event\n%s", env.T.Serialize())
|
||||||
for _, t := range env.Tags.ToSliceOfTags() {
|
for _, t := range env.Tags.ToSliceOfTags() {
|
||||||
var res []*event.T
|
var res []*event.T
|
||||||
@@ -106,23 +125,24 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server,
|
|||||||
}
|
}
|
||||||
res, err = sto.QueryEvents(c, &filter.T{IDs: tag.New(evId)})
|
res, err = sto.QueryEvents(c, &filter.T{IDs: tag.New(evId)})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Ok("failed to query for target event", reason.Error, env); chk.T(err) {
|
||||||
normalize.Error.F("failed to query for target event")).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := range res {
|
for i := range res {
|
||||||
if res[i].Kind.Equal(kind.Deletion) {
|
if res[i].Kind.Equal(kind.Deletion) {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Blocked(env,
|
||||||
normalize.Blocked.F("not processing or storing delete event containing delete event references")).Write(a.Listener); chk.E(err) {
|
"not processing or storing delete event containing delete event references",
|
||||||
|
); chk.E(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !bytes.Equal(res[i].Pubkey, env.T.Pubkey) {
|
if !bytes.Equal(res[i].Pubkey, env.T.Pubkey) {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Blocked(env,
|
||||||
normalize.Blocked.F("cannot delete other users' events (delete by e tag)")).Write(a.Listener); chk.E(err) {
|
"cannot delete other users' events (delete by e tag)",
|
||||||
|
); chk.E(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -135,57 +155,47 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server,
|
|||||||
}
|
}
|
||||||
var pk []byte
|
var pk []byte
|
||||||
if pk, err = hex.DecAppend(nil, split[1]); chk.E(err) {
|
if pk, err = hex.DecAppend(nil, split[1]); chk.E(err) {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Invalid(env,
|
||||||
normalize.Invalid.F("delete event a tag pubkey value invalid: %s",
|
"delete event a tag pubkey value invalid: %s", t.Value()); chk.T(err) {
|
||||||
t.Value())).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
kin := ints.New(uint16(0))
|
kin := ints.New(uint16(0))
|
||||||
if _, err = kin.Unmarshal(split[0]); chk.E(err) {
|
if _, err = kin.Unmarshal(split[0]); chk.E(err) {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Invalid(env,
|
||||||
normalize.Invalid.F("delete event a tag kind value invalid: %s",
|
"delete event a tag kind value invalid: %s", t.Value()); chk.T(err) {
|
||||||
t.Value())).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
kk := kind.New(kin.Uint16())
|
kk := kind.New(kin.Uint16())
|
||||||
if kk.Equal(kind.Deletion) {
|
if kk.Equal(kind.Deletion) {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Blocked(env, "delete event kind may not be deleted"); chk.E(err) {
|
||||||
normalize.Blocked.F("delete event kind may not be deleted")).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !kk.IsParameterizedReplaceable() {
|
if !kk.IsParameterizedReplaceable() {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Error(env,
|
||||||
normalize.Error.F("delete tags with a tags containing non-parameterized-replaceable events cannot be processed")).Write(a.Listener); chk.E(err) {
|
"delete tags with a tags containing non-parameterized-replaceable events cannot be processed"); chk.E(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !bytes.Equal(pk, env.T.Pubkey) {
|
if !bytes.Equal(pk, env.T.Pubkey) {
|
||||||
log.I.S(pk, env.T.Pubkey, env.T)
|
log.I.S(pk, env.T.Pubkey, env.T)
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if err = a.Blocked(env,
|
||||||
normalize.Blocked.F("cannot delete other users' events (delete by a tag)")).Write(a.Listener); chk.E(err) {
|
"cannot delete other users' events (delete by a tag)"); chk.E(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f := filter.New()
|
f := filter.New()
|
||||||
f.Kinds.K = []*kind.T{kk}
|
f.Kinds.K = []*kind.T{kk}
|
||||||
// aut := make(by, 0, len(pk)/2)
|
|
||||||
// if aut, err = hex.DecAppend(aut, pk); chk.E(err) {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
f.Authors.Append(pk)
|
f.Authors.Append(pk)
|
||||||
f.Tags.AppendTags(tag.New([]byte{'#', 'd'}, split[2]))
|
f.Tags.AppendTags(tag.New([]byte{'#', 'd'}, split[2]))
|
||||||
res, err = sto.QueryEvents(c, f)
|
if res, err = sto.QueryEvents(c, f); err != nil {
|
||||||
if err != nil {
|
if err = a.Error(env, "failed to query for target event", err); chk.T(err) {
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
|
||||||
normalize.Error.F("failed to query for target event")).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -203,30 +213,10 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server,
|
|||||||
}
|
}
|
||||||
res = resTmp
|
res = resTmp
|
||||||
for _, target := range res {
|
for _, target := range res {
|
||||||
if target.Kind.K == kind.Deletion.K {
|
var skip bool
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
if skip, err = a.ProcessDelete(c, target, env, sto); skip {
|
||||||
normalize.Error.F("cannot delete delete event %s",
|
|
||||||
env.Id)).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if target.CreatedAt.Int() > env.T.CreatedAt.Int() {
|
|
||||||
log.I.F("not deleting\n%d%\nbecause delete event is older\n%d",
|
|
||||||
target.CreatedAt.Int(), env.T.CreatedAt.Int())
|
|
||||||
continue
|
continue
|
||||||
}
|
} else if err != nil {
|
||||||
if !bytes.Equal(target.Pubkey, env.Pubkey) {
|
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
|
||||||
normalize.Error.F("only author can delete event")).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err = sto.DeleteEvent(c, target.EventId()); chk.T(err) {
|
|
||||||
if err = okenvelope.NewFrom(env.Id, false,
|
|
||||||
normalize.Error.F(err.Error())).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,15 +225,34 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server,
|
|||||||
if err = okenvelope.NewFrom(env.Id, true).Write(a.Listener); chk.E(err) {
|
if err = okenvelope.NewFrom(env.Id, true).Write(a.Listener); chk.E(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
var reason []byte
|
|
||||||
ok, reason = srv.AddEvent(c, env.T, a.Listener.Req(), a.Listener.AuthedBytes(), remote)
|
|
||||||
log.T.F("event added %v", ok)
|
|
||||||
if err = okenvelope.NewFrom(env.Id, ok, reason).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if after != nil {
|
|
||||||
after()
|
func (a *A) ProcessDelete(c context.T, target *event.T, env *eventenvelope.Submission, sto store.I) (skip bool, err error) {
|
||||||
|
if target.Kind.K == kind.Deletion.K {
|
||||||
|
if err = a.Error(env, "cannot delete delete event %s", env.Id); chk.E(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if target.CreatedAt.Int() > env.T.CreatedAt.Int() {
|
||||||
|
if err = a.Error(env,
|
||||||
|
"not deleting\n%d%\nbecause delete event is older\n%d",
|
||||||
|
target.CreatedAt.Int(), env.T.CreatedAt.Int()); chk.E(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
skip = true
|
||||||
|
}
|
||||||
|
if !bytes.Equal(target.Pubkey, env.Pubkey) {
|
||||||
|
if err = a.Error(env, "only author can delete event"); chk.E(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = sto.DeleteEvent(c, target.EventId()); chk.T(err) {
|
||||||
|
if err = a.Error(env, err.Error()); chk.T(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ import (
|
|||||||
"realy.mleku.dev/kind"
|
"realy.mleku.dev/kind"
|
||||||
"realy.mleku.dev/kinds"
|
"realy.mleku.dev/kinds"
|
||||||
"realy.mleku.dev/log"
|
"realy.mleku.dev/log"
|
||||||
"realy.mleku.dev/normalize"
|
|
||||||
"realy.mleku.dev/publish"
|
"realy.mleku.dev/publish"
|
||||||
"realy.mleku.dev/realy/interfaces"
|
"realy.mleku.dev/realy/interfaces"
|
||||||
"realy.mleku.dev/realy/pointers"
|
"realy.mleku.dev/realy/pointers"
|
||||||
|
"realy.mleku.dev/reason"
|
||||||
"realy.mleku.dev/tag"
|
"realy.mleku.dev/tag"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ func (a *A) HandleReq(
|
|||||||
var rem []byte
|
var rem []byte
|
||||||
env := reqenvelope.New()
|
env := reqenvelope.New()
|
||||||
if rem, err = env.Unmarshal(req); chk.E(err) {
|
if rem, err = env.Unmarshal(req); chk.E(err) {
|
||||||
return normalize.Error.F(err.Error())
|
return reason.Error.F(err.Error())
|
||||||
}
|
}
|
||||||
if len(rem) > 0 {
|
if len(rem) > 0 {
|
||||||
log.I.F("extra '%s'", rem)
|
log.I.F("extra '%s'", rem)
|
||||||
@@ -48,7 +48,7 @@ func (a *A) HandleReq(
|
|||||||
if srv.AuthRequired() && !a.Listener.AuthRequested() {
|
if srv.AuthRequired() && !a.Listener.AuthRequested() {
|
||||||
a.Listener.RequestAuth()
|
a.Listener.RequestAuth()
|
||||||
if err = closedenvelope.NewFrom(env.Subscription,
|
if err = closedenvelope.NewFrom(env.Subscription,
|
||||||
normalize.AuthRequired.F("auth required for request processing")).Write(a.Listener); chk.E(err) {
|
reason.AuthRequired.F("auth required for request processing")).Write(a.Listener); chk.E(err) {
|
||||||
}
|
}
|
||||||
log.T.F("requesting auth from client from %s, challenge '%s'",
|
log.T.F("requesting auth from client from %s, challenge '%s'",
|
||||||
a.Listener.RealRemote(), a.Listener.Challenge())
|
a.Listener.RealRemote(), a.Listener.Challenge())
|
||||||
@@ -60,18 +60,13 @@ func (a *A) HandleReq(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// log.I.ToSliceOfBytes("handling %s", env.Marshal(nil))
|
var notice []byte
|
||||||
if allowed != env.Filters {
|
if allowed != env.Filters {
|
||||||
defer func() {
|
defer func() {
|
||||||
if srv.AuthRequired() &&
|
if srv.AuthRequired() &&
|
||||||
!a.Listener.AuthRequested() {
|
!a.Listener.AuthRequested() {
|
||||||
a.Listener.RequestAuth()
|
a.Listener.RequestAuth()
|
||||||
if err = closedenvelope.NewFrom(env.Subscription,
|
if notice, err = a.AuthRequiredResponse(env, remote); chk.E(err) {
|
||||||
normalize.AuthRequired.F("auth required for request processing")).Write(a.Listener); chk.E(err) {
|
|
||||||
}
|
|
||||||
log.T.F("requesting auth from client from %s, challenge '%s'",
|
|
||||||
remote, a.Listener.Challenge())
|
|
||||||
if err = authenvelope.NewChallengeWith(a.Listener.Challenge()).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -89,35 +84,25 @@ func (a *A) HandleReq(
|
|||||||
}
|
}
|
||||||
i = *f.Limit
|
i = *f.Limit
|
||||||
}
|
}
|
||||||
if srv.AuthRequired() {
|
if srv.AuthRequired() && f.Kinds.IsPrivileged() {
|
||||||
if f.Kinds.IsPrivileged() {
|
|
||||||
log.T.F("privileged request\n%s", f.Serialize())
|
log.T.F("privileged request\n%s", f.Serialize())
|
||||||
senders := f.Authors
|
senders := f.Authors
|
||||||
receivers := f.Tags.GetAll(tag.New("#p"))
|
receivers := f.Tags.GetAll(tag.New("#p"))
|
||||||
switch {
|
switch {
|
||||||
case len(a.Listener.Authed()) == 0:
|
case len(a.Listener.Authed()) == 0:
|
||||||
// a.RequestAuth()
|
if notice, err = a.AuthRequiredResponse(env, remote); chk.E(err) {
|
||||||
if err = closedenvelope.NewFrom(env.Subscription,
|
|
||||||
normalize.AuthRequired.F("auth required for processing request due to presence of privileged kinds (DMs, app specific data)")).Write(a.Listener); chk.E(err) {
|
|
||||||
}
|
|
||||||
log.I.F("requesting auth from client from %s", remote)
|
|
||||||
if err = authenvelope.NewChallengeWith(a.Listener.Challenge()).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
notice := normalize.Restricted.F("this realy does not serve DMs or Application Specific Data " +
|
|
||||||
"to unauthenticated users or to npubs not found in the event tags or author fields, does your " +
|
|
||||||
"client implement NIP-42?")
|
|
||||||
return notice
|
return notice
|
||||||
case senders.Contains(a.Listener.AuthedBytes()) ||
|
case senders.Contains(a.Listener.AuthedBytes()) ||
|
||||||
receivers.ContainsAny([]byte("#p"), tag.New(a.Listener.AuthedBytes())):
|
receivers.ContainsAny([]byte("#p"), tag.New(a.Listener.AuthedBytes())):
|
||||||
log.T.F("user %0x from %s allowed to query for privileged event",
|
log.T.F("user %0x from %s allowed to query for privileged event",
|
||||||
a.Listener.AuthedBytes(), remote)
|
a.Listener.AuthedBytes(), remote)
|
||||||
default:
|
default:
|
||||||
return normalize.Restricted.F("authenticated user %0x does not have authorization for "+
|
return reason.Restricted.F("authenticated user %0x does not have authorization for "+
|
||||||
"requested filters", a.Listener.AuthedBytes())
|
"requested filters", a.Listener.AuthedBytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
var events event.Ts
|
var events event.Ts
|
||||||
log.D.F("query from %s %0x,%s", remote, a.Listener.AuthedBytes(), f.Serialize())
|
log.D.F("query from %s %0x,%s", remote, a.Listener.AuthedBytes(), f.Serialize())
|
||||||
if events, err = sto.QueryEvents(c, f); err != nil {
|
if events, err = sto.QueryEvents(c, f); err != nil {
|
||||||
@@ -161,37 +146,20 @@ func (a *A) HandleReq(
|
|||||||
// remove privileged events as they come through in scrape queries
|
// remove privileged events as they come through in scrape queries
|
||||||
var tmp event.Ts
|
var tmp event.Ts
|
||||||
for _, ev := range events {
|
for _, ev := range events {
|
||||||
receivers := f.Tags.GetAll(tag.New("#p"))
|
|
||||||
// if auth is required, kind is privileged and there is no authed pubkey, skip
|
// if auth is required, kind is privileged and there is no authed pubkey, skip
|
||||||
if srv.AuthRequired() && ev.Kind.IsPrivileged() && len(aut) == 0 {
|
if srv.AuthRequired() && ev.Kind.IsPrivileged() && len(aut) == 0 {
|
||||||
// log.I.ToSliceOfBytes("skipping event because event kind is %d and no auth", ev.Kind.K)
|
if notice, err = a.AuthRequiredResponse(env, remote); chk.E(err) {
|
||||||
if err = closedenvelope.NewFrom(env.Subscription,
|
|
||||||
normalize.AuthRequired.F("auth required for processing request due to presence of privileged kinds (DMs, app specific data)")).Write(a.Listener); chk.E(err) {
|
|
||||||
}
|
|
||||||
log.I.F("requesting auth from client from %s", remote)
|
|
||||||
if err = authenvelope.NewChallengeWith(a.Listener.Challenge()).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
notice := normalize.Restricted.F("this realy does not serve DMs or Application Specific Data " +
|
|
||||||
"to unauthenticated users or to npubs not found in the event tags or author fields, does your " +
|
|
||||||
"client implement NIP-42?")
|
|
||||||
return notice
|
return notice
|
||||||
}
|
}
|
||||||
// if the authed pubkey is not present in the pubkey or p tags, skip
|
// if the authed pubkey is not present in the pubkey or p tags, skip
|
||||||
|
receivers := f.Tags.GetAll(tag.New("#p"))
|
||||||
if ev.Kind.IsPrivileged() && (!bytes.Equal(ev.Pubkey, aut) ||
|
if ev.Kind.IsPrivileged() && (!bytes.Equal(ev.Pubkey, aut) ||
|
||||||
!receivers.ContainsAny([]byte("#p"), tag.New(a.Listener.AuthedBytes()))) {
|
!receivers.ContainsAny([]byte("#p"), tag.New(a.Listener.AuthedBytes()))) {
|
||||||
// log.I.ToSliceOfBytes("skipping event %0x because authed key %0x is in neither pubkey or p tag",
|
if notice, err = a.AuthRequiredResponse(env, remote); chk.E(err) {
|
||||||
// ev.Id, aut)
|
|
||||||
if err = closedenvelope.NewFrom(env.Subscription,
|
|
||||||
normalize.AuthRequired.F("auth required for processing request due to presence of privileged kinds (DMs, app specific data)")).Write(a.Listener); chk.E(err) {
|
|
||||||
}
|
|
||||||
log.I.F("requesting auth from client from %s", remote)
|
|
||||||
if err = authenvelope.NewChallengeWith(a.Listener.Challenge()).Write(a.Listener); chk.E(err) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
notice := normalize.Restricted.F("this realy does not serve DMs or Application Specific Data " +
|
|
||||||
"to unauthenticated users or to npubs not found in the event tags or author fields, does your " +
|
|
||||||
"client implement NIP-42?")
|
|
||||||
return notice
|
return notice
|
||||||
}
|
}
|
||||||
tmp = append(tmp, ev)
|
tmp = append(tmp, ev)
|
||||||
@@ -228,3 +196,21 @@ func (a *A) HandleReq(
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *A) AuthRequiredResponse(env *reqenvelope.T, remote string) (notice []byte, err error) {
|
||||||
|
if err = closedenvelope.NewFrom(env.Subscription,
|
||||||
|
reason.AuthRequired.F(privilegedClosedNotice)).Write(a.Listener); chk.E(err) {
|
||||||
|
}
|
||||||
|
log.I.F("requesting auth from client from %s", remote)
|
||||||
|
if err = authenvelope.NewChallengeWith(a.Listener.Challenge()).Write(a.Listener); chk.E(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
notice = reason.Restricted.F(privilegedNotice)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var privilegedNotice = "this realy does not serve DMs or Application Specific Data " +
|
||||||
|
"to unauthenticated users or to npubs not found in the event tags or author fields, does your " +
|
||||||
|
"client implement NIP-42?"
|
||||||
|
|
||||||
|
var privilegedClosedNotice = "auth required for processing request due to presence of privileged kinds (DMs, app specific data)"
|
||||||
|
|||||||
@@ -128,6 +128,6 @@ func (a *A) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go a.HandleMessage(message, remote)
|
a.HandleMessage(message, remote)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
48
socketapi/ok.go
Normal file
48
socketapi/ok.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package socketapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"realy.mleku.dev/envelopes/eventenvelope"
|
||||||
|
"realy.mleku.dev/envelopes/okenvelope"
|
||||||
|
"realy.mleku.dev/reason"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *A) Ok(format string, prefix reason.R, env *eventenvelope.Submission, params ...any) (err error) {
|
||||||
|
err = okenvelope.NewFrom(env.Id, false, prefix.F(format, params...)).Write(a.Listener)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) AuthRequired(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.AuthRequired.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) PoW(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.PoW.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) Duplicate(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.Duplicate.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) Blocked(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.Blocked.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) RateLimited(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.RateLimited.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) Invalid(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.Invalid.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) Error(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.Error.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) Unsupported(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.Unsupported.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *A) Restricted(env *eventenvelope.Submission, format string, params ...any) (err error) {
|
||||||
|
return okenvelope.NewFrom(env.Id, false, reason.Restricted.F(format, params...)).Write(a.Listener)
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"realy.mleku.dev/kind"
|
"realy.mleku.dev/kind"
|
||||||
"realy.mleku.dev/normalize"
|
"realy.mleku.dev/normalize"
|
||||||
"realy.mleku.dev/p256k"
|
"realy.mleku.dev/p256k"
|
||||||
|
"realy.mleku.dev/reason"
|
||||||
"realy.mleku.dev/tag"
|
"realy.mleku.dev/tag"
|
||||||
"realy.mleku.dev/tags"
|
"realy.mleku.dev/tags"
|
||||||
"realy.mleku.dev/timestamp"
|
"realy.mleku.dev/timestamp"
|
||||||
@@ -115,7 +116,7 @@ func TestPublishBlocked(t *testing.T) {
|
|||||||
// send back a not ok nip-20 command result
|
// send back a not ok nip-20 command result
|
||||||
var res []byte
|
var res []byte
|
||||||
if res = okenvelope.NewFrom(textNote.Id, false,
|
if res = okenvelope.NewFrom(textNote.Id, false,
|
||||||
normalize.Msg(normalize.Blocked, "no reason")).Marshal(res); chk.E(err) {
|
reason.Msg(reason.Blocked, "no reason")).Marshal(res); chk.E(err) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := websocket.Message.Send(conn, res); chk.T(err) {
|
if err := websocket.Message.Send(conn, res); chk.T(err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user