fix: harden media + conversation queries against empty-uuid casts

This commit is contained in:
Abhinav Raut
2026-05-19 14:13:56 +05:30
parent df1d5815ce
commit 4e13e72cc3
6 changed files with 26 additions and 12 deletions
+6
View File
@@ -53,6 +53,9 @@ func handleCreateTemplate(r *fastglue.Request) error {
if req.Name == "" {
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.empty", "name", "`name`"), nil, envelope.InputError)
}
if req.Type == "" {
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.empty", "name", "`type`"), nil, envelope.InputError)
}
template, err := app.tmpl.Create(req)
if err != nil {
return sendErrorEnvelope(r, err)
@@ -77,6 +80,9 @@ func handleUpdateTemplate(r *fastglue.Request) error {
if req.Name == "" {
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.empty", "name", "`name`"), nil, envelope.InputError)
}
if req.Type == "" {
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.empty", "name", "`type`"), nil, envelope.InputError)
}
updatedTemplate, err := app.tmpl.Update(id, req)
if err != nil {
return sendErrorEnvelope(r, err)
+1 -1
View File
@@ -141,7 +141,7 @@ type mediaStore interface {
SetContentID(id int, contentID string) error
GetByModel(id int, model string) ([]mmodels.Media, error)
GetByContentIDs(contentIDs []string, conversationUUID string) ([]mmodels.Media, error)
ContentIDExists(contentID string) (bool, string, error)
ContentIDExists(contentID, conversationUUID string) (bool, string, error)
Upload(fileName, contentType string, content io.ReadSeeker) (string, string, error)
UploadAndInsert(fileName, contentType, contentID string, modelType null.String, modelID null.Int, content io.ReadSeeker, fileSize int, disposition null.String, meta []byte) (mmodels.Media, error)
}
+1 -1
View File
@@ -1425,7 +1425,7 @@ func (m *Manager) findExistingMedia(rawContentID, conversationUUID string) (stri
if !strings.HasPrefix(rawContentID, "ldsk-") {
storedCID = conversationUUID + "_" + rawContentID
}
exists, mediaUUID, err := m.mediaStore.ContentIDExists(storedCID)
exists, mediaUUID, err := m.mediaStore.ContentIDExists(storedCID, conversationUUID)
if err != nil {
m.lo.Error("error checking media existence by content ID", "content_id", storedCID, "error", err)
}
+4 -4
View File
@@ -204,10 +204,10 @@ LEFT JOIN LATERAL (
ORDER BY se.created_at DESC
LIMIT 1
) nxt_resp_event ON true
WHERE
WHERE
($1 > 0 AND c.id = $1)
OR
($2::uuid IS NOT NULL AND c.uuid = $2::uuid)
OR
(NULLIF($2, '')::uuid IS NOT NULL AND c.uuid = NULLIF($2, '')::uuid)
OR
($3::TEXT != '' AND c.reference_number = $3::TEXT)
@@ -799,7 +799,7 @@ ORDER BY cd.updated_at DESC;
DELETE FROM conversation_drafts
WHERE conversation_id IN (
SELECT id FROM conversations
WHERE ($1 > 0 AND id = $1) OR ($2::uuid IS NOT NULL AND uuid = $2::uuid)
WHERE ($1 > 0 AND id = $1) OR (NULLIF($2, '')::uuid IS NOT NULL AND uuid = NULLIF($2, '')::uuid)
) AND user_id = $3;
-- name: delete-stale-drafts
+6 -3
View File
@@ -180,10 +180,13 @@ func (m *Manager) SetContentID(id int, contentID string) error {
return nil
}
// ContentIDExists checks if a content_id exists in the database and returns the UUID of the media file.
func (m *Manager) ContentIDExists(contentID string) (bool, string, error) {
// ContentIDExists reports whether a media row with the given content_id is linked to a message in the given conversation. Scoped this way so an orphan media row (e.g., from a partial failure) doesn't short-circuit a retry into skipping the upload.
func (m *Manager) ContentIDExists(contentID, conversationUUID string) (bool, string, error) {
if contentID == "" || conversationUUID == "" {
return false, "", nil
}
var uuid string
if err := m.queries.ContentIDExists.Get(&uuid, contentID); err != nil {
if err := m.queries.ContentIDExists.Get(&uuid, contentID, conversationUUID); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return false, "", nil
}
+8 -3
View File
@@ -17,10 +17,10 @@ RETURNING id;
-- name: get-media
SELECT id, created_at, updated_at, "uuid", store, filename, content_type, content_id, model_id, model_type, disposition, "size", meta
FROM media
WHERE
WHERE
($1 > 0 AND id = $1)
OR
($2 != '' AND uuid = $2::uuid)
($2 != '' AND uuid = NULLIF($2, '')::uuid)
-- name: get-media-by-uuid
SELECT id, created_at, updated_at, "uuid", store, filename, content_type, content_id, model_id, model_type, disposition, "size", meta
@@ -51,7 +51,12 @@ WHERE model_type = 'messages'
AND created_at < NOW() - INTERVAL '7 days';
-- name: content-id-exists
SELECT uuid FROM media WHERE content_id = $1;
SELECT m.uuid
FROM media m
INNER JOIN conversation_messages cm ON cm.id = m.model_id
WHERE m.model_type = 'messages'
AND m.content_id = $1
AND cm.conversation_id = (SELECT id FROM conversations WHERE uuid = $2::uuid LIMIT 1);
-- name: get-media-by-content-ids
SELECT m.id, m.created_at, m.updated_at, m."uuid", m.store, m.filename, m.content_type, m.content_id, m.model_id, m.model_type, m.disposition, m."size", m.meta