mirror of
https://github.com/Airsonic-Pulse/airsonic-pulse.git
synced 2026-07-09 21:18:27 +00:00
temporary commit
This commit is contained in:
parent
0e1a00f6c3
commit
b1734ab893
13 changed files with 159 additions and 49 deletions
|
|
@ -67,7 +67,7 @@ public class JAXBWriter {
|
|||
private final String SERVER_TYPE = "Airsonic-Advanced";
|
||||
|
||||
public JAXBWriter() {
|
||||
Map<String, Object> properties = Map.of(JAXBContext.JAXB_CONTEXT_FACTORY, "org.eclipse.persistence.jaxb.JAXBContextFactory");
|
||||
Map<String, Object> properties = Map.of(JAXBContext.JAXB_CONTEXT_FACTORY, "org.glassfish.jaxb.runtime.v2.ContextFactory");
|
||||
Class<?>[] classes = {Response.class};
|
||||
try {
|
||||
jaxbContext = JAXBContext.newInstance(classes, properties);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import org.springframework.security.web.context.request.async.WebAsyncManagerInt
|
|||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -301,10 +300,12 @@ public class GlobalSecurityConfig {
|
|||
return http.build();
|
||||
}
|
||||
|
||||
/*
|
||||
@Bean(name = "mvcHandlerMappingIntrospector")
|
||||
public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
|
||||
return new HandlerMappingIntrospector();
|
||||
}
|
||||
*/
|
||||
|
||||
CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ import org.airsonic.player.domain.SonosLink;
|
|||
import org.airsonic.player.repository.SonosLinkRepository;
|
||||
import org.airsonic.player.service.search.IndexType;
|
||||
import org.airsonic.player.service.sonos.SonosHelper;
|
||||
import org.airsonic.player.service.sonos.SonosLinkSecurityInterceptor;
|
||||
import org.airsonic.player.service.sonos.SonosServiceRegistration;
|
||||
import org.airsonic.player.service.sonos.SonosSoapFault;
|
||||
import org.airsonic.player.service.sonos.SonosUtilComponent;
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
|
@ -117,6 +117,8 @@ public class SonosService implements SonosSoap {
|
|||
private SonosServiceRegistration registration;
|
||||
@Autowired
|
||||
private SonosLinkRepository sonosLinkRepository;
|
||||
@Autowired
|
||||
private SonosUtilComponent sonosUtil;
|
||||
|
||||
/**
|
||||
* The context for the request. This is used to get the Auth information
|
||||
|
|
@ -672,7 +674,7 @@ public class SonosService implements SonosSoap {
|
|||
@Override
|
||||
public DeviceAuthTokenResult refreshAuthToken() throws CustomFault {
|
||||
try {
|
||||
Credentials expiredCreds = SonosLinkSecurityInterceptor.getCredentials(getMessage());
|
||||
Credentials expiredCreds = sonosUtil.getCredentials(getMessage());
|
||||
return refreshAuthToken(expiredCreds, getRequest());
|
||||
} catch (Exception e) {
|
||||
throw new SonosSoapFault.LoginInvalid();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This file is part of Airsonic.
|
||||
*
|
||||
* Airsonic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Airsonic is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Airsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2024 (C) Y.Tory
|
||||
*/
|
||||
package org.airsonic.player.service.sonos;
|
||||
|
||||
import org.eclipse.persistence.jaxb.JAXBContextFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
public class MoxyConfiguration {
|
||||
|
||||
@Bean
|
||||
public JAXBContext jaxbContext() {
|
||||
try {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
return JAXBContextFactory.createContext("com.sonos.services._1", this.getClass().getClassLoader(), properties);
|
||||
} catch (JAXBException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with Airsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2024 (C) Y.Tory
|
||||
* Copyright 2015 (C) Sindre Mehus
|
||||
*/
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ public class SonosFaultInterceptor extends AbstractSoapInterceptor {
|
|||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SonosFaultInterceptor.class);
|
||||
|
||||
private static Marshaller marshaller = createMarshaller();
|
||||
private Marshaller marshaller = createMarshaller();
|
||||
|
||||
private static Marshaller createMarshaller() {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -580,7 +580,6 @@ public class SonosHelper {
|
|||
result.setItemType(ItemType.TRACK);
|
||||
result.setMimeType(StringUtil.getMimeType(suffix, true));
|
||||
result.setTitle(song.getTitle());
|
||||
result.setGenre(song.getGenre());
|
||||
result.setIsFavorite(song.getStarredDate() != null);
|
||||
// result.setDynamic();// TODO: For starred songs
|
||||
|
||||
|
|
@ -594,6 +593,7 @@ public class SonosHelper {
|
|||
trackMetadata.setAlbumArtURI(albumArtURI);
|
||||
trackMetadata.setDuration((int) Math.round(song.getDuration()));
|
||||
trackMetadata.setTrackNumber(song.getTrackNumber());
|
||||
trackMetadata.setGenre(song.getGenre());
|
||||
|
||||
MediaFile parent = mediaFileService.getParentOf(song);
|
||||
if (parent != null && parent.isAlbum()) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package org.airsonic.player.service.sonos;
|
|||
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sonos.services._1.Credentials;
|
||||
import com.sonos.services._1.DeviceAuthTokenResult;
|
||||
import com.sonos.services._1.RefreshAuthTokenResponse;
|
||||
import org.airsonic.player.domain.SonosLink;
|
||||
|
|
@ -16,7 +15,6 @@ import org.airsonic.player.service.SonosService;
|
|||
import org.apache.commons.codec.binary.StringUtils;
|
||||
import org.apache.cxf.binding.soap.SoapMessage;
|
||||
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
|
||||
import org.apache.cxf.headers.Header;
|
||||
import org.apache.cxf.interceptor.Fault;
|
||||
import org.apache.cxf.phase.Phase;
|
||||
import org.apache.cxf.transport.http.AbstractHTTPDestination;
|
||||
|
|
@ -28,13 +26,8 @@ import org.springframework.security.authentication.CredentialsExpiredException;
|
|||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
import jakarta.xml.bind.Unmarshaller;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -75,15 +68,8 @@ public class SonosLinkSecurityInterceptor extends AbstractSoapInterceptor {
|
|||
@Autowired
|
||||
private SonosService sonosService;
|
||||
|
||||
private static Unmarshaller unmarshaller = createUnmarshaller();
|
||||
|
||||
private static Unmarshaller createUnmarshaller() {
|
||||
try {
|
||||
return JAXBContext.newInstance("com.sonos.services._1").createUnmarshaller();
|
||||
} catch (JAXBException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
@Autowired
|
||||
private SonosUtilComponent sonosUtil;
|
||||
|
||||
@Override
|
||||
public void handleMessage(SoapMessage message) throws Fault {
|
||||
|
|
@ -102,7 +88,7 @@ public class SonosLinkSecurityInterceptor extends AbstractSoapInterceptor {
|
|||
LOG.debug("No auth required for SOAP message: {}", message.toString());
|
||||
|
||||
} else if (action != null && authenticationType == AuthenticationType.APPLICATION_LINK) {
|
||||
String sonosLinkToken = getCredentials(message).getLoginToken().getToken();
|
||||
String sonosLinkToken = sonosUtil.getCredentials(message).getLoginToken().getToken();
|
||||
if (sonosLinkToken != null) {
|
||||
JWTAuthenticationToken token = new JWTAuthenticationToken(null, sonosLinkToken,
|
||||
request.getRequestURI().substring(request.getContextPath().length() + 1) + "?" + request.getQueryString());
|
||||
|
|
@ -121,7 +107,7 @@ public class SonosLinkSecurityInterceptor extends AbstractSoapInterceptor {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
DeviceAuthTokenResult token = sonosService.refreshAuthToken(getCredentials(message), request);
|
||||
DeviceAuthTokenResult token = sonosService.refreshAuthToken(sonosUtil.getCredentials(message), request);
|
||||
RefreshAuthTokenResponse resp = new RefreshAuthTokenResponse();
|
||||
resp.setRefreshAuthTokenResult(token);
|
||||
throw new SonosSoapFault.TokenRefreshRequired(resp);
|
||||
|
|
@ -138,17 +124,6 @@ public class SonosLinkSecurityInterceptor extends AbstractSoapInterceptor {
|
|||
}
|
||||
}
|
||||
|
||||
public static Credentials getCredentials(SoapMessage message) throws JAXBException {
|
||||
QName credentialQName = new QName("http://www.sonos.com/Services/1.1", "credentials");
|
||||
|
||||
for (Header header : message.getHeaders()) {
|
||||
if (credentialQName.equals(header.getName())) {
|
||||
return unmarshaller.unmarshal((Node) header.getObject(), Credentials.class).getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getAction(SoapMessage message) {
|
||||
Object soapAction = message.get("SOAPAction");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
package org.airsonic.player.service.sonos;
|
||||
|
||||
import com.sonos.services._1.Credentials;
|
||||
import org.apache.cxf.binding.soap.SoapMessage;
|
||||
import org.apache.cxf.headers.Header;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
import jakarta.xml.bind.Unmarshaller;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
|
||||
@Component
|
||||
public class SonosUtilComponent {
|
||||
|
||||
private Unmarshaller unmarshaller = createUnmarshaller();
|
||||
|
||||
private Unmarshaller createUnmarshaller() {
|
||||
Class<?>[] classes = {Credentials.class};
|
||||
Map<String, Object> properties = Map.of(JAXBContext.JAXB_CONTEXT_FACTORY, "org.eclipse.persistence.jaxb.JAXBContextFactory");
|
||||
try {
|
||||
return JAXBContext.newInstance(classes, properties).createUnmarshaller();
|
||||
} catch (JAXBException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Credentials getCredentials(SoapMessage message) throws JAXBException {
|
||||
QName credentialQName = new QName("http://www.sonos.com/Services/0.1", "credentials");
|
||||
|
||||
for (Header header : message.getHeaders()) {
|
||||
if (credentialQName.equals(header.getName())) {
|
||||
return unmarshaller.unmarshal((Node) header.getObject(), Credentials.class).getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -4,25 +4,33 @@ import org.airsonic.player.service.SonosService;
|
|||
import org.airsonic.player.service.sonos.SonosFaultInterceptor;
|
||||
import org.airsonic.player.service.sonos.SonosLinkSecurityInterceptor;
|
||||
import org.apache.cxf.Bus;
|
||||
import org.apache.cxf.jaxb.JAXBDataBinding;
|
||||
import org.apache.cxf.jaxws.EndpointImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
|
||||
import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.ws.Endpoint;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
|
||||
@Configuration
|
||||
@ImportResource({"classpath:META-INF/cxf/cxf.xml", "classpath:META-INF/cxf/cxf-servlet.xml"})
|
||||
public class SonosConfiguration {
|
||||
|
||||
@Autowired
|
||||
private JAXBContext jaxbContext;
|
||||
|
||||
@Bean
|
||||
public Endpoint sonosEndpoint(Bus bus, SonosService sonosService,
|
||||
SonosFaultInterceptor sonosFaultInterceptor,
|
||||
SonosLinkSecurityInterceptor sonosSecurity) {
|
||||
EndpointImpl endpoint = new EndpointImpl(bus, sonosService);
|
||||
endpoint.setOutFaultInterceptors(Collections.singletonList(sonosFaultInterceptor));
|
||||
endpoint.setDataBinding(new JAXBDataBinding(jaxbContext));
|
||||
endpoint.setInInterceptors(Collections.singletonList(sonosSecurity));
|
||||
endpoint.publish("/Sonos");
|
||||
return endpoint;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-codegen-plugin</artifactId>
|
||||
<version>${cxf.version}</version>
|
||||
<version>${cxf.version}</version><!-- 4.x is not compatible with eclispse MoXY-->
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-sources</id>
|
||||
|
|
@ -50,6 +50,29 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!--<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<fileset dir="${project.build.directory}/generated-sources/cxf" includes="**/*.java">
|
||||
<filename name="**/*.java"/>
|
||||
</fileset>
|
||||
<replace dir="${project.build.directory}/generated-sources/cxf" includes="**/*.java" token="javax.xml.ws" value="jakarta.xml.ws"/>
|
||||
<replace dir="${project.build.directory}/generated-sources/cxf" includes="**/*.java" token="javax.xml.bind" value="jakarta.xml.bind"/>
|
||||
<replace dir="${project.build.directory}/generated-sources/cxf" includes="**/*.java" token="javax.jws" value="jakarta.jws"/>
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>-->
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
|||
7
pom.xml
7
pom.xml
|
|
@ -25,7 +25,7 @@
|
|||
<failOnDependencyWarning>true</failOnDependencyWarning>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>17</java.version>
|
||||
<cxf.version>4.0.3</cxf.version>
|
||||
<cxf.version>4.0.4</cxf.version>
|
||||
<snakeyaml.version>2.2</snakeyaml.version>
|
||||
<docker.container.repo>ghcr.io/kagemomiji/airsonic-advanced</docker.container.repo>
|
||||
</properties>
|
||||
|
|
@ -329,6 +329,7 @@
|
|||
<ignoredUsedUndeclaredDependency>org.springframework.data:spring-data-commons:*</ignoredUsedUndeclaredDependency>
|
||||
<ignoredUsedUndeclaredDependency>commons-collections:commons-collections:*</ignoredUsedUndeclaredDependency>
|
||||
<ignoredUsedUndeclaredDependency>com.sun.mail:jakarta.mail*</ignoredUsedUndeclaredDependency>
|
||||
<ignoredUsedUndeclaredDependency>org.glassfish.jaxb:jaxb-runtime</ignoredUsedUndeclaredDependency>
|
||||
</ignoredUsedUndeclaredDependencies>
|
||||
<ignoredUnusedDeclaredDependencies>
|
||||
<ignoredUnusedDeclaredDependency>com.google.code.findbugs:jsr305:*</ignoredUnusedDeclaredDependency>
|
||||
|
|
@ -349,7 +350,9 @@
|
|||
<ignoredUnusedDeclaredDependency>jakarta.annotation:jakarta.annotation-api</ignoredUnusedDeclaredDependency>
|
||||
<ignoredUnusedDeclaredDependency>org.springframework:spring-aspects</ignoredUnusedDeclaredDependency>
|
||||
<ignoredUnusedDeclaredDependency>org.yaml:snakeyaml</ignoredUnusedDeclaredDependency>
|
||||
<ignoredUnusedDeclaredDependency>org.glassfish.jaxb:jaxb-runtime</ignoredUnusedDeclaredDependency>
|
||||
<ignoredUnusedDeclaredDependency>org.eclipse.persistence:org.eclipse.persistence.moxy</ignoredUnusedDeclaredDependency>
|
||||
<ignoredUnusedDeclaredDependency>org.apache.cxf:cxf-tools-wsdlto-databinding-jaxb</ignoredUnusedDeclaredDependency>
|
||||
<ignoredUsedUndeclaredDependency>org.glassfish.jaxb:jaxb-runtime</ignoredUsedUndeclaredDependency>
|
||||
</ignoredUnusedDeclaredDependencies>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
|||
|
|
@ -28,23 +28,29 @@
|
|||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-xjc-plugin</artifactId>
|
||||
<version>4.0.0</version>
|
||||
<configuration>
|
||||
<sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
|
||||
<xsdOptions>
|
||||
<xsdOption>
|
||||
<xsd>${basedir}/src/main/resources/subsonic-rest-api.xsd</xsd>
|
||||
<packagename>org.subsonic.restapi</packagename>
|
||||
</xsdOption>
|
||||
</xsdOptions>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>xjc</id>
|
||||
<goals>
|
||||
<goal>xjc</goal>
|
||||
</goals>
|
||||
<goals>
|
||||
<goal>xsdtojava</goal>
|
||||
</goals>
|
||||
<phase>generate-sources</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src/main/resources/subsonic-rest-api.xsd</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
|
||||
jaxb:version="3.0"
|
||||
xmlns:sub="http://subsonic.org/restapi"
|
||||
targetNamespace="http://subsonic.org/restapi"
|
||||
attributeFormDefault="unqualified"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue