diff --git a/core/external_metadata.go b/core/external_metadata.go index 1d7b8825a..d15fb8ea5 100644 --- a/core/external_metadata.go +++ b/core/external_metadata.go @@ -9,7 +9,6 @@ import ( "github.com/Masterminds/squirrel" "github.com/kennygrant/sanitize" - "github.com/microcosm-cc/bluemonday" "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/core/agents" _ "github.com/navidrome/navidrome/core/agents/lastfm" @@ -284,8 +283,7 @@ func (e *externalMetadata) callGetBiography(ctx context.Context, agent agents.Ar if bio == "" || err != nil { return } - policy := bluemonday.UGCPolicy() - bio = policy.Sanitize(bio) + bio = utils.SanitizeText(bio) bio = strings.ReplaceAll(bio, "\n", " ") artist.Biography = strings.ReplaceAll(bio, "<a ", "<a target='_blank' ") } diff --git a/db/migration/20211026191915_unescape_lyrics_and_comments.go b/db/migration/20211026191915_unescape_lyrics_and_comments.go new file mode 100644 index 000000000..186383212 --- /dev/null +++ b/db/migration/20211026191915_unescape_lyrics_and_comments.go @@ -0,0 +1,46 @@ +package migrations + +import ( + "database/sql" + + "github.com/navidrome/navidrome/log" + "github.com/navidrome/navidrome/utils" + "github.com/pressly/goose" +) + +func init() { + goose.AddMigration(upUnescapeLyricsAndComments, downUnescapeLyricsAndComments) +} + +func upUnescapeLyricsAndComments(tx *sql.Tx) error { + rows, err := tx.Query(`select id, comment, lyrics, title from media_file`) + if err != nil { + return err + } + defer rows.Close() + + stmt, err := tx.Prepare("update media_file set comment = ?, lyrics = ? where id = ?") + if err != nil { + return err + } + + var id, comment, lyrics, title string + for rows.Next() { + err = rows.Scan(&id, &comment, &lyrics, &title) + if err != nil { + return err + } + + comment = utils.SanitizeText(comment) + lyrics = utils.SanitizeText(lyrics) + _, err = stmt.Exec(comment, lyrics, id) + if err != nil { + log.Error("Error unescaping media_file's lyrics and comments", "title", title, "id", id, err) + } + } + return rows.Err() +} + +func downUnescapeLyricsAndComments(tx *sql.Tx) error { + return nil +} diff --git a/scanner/mapping.go b/scanner/mapping.go index 2930b0eea..f6501923a 100644 --- a/scanner/mapping.go +++ b/scanner/mapping.go @@ -9,7 +9,6 @@ import ( "time" "github.com/kennygrant/sanitize" - "github.com/microcosm-cc/bluemonday" "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/model" @@ -19,14 +18,12 @@ import ( type mediaFileMapper struct { rootFolder string - policy *bluemonday.Policy genres model.GenreRepository } func newMediaFileMapper(rootFolder string, genres model.GenreRepository) *mediaFileMapper { return &mediaFileMapper{ rootFolder: rootFolder, - policy: bluemonday.UGCPolicy(), genres: genres, } } @@ -71,8 +68,8 @@ func (s mediaFileMapper) toMediaFile(md metadata.Tags) model.MediaFile { mf.MbzAlbumArtistID = md.MbzAlbumArtistID() mf.MbzAlbumType = md.MbzAlbumType() mf.MbzAlbumComment = md.MbzAlbumComment() - mf.Comment = s.policy.Sanitize(md.Comment()) - mf.Lyrics = s.policy.Sanitize(md.Lyrics()) + mf.Comment = utils.SanitizeText(md.Comment()) + mf.Lyrics = utils.SanitizeText(md.Lyrics()) mf.Bpm = md.Bpm() mf.CreatedAt = time.Now() mf.UpdatedAt = md.ModificationTime() diff --git a/server/serve_index.go b/server/serve_index.go index 424f2ffd6..26abc346b 100644 --- a/server/serve_index.go +++ b/server/serve_index.go @@ -8,11 +8,11 @@ import ( "net/http" "strings" - "github.com/microcosm-cc/bluemonday" "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" + "github.com/navidrome/navidrome/utils" ) // Injects the config in the `index.html` template @@ -26,14 +26,13 @@ func serveIndex(ds model.DataStore, fs fs.FS) http.HandlerFunc { http.NotFound(w, r) return } - policy := bluemonday.UGCPolicy() appConfig := map[string]interface{}{ "version": consts.Version(), "firstTime": firstTime, "variousArtistsId": consts.VariousArtistsID, - "baseURL": policy.Sanitize(strings.TrimSuffix(conf.Server.BaseURL, "/")), - "loginBackgroundURL": policy.Sanitize(conf.Server.UILoginBackgroundURL), - "welcomeMessage": policy.Sanitize(conf.Server.UIWelcomeMessage), + "baseURL": utils.SanitizeText(strings.TrimSuffix(conf.Server.BaseURL, "/")), + "loginBackgroundURL": utils.SanitizeText(conf.Server.UILoginBackgroundURL), + "welcomeMessage": utils.SanitizeText(conf.Server.UIWelcomeMessage), "enableTranscodingConfig": conf.Server.EnableTranscodingConfig, "enableDownloads": conf.Server.EnableDownloads, "enableFavourites": conf.Server.EnableFavourites, diff --git a/utils/sanitize_strings.go b/utils/sanitize_strings.go index e64c5654e..93a36ebb4 100644 --- a/utils/sanitize_strings.go +++ b/utils/sanitize_strings.go @@ -1,11 +1,13 @@ package utils import ( + "html" "regexp" "sort" "strings" "github.com/kennygrant/sanitize" + "github.com/microcosm-cc/bluemonday" ) var quotesRegex = regexp.MustCompile("[“”‘’'\"\\[\\(\\{\\]\\)\\}]") @@ -29,3 +31,10 @@ func SanitizeStrings(text ...string) string { sort.Strings(fullText) return strings.Join(fullText, " ") } + +var policy = bluemonday.UGCPolicy() + +func SanitizeText(text string) string { + s := policy.Sanitize(text) + return html.UnescapeString(s) +}