Merge remote-tracking branch 'origin/pr/1326'

master
Andrew DeMaria 5 years ago
commit e789e531d0
  1. 4
      airsonic-main/src/main/java/org/airsonic/player/ajax/CoverArtService.java
  2. 9
      airsonic-main/src/main/java/org/airsonic/player/ajax/NowPlayingService.java
  3. 4
      airsonic-main/src/main/java/org/airsonic/player/controller/SetMusicFileInfoController.java
  4. 8
      airsonic-main/src/main/java/org/airsonic/player/controller/UploadController.java
  5. 17
      airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java
  6. 138
      airsonic-main/src/main/java/org/airsonic/player/util/StringUtil.java
  7. 26
      airsonic-main/src/test/java/org/airsonic/player/util/StringUtilTestCase.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.

@ -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();

@ -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);
}

@ -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();

@ -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".
*

@ -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 = {
{"&", "&"},
{"<", "&lt;"},
{">", "&gt;"},
{"'", "&#39;"},
{"\"", "&#34;"},
};
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.
* <p/>
* 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<String> result = new ArrayList<String>();
while (matcher.find()) {
String element = matcher.group();
if (element.startsWith("\"") && element.endsWith("\"") && element.length() > 1) {
element = element.substring(1, element.length() - 1);
List<String> result = new ArrayList<>();
Matcher m = SPLIT_PATTERN.matcher(input);
while (m.find()) {
if (m.group(1) != null) {
result.add(m.group(1)); // quoted string
} else {
result.add(m.group(2)); // unquoted string
}
result.add(element);
}
return result.toArray(new String[result.size()]);
@ -320,21 +260,9 @@ public final class StringUtil {
return new int[0];
}
String[] strings = StringUtils.split(s);
int[] ints = new int[strings.length];
for (int i = 0; i < strings.length; i++) {
ints[i] = Integer.parseInt(strings[i]);
}
return ints;
}
/**
* Determines whether a is equal to b, taking null into account.
*
* @return Whether a and b are equal, or both null.
*/
public static boolean isEqual(Object a, Object b) {
return Objects.equals(a, b);
return Stream.of(StringUtils.split(s))
.mapToInt(Integer::parseInt)
.toArray();
}
/**
@ -348,18 +276,11 @@ public final class StringUtil {
return null;
}
String[] elements = s.split("_");
if (elements.length == 0) {
return new Locale(s, "", "");
}
if (elements.length == 1) {
return new Locale(elements[0], "", "");
List<String> elements = new ArrayList<>(Arrays.asList(s.split("_", 3)));
while (elements.size() < 3) {
elements.add("");
}
if (elements.length == 2) {
return new Locale(elements[0], elements[1], "");
}
return new Locale(elements[0], elements[1], elements[2]);
return new Locale(elements.get(0), elements.get(1), elements.get(2));
}
/**
@ -404,34 +325,15 @@ public final class StringUtil {
*
* @param s The string to decode.
* @return The decoded string.
* @throws Exception If an error occurs.
* @throws DecoderException If an error occurs.
*/
public static String utf8HexDecode(String s) throws Exception {
public static String utf8HexDecode(String s) throws DecoderException {
if (s == null) {
return null;
}
return new String(Hex.decodeHex(s.toCharArray()), StandardCharsets.UTF_8);
}
/**
* Calculates the MD5 digest and returns the value as a 32 character hex string.
*
* @param s Data to digest.
* @return MD5 digest as a hex string.
*/
public static String md5Hex(String s) {
if (s == null) {
return null;
}
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return new String(Hex.encodeHex(md5.digest(s.getBytes(StandardCharsets.UTF_8))));
} catch (Exception x) {
throw new RuntimeException(x.getMessage(), x);
}
}
/**
* Returns the file part of an URL. For instance:
* <p/>

@ -20,6 +20,7 @@
package org.airsonic.player.util;
import junit.framework.TestCase;
import org.apache.commons.lang.StringEscapeUtils;
import java.util.Arrays;
import java.util.Locale;
@ -32,20 +33,11 @@ import java.util.Locale;
public class StringUtilTestCase extends TestCase {
public void testToHtml() {
assertEquals(null, StringUtil.toHtml(null));
assertEquals("", StringUtil.toHtml(""));
assertEquals(" ", StringUtil.toHtml(" "));
assertEquals("q &amp; a", StringUtil.toHtml("q & a"));
assertEquals("q &amp; a &lt;&gt; b", StringUtil.toHtml("q & a <> b"));
}
public void testRemoveSuffix() {
assertEquals("Error in removeSuffix().", "foo", StringUtil.removeSuffix("foo.mp3"));
assertEquals("Error in removeSuffix().", "", StringUtil.removeSuffix(".mp3"));
assertEquals("Error in removeSuffix().", "foo.bar", StringUtil.removeSuffix("foo.bar.mp3"));
assertEquals("Error in removeSuffix().", "foo.", StringUtil.removeSuffix("foo..mp3"));
assertEquals("Error in removeSuffix().", "foo", StringUtil.removeSuffix("foo"));
assertEquals("Error in removeSuffix().", "", StringUtil.removeSuffix(""));
assertEquals(null, StringEscapeUtils.escapeHtml(null));
assertEquals("", StringEscapeUtils.escapeHtml(""));
assertEquals(" ", StringEscapeUtils.escapeHtml(" "));
assertEquals("q &amp; a", StringEscapeUtils.escapeHtml("q & a"));
assertEquals("q &amp; a &lt;&gt; b", StringEscapeUtils.escapeHtml("q & a <> b"));
}
public void testGetMimeType() {
@ -184,12 +176,6 @@ public class StringUtilTestCase extends TestCase {
assertEquals("Error in utf8hex.", s, StringUtil.utf8HexDecode(StringUtil.utf8HexEncode(s)));
}
public void testMd5Hex() {
assertNull("Error in md5Hex().", StringUtil.md5Hex(null));
assertEquals("Error in md5Hex().", "d41d8cd98f00b204e9800998ecf8427e", StringUtil.md5Hex(""));
assertEquals("Error in md5Hex().", "308ed0af23d48f6d2fd4717e77a23e0c", StringUtil.md5Hex("sindre@activeobjects.no"));
}
public void testGetUrlFile() {
assertEquals("Error in getUrlFile().", "foo.mp3", StringUtil.getUrlFile("http://www.asdf.com/foo.mp3"));
assertEquals("Error in getUrlFile().", "foo.mp3", StringUtil.getUrlFile("http://www.asdf.com/bar/foo.mp3"));

Loading…
Cancel
Save