fix: escape wildcard list queries
This commit is contained in:
parent
716e7a8496
commit
999461ce0e
@ -27,8 +27,8 @@ func (d *DB) ListChats(query string, limit int) ([]Chat, error) {
|
||||
q := `SELECT jid, kind, COALESCE(name,''), COALESCE(last_message_ts,0) FROM chats WHERE 1=1`
|
||||
var args []interface{}
|
||||
if strings.TrimSpace(query) != "" {
|
||||
q += ` AND (LOWER(name) LIKE LOWER(?) OR LOWER(jid) LIKE LOWER(?))`
|
||||
needle := "%" + query + "%"
|
||||
q += ` AND (LOWER(name) LIKE LOWER(?) ESCAPE '\' OR LOWER(jid) LIKE LOWER(?) ESCAPE '\')`
|
||||
needle := likeContains(query)
|
||||
args = append(args, needle, needle)
|
||||
}
|
||||
q += ` ORDER BY last_message_ts DESC LIMIT ?`
|
||||
|
||||
@ -21,10 +21,10 @@ func (d *DB) SearchContacts(query string, limit int) ([]Contact, error) {
|
||||
c.updated_at
|
||||
FROM contacts c
|
||||
LEFT JOIN contact_aliases a ON a.jid = c.jid
|
||||
WHERE LOWER(COALESCE(a.alias,'')) LIKE LOWER(?) OR LOWER(COALESCE(c.full_name,'')) LIKE LOWER(?) OR LOWER(COALESCE(c.push_name,'')) LIKE LOWER(?) OR LOWER(COALESCE(c.phone,'')) LIKE LOWER(?) OR LOWER(c.jid) LIKE LOWER(?)
|
||||
WHERE LOWER(COALESCE(a.alias,'')) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(c.full_name,'')) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(c.push_name,'')) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(c.phone,'')) LIKE LOWER(?) ESCAPE '\' OR LOWER(c.jid) LIKE LOWER(?) ESCAPE '\'
|
||||
ORDER BY COALESCE(NULLIF(a.alias,''), NULLIF(c.full_name,''), NULLIF(c.push_name,''), c.jid)
|
||||
LIMIT ?`
|
||||
needle := "%" + query + "%"
|
||||
needle := likeContains(query)
|
||||
rows, err := d.sql.Query(q, needle, needle, needle, needle, needle, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -59,8 +59,8 @@ func (d *DB) ListGroups(query string, limit int) ([]Group, error) {
|
||||
q := `SELECT jid, COALESCE(name,''), COALESCE(owner_jid,''), COALESCE(created_ts,0), updated_at FROM groups WHERE 1=1`
|
||||
var args []interface{}
|
||||
if strings.TrimSpace(query) != "" {
|
||||
needle := "%" + query + "%"
|
||||
q += ` AND (LOWER(name) LIKE LOWER(?) OR LOWER(jid) LIKE LOWER(?))`
|
||||
needle := likeContains(query)
|
||||
q += ` AND (LOWER(name) LIKE LOWER(?) ESCAPE '\' OR LOWER(jid) LIKE LOWER(?) ESCAPE '\')`
|
||||
args = append(args, needle, needle)
|
||||
}
|
||||
q += ` ORDER BY COALESCE(created_ts,0) DESC LIMIT ?`
|
||||
|
||||
@ -39,14 +39,18 @@ func escapeLIKE(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func likeContains(s string) string {
|
||||
return "%" + escapeLIKE(s) + "%"
|
||||
}
|
||||
|
||||
func (d *DB) searchLIKE(p SearchMessagesParams) ([]Message, error) {
|
||||
query := `
|
||||
SELECT m.chat_jid, COALESCE(c.name,''), m.msg_id, COALESCE(m.sender_jid,''), m.ts, m.from_me, COALESCE(m.text,''), COALESCE(m.display_text,''), COALESCE(m.media_type,''), ''
|
||||
FROM messages m
|
||||
LEFT JOIN chats c ON c.jid = m.chat_jid
|
||||
WHERE (LOWER(m.text) LIKE LOWER(?) ESCAPE '\' OR LOWER(m.display_text) LIKE LOWER(?) ESCAPE '\' OR LOWER(m.media_caption) LIKE LOWER(?) ESCAPE '\' OR LOWER(m.filename) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(m.chat_name,'')) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(m.sender_name,'')) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(c.name,'')) LIKE LOWER(?) ESCAPE '\')`
|
||||
WHERE (LOWER(m.text) LIKE LOWER(?) ESCAPE '\' OR LOWER(m.display_text) LIKE LOWER(?) ESCAPE '\' OR LOWER(m.media_caption) LIKE LOWER(?) ESCAPE '\' OR LOWER(m.filename) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(m.chat_name,'')) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(m.sender_name,'')) LIKE LOWER(?) ESCAPE '\' OR LOWER(COALESCE(c.name,'')) LIKE LOWER(?) ESCAPE '\')`
|
||||
// Escape wildcards before wrapping in % so user input is literal (#56).
|
||||
needle := "%" + escapeLIKE(p.Query) + "%"
|
||||
needle := likeContains(p.Query)
|
||||
args := []interface{}{needle, needle, needle, needle, needle, needle, needle}
|
||||
query, args = applyMessageFilters(query, args, p)
|
||||
query += " ORDER BY m.ts DESC LIMIT ?"
|
||||
|
||||
@ -305,6 +305,53 @@ func TestContactsAliasTagsAndSearch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestListQueriesEscapeLIKEWildcards(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
when := time.Date(2024, 3, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
if err := db.UpsertChat("literal_percent@s.whatsapp.net", "dm", "100% literal", when); err != nil {
|
||||
t.Fatalf("UpsertChat literal: %v", err)
|
||||
}
|
||||
if err := db.UpsertChat("wildcard@s.whatsapp.net", "dm", "100X wildcard", when); err != nil {
|
||||
t.Fatalf("UpsertChat wildcard: %v", err)
|
||||
}
|
||||
chats, err := db.ListChats("100%", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("ListChats: %v", err)
|
||||
}
|
||||
if len(chats) != 1 || chats[0].JID != "literal_percent@s.whatsapp.net" {
|
||||
t.Fatalf("ListChats wildcard leak: %+v", chats)
|
||||
}
|
||||
|
||||
if err := db.UpsertContact("literal_under@s.whatsapp.net", "", "Ann_", "", "", ""); err != nil {
|
||||
t.Fatalf("UpsertContact literal: %v", err)
|
||||
}
|
||||
if err := db.UpsertContact("wildcard_under@s.whatsapp.net", "", "AnnX", "", "", ""); err != nil {
|
||||
t.Fatalf("UpsertContact wildcard: %v", err)
|
||||
}
|
||||
contacts, err := db.SearchContacts("Ann_", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("SearchContacts: %v", err)
|
||||
}
|
||||
if len(contacts) != 1 || contacts[0].JID != "literal_under@s.whatsapp.net" {
|
||||
t.Fatalf("SearchContacts wildcard leak: %+v", contacts)
|
||||
}
|
||||
|
||||
if err := db.UpsertGroup("literal_group@g.us", "team_1", "", when); err != nil {
|
||||
t.Fatalf("UpsertGroup literal: %v", err)
|
||||
}
|
||||
if err := db.UpsertGroup("wildcard_group@g.us", "teamA1", "", when); err != nil {
|
||||
t.Fatalf("UpsertGroup wildcard: %v", err)
|
||||
}
|
||||
groups, err := db.ListGroups("team_1", 10)
|
||||
if err != nil {
|
||||
t.Fatalf("ListGroups: %v", err)
|
||||
}
|
||||
if len(groups) != 1 || groups[0].JID != "literal_group@g.us" {
|
||||
t.Fatalf("ListGroups wildcard leak: %+v", groups)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCountMessagesAndOldestMessageInfo(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user