diff --git a/airsonic-main/src/main/java/org/airsonic/player/ajax/CoverArtService.java b/airsonic-main/src/main/java/org/airsonic/player/ajax/CoverArtService.java index 9d8d3407..498936eb 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/ajax/CoverArtService.java +++ b/airsonic-main/src/main/java/org/airsonic/player/ajax/CoverArtService.java @@ -25,8 +25,8 @@ import org.airsonic.player.service.LastFmService; import org.airsonic.player.service.MediaFileService; import org.airsonic.player.service.SecurityService; import org.airsonic.player.util.FileUtil; -import org.airsonic.player.util.StringUtil; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringEscapeUtils; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; @@ -109,7 +109,7 @@ public class CoverArtService { // Check permissions. File newCoverFile = new File(path, "cover." + suffix); if (!securityService.isWriteAllowed(newCoverFile)) { - throw new Exception("Permission denied: " + StringUtil.toHtml(newCoverFile.getPath())); + throw new Exception("Permission denied: " + StringEscapeUtils.escapeHtml(newCoverFile.getPath())); } // If file exists, create a backup. diff --git a/airsonic-main/src/main/java/org/airsonic/player/ajax/NowPlayingService.java b/airsonic-main/src/main/java/org/airsonic/player/ajax/NowPlayingService.java index 302b1aa4..63e0a28a 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/ajax/NowPlayingService.java +++ b/airsonic-main/src/main/java/org/airsonic/player/ajax/NowPlayingService.java @@ -22,6 +22,7 @@ package org.airsonic.player.ajax; import org.airsonic.player.domain.*; import org.airsonic.player.service.*; import org.airsonic.player.util.StringUtil; +import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.directwebremoting.WebContext; import org.directwebremoting.WebContextFactory; @@ -129,14 +130,14 @@ public class NowPlayingService { avatarUrl = url + "avatar.view?usernameUtf8Hex=" + StringUtil.utf8HexEncode(username); } - String tooltip = StringUtil.toHtml(artist) + " – " + StringUtil.toHtml(title); + String tooltip = StringEscapeUtils.escapeHtml(artist) + " – " + StringEscapeUtils.escapeHtml(title); if (StringUtils.isNotBlank(player.getName())) { username += "@" + player.getName(); } - artist = StringUtil.toHtml(StringUtils.abbreviate(artist, 25)); - title = StringUtil.toHtml(StringUtils.abbreviate(title, 25)); - username = StringUtil.toHtml(StringUtils.abbreviate(username, 25)); + artist = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(artist, 25)); + title = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(title, 25)); + username = StringEscapeUtils.escapeHtml(StringUtils.abbreviate(username, 25)); long minutesAgo = status.getMinutesAgo(); diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/SetMusicFileInfoController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/SetMusicFileInfoController.java index 92018ecd..8a37d5ee 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/SetMusicFileInfoController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/SetMusicFileInfoController.java @@ -21,7 +21,7 @@ package org.airsonic.player.controller; import org.airsonic.player.domain.MediaFile; import org.airsonic.player.service.MediaFileService; -import org.airsonic.player.util.StringUtil; +import org.apache.commons.lang.StringEscapeUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.ServletRequestUtils; @@ -52,7 +52,7 @@ public class SetMusicFileInfoController { MediaFile mediaFile = mediaFileService.getMediaFile(id); if ("comment".equals(action)) { - mediaFile.setComment(StringUtil.toHtml(request.getParameter("comment"))); + mediaFile.setComment(StringEscapeUtils.escapeHtml(request.getParameter("comment"))); mediaFileService.updateMediaFile(mediaFile); } diff --git a/airsonic-main/src/main/java/org/airsonic/player/controller/UploadController.java b/airsonic-main/src/main/java/org/airsonic/player/controller/UploadController.java index 82acf520..ceae1194 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/controller/UploadController.java +++ b/airsonic-main/src/main/java/org/airsonic/player/controller/UploadController.java @@ -27,10 +27,10 @@ import org.airsonic.player.service.SettingsService; import org.airsonic.player.service.StatusService; import org.airsonic.player.upload.MonitoredDiskFileItemFactory; import org.airsonic.player.upload.UploadListener; -import org.airsonic.player.util.StringUtil; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.lang.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -126,7 +126,7 @@ public class UploadController { File targetFile = new File(dir, new File(fileName).getName()); if (!securityService.isUploadAllowed(targetFile)) { - throw new Exception("Permission denied: " + StringUtil.toHtml(targetFile.getPath())); + throw new Exception("Permission denied: " + StringEscapeUtils.escapeHtml(targetFile.getPath())); } if (!dir.exists()) { @@ -173,13 +173,13 @@ public class UploadController { ZipEntry entry = (ZipEntry) entries.nextElement(); File entryFile = new File(file.getParentFile(), entry.getName()); if (!entryFile.toPath().normalize().startsWith(file.getParentFile().toPath())) { - throw new Exception("Bad zip filename: " + StringUtil.toHtml(entryFile.getPath())); + throw new Exception("Bad zip filename: " + StringEscapeUtils.escapeHtml(entryFile.getPath())); } if (!entry.isDirectory()) { if (!securityService.isUploadAllowed(entryFile)) { - throw new Exception("Permission denied: " + StringUtil.toHtml(entryFile.getPath())); + throw new Exception("Permission denied: " + StringEscapeUtils.escapeHtml(entryFile.getPath())); } entryFile.getParentFile().mkdirs(); diff --git a/airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java b/airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java index a8f000e9..ed7ec770 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java +++ b/airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java @@ -877,7 +877,7 @@ public class SettingsService { String[] lines = StringUtil.readLines(in); for (String line : lines) { - locales.add(parseLocale(line)); + locales.add(StringUtil.parseLocale(line)); } } catch (IOException x) { @@ -888,21 +888,6 @@ public class SettingsService { return locales.toArray(new Locale[locales.size()]); } - private Locale parseLocale(String line) { - String[] s = line.split("_"); - String language = s[0]; - String country = ""; - String variant = ""; - - if (s.length > 1) { - country = s[1]; - } - if (s.length > 2) { - variant = s[2]; - } - return new Locale(language, country, variant); - } - /** * Returns the "brand" name. Normally, this is just "Airsonic". * diff --git a/airsonic-main/src/main/java/org/airsonic/player/util/StringUtil.java b/airsonic-main/src/main/java/org/airsonic/player/util/StringUtil.java index 6519967c..3da90d1b 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/util/StringUtil.java +++ b/airsonic-main/src/main/java/org/airsonic/player/util/StringUtil.java @@ -19,6 +19,7 @@ */ package org.airsonic.player.util; +import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang.StringUtils; @@ -28,11 +29,11 @@ import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; import java.text.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Stream; /** * Miscellaneous string utility methods. @@ -42,15 +43,8 @@ import java.util.regex.Pattern; public final class StringUtil { public static final String ENCODING_UTF8 = "UTF-8"; - private static final DateFormat ISO_8601_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - - private static final String[][] HTML_SUBSTITUTIONS = { - {"&", "&"}, - {"<", "<"}, - {">", ">"}, - {"'", "'"}, - {"\"", """}, - }; + + private static final Pattern SPLIT_PATTERN = Pattern.compile("\"([^\"]*)\"|(\\S+)"); private static final String[][] MIME_TYPES = { {"mp3", "audio/mpeg"}, @@ -98,58 +92,6 @@ public final class StringUtil { private StringUtil() { } - /** - * Returns the specified string converted to a format suitable for - * HTML. All single-quote, double-quote, greater-than, less-than and - * ampersand characters are replaces with their corresponding HTML - * Character Entity code. - * - * @param s the string to convert - * @return the converted string - */ - public static String toHtml(String s) { - if (s == null) { - return null; - } - for (String[] substitution : HTML_SUBSTITUTIONS) { - if (s.contains(substitution[0])) { - s = s.replaceAll(substitution[0], substitution[1]); - } - } - return s; - } - - - /** - * Formats the given date to a ISO-8601 date/time format, and UTC timezone. - *
- * The returned date uses the following format: 2007-12-17T14:57:17 - * - * @param date The date to format - * @return The corresponding ISO-8601 formatted string. - */ - public static String toISO8601(Date date) { - if (date == null) { - return null; - } - - synchronized (ISO_8601_DATE_FORMAT) { - return ISO_8601_DATE_FORMAT.format(date); - } - } - - /** - * Removes the suffix (the substring after the last dot) of the given string. The dot is - * also removed. - * - * @param s The string in question, e.g., "foo.mp3". - * @return The string without the suffix, e.g., "foo". - */ - public static String removeSuffix(String s) { - int index = s.lastIndexOf('.'); - return index == -1 ? s : s.substring(0, index); - } - /** * Returns the proper MIME type for the given suffix. * @@ -269,16 +211,14 @@ public final class StringUtil { return new String[0]; } - Pattern pattern = Pattern.compile("\".*?\"|\\S+"); - Matcher matcher = pattern.matcher(input); - - List