Search: Improve input sanitation and filter queries #1994 #2079 #2181

This commit is contained in:
Michael Mayer 2022-03-25 18:01:34 +01:00
parent bd5c773232
commit e77a029f13
7 changed files with 28 additions and 15 deletions

View file

@ -143,7 +143,6 @@ func NewFolderAlbum(albumTitle, albumPath, albumFilter string) *Album {
result := &Album{ result := &Album{
AlbumOrder: SortOrderAdded, AlbumOrder: SortOrderAdded,
AlbumType: AlbumFolder, AlbumType: AlbumFolder,
AlbumTitle: txt.Clip(albumTitle, txt.ClipDefault),
AlbumSlug: txt.Clip(albumSlug, txt.ClipSlug), AlbumSlug: txt.Clip(albumSlug, txt.ClipSlug),
AlbumPath: txt.Clip(albumPath, txt.ClipPath), AlbumPath: txt.Clip(albumPath, txt.ClipPath),
AlbumFilter: albumFilter, AlbumFilter: albumFilter,
@ -151,6 +150,8 @@ func NewFolderAlbum(albumTitle, albumPath, albumFilter string) *Album {
UpdatedAt: now, UpdatedAt: now,
} }
result.SetTitle(albumTitle)
return result return result
} }
@ -165,13 +166,14 @@ func NewMomentsAlbum(albumTitle, albumSlug, albumFilter string) *Album {
result := &Album{ result := &Album{
AlbumOrder: SortOrderOldest, AlbumOrder: SortOrderOldest,
AlbumType: AlbumMoment, AlbumType: AlbumMoment,
AlbumTitle: txt.Clip(albumTitle, txt.ClipDefault),
AlbumSlug: txt.Clip(albumSlug, txt.ClipSlug), AlbumSlug: txt.Clip(albumSlug, txt.ClipSlug),
AlbumFilter: albumFilter, AlbumFilter: albumFilter,
CreatedAt: now, CreatedAt: now,
UpdatedAt: now, UpdatedAt: now,
} }
result.SetTitle(albumTitle)
return result return result
} }
@ -189,13 +191,14 @@ func NewStateAlbum(albumTitle, albumSlug, albumFilter string) *Album {
result := &Album{ result := &Album{
AlbumOrder: SortOrderNewest, AlbumOrder: SortOrderNewest,
AlbumType: AlbumState, AlbumType: AlbumState,
AlbumTitle: txt.Clip(albumTitle, txt.ClipDefault),
AlbumSlug: txt.Clip(albumSlug, txt.ClipSlug), AlbumSlug: txt.Clip(albumSlug, txt.ClipSlug),
AlbumFilter: albumFilter, AlbumFilter: albumFilter,
CreatedAt: now, CreatedAt: now,
UpdatedAt: now, UpdatedAt: now,
} }
result.SetTitle(albumTitle)
return result return result
} }
@ -219,7 +222,6 @@ func NewMonthAlbum(albumTitle, albumSlug string, year, month int) *Album {
result := &Album{ result := &Album{
AlbumOrder: SortOrderOldest, AlbumOrder: SortOrderOldest,
AlbumType: AlbumMonth, AlbumType: AlbumMonth,
AlbumTitle: albumTitle,
AlbumSlug: albumSlug, AlbumSlug: albumSlug,
AlbumFilter: f.Serialize(), AlbumFilter: f.Serialize(),
AlbumYear: year, AlbumYear: year,
@ -228,6 +230,8 @@ func NewMonthAlbum(albumTitle, albumSlug string, year, month int) *Album {
UpdatedAt: now, UpdatedAt: now,
} }
result.SetTitle(albumTitle)
return result return result
} }
@ -367,13 +371,15 @@ func (m *Album) IsDefault() bool {
// SetTitle changes the album name. // SetTitle changes the album name.
func (m *Album) SetTitle(title string) { func (m *Album) SetTitle(title string) {
title = strings.TrimSpace(title) title = strings.Trim(title, "_&|{}<>: \n\r\t\\")
title = strings.ReplaceAll(title, "\"", "'")
title = txt.Shorten(title, txt.ClipDefault, txt.Ellipsis)
if title == "" { if title == "" {
title = m.CreatedAt.Format("January 2006") title = m.CreatedAt.Format("January 2006")
} }
m.AlbumTitle = txt.Clip(title, txt.ClipDefault) m.AlbumTitle = title
if m.AlbumType == AlbumDefault || m.AlbumSlug == "" { if m.AlbumType == AlbumDefault || m.AlbumSlug == "" {
if len(m.AlbumTitle) < txt.ClipSlug { if len(m.AlbumTitle) < txt.ClipSlug {
@ -408,7 +414,9 @@ func (m *Album) UpdateSlug(title, slug string) error {
return nil return nil
} }
m.AlbumTitle = title if title != "" {
m.SetTitle(title)
}
return m.Updates(Values{"album_title": m.AlbumTitle, "album_slug": m.AlbumSlug}) return m.Updates(Values{"album_title": m.AlbumTitle, "album_slug": m.AlbumSlug})
} }
@ -449,7 +457,9 @@ func (m *Album) UpdateState(title, slug, stateName, countryCode string) error {
return nil return nil
} }
m.AlbumTitle = title if title != "" {
m.SetTitle(title)
}
return m.Updates(Values{"album_title": m.AlbumTitle, "album_slug": m.AlbumSlug, "album_location": m.AlbumLocation, "album_country": m.AlbumCountry, "album_state": m.AlbumState}) return m.Updates(Values{"album_title": m.AlbumTitle, "album_slug": m.AlbumSlug, "album_location": m.AlbumLocation, "album_country": m.AlbumCountry, "album_state": m.AlbumState})
} }

View file

@ -60,7 +60,7 @@ the further from the equator you get. The precision of the latitude part does no
more strictly however, a meridian arc length per 1 second depends on the latitude at the point in question. more strictly however, a meridian arc length per 1 second depends on the latitude at the point in question.
The discrepancy of 1 second meridian arc length between equator and pole is about 0.3 metres because the earth The discrepancy of 1 second meridian arc length between equator and pole is about 0.3 metres because the earth
is an oblate spheroid.` is an oblate spheroid.`
expected := txt.Clip(longName, txt.ClipDefault) expected := txt.Shorten(longName, txt.ClipDefault, txt.Ellipsis)
slugExpected := txt.Clip(longName, txt.ClipSlug) slugExpected := txt.Clip(longName, txt.ClipSlug)
album := NewAlbum(longName, AlbumDefault) album := NewAlbum(longName, AlbumDefault)
assert.Equal(t, expected, album.AlbumTitle) assert.Equal(t, expected, album.AlbumTitle)

View file

@ -26,6 +26,8 @@ func (m *Photo) NoTitle() bool {
// SetTitle changes the photo title and clips it to 300 characters. // SetTitle changes the photo title and clips it to 300 characters.
func (m *Photo) SetTitle(title, source string) { func (m *Photo) SetTitle(title, source string) {
title = strings.Trim(title, "_&|{}<>: \n\r\t\\")
title = strings.ReplaceAll(title, "\"", "'")
title = txt.Shorten(title, txt.ClipTitle, txt.Ellipsis) title = txt.Shorten(title, txt.ClipTitle, txt.Ellipsis)
if title == "" { if title == "" {

View file

@ -306,7 +306,7 @@ func Photos(f form.SearchPhotos) (results PhotoResults, count int, err error) {
s = s.Where("photos.camera_id = ?", txt.UInt(f.Camera)) s = s.Where("photos.camera_id = ?", txt.UInt(f.Camera))
} else if txt.NotEmpty(f.Camera) { } else if txt.NotEmpty(f.Camera) {
v := strings.Trim(f.Camera, "*%") + "%" v := strings.Trim(f.Camera, "*%") + "%"
s = s.Where("cameras.camera_make LIKE ? OR cameras.camera_model LIKE ? OR cameras.camera_slug LIKE ?", v, v, v) s = s.Where("cameras.camera_name LIKE ? OR cameras.camera_model LIKE ? OR cameras.camera_slug LIKE ?", v, v, v)
} }
// Filter by lens id or name? // Filter by lens id or name?
@ -314,7 +314,7 @@ func Photos(f form.SearchPhotos) (results PhotoResults, count int, err error) {
s = s.Where("photos.lens_id = ?", txt.UInt(f.Lens)) s = s.Where("photos.lens_id = ?", txt.UInt(f.Lens))
} else if txt.NotEmpty(f.Lens) { } else if txt.NotEmpty(f.Lens) {
v := strings.Trim(f.Lens, "*%") + "%" v := strings.Trim(f.Lens, "*%") + "%"
s = s.Where("lenses.lens_make LIKE ? OR lenses.lens_model LIKE ? OR lenses.lens_slug LIKE ?", v, v, v) s = s.Where("lenses.lens_name LIKE ? OR lenses.lens_model LIKE ? OR lenses.lens_slug LIKE ?", v, v, v)
} }
// Filter by year? // Filter by year?

View file

@ -27,7 +27,7 @@ func SearchString(s string) string {
s = strings.ReplaceAll(s, "**", "*") s = strings.ReplaceAll(s, "**", "*")
// Trim. // Trim.
return strings.Trim(s, "&|\\<>\n\r\t") return strings.Trim(s, "|\\<>\n\r\t")
} }
// SearchQuery replaces search operator with default symbols. // SearchQuery replaces search operator with default symbols.
@ -49,5 +49,5 @@ func SearchQuery(s string) string {
s = strings.ReplaceAll(s, "**", "*") s = strings.ReplaceAll(s, "**", "*")
// Trim. // Trim.
return strings.Trim(s, "+&|-=$^(){}\\<>,;: \n\r\t") return strings.Trim(s, "|${}\\<>: \n\r\t")
} }

View file

@ -28,7 +28,7 @@ func TestSearchQuery(t *testing.T) {
}) })
t.Run("AndOr", func(t *testing.T) { t.Run("AndOr", func(t *testing.T) {
q := SearchQuery("Jens AND Mander and me Or Kitty AND ") q := SearchQuery("Jens AND Mander and me Or Kitty AND ")
assert.Equal(t, "Jens&Mander&me|Kitty", q) assert.Equal(t, "Jens&Mander&me|Kitty&", q)
}) })
t.Run("FlowersInThePark", func(t *testing.T) { t.Run("FlowersInThePark", func(t *testing.T) {
q := SearchQuery(" Flowers in the Park ") q := SearchQuery(" Flowers in the Park ")

View file

@ -5,7 +5,8 @@ import (
) )
// sqlSpecialBytes contains special bytes to escape in SQL search queries. // sqlSpecialBytes contains special bytes to escape in SQL search queries.
var sqlSpecialBytes = []byte{34, 39, 92, 95} // see https://mariadb.com/kb/en/string-literals/
var sqlSpecialBytes = []byte{34, 39, 92, 95} // ", ', \, _
// SqlString escapes a string for use in an SQL query. // SqlString escapes a string for use in an SQL query.
func SqlString(s string) string { func SqlString(s string) string {