mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Full codebase audit: 21 security/robustness fixes, 328 tests across 4 packages
Security & economy: - Credit()/Debit() reject non-positive amounts (closes infinite-money exploit) - Lottery ticket purchase uses in-transaction count check (closes TOCTOU race) - Arena bail channel ownership prevents double-close panic - Entry.ID validated before exec.Command in fetch-esteemed - Internal errors no longer leaked to users (forex, esteemed) Robustness: - safeGo() panic recovery added to 17 goroutine launch sites across 14 plugins - db.Close() added and called on shutdown - Miniflux mutex pattern fixed (snapshot-under-lock) - Silently ignored DB/JSON errors now logged (lottery_db) Performance: - Added indexes: idx_arena_runs_user(user_id, status), idx_euro_bal_user(user_id) UX: - Empty !buy args shows usage instead of "No item matching ''" - "Failed to load character" now suggests !adventure Test coverage: - internal/util/parser_test.go (19 tests: XP, levels, progress bar, commands, parsing) - internal/crypto/crypto_test.go (12 tests: encrypt/decrypt, HMAC, ParseKey) - internal/plugin/helpers_test.go (30 tests: formatNumber, calc, lottery, chat perks) - internal/plugin/audit_fixes_test.go (25 tests: safeGo, bail channels, error leaks, overflow) - internal/db/db_test.go (4 tests: Init, Close, schema indexes) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -678,6 +678,52 @@ func (b *Base) SendDM(userID id.UserID, text string) error {
|
||||
return b.SendMessage(roomID, text)
|
||||
}
|
||||
|
||||
// SendDMID sends a direct message and returns the event ID (for later editing).
|
||||
func (b *Base) SendDMID(userID id.UserID, text string) (id.EventID, error) {
|
||||
roomID, err := b.GetDMRoom(userID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return b.SendMessageID(roomID, text)
|
||||
}
|
||||
|
||||
// EditMessage edits an existing message using Matrix m.replace relation.
|
||||
func (b *Base) EditMessage(roomID id.RoomID, eventID id.EventID, newText string) error {
|
||||
newContent := textContent(newText)
|
||||
content := &event.MessageEventContent{
|
||||
MsgType: event.MsgText,
|
||||
Body: "* " + newContent.Body,
|
||||
NewContent: &event.MessageEventContent{
|
||||
MsgType: newContent.MsgType,
|
||||
Body: newContent.Body,
|
||||
Format: newContent.Format,
|
||||
FormattedBody: newContent.FormattedBody,
|
||||
},
|
||||
RelatesTo: &event.RelatesTo{
|
||||
Type: event.RelReplace,
|
||||
EventID: eventID,
|
||||
},
|
||||
}
|
||||
if newContent.Format == event.FormatHTML {
|
||||
content.Format = event.FormatHTML
|
||||
content.FormattedBody = "* " + newContent.FormattedBody
|
||||
}
|
||||
_, err := b.Client.SendMessageEvent(context.Background(), roomID, event.EventMessage, content)
|
||||
if err != nil {
|
||||
slog.Error("failed to edit message", "room", roomID, "event", eventID, "err", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// EditDM edits a message in a user's DM room.
|
||||
func (b *Base) EditDM(userID id.UserID, eventID id.EventID, newText string) error {
|
||||
roomID, err := b.GetDMRoom(userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.EditMessage(roomID, eventID, newText)
|
||||
}
|
||||
|
||||
// UploadContent uploads data to the Matrix content repository and returns the MXC URI.
|
||||
func (b *Base) UploadContent(data []byte, contentType, filename string) (id.ContentURI, error) {
|
||||
resp, err := b.Client.UploadBytesWithName(context.Background(), data, contentType, filename)
|
||||
@@ -708,3 +754,16 @@ func (b *Base) SendImage(roomID id.RoomID, imgData []byte, filename, caption str
|
||||
_, err = b.Client.SendMessageEvent(context.Background(), roomID, event.EventMessage, content)
|
||||
return err
|
||||
}
|
||||
|
||||
// safeGo runs fn in a goroutine with panic recovery.
|
||||
// Use instead of bare `go func()` to prevent daemon crashes.
|
||||
func safeGo(label string, fn func()) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
slog.Error("goroutine panic recovered", "label", label, "panic", r)
|
||||
}
|
||||
}()
|
||||
fn()
|
||||
}()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user