Merge remote-tracking branch 'origin/stable' into develop

Conflicts:
	documentation/developer/jmeter-main-test-plan.png
	documentation/developer/metrics-visualvm-screenshot.png
This commit is contained in:
Andrew DeMaria
2017-05-18 22:38:46 -06:00
21 changed files with 56 additions and 811 deletions
@@ -22,9 +22,9 @@ package org.libresonic.player.controller;
import org.libresonic.player.domain.MediaFile;
import org.libresonic.player.domain.PlayQueue;
import org.libresonic.player.domain.Player;
import org.libresonic.player.service.JWTSecurityService;
import org.libresonic.player.service.NetworkService;
import org.libresonic.player.service.PlayerService;
import org.libresonic.player.service.SettingsService;
import org.libresonic.player.service.TranscodingService;
import org.libresonic.player.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
@@ -32,6 +32,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -52,9 +53,9 @@ public class M3UController {
@Autowired
private PlayerService playerService;
@Autowired
private SettingsService settingsService;
@Autowired
private TranscodingService transcodingService;
@Autowired
private JWTSecurityService jwtSecurityService;
@RequestMapping(method = RequestMethod.GET)
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
@@ -89,7 +90,12 @@ public class M3UController {
duration = -1;
}
out.println("#EXTINF:" + duration + "," + mediaFile.getArtist() + " - " + mediaFile.getTitle());
out.println(url + "player=" + player.getId() + "&id=" + mediaFile.getId() + "&suffix=." + transcodingService.getSuffix(player, mediaFile, null));
String urlNoAuth = url + "player=" + player.getId() + "&id=" + mediaFile.getId() + "&suffix=." +
transcodingService.getSuffix(player, mediaFile, null);
String urlWithAuth = jwtSecurityService.addJWTToken(UriComponentsBuilder.fromUriString(urlNoAuth)).build().toUriString();
out.println(urlWithAuth);
out.println();
}
}
@@ -59,7 +59,7 @@ public class RatingDao extends AbstractDao {
String sql = "select user_rating.path from user_rating, media_file " +
"where user_rating.path=media_file.path and media_file.present and media_file.type = :type and media_file.folder in (:folders) " +
"group by path " +
"group by user_rating.path " +
"order by avg(rating) desc limit :count offset :offset";
return namedQueryForStrings(sql, args);
}
@@ -94,7 +94,7 @@ public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter
.csrf().requireCsrfProtectionMatcher(csrfSecurityRequestMatcher).and()
.headers().frameOptions().sameOrigin().and()
.authorizeRequests()
.antMatchers("/ext/stream/**", "/ext/coverArt.view", "/ext/share/**", "/ext/hls/**")
.antMatchers("/ext/stream/**", "/ext/coverArt*", "/ext/share/**", "/ext/hls/**")
.hasAnyRole("TEMP", "USER").and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling().and()
@@ -125,29 +125,29 @@ public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter
.frameOptions()
.sameOrigin()
.and().authorizeRequests()
.antMatchers("/recover.view", "/accessDenied.view",
.antMatchers("/recover*", "/accessDenied*",
"/style/**", "/icons/**", "/flash/**", "/script/**",
"/sonos/**", "/crossdomain.xml", "/login", "/error")
.permitAll()
.antMatchers("/personalSettings.view", "/passwordSettings.view",
"/playerSettings.view", "/shareSettings.view", "/passwordSettings.view")
.antMatchers("/personalSettings*", "/passwordSettings*",
"/playerSettings*", "/shareSettings*", "/passwordSettings*")
.hasRole("SETTINGS")
.antMatchers("/generalSettings.view", "/advancedSettings.view", "/userSettings.view",
"/musicFolderSettings.view", "/databaseSettings.view")
.antMatchers("/generalSettings*", "/advancedSettings*", "/userSettings*",
"/musicFolderSettings*", "/databaseSettings*")
.hasRole("ADMIN")
.antMatchers("/deletePlaylist.view", "/savePlaylist.view")
.antMatchers("/deletePlaylist*", "/savePlaylist*", "/db*")
.hasRole("PLAYLIST")
.antMatchers("/download.view")
.antMatchers("/download*")
.hasRole("DOWNLOAD")
.antMatchers("/upload.view")
.antMatchers("/upload*")
.hasRole("UPLOAD")
.antMatchers("/createShare.view")
.antMatchers("/createShare*")
.hasRole("SHARE")
.antMatchers("/changeCoverArt.view", "/editTags.view")
.antMatchers("/changeCoverArt*", "/editTags*")
.hasRole("COVERART")
.antMatchers("/setMusicFileInfo.view")
.antMatchers("/setMusicFileInfo*")
.hasRole("COMMENT")
.antMatchers("/podcastReceiverAdmin.view")
.antMatchers("/podcastReceiverAdmin*")
.hasRole("PODCAST")
.antMatchers("/**")
.hasRole("USER")
@@ -155,7 +155,7 @@ public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter
.and().formLogin()
.loginPage("/login")
.permitAll()
.defaultSuccessUrl("/index.view", true)
.defaultSuccessUrl("/index", true)
.failureUrl(FAILURE_URL)
.usernameParameter("j_username")
.passwordParameter("j_password")
@@ -61,8 +61,21 @@ public class NetworkService {
private static URI calculateProxyUri(HttpServletRequest request) throws URISyntaxException {
String xForardedHost = request.getHeader(X_FORWARDED_HOST);
// If the request has been through multiple reverse proxies,
// We need to return the original Host that the client used
if (xForardedHost != null) {
xForardedHost = xForardedHost.split(",")[0];
}
if(!isValidXForwardedHost(xForardedHost)) {
xForardedHost = request.getHeader(X_FORWARDED_SERVER);
// If the request has been through multiple reverse proxies,
// We need to return the original Host that the client used
if (xForardedHost != null) {
xForardedHost = xForardedHost.split(",")[0];
}
if(!isValidXForwardedHost(xForardedHost)) {
throw new RuntimeException("Cannot calculate proxy uri without HTTP header " + X_FORWARDED_HOST);
}
@@ -72,6 +85,9 @@ public class NetworkService {
String host = proxyHost.getHost();
int port = proxyHost.getPort();
String scheme = request.getHeader(X_FORWARDED_PROTO);
if(StringUtils.isBlank(scheme)) {
throw new RuntimeException("Scheme not provided");
}
return new URI(scheme, null, host, port, urlPathHelper.getContextPath(request), null, null);
}
@@ -17,6 +17,7 @@
</changeSet>
<changeSet id="schema52_002" author="muff1nman">
<validCheckSum>7:8fde86035edbca443a54b1861ae70819</validCheckSum>
<validCheckSum>7:e7e0f04cd4691ec2b5d955b449e0154b</validCheckSum>
<preConditions onFail="MARK_RAN">
<not>
<tableExists tableName="music_folder_user" />
@@ -317,6 +317,7 @@ advancedsettings.ldapsearchfilter = LDAP Suchfilter
advancedsettings.ldapmanagerdn = LDAP Manager DN<br><div class="detail">(Optional)</div>
advancedsettings.ldapmanagerpassword = Passwort
advancedsettings.ldapautoshadowing = Automatische Erstellung von Benutzern in {0}
advancedsettings.ldapRequiresRestart = \u00C4nderungen an den LDAP Einstellungen erfordern einen Neustart
# personalSettings.jsp
personalsettings.title = Layout Einstellungen f\u00FCr {0}
@@ -409,7 +410,7 @@ transcodingsettings.info = <p class="Detail">(%s = Die Datei die transcodiert wi
Festplattenspeicher.<p/> \
<p>Das Transcoding wird von Drittanbieter-Kommandozeilenprogrammen \u00FCbernommen, welche in {0} installiert sein m\u00FCssen. \
Mehr \u00FCber das Transcoding erf\u00E4hrst du \
hier <a target="_blank" href="http://libresonic.org/pages/transcoding.jsp"><b>hier</b></a>. Du kannst deinen eigenen Transcoder verwenden, wenn er \
hier <a target="_blank" href="http://libresonic.github.io/wiki/transcode/"><b>hier</b></a>. Du kannst deinen eigenen Transcoder verwenden, wenn er \
folgende Funktionen erf\u00FCllt: \
<ul> \
<li>Er muss ein Kommandozeilen-Interface haben.</li> \
@@ -636,7 +637,7 @@ podcastreceiver.status.deleted = Gel\u00F6scht
podcastreceiver.status.skipped = Abgebrochen
podcastreceiver.downloadselected= Ausgew\u00E4hlte downloaden
podcastreceiver.deleteselected= L\u00F6sche ausgew\u00E4hlte
podcastreceiver.confirmdelete= Ausgew\u00C4hlte Podcasts wirklich l\u00F6schen?
podcastreceiver.confirmdelete= Ausgew\u00E4hlte Podcasts wirklich l\u00F6schen?
podcastreceiver.check = Suche nach neuen Episoden
podcastreceiver.refresh = Seite neu laden
podcastreceiver.settings = Podcast Einstellungen