diff options
Diffstat (limited to 'internal/repository/media.go')
| -rw-r--r-- | internal/repository/media.go | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/internal/repository/media.go b/internal/repository/media.go index a7a9553..c40b511 100644 --- a/internal/repository/media.go +++ b/internal/repository/media.go @@ -181,12 +181,9 @@ func (s *SQLite) ListMedia(ctx context.Context, filter MediaFilter) ([]model.Med query := `SELECT DISTINCT media.id, media.set_id, media.rel_path, media.file_name, media.abs_path, media.type, media.duration, media.codec, media.resolution, media.bitrate, media.file_size_bytes, media.width, media.height, media.exif_camera, media.exif_lens, media.exif_date, media.exif_iso, media.exif_f_number, media.exif_exposure, media.exif_focal_length, media.thumbnail_path, media.play_count, media.deleted_at, media.created_at FROM media` if filter.Search != "" { + // escapeLike escapes LIKE wildcards so user input is treated as a literal substring. conds = append(conds, `(media.file_name LIKE ? ESCAPE '\' OR media.rel_path LIKE ? ESCAPE '\')`) - term := filter.Search - term = strings.ReplaceAll(term, "\\", "\\\\") - term = strings.ReplaceAll(term, "%", "\\%") - term = strings.ReplaceAll(term, "_", "\\_") - like := "%" + term + "%" + like := "%" + escapeLike(filter.Search) + "%" args = append(args, like, like) } if filter.Favorites { @@ -307,6 +304,16 @@ func (s *SQLite) IncrementPlayCount(ctx context.Context, id int64) error { return nil } +// escapeLike escapes backslash, percent, and underscore in s so it can be +// used as a literal substring in a SQL LIKE ? ESCAPE '\' clause without +// allowing timing-based wildcard injection. +func escapeLike(s string) string { + s = strings.ReplaceAll(s, `\`, `\\`) + s = strings.ReplaceAll(s, `%`, `\%`) + s = strings.ReplaceAll(s, `_`, `\_`) + return s +} + func placeholders(n int) string { if n <= 0 { return "" |
