tinyrelayfile
tinyrelay/internal/daemon/client_events.go/

internal/daemon/client_events.go raw
1package daemon
2
3import (
4 "context"
5 "database/sql"
6 "errors"
7 "strings"
8
9 "github.com/FelineStateMachine/tinyrelay/internal/community"
10 "github.com/FelineStateMachine/tinyrelay/internal/event"
11 "github.com/FelineStateMachine/tinyrelay/internal/policy"
12 "github.com/FelineStateMachine/tinyrelay/internal/relay"
13 "github.com/FelineStateMachine/tinyrelay/internal/replication"
14 "github.com/FelineStateMachine/tinyrelay/internal/storage"
15)
16
17type metadataProjection struct {
18 next policy.Policy
19 changed bool
20}
21
22func (t *Tenant) publishReport(ctx context.Context, e event.Event) (string, error) {
23 target := ""
24 targetType := ""
25 reportType := ""
26 for _, tag := range e.Tags {
27 if len(tag) > 1 && tag[0] == "e" && target == "" {
28 target = tag[1]
29 targetType = "event"
30 if len(tag) > 2 {
31 reportType = tag[2]
32 }
33 }
34 if len(tag) > 1 && tag[0] == "p" && target == "" {
35 target = tag[1]
36 targetType = "pubkey"
37 if len(tag) > 2 {
38 reportType = tag[2]
39 }
40 }
41 if len(tag) > 1 && tag[0] == "x" && target == "" {
42 target = tag[1]
43 targetType = "blob"
44 if len(tag) > 2 {
45 reportType = tag[2]
46 }
47 }
48 }
49 if target == "" {
50 return "", errors.New("invalid: report needs an e or p tag")
51 }
52 if err := t.community.SubmitReportTarget(ctx, e.PubKey, target, targetType, reportType, e.Content, t.Policy().ReportThreshold); err != nil {
53 return "", err
54 }
55 return "info: report received", nil
56}
57
58func (t *Tenant) prepareClientEvent(ctx context.Context, e event.Event, s relay.Session, now int64) (eventCommitPlan, *metadataProjection, error) {
59 metadata := &metadataProjection{}
60 plan, err := t.prepareStoredEvent(ctx, e, replication.OriginClient, now)
61 if err != nil {
62 return plan, metadata, err
63 }
64 opts := plan.options
65 if (e.Kind == event.KIND_EDIT_METADATA || e.Kind == event.KIND_PINS) && t.roomScope(e) == "" {
66 role, roleErr := t.community.Role(ctx, e.PubKey)
67 if roleErr != nil {
68 return plan, metadata, roleErr
69 }
70 if role != "owner" && role != "moderator" {
71 return plan, metadata, errors.New("restricted: not a group admin")
72 }
73 opts.AddBeforeCommit(func(txCtx context.Context, tx *sql.Tx) error {
74 return t.community.HandleProjectionEventTx(txCtx, tx, e, func(sideTx *sql.Tx) error {
75 if e.Kind == event.KIND_EDIT_METADATA {
76 metadata.next = t.Policy()
77 for _, tag := range e.Tags {
78 if len(tag) < 2 {
79 continue
80 }
81 switch tag[0] {
82 case "name":
83 metadata.next.Name = tag[1][:min(200, len(tag[1]))]
84 case "about":
85 metadata.next.Description = tag[1][:min(2000, len(tag[1]))]
86 case "picture":
87 metadata.next.Icon = tag[1][:min(2000, len(tag[1]))]
88 }
89 }
90 metadata.changed = true
91 return storage.PutSetting(txCtx, sideTx, "policy", metadata.next)
92 }
93 pins, err := parsePinTags(e.Tags)
94 if err != nil {
95 return err
96 }
97 return t.records.ReplacePinsTx(txCtx, sideTx, pins)
98 })
99 })
100 }
101 opts.Intents = append(opts.Intents, t.replication.Prepare(e, replication.OriginClient)...)
102 if e.Kind == event.KIND_MARMOT_GROUP {
103 principal, principalErr := t.gate.Principal(ctx, e, s)
104 if principalErr != nil {
105 return plan, metadata, principalErr
106 }
107 opts.AddBeforeCommit(func(txCtx context.Context, tx *sql.Tx) error {
108 _, err := tx.ExecContext(txCtx, `INSERT OR REPLACE INTO marmot_principals(event_id,pubkey) VALUES(?,?)`, e.ID, principal)
109 return err
110 })
111 }
112 plan.options = opts
113 return plan, metadata, nil
114}
115
116func (t *Tenant) persistClientEvent(ctx context.Context, e event.Event, opts storage.SaveOptions) (string, error) {
117 var err error
118 persist := func(tx *sql.Tx) error {
119 _, saveErr := storage.SaveTx(ctx, tx, e, opts)
120 return saveErr
121 }
122 // reason is the OK message; an access request tells the asker it waits,
123 // and a member asking again is told so.
124 reason := ""
125 room := t.roomScope(e)
126 switch {
127 case room != "" && community.RoomAdminKind(e.Kind):
128 _, err = t.community.HandleRoomEventTx(ctx, e, persist)
129 case room != "" && !event.IsEphemeral(e.Kind):
130 err = t.community.HandleRoomMessageTx(ctx, e, persist)
131 case e.Kind == event.KIND_JOIN, e.Kind == event.KIND_LEAVE, e.Kind == event.KIND_NIP43_JOIN, e.Kind == event.KIND_NIP43_LEAVE:
132 var membership community.MembershipResult
133 membership, err = t.community.HandleMembershipEventTx(ctx, e, persist)
134 if err == nil && (membership.AccessRequest || strings.HasPrefix(membership.Message, "duplicate:")) {
135 reason = membership.Message
136 }
137 if err == nil && membership.NewRequest {
138 t.notifyJoinRequest(ctx, e)
139 }
140 case e.Kind == event.KIND_PUT_USER, e.Kind == event.KIND_REMOVE_USER, e.Kind == event.KIND_DELETE_EVENT, e.Kind == event.KIND_CREATE_INVITE:
141 _, err = t.community.HandleModerationEventTx(ctx, e, persist)
142 default:
143 _, err = t.store.Save(ctx, e, opts)
144 }
145 return reason, err
146}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs