backend for xcvr appview
at main 255 lines 7.2 kB view raw
1package recordmanager 2 3import ( 4 "context" 5 "errors" 6 atoauth "github.com/bluesky-social/indigo/atproto/auth/oauth" 7 "github.com/bluesky-social/indigo/atproto/syntax" 8 "github.com/rachel-mp4/lrcd" 9 "os" 10 "rvcx/internal/atputils" 11 "rvcx/internal/lex" 12 "rvcx/internal/oauth" 13 "rvcx/internal/types" 14 "slices" 15 "time" 16) 17 18func (rm *RecordManager) AcceptMessage(m *types.Message, ctx context.Context) error { 19 wasNew, err := rm.storeMessage(m, ctx) 20 if err != nil { 21 return errors.New("failed to store message: " + err.Error()) 22 } 23 if !wasNew { 24 return nil 25 } 26 err = rm.forwardMessage(m, ctx) 27 if err != nil { 28 return errors.New("failed to forward message: " + err.Error()) 29 } 30 return nil 31} 32 33func (rm *RecordManager) AcceptMessageUpdate(m *types.Message, did string, ctx context.Context) error { 34 err := rm.updateMessage(m, ctx) 35 if err != nil { 36 return errors.New("failed to store message: " + err.Error()) 37 } 38 err = rm.checkInterference(m, did, ctx) 39 if err != nil { 40 return errors.New("error while checking interference: " + err.Error()) 41 } 42 return nil 43} 44 45func (rm *RecordManager) AcceptMessageDelete(uri string, ctx context.Context) error { 46 err := rm.db.DeleteMessage(uri, ctx) 47 if err != nil { 48 return errors.New("failed to delete message: " + err.Error()) 49 } 50 return nil 51} 52 53func (rm *RecordManager) checkInterference(m *types.Message, did string, ctx context.Context) error { 54 handle, err := rm.db.QuerySignetHandle(m.SignetURI, ctx) 55 if err != nil { 56 return errors.New("couldn't find signet") 57 } 58 sdid, err := atputils.DidFromUri(m.SignetURI) 59 if sdid != atputils.GetMyDid() { 60 return nil 61 } 62 mhandle, err := rm.db.ResolveDid(did, ctx) 63 if err != nil { 64 return errors.New("couldn't resolve mhandle") 65 } 66 if handle != mhandle { 67 return nil 68 } 69 err = rm.DeleteSignet(m.SignetURI, ctx) 70 if err != nil { 71 return errors.New("failed to delete signet") 72 } 73 return nil 74} 75 76func (rm *RecordManager) PostMessage(cs *atoauth.ClientSession, ctx context.Context, pmr *types.PostMessageRequest) error { 77 rm.log.Deprintln("validate") 78 lmr, now, _, _, err := rm.validateMessage(pmr, ctx) 79 if err != nil { 80 return errors.New("failed to validate message: " + err.Error()) 81 } 82 rm.log.Deprintln("create") 83 m, err := rm.createMessage(cs, lmr, now, ctx) 84 if err != nil { 85 return errors.New("failed to create message: " + err.Error()) 86 } 87 rm.log.Deprintln("store") 88 wasNew, err := rm.storeMessage(m, ctx) 89 if err != nil { 90 return errors.New("failed to store message: " + err.Error()) 91 } 92 if !wasNew { 93 return nil 94 } 95 rm.log.Deprintln("forward") 96 err = rm.forwardMessage(m, ctx) 97 if err != nil { 98 return errors.New("failed to forward message: " + err.Error()) 99 } 100 return nil 101} 102 103func (rm *RecordManager) PostMyMessage(ctx context.Context, pmr *types.PostMessageRequest) error { 104 lmr, now, handle, nonce, err := rm.validateMessage(pmr, ctx) 105 if err != nil { 106 return errors.New("failed to validate message: " + err.Error()) 107 } 108 err = rm.validateHandleAndNonce(handle, nonce, lmr.SignetURI, ctx) 109 if err != nil { 110 return errors.New("failed to validate my handle and nonce: " + err.Error()) 111 } 112 m, err := rm.createMyMessage(lmr, now, ctx) 113 if err != nil { 114 return errors.New("failed to create message: " + err.Error()) 115 } 116 wasNew, err := rm.storeMessage(m, ctx) 117 if err != nil { 118 return errors.New("failed to store message: " + err.Error()) 119 } 120 if !wasNew { 121 return nil 122 } 123 err = rm.forwardMessage(m, ctx) 124 if err != nil { 125 return errors.New("failed to forward message: " + err.Error()) 126 } 127 return nil 128} 129 130func (rm *RecordManager) validateHandleAndNonce(handle *string, nonce []byte, signetUri string, ctx context.Context) error { 131 if handle == nil || *handle != atputils.GetMyHandle() { 132 return errors.New("i only post my messages") 133 } 134 curi, mid, err := rm.db.QuerySignetChannelIdNum(signetUri, ctx) 135 if err != nil { 136 return errors.New("failed to find signet") 137 } 138 correctNonce := lrcd.GenerateNonce(mid, curi, os.Getenv("LRCD_SECRET")) 139 if !slices.Equal(nonce, correctNonce) { 140 return errors.New("i think user tried to post someone else's post") 141 } 142 return nil 143} 144 145func (rm *RecordManager) createMyMessage(lmr *lex.MessageRecord, now *time.Time, ctx context.Context) (*types.Message, error) { 146 cid, uri, err := rm.myClient.CreateXCVRMessage(lmr, ctx) 147 if err != nil { 148 return nil, errors.New("couldn't add to user repo: " + err.Error()) 149 } 150 var coloruint32ptr *uint32 151 if lmr.Color != nil { 152 color := uint32(*lmr.Color) 153 coloruint32ptr = &color 154 } 155 message := &types.Message{ 156 URI: uri, 157 DID: atputils.GetMyDid(), 158 CID: cid, 159 SignetURI: lmr.SignetURI, 160 Body: lmr.Body, 161 Nick: lmr.Nick, 162 Color: coloruint32ptr, 163 PostedAt: *now, 164 } 165 return message, nil 166} 167 168func (rm *RecordManager) createMessage(cs *atoauth.ClientSession, lmr *lex.MessageRecord, now *time.Time, ctx context.Context) (*types.Message, error) { 169 uri, cid, err := oauth.CreateXCVRMessage(cs, lmr, ctx) 170 if err != nil { 171 return nil, errors.New("couldn't add to user repo: " + err.Error()) 172 } 173 var coloruint32ptr *uint32 174 if lmr.Color != nil { 175 color := uint32(*lmr.Color) 176 coloruint32ptr = &color 177 } 178 message := &types.Message{ 179 URI: uri, 180 DID: cs.Data.AccountDID.String(), 181 CID: cid, 182 SignetURI: lmr.SignetURI, 183 Body: lmr.Body, 184 Nick: lmr.Nick, 185 Color: coloruint32ptr, 186 PostedAt: *now, 187 } 188 return message, nil 189} 190 191func (rm *RecordManager) updateMessage(m *types.Message, ctx context.Context) error { 192 return rm.db.UpdateMessage(m, ctx) 193} 194 195func (rm *RecordManager) storeMessage(m *types.Message, ctx context.Context) (wasNew bool, err error) { 196 return rm.db.StoreMessage(m, ctx) 197} 198 199func (rm *RecordManager) forwardMessage(m *types.Message, ctx context.Context) error { 200 curi, err := rm.db.GetMsgChannelURI(m.SignetURI, ctx) 201 if err != nil { 202 return errors.New("aaaaaaaaaaaa " + err.Error()) 203 } 204 return rm.broadcaster.BroadcastMessage(curi, m) 205} 206 207func (rm *RecordManager) validateMessage(mr *types.PostMessageRequest, ctx context.Context) (lmr *lex.MessageRecord, now *time.Time, handle *string, nonce []byte, err error) { 208 lmr = &lex.MessageRecord{} 209 if mr.SignetURI == nil { 210 if mr.MessageID == nil || mr.ChannelURI == nil { 211 err = errors.New("must provide a way to determine signet") 212 return 213 } 214 signetUri, signetHandle, yorks := rm.db.QuerySignet(*mr.ChannelURI, *mr.MessageID, ctx) 215 if yorks != nil { 216 err = errors.New("i couldn't find the signet :c : " + yorks.Error()) 217 return 218 } 219 mr.SignetURI = &signetUri 220 handle = &signetHandle 221 } else { 222 signetHandle, yorks := rm.db.QuerySignetHandle(*mr.SignetURI, ctx) 223 if yorks != nil { 224 err = errors.New("yorks skooby 💀" + yorks.Error()) 225 return 226 } 227 handle = &signetHandle 228 } 229 lmr.SignetURI = *mr.SignetURI 230 lmr.Body = mr.Body 231 if mr.Nick != nil { 232 nick := *mr.Nick 233 if atputils.ValidateLength(nick, 16) { 234 err = errors.New("that nick is too long") 235 return 236 } 237 } 238 lmr.Nick = mr.Nick 239 240 if mr.Color != nil { 241 color := uint64(*mr.Color) 242 if color > 16777215 { 243 err = errors.New("that color is too big") 244 return 245 } 246 lmr.Color = &color 247 } 248 249 nonce = mr.Nonce 250 nowsyn := syntax.DatetimeNow() 251 lmr.PostedAt = nowsyn.String() 252 nt := nowsyn.Time() 253 now = &nt 254 return 255}