Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
85d806b157
|
|||
|
6207f9d426
|
|||
|
ebb5e2c0f3
|
|||
|
9dec51cd40
|
|||
|
f570660f37
|
|||
|
3d3a0fa520
|
@@ -122,16 +122,26 @@ func (l *Listener) HandleEvent(msg []byte) (err error) {
|
||||
if _, _, err = l.SaveEvent(l.Ctx, env.E); chk.E(err) {
|
||||
return
|
||||
}
|
||||
// if a follow list was saved, reconfigure ACLs now that it is persisted
|
||||
if env.E.Kind == kind.FollowList.K {
|
||||
if err = acl.Registry.Configure(); chk.E(err) {
|
||||
}
|
||||
}
|
||||
l.publishers.Deliver(env.E)
|
||||
// Send a success response storing
|
||||
if err = Ok.Ok(l, env, ""); chk.E(err) {
|
||||
return
|
||||
}
|
||||
defer l.publishers.Deliver(env.E)
|
||||
log.D.F("saved event %0x", env.E.ID)
|
||||
var isNewFromAdmin bool
|
||||
for _, admin := range l.Admins {
|
||||
if utils.FastEqual(admin, env.E.Pubkey) {
|
||||
isNewFromAdmin = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isNewFromAdmin {
|
||||
// if a follow list was saved, reconfigure ACLs now that it is persisted
|
||||
if env.E.Kind == kind.FollowList.K ||
|
||||
env.E.Kind == kind.RelayListMetadata.K {
|
||||
if err = acl.Registry.Configure(); chk.E(err) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -33,32 +33,32 @@ func (s *Server) HandleRelayInfo(w http.ResponseWriter, r *http.Request) {
|
||||
relayinfo.BasicProtocol,
|
||||
// relayinfo.Authentication,
|
||||
// relayinfo.EncryptedDirectMessage,
|
||||
// relayinfo.EventDeletion,
|
||||
relayinfo.EventDeletion,
|
||||
relayinfo.RelayInformationDocument,
|
||||
// relayinfo.GenericTagQueries,
|
||||
// relayinfo.NostrMarketplace,
|
||||
// relayinfo.EventTreatment,
|
||||
relayinfo.EventTreatment,
|
||||
// relayinfo.CommandResults,
|
||||
// relayinfo.ParameterizedReplaceableEvents,
|
||||
relayinfo.ParameterizedReplaceableEvents,
|
||||
// relayinfo.ExpirationTimestamp,
|
||||
// relayinfo.ProtectedEvents,
|
||||
// relayinfo.RelayListMetadata,
|
||||
relayinfo.ProtectedEvents,
|
||||
relayinfo.RelayListMetadata,
|
||||
)
|
||||
if s.Config.ACLMode != "none" {
|
||||
supportedNIPs = relayinfo.GetList(
|
||||
relayinfo.BasicProtocol,
|
||||
relayinfo.Authentication,
|
||||
// relayinfo.EncryptedDirectMessage,
|
||||
// relayinfo.EventDeletion,
|
||||
relayinfo.EventDeletion,
|
||||
relayinfo.RelayInformationDocument,
|
||||
// relayinfo.GenericTagQueries,
|
||||
// relayinfo.NostrMarketplace,
|
||||
// relayinfo.EventTreatment,
|
||||
relayinfo.EventTreatment,
|
||||
// relayinfo.CommandResults,
|
||||
// relayinfo.ParameterizedReplaceableEvents,
|
||||
// relayinfo.ExpirationTimestamp,
|
||||
// relayinfo.ProtectedEvents,
|
||||
// relayinfo.RelayListMetadata,
|
||||
relayinfo.ProtectedEvents,
|
||||
relayinfo.RelayListMetadata,
|
||||
)
|
||||
}
|
||||
sort.Sort(supportedNIPs)
|
||||
|
||||
@@ -172,11 +172,12 @@ privCheck:
|
||||
if !cancel {
|
||||
l.publishers.Receive(
|
||||
&W{
|
||||
Conn: l.conn,
|
||||
remote: l.remote,
|
||||
Id: string(env.Subscription),
|
||||
Receiver: receiver,
|
||||
Filters: env.Filters,
|
||||
Conn: l.conn,
|
||||
remote: l.remote,
|
||||
Id: string(env.Subscription),
|
||||
Receiver: receiver,
|
||||
Filters: env.Filters,
|
||||
AuthedPubkey: l.authedPubkey.Load(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
||||
110
app/publisher.go
110
app/publisher.go
@@ -8,17 +8,21 @@ import (
|
||||
"encoders.orly/envelopes/eventenvelope"
|
||||
"encoders.orly/event"
|
||||
"encoders.orly/filter"
|
||||
"encoders.orly/hex"
|
||||
"encoders.orly/kind"
|
||||
"github.com/coder/websocket"
|
||||
"interfaces.orly/publisher"
|
||||
"interfaces.orly/typer"
|
||||
"lol.mleku.dev/chk"
|
||||
"lol.mleku.dev/log"
|
||||
utils "utils.orly"
|
||||
)
|
||||
|
||||
const Type = "socketapi"
|
||||
|
||||
type Subscription struct {
|
||||
remote string
|
||||
remote string
|
||||
AuthedPubkey []byte
|
||||
*filter.S
|
||||
}
|
||||
|
||||
@@ -46,6 +50,9 @@ type W struct {
|
||||
// associated with this WebSocket connection. It is used to determine which
|
||||
// notifications or data should be received by the subscriber.
|
||||
Filters *filter.S
|
||||
|
||||
// AuthedPubkey is the authenticated pubkey associated with the listener (if any).
|
||||
AuthedPubkey []byte
|
||||
}
|
||||
|
||||
func (w *W) Type() (typeName string) { return Type }
|
||||
@@ -56,7 +63,7 @@ func (w *W) Type() (typeName string) { return Type }
|
||||
type P struct {
|
||||
c context.Context
|
||||
// Mx is the mutex for the Map.
|
||||
Mx sync.Mutex
|
||||
Mx sync.RWMutex
|
||||
// Map is the map of subscribers and subscriptions from the websocket api.
|
||||
Map
|
||||
}
|
||||
@@ -112,7 +119,7 @@ func (p *P) Receive(msg typer.T) {
|
||||
defer p.Mx.Unlock()
|
||||
if subs, ok := p.Map[m.Conn]; !ok {
|
||||
subs = make(map[string]Subscription)
|
||||
subs[m.Id] = Subscription{S: m.Filters, remote: m.remote}
|
||||
subs[m.Id] = Subscription{S: m.Filters, remote: m.remote, AuthedPubkey: m.AuthedPubkey}
|
||||
p.Map[m.Conn] = subs
|
||||
log.D.C(
|
||||
func() string {
|
||||
@@ -124,7 +131,7 @@ func (p *P) Receive(msg typer.T) {
|
||||
},
|
||||
)
|
||||
} else {
|
||||
subs[m.Id] = Subscription{S: m.Filters, remote: m.remote}
|
||||
subs[m.Id] = Subscription{S: m.Filters, remote: m.remote, AuthedPubkey: m.AuthedPubkey}
|
||||
log.D.C(
|
||||
func() string {
|
||||
return fmt.Sprintf(
|
||||
@@ -150,48 +157,77 @@ func (p *P) Receive(msg typer.T) {
|
||||
// for unauthenticated users when events are privileged.
|
||||
func (p *P) Deliver(ev *event.E) {
|
||||
var err error
|
||||
p.Mx.Lock()
|
||||
defer p.Mx.Unlock()
|
||||
// Snapshot the deliveries under read lock to avoid holding locks during I/O
|
||||
p.Mx.RLock()
|
||||
type delivery struct {
|
||||
w *websocket.Conn
|
||||
id string
|
||||
sub Subscription
|
||||
}
|
||||
var deliveries []delivery
|
||||
for w, subs := range p.Map {
|
||||
for id, subscriber := range subs {
|
||||
if subscriber.Match(ev) {
|
||||
deliveries = append(deliveries, delivery{w: w, id: id, sub: subscriber})
|
||||
}
|
||||
}
|
||||
}
|
||||
p.Mx.RUnlock()
|
||||
log.D.C(
|
||||
func() string {
|
||||
return fmt.Sprintf(
|
||||
"delivering event %0x to websocket subscribers %d", ev.ID,
|
||||
len(p.Map),
|
||||
len(deliveries),
|
||||
)
|
||||
},
|
||||
)
|
||||
for w, subs := range p.Map {
|
||||
for id, subscriber := range subs {
|
||||
if !subscriber.Match(ev) {
|
||||
continue
|
||||
}
|
||||
// if p.Server.AuthRequired() {
|
||||
// if !auth.CheckPrivilege(w.AuthedPubkey(), ev) {
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
var res *eventenvelope.Result
|
||||
if res, err = eventenvelope.NewResultWith(id, ev); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
if err = w.Write(
|
||||
p.c, websocket.MessageText, res.Marshal(nil),
|
||||
); chk.E(err) {
|
||||
p.removeSubscriber(w)
|
||||
if err = w.CloseNow(); chk.E(err) {
|
||||
continue
|
||||
for _, d := range deliveries {
|
||||
// If the event is privileged, enforce that the subscriber's authed pubkey matches
|
||||
// either the event pubkey or appears in any 'p' tag of the event.
|
||||
if kind.IsPrivileged(ev.Kind) && len(d.sub.AuthedPubkey) > 0 {
|
||||
pk := d.sub.AuthedPubkey
|
||||
allowed := false
|
||||
// Direct author match
|
||||
if utils.FastEqual(ev.Pubkey, pk) {
|
||||
allowed = true
|
||||
} else if ev.Tags != nil {
|
||||
for _, pTag := range ev.Tags.GetAll([]byte("p")) {
|
||||
// pTag.Value() returns []byte hex string; decode to bytes
|
||||
dec, derr := hex.Dec(string(pTag.Value()))
|
||||
if derr != nil {
|
||||
continue
|
||||
}
|
||||
if utils.FastEqual(dec, pk) {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !allowed {
|
||||
// Skip delivery for this subscriber
|
||||
continue
|
||||
}
|
||||
log.D.C(
|
||||
func() string {
|
||||
return fmt.Sprintf(
|
||||
"dispatched event %0x to subscription %s, %s",
|
||||
ev.ID, id, subscriber.remote,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
var res *eventenvelope.Result
|
||||
if res, err = eventenvelope.NewResultWith(d.id, ev); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
if err = d.w.Write(
|
||||
p.c, websocket.MessageText, res.Marshal(nil),
|
||||
); chk.E(err) {
|
||||
// On error, remove the subscriber connection safely
|
||||
p.removeSubscriber(d.w)
|
||||
_ = d.w.CloseNow()
|
||||
continue
|
||||
}
|
||||
log.D.C(
|
||||
func() string {
|
||||
return fmt.Sprintf(
|
||||
"dispatched event %0x to subscription %s, %s",
|
||||
ev.ID, d.id, d.sub.remote,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +235,7 @@ func (p *P) Deliver(ev *event.E) {
|
||||
// websocket.
|
||||
func (p *P) removeSubscriberId(ws *websocket.Conn, id string) {
|
||||
p.Mx.Lock()
|
||||
defer p.Mx.Unlock()
|
||||
var subs map[string]Subscription
|
||||
var ok bool
|
||||
if subs, ok = p.Map[ws]; ok {
|
||||
@@ -208,13 +245,12 @@ func (p *P) removeSubscriberId(ws *websocket.Conn, id string) {
|
||||
delete(p.Map, ws)
|
||||
}
|
||||
}
|
||||
p.Mx.Unlock()
|
||||
}
|
||||
|
||||
// removeSubscriber removes a websocket from the P collection.
|
||||
func (p *P) removeSubscriber(ws *websocket.Conn) {
|
||||
p.Mx.Lock()
|
||||
defer p.Mx.Unlock()
|
||||
clear(p.Map[ws])
|
||||
delete(p.Map, ws)
|
||||
p.Mx.Unlock()
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
type Signer struct {
|
||||
SecretKey *secp256k1.SecretKey
|
||||
PublicKey *secp256k1.PublicKey
|
||||
BTCECSec *ec.SecretKey
|
||||
BTCECSec *secp256k1.SecretKey
|
||||
pkb, skb []byte
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ var _ signer.I = &Signer{}
|
||||
|
||||
// Generate creates a new Signer.
|
||||
func (s *Signer) Generate() (err error) {
|
||||
if s.SecretKey, err = ec.NewSecretKey(); chk.E(err) {
|
||||
if s.SecretKey, err = secp256k1.GenerateSecretKey(); chk.E(err) {
|
||||
return
|
||||
}
|
||||
s.skb = s.SecretKey.Serialize()
|
||||
s.BTCECSec, _ = ec.PrivKeyFromBytes(s.skb)
|
||||
s.BTCECSec = secp256k1.PrivKeyFromBytes(s.skb)
|
||||
s.PublicKey = s.SecretKey.PubKey()
|
||||
s.pkb = schnorr.SerializePubKey(s.PublicKey)
|
||||
return
|
||||
@@ -43,7 +43,7 @@ func (s *Signer) InitSec(sec []byte) (err error) {
|
||||
s.SecretKey = secp256k1.SecKeyFromBytes(sec)
|
||||
s.PublicKey = s.SecretKey.PubKey()
|
||||
s.pkb = schnorr.SerializePubKey(s.PublicKey)
|
||||
s.BTCECSec, _ = ec.PrivKeyFromBytes(s.skb)
|
||||
s.BTCECSec = secp256k1.PrivKeyFromBytes(s.skb)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ func (s *Signer) ECDH(pubkeyBytes []byte) (secret []byte, err error) {
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
secret = ec.GenerateSharedSecret(s.BTCECSec, pub)
|
||||
secret = secp256k1.GenerateSharedSecret(s.BTCECSec, pub)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ type Keygen struct {
|
||||
// Generate a new key pair. If the result is suitable, the embedded Signer can have its contents
|
||||
// extracted.
|
||||
func (k *Keygen) Generate() (pubBytes []byte, err error) {
|
||||
if k.Signer.SecretKey, err = ec.NewSecretKey(); chk.E(err) {
|
||||
if k.Signer.SecretKey, err = secp256k1.GenerateSecretKey(); chk.E(err) {
|
||||
return
|
||||
}
|
||||
k.Signer.PublicKey = k.SecretKey.PubKey()
|
||||
|
||||
@@ -1 +1 @@
|
||||
v0.2.0
|
||||
v0.2.1
|
||||
Reference in New Issue
Block a user