mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[magentatv] Adapt to new Telekom OAuth flow (required to retrieve the userId) (#10267)
Signed-off-by: Markus Michels <markus7017@gmail.com>
This commit is contained in:
parent
754751c19b
commit
c582dda1d5
@ -117,7 +117,7 @@ For security reasons the credentials are automatically deleted from the thing co
|
||||
| |key |String |Send key code to the receiver (see code table below) |
|
||||
| |mute |Switch |Mute volume (mute the speaker) |
|
||||
|status |playMode |String |Current play mode - this info is not reliable |
|
||||
| |channelCode |Number |The channel code from the EPG. |
|
||||
| |channelCode |Number |The channel code from the EPG. |
|
||||
|program |title |String |Title of the running program or video being played |
|
||||
| |text |String |Some description (as reported by the receiver, could be empty) |
|
||||
| |start |DateTime |Time when the program started |
|
||||
@ -327,4 +327,4 @@ to switch it ON and
|
||||
|
||||
to switch it off.
|
||||
|
||||
After an openHAB restart you need to make sure that OH and receiver are in sync, because the binding can't read the power status at startup.
|
||||
After an openHAB restart you need to make sure that OH and receiver are in sync, because the binding can't read the power status at startup.
|
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVBindingConstants.java
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVBindingConstants.java
Normal file → Executable file
@ -20,18 +20,15 @@ import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.magentatv.internal.network.MagentaTVOAuth;
|
||||
import org.openhab.core.io.console.Console;
|
||||
import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
|
||||
import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.component.annotations.ReferenceCardinality;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -47,14 +44,12 @@ public class MagentaTVConsoleHandler extends AbstractConsoleCommandExtension {
|
||||
private static final String CMD_LOGIN = "login";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(MagentaTVConsoleHandler.class);
|
||||
private final MagentaTVOAuth oauth = new MagentaTVOAuth();
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.OPTIONAL)
|
||||
private @Nullable ClientBuilder injectedClientBuilder;
|
||||
private final MagentaTVOAuth oauth;
|
||||
|
||||
@Activate
|
||||
public MagentaTVConsoleHandler() {
|
||||
public MagentaTVConsoleHandler(@Reference HttpClientFactory httpClientFactory) {
|
||||
super(BINDING_ID, "Interact with the " + BINDING_ID + " integration.");
|
||||
oauth = new MagentaTVOAuth(httpClientFactory.getCommonHttpClient());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVException.java
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVException.java
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVGsonDTO.java
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVGsonDTO.java
Normal file → Executable file
11
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVHandlerFactory.java
Normal file → Executable file
11
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVHandlerFactory.java
Normal file → Executable file
@ -19,10 +19,12 @@ import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVDeviceManager.MagentaTVDevice;
|
||||
import org.openhab.binding.magentatv.internal.handler.MagentaTVHandler;
|
||||
import org.openhab.binding.magentatv.internal.network.MagentaTVNetwork;
|
||||
import org.openhab.binding.magentatv.internal.network.MagentaTVPoweroffListener;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.net.HttpServiceUtil;
|
||||
import org.openhab.core.net.NetworkAddressService;
|
||||
import org.openhab.core.thing.Thing;
|
||||
@ -51,6 +53,7 @@ public class MagentaTVHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final MagentaTVNetwork network = new MagentaTVNetwork();
|
||||
private final MagentaTVDeviceManager manager;
|
||||
private final HttpClient httpClient;
|
||||
private @Nullable MagentaTVPoweroffListener upnpListener;
|
||||
private boolean servletInitialized = false;
|
||||
|
||||
@ -64,11 +67,11 @@ public class MagentaTVHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
@Activate
|
||||
public MagentaTVHandlerFactory(@Reference NetworkAddressService networkAddressService,
|
||||
@Reference MagentaTVDeviceManager manager, ComponentContext componentContext,
|
||||
Map<String, String> configProperties) throws IOException {
|
||||
@Reference HttpClientFactory httpClientFactory, @Reference MagentaTVDeviceManager manager,
|
||||
ComponentContext componentContext, Map<String, String> configProperties) throws IOException {
|
||||
super.activate(componentContext);
|
||||
this.manager = manager;
|
||||
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
try {
|
||||
logger.debug("Initialize network access");
|
||||
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||
@ -99,7 +102,7 @@ public class MagentaTVHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
logger.debug("Create thing type {}", thing.getThingTypeUID().getAsString());
|
||||
if (THING_TYPE_RECEIVER.equals(thingTypeUID)) {
|
||||
return new MagentaTVHandler(manager, thing, network);
|
||||
return new MagentaTVHandler(manager, thing, network, httpClient);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
10
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVControl.java
Normal file → Executable file
10
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVControl.java
Normal file → Executable file
@ -23,6 +23,7 @@ import java.util.HashMap;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVException;
|
||||
import org.openhab.binding.magentatv.internal.config.MagentaTVDynamicConfig;
|
||||
import org.openhab.binding.magentatv.internal.network.MagentaTVHttp;
|
||||
@ -44,7 +45,7 @@ public class MagentaTVControl {
|
||||
|
||||
private final MagentaTVNetwork network;
|
||||
private final MagentaTVHttp http = new MagentaTVHttp();
|
||||
private final MagentaTVOAuth oauth = new MagentaTVOAuth();
|
||||
private final MagentaTVOAuth oauth;
|
||||
private final MagentaTVDynamicConfig config;
|
||||
private boolean initialized = false;
|
||||
private String thingId = "";
|
||||
@ -52,11 +53,13 @@ public class MagentaTVControl {
|
||||
public MagentaTVControl() {
|
||||
config = new MagentaTVDynamicConfig();
|
||||
network = new MagentaTVNetwork();
|
||||
oauth = new MagentaTVOAuth(new HttpClient());
|
||||
}
|
||||
|
||||
public MagentaTVControl(MagentaTVDynamicConfig config, MagentaTVNetwork network) {
|
||||
public MagentaTVControl(MagentaTVDynamicConfig config, MagentaTVNetwork network, HttpClient httpClient) {
|
||||
thingId = config.getFriendlyName();
|
||||
this.network = network;
|
||||
this.oauth = new MagentaTVOAuth(httpClient);
|
||||
this.config = config;
|
||||
this.config.setTerminalID(computeMD5(network.getLocalMAC().toUpperCase() + config.getUDN()));
|
||||
this.config.setLocalIP(network.getLocalIP());
|
||||
@ -391,7 +394,8 @@ public class MagentaTVControl {
|
||||
// direct key code
|
||||
return key;
|
||||
}
|
||||
return KEY_MAP.getOrDefault(key, "");
|
||||
String code = KEY_MAP.get(key);
|
||||
return code != null ? code : "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
10
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVHandler.java
Normal file → Executable file
10
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVHandler.java
Normal file → Executable file
@ -33,6 +33,7 @@ import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVDeviceManager;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVException;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVGsonDTO.MRPayEvent;
|
||||
@ -88,6 +89,7 @@ public class MagentaTVHandler extends BaseThingHandler implements MagentaTVListe
|
||||
private final Gson gson;
|
||||
protected final MagentaTVNetwork network;
|
||||
protected final MagentaTVDeviceManager manager;
|
||||
private final HttpClient httpClient;
|
||||
protected MagentaTVControl control = new MagentaTVControl();
|
||||
|
||||
private String thingId = "";
|
||||
@ -102,10 +104,12 @@ public class MagentaTVHandler extends BaseThingHandler implements MagentaTVListe
|
||||
* @param thing
|
||||
* @param bindingConfig
|
||||
*/
|
||||
public MagentaTVHandler(MagentaTVDeviceManager manager, Thing thing, MagentaTVNetwork network) {
|
||||
public MagentaTVHandler(MagentaTVDeviceManager manager, Thing thing, MagentaTVNetwork network,
|
||||
HttpClient httpClient) {
|
||||
super(thing);
|
||||
this.manager = manager;
|
||||
this.network = network;
|
||||
this.httpClient = httpClient;
|
||||
gson = new GsonBuilder().registerTypeAdapter(OauthCredentials.class, new MRProgramInfoEventInstanceCreator())
|
||||
.registerTypeAdapter(OAuthTokenResponse.class, new MRProgramStatusInstanceCreator())
|
||||
.registerTypeAdapter(OAuthAuthenticateResponse.class, new MRShortProgramInfoInstanceCreator())
|
||||
@ -150,7 +154,7 @@ public class MagentaTVHandler extends BaseThingHandler implements MagentaTVListe
|
||||
}
|
||||
config.setMacAddress(macAddress);
|
||||
}
|
||||
control = new MagentaTVControl(config, network);
|
||||
control = new MagentaTVControl(config, network, httpClient);
|
||||
config.updateNetwork(control.getConfig()); // get network parameters from control
|
||||
|
||||
// Check for emoty credentials (e.g. missing in .things file)
|
||||
@ -185,7 +189,7 @@ public class MagentaTVHandler extends BaseThingHandler implements MagentaTVListe
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine is called every time the Thing configuration has been changed.
|
||||
* This routine is called every time the Thing configuration has been changed
|
||||
*/
|
||||
@Override
|
||||
public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
|
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVListener.java
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVListener.java
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVHttp.java
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVHttp.java
Normal file → Executable file
29
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNetwork.java
Normal file → Executable file
29
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNetwork.java
Normal file → Executable file
@ -20,7 +20,6 @@ import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.apache.commons.net.util.SubnetUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVException;
|
||||
@ -76,34 +75,6 @@ public class MagentaTVNetwork {
|
||||
"Unable to get local IP / MAC address, check network settings in openHAB system configuration!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if client ip equals or is in range of ip networks provided by
|
||||
* semicolon separated list
|
||||
*
|
||||
* @param clientIp in numeric form like "192.168.0.10"
|
||||
* @param ipList like "127.0.0.1;192.168.0.0/24;10.0.0.0/8"
|
||||
* @return true if client ip from the list os ips and networks
|
||||
*/
|
||||
public static boolean isIpInSubnet(String clientIp, String ipList) {
|
||||
if (ipList.isEmpty()) {
|
||||
// No ip address provided
|
||||
return true;
|
||||
}
|
||||
String[] subnetMasks = ipList.split(";");
|
||||
for (String subnetMask : subnetMasks) {
|
||||
subnetMask = subnetMask.trim();
|
||||
if (clientIp.equals(subnetMask)) {
|
||||
return true;
|
||||
}
|
||||
if (subnetMask.contains("/")) {
|
||||
if (new SubnetUtils(subnetMask).getInfo().isInRange(clientIp)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public NetworkInterface getLocalInterface() {
|
||||
return localInterface;
|
||||
|
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNotifyServlet.java
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNotifyServlet.java
Normal file → Executable file
302
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVOAuth.java
Normal file → Executable file
302
bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVOAuth.java
Normal file → Executable file
@ -13,21 +13,34 @@
|
||||
package org.openhab.binding.magentatv.internal.network;
|
||||
|
||||
import static org.openhab.binding.magentatv.internal.MagentaTVBindingConstants.*;
|
||||
import static org.openhab.binding.magentatv.internal.MagentaTVUtil.substringAfterLast;
|
||||
import static org.openhab.binding.magentatv.internal.MagentaTVUtil.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVException;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVGsonDTO.OAuthAuthenticateResponse;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVGsonDTO.OAuthAuthenticateResponseInstanceCreator;
|
||||
@ -37,7 +50,6 @@ import org.openhab.binding.magentatv.internal.MagentaTVGsonDTO.OauthCredentials;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVGsonDTO.OauthCredentialsInstanceCreator;
|
||||
import org.openhab.binding.magentatv.internal.MagentaTVGsonDTO.OauthKeyValue;
|
||||
import org.openhab.binding.magentatv.internal.handler.MagentaTVControl;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -50,7 +62,7 @@ import com.google.gson.GsonBuilder;
|
||||
*
|
||||
* @author Markus Michels - Initial contribution
|
||||
*
|
||||
* Deutsche Telekom uses a OAuth-based authentication to access the EPG portal. The
|
||||
* Deutsche Telekom uses an OAuth-based authentication to access the EPG portal. The
|
||||
* communication between the MR and the remote app requires a pairing before the receiver could be
|
||||
* controlled by sending keys etc. The so called userID is not directly derived from any local parameters
|
||||
* (like terminalID as a has from the mac address), but will be returned as a result from the OAuth
|
||||
@ -63,9 +75,12 @@ import com.google.gson.GsonBuilder;
|
||||
@NonNullByDefault
|
||||
public class MagentaTVOAuth {
|
||||
private final Logger logger = LoggerFactory.getLogger(MagentaTVOAuth.class);
|
||||
final Gson gson;
|
||||
private HttpClient httpClient;
|
||||
private final Gson gson;
|
||||
private List<HttpCookie> cookies = new ArrayList<>();
|
||||
|
||||
public MagentaTVOAuth() {
|
||||
public MagentaTVOAuth(HttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
gson = new GsonBuilder().registerTypeAdapter(OauthCredentials.class, new OauthCredentialsInstanceCreator())
|
||||
.registerTypeAdapter(OAuthTokenResponse.class, new OAuthTokenResponseInstanceCreator())
|
||||
.registerTypeAdapter(OAuthAuthenticateResponse.class, new OAuthAuthenticateResponseInstanceCreator())
|
||||
@ -78,124 +93,209 @@ public class MagentaTVOAuth {
|
||||
throw new MagentaTVException("Credentials for OAuth missing, check thing config!");
|
||||
}
|
||||
|
||||
String step = "initialize";
|
||||
String url = "";
|
||||
Properties httpHeader;
|
||||
Properties httpHeader = initHttpHeader();
|
||||
String postData = "";
|
||||
String httpResponse = "";
|
||||
InputStream dataStream = null;
|
||||
|
||||
// OAuth autentication results
|
||||
String oAuthScope = "";
|
||||
String oAuthService = "";
|
||||
String epghttpsurl = "";
|
||||
String retcode = "";
|
||||
String retmsg = "";
|
||||
|
||||
// Get credentials
|
||||
url = OAUTH_GET_CRED_URL + ":" + OAUTH_GET_CRED_PORT + OAUTH_GET_CRED_URI;
|
||||
httpHeader.setProperty(HttpHeader.HOST.toString(), substringAfterLast(OAUTH_GET_CRED_URL, "/"));
|
||||
httpResponse = httpRequest(HttpMethod.GET, url, httpHeader, "");
|
||||
OauthCredentials cred = gson.fromJson(httpResponse, OauthCredentials.class);
|
||||
epghttpsurl = getString(cred.epghttpsurl);
|
||||
if (epghttpsurl.isEmpty()) {
|
||||
throw new MagentaTVException("Unable to determine EPG url");
|
||||
}
|
||||
if (!epghttpsurl.contains("/EPG")) {
|
||||
epghttpsurl = epghttpsurl + "/EPG";
|
||||
}
|
||||
logger.debug("OAuth: epghttpsurl = {}", epghttpsurl);
|
||||
|
||||
// get OAuth data from response
|
||||
if (cred.sam3Para != null) {
|
||||
for (OauthKeyValue si : cred.sam3Para) {
|
||||
logger.trace("sam3Para.{} = {}", si.key, si.value);
|
||||
if (si.key.equalsIgnoreCase("oAuthScope")) {
|
||||
oAuthScope = si.value;
|
||||
} else if (si.key.equalsIgnoreCase("SAM3ServiceURL")) {
|
||||
oAuthService = si.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oAuthScope.isEmpty() || oAuthService.isEmpty()) {
|
||||
throw new MagentaTVException("OAuth failed: Can't get Scope and Service: " + httpResponse);
|
||||
}
|
||||
|
||||
// Get OAuth token (New flow based on WebTV)
|
||||
String userId = "";
|
||||
String terminalId = UUID.randomUUID().toString();
|
||||
String cnonce = MagentaTVControl.computeMD5(terminalId);
|
||||
|
||||
url = oAuthService + "/oauth2/tokens";
|
||||
postData = MessageFormat.format(
|
||||
"password={0}&scope={1}+offline_access&grant_type=password&username={2}&x_telekom.access_token.format=CompactToken&x_telekom.access_token.encoding=text%2Fbase64&client_id=10LIVESAM30000004901NGTVWEB0000000000000",
|
||||
urlEncode(accountPassword), oAuthScope, urlEncode(accountName));
|
||||
url = oAuthService + "/oauth2/tokens";
|
||||
httpResponse = httpRequest(HttpMethod.POST, url, httpHeader, postData);
|
||||
OAuthTokenResponse resp = gson.fromJson(httpResponse, OAuthTokenResponse.class);
|
||||
if (resp.accessToken.isEmpty()) {
|
||||
String errorMessage = MessageFormat.format("Unable to authenticate: accountName={0}, rc={1} ({2})",
|
||||
accountName, getString(resp.errorDescription), getString(resp.error));
|
||||
logger.warn("{}", errorMessage);
|
||||
throw new MagentaTVException(errorMessage);
|
||||
}
|
||||
logger.debug("OAuth: Access Token retrieved");
|
||||
|
||||
// General authentication
|
||||
logger.debug("OAuth: Generating CSRF token");
|
||||
url = "https://api.prod.sngtv.magentatv.de/EPG/JSON/Authenticate";
|
||||
httpHeader = initHttpHeader();
|
||||
httpHeader.setProperty(HttpHeader.HOST.toString(), "api.prod.sngtv.magentatv.de");
|
||||
httpHeader.setProperty("Origin", "https://web.magentatv.de");
|
||||
httpHeader.setProperty(HttpHeader.REFERER.toString(), "https://web.magentatv.de/");
|
||||
postData = "{\"areaid\":\"1\",\"cnonce\":\"" + cnonce + "\",\"mac\":\"" + terminalId
|
||||
+ "\",\"preSharedKeyID\":\"NGTV000001\",\"subnetId\":\"4901\",\"templatename\":\"NGTV\",\"terminalid\":\""
|
||||
+ terminalId
|
||||
+ "\",\"terminaltype\":\"WEB-MTV\",\"terminalvendor\":\"WebTV\",\"timezone\":\"Europe/Berlin\",\"usergroup\":\"-1\",\"userType\":3,\"utcEnable\":1}";
|
||||
httpResponse = httpRequest(HttpMethod.POST, url, httpHeader, postData);
|
||||
String csrf = "";
|
||||
for (HttpCookie c : cookies) { // get CRSF Token
|
||||
String value = c.getValue();
|
||||
if (value.contains("CSRFSESSION")) {
|
||||
csrf = substringBetween(value, "CSRFSESSION" + "=", ";");
|
||||
}
|
||||
}
|
||||
if (csrf.isEmpty()) {
|
||||
throw new MagentaTVException("OAuth: Unable to get CSRF token!");
|
||||
}
|
||||
|
||||
// Final step: Retrieve userId
|
||||
url = "https://api.prod.sngtv.magentatv.de/EPG/JSON/DTAuthenticate";
|
||||
httpHeader = initHttpHeader();
|
||||
httpHeader.setProperty(HttpHeader.HOST.toString(), "api.prod.sngtv.magentatv.de");
|
||||
httpHeader.setProperty("Origin", "https://web.magentatv.de");
|
||||
httpHeader.setProperty(HttpHeader.REFERER.toString(), "https://web.magentatv.de/");
|
||||
httpHeader.setProperty("X_CSRFToken", csrf);
|
||||
postData = "{\"areaid\":\"1\",\"cnonce\":\"" + cnonce + "\",\"mac\":\"" + terminalId + "\","
|
||||
+ "\"preSharedKeyID\":\"NGTV000001\",\"subnetId\":\"4901\",\"templatename\":\"NGTV\","
|
||||
+ "\"terminalid\":\"" + terminalId + "\",\"terminaltype\":\"WEB-MTV\",\"terminalvendor\":\"WebTV\","
|
||||
+ "\"timezone\":\"Europe/Berlin\",\"usergroup\":\"\",\"userType\":\"1\",\"utcEnable\":1,"
|
||||
+ "\"accessToken\":\"" + resp.accessToken
|
||||
+ "\",\"caDeviceInfo\":[{\"caDeviceId\":\"4ef4d933-9a43-41d3-9e3a-84979f22c9eb\","
|
||||
+ "\"caDeviceType\":8}],\"connectType\":1,\"osversion\":\"Mac OS 10.15.7\",\"softwareVersion\":\"1.33.4.3\","
|
||||
+ "\"terminalDetail\":[{\"key\":\"GUID\",\"value\":\"" + terminalId + "\"},"
|
||||
+ "{\"key\":\"HardwareSupplier\",\"value\":\"WEB-MTV\"},{\"key\":\"DeviceClass\",\"value\":\"TV\"},"
|
||||
+ "{\"key\":\"DeviceStorage\",\"value\":0},{\"key\":\"DeviceStorageSize\",\"value\":0}]}";
|
||||
httpResponse = httpRequest(HttpMethod.POST, url, httpHeader, postData);
|
||||
OAuthAuthenticateResponse authResp = gson.fromJson(httpResponse, OAuthAuthenticateResponse.class);
|
||||
if (authResp.userID.isEmpty()) {
|
||||
String errorMessage = MessageFormat.format("Unable to authenticate: accountName={0}, rc={1} {2}",
|
||||
accountName, getString(authResp.retcode), getString(authResp.desc));
|
||||
logger.warn("{}", errorMessage);
|
||||
throw new MagentaTVException(errorMessage);
|
||||
}
|
||||
userId = getString(authResp.userID);
|
||||
if (userId.isEmpty()) {
|
||||
throw new MagentaTVException("No userID received!");
|
||||
}
|
||||
String hashedUserID = MagentaTVControl.computeMD5(userId).toUpperCase();
|
||||
logger.trace("done, userID = {}", hashedUserID);
|
||||
return hashedUserID;
|
||||
}
|
||||
|
||||
private String httpRequest(String method, String url, Properties headers, String data) throws MagentaTVException {
|
||||
String result = "";
|
||||
try {
|
||||
step = "get credentials";
|
||||
httpHeader = initHttpHeader();
|
||||
url = OAUTH_GET_CRED_URL + ":" + OAUTH_GET_CRED_PORT + OAUTH_GET_CRED_URI;
|
||||
httpHeader.setProperty(HEADER_HOST, substringAfterLast(OAUTH_GET_CRED_URL, "/"));
|
||||
logger.trace("{} from {}", step, url);
|
||||
httpResponse = HttpUtil.executeUrl(HttpMethod.GET, url, httpHeader, null, null, NETWORK_TIMEOUT_MS);
|
||||
logger.trace("http response = {}", httpResponse);
|
||||
OauthCredentials cred = gson.fromJson(httpResponse, OauthCredentials.class);
|
||||
epghttpsurl = getString(cred.epghttpsurl);
|
||||
if (epghttpsurl.isEmpty()) {
|
||||
throw new MagentaTVException("Unable to determine EPG url");
|
||||
Request request = httpClient.newRequest(url).method(method).timeout(NETWORK_TIMEOUT_MS,
|
||||
TimeUnit.MILLISECONDS);
|
||||
for (Enumeration<?> e = headers.keys(); e.hasMoreElements();) {
|
||||
String key = (String) e.nextElement();
|
||||
String val = (String) headers.get(key);
|
||||
request.header(key, val);
|
||||
}
|
||||
if (!epghttpsurl.contains("/EPG")) {
|
||||
epghttpsurl = epghttpsurl + "/EPG";
|
||||
if (method.equals(HttpMethod.POST)) {
|
||||
fillPostData(request, data);
|
||||
}
|
||||
logger.debug("epghttpsurl = {}", epghttpsurl);
|
||||
if (cookies.size() > 0) {
|
||||
// Add cookies
|
||||
String cookieValue = "";
|
||||
for (HttpCookie c : cookies) {
|
||||
cookieValue = cookieValue + substringBefore(c.getValue(), ";") + "; ";
|
||||
}
|
||||
request.header("Cookie", substringBeforeLast(cookieValue, ";"));
|
||||
}
|
||||
logger.debug("OAuth: HTTP Request\n\tHTTP {} {}\n\tData={}", method, url, data.isEmpty() ? "<none>" : data);
|
||||
logger.trace("\n\tHeaders={}\tCookies={}", request.getHeaders(), request.getCookies());
|
||||
|
||||
// get OAuth data from response
|
||||
if (cred.sam3Para != null) {
|
||||
for (OauthKeyValue si : cred.sam3Para) {
|
||||
logger.trace("sam3Para.{} = {}", si.key, si.value);
|
||||
if (si.key.equalsIgnoreCase("oAuthScope")) {
|
||||
oAuthScope = si.value;
|
||||
} else if (si.key.equalsIgnoreCase("SAM3ServiceURL")) {
|
||||
oAuthService = si.value;
|
||||
}
|
||||
ContentResponse contentResponse = request.send();
|
||||
result = contentResponse.getContentAsString().replace("\t", "").replace("\r\n", "").trim();
|
||||
int status = contentResponse.getStatus();
|
||||
logger.debug("OAuth: HTTP Response\n\tStatus={} {}\n\tData={}", status, contentResponse.getReason(),
|
||||
result.isEmpty() ? "<none>" : result);
|
||||
logger.trace("\n\tHeaders={}", contentResponse.getHeaders());
|
||||
|
||||
// validate response, API errors are reported as Json
|
||||
HttpFields responseHeaders = contentResponse.getHeaders();
|
||||
for (HttpField f : responseHeaders) {
|
||||
if (f.getName().equals("Set-Cookie")) {
|
||||
HttpCookie c = new HttpCookie(f.getName(), f.getValue());
|
||||
cookies.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (oAuthScope.isEmpty() || oAuthService.isEmpty()) {
|
||||
throw new MagentaTVException("OAuth failed: Can't get Scope and Service: " + httpResponse);
|
||||
if (status != HttpStatus.OK_200) {
|
||||
String error = "HTTP reqaest failed for URL " + url + ", Code=" + contentResponse.getReason() + "("
|
||||
+ status + ")";
|
||||
throw new MagentaTVException(error);
|
||||
}
|
||||
|
||||
// Get OAuth token
|
||||
step = "get token";
|
||||
url = oAuthService + "/oauth2/tokens";
|
||||
logger.debug("{} from {}", step, url);
|
||||
|
||||
String userId = "";
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
String cnonce = MagentaTVControl.computeMD5(uuid);
|
||||
// New flow based on WebTV
|
||||
postData = MessageFormat.format(
|
||||
"password={0}&scope={1}+offline_access&grant_type=password&username={2}&x_telekom.access_token.format=CompactToken&x_telekom.access_token.encoding=text%2Fbase64&client_id=10LIVESAM30000004901NGTVWEB0000000000000",
|
||||
URLEncoder.encode(accountPassword, UTF_8), oAuthScope, URLEncoder.encode(accountName, UTF_8));
|
||||
url = oAuthService + "/oauth2/tokens";
|
||||
dataStream = new ByteArrayInputStream(postData.getBytes(Charset.forName("UTF-8")));
|
||||
httpResponse = HttpUtil.executeUrl(HttpMethod.POST, url, httpHeader, dataStream, null, NETWORK_TIMEOUT_MS);
|
||||
logger.trace("http response={}", httpResponse);
|
||||
OAuthTokenResponse resp = gson.fromJson(httpResponse, OAuthTokenResponse.class);
|
||||
if (resp.accessToken.isEmpty()) {
|
||||
String errorMessage = MessageFormat.format("Unable to authenticate: accountName={0}, rc={1} ({2})",
|
||||
accountName, getString(resp.errorDescription), getString(resp.error));
|
||||
logger.warn("{}", errorMessage);
|
||||
throw new MagentaTVException(errorMessage);
|
||||
}
|
||||
|
||||
uuid = "t_" + MagentaTVControl.computeMD5(accountName);
|
||||
url = "https://web.magentatv.de/EPG/JSON/DTAuthenticate?SID=user&T=Mac_chrome_81";
|
||||
postData = "{\"userType\":1,\"terminalid\":\"" + uuid + "\",\"mac\":\"" + uuid + "\""
|
||||
+ ",\"terminaltype\":\"MACWEBTV\",\"utcEnable\":1,\"timezone\":\"Europe/Berlin\","
|
||||
+ "\"terminalDetail\":[{\"key\":\"GUID\",\"value\":\"" + uuid + "\"},"
|
||||
+ "{\"key\":\"HardwareSupplier\",\"value\":\"\"},{\"key\":\"DeviceClass\",\"value\":\"PC\"},"
|
||||
+ "{\"key\":\"DeviceStorage\",\"value\":\"1\"},{\"key\":\"DeviceStorageSize\",\"value\":\"\"}],"
|
||||
+ "\"softwareVersion\":\"\",\"osversion\":\"\",\"terminalvendor\":\"Unknown\","
|
||||
+ "\"caDeviceInfo\":[{\"caDeviceType\":6,\"caDeviceId\":\"" + uuid + "\"}]," + "\"accessToken\":\""
|
||||
+ resp.accessToken + "\",\"preSharedKeyID\":\"PC01P00002\",\"cnonce\":\"" + cnonce + "\"}";
|
||||
dataStream = new ByteArrayInputStream(postData.getBytes(Charset.forName("UTF-8")));
|
||||
logger.debug("HTTP POST {}, postData={}", url, postData);
|
||||
httpResponse = HttpUtil.executeUrl(HttpMethod.POST, url, httpHeader, dataStream, null, NETWORK_TIMEOUT_MS);
|
||||
|
||||
logger.trace("http response={}", httpResponse);
|
||||
OAuthAuthenticateResponse authResp = gson.fromJson(httpResponse, OAuthAuthenticateResponse.class);
|
||||
if (authResp.userID.isEmpty()) {
|
||||
String errorMessage = MessageFormat.format("Unable to authenticate: accountName={0}, rc={1} {2}",
|
||||
accountName, getString(authResp.retcode), getString(authResp.desc));
|
||||
logger.warn("{}", errorMessage);
|
||||
throw new MagentaTVException(errorMessage);
|
||||
}
|
||||
userId = getString(authResp.userID);
|
||||
if (userId.isEmpty()) {
|
||||
throw new MagentaTVException("No userID received!");
|
||||
}
|
||||
String hashedUserID = MagentaTVControl.computeMD5(userId).toUpperCase();
|
||||
logger.trace("done, userID = {}", hashedUserID);
|
||||
return hashedUserID;
|
||||
} catch (IOException e) {
|
||||
throw new MagentaTVException(e,
|
||||
"Unable to authenticate {0}: {1} failed; serviceURL={2}, rc={3}/{4}, response={5}", accountName,
|
||||
step, oAuthService, retcode, retmsg, httpResponse);
|
||||
} catch (ExecutionException | InterruptedException | TimeoutException e) {
|
||||
String error = "HTTP reqaest failed for URL " + url;
|
||||
logger.info("{}", error, e);
|
||||
throw new MagentaTVException(e, error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Properties initHttpHeader() {
|
||||
Properties httpHeader = new Properties();
|
||||
httpHeader.setProperty(HEADER_USER_AGENT, OAUTH_USER_AGENT);
|
||||
httpHeader.setProperty(HEADER_ACCEPT, "*/*");
|
||||
httpHeader.setProperty(HEADER_LANGUAGE, "de-de");
|
||||
httpHeader.setProperty(HEADER_CACHE_CONTROL, "no-cache");
|
||||
httpHeader.setProperty(HttpHeader.ACCEPT.toString(), "*/*");
|
||||
httpHeader.setProperty(HttpHeader.ACCEPT_LANGUAGE.toString(), "en-US,en;q=0.9,de;q=0.8");
|
||||
httpHeader.setProperty(HttpHeader.CACHE_CONTROL.toString(), "no-cache");
|
||||
return httpHeader;
|
||||
}
|
||||
|
||||
private void fillPostData(Request request, String data) {
|
||||
if (!data.isEmpty()) {
|
||||
StringContentProvider postData;
|
||||
if (request.getHeaders().contains(HttpHeader.CONTENT_TYPE)) {
|
||||
String contentType = request.getHeaders().get(HttpHeader.CONTENT_TYPE);
|
||||
postData = new StringContentProvider(contentType, data, StandardCharsets.UTF_8);
|
||||
} else {
|
||||
boolean json = data.startsWith("{");
|
||||
postData = new StringContentProvider(json ? "application/json" : "application/x-www-form-urlencoded",
|
||||
data, StandardCharsets.UTF_8);
|
||||
}
|
||||
request.content(postData);
|
||||
request.header(HttpHeader.CONTENT_LENGTH, Long.toString(postData.getLength()));
|
||||
}
|
||||
}
|
||||
|
||||
private String getString(@Nullable String value) {
|
||||
return value != null ? value : "";
|
||||
}
|
||||
|
||||
private String urlEncode(String url) {
|
||||
try {
|
||||
return URLEncoder.encode(url, UTF_8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.warn("OAuth: Unable to URL encode string {}", url, e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
0
bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/binding/binding.xml
Normal file → Executable file
0
bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/binding/binding.xml
Normal file → Executable file
@ -9,8 +9,8 @@ thing-type.magentatv.receiver.description = Media Receiver zum Epmfang von Magen
|
||||
# Thing configuration
|
||||
thing-type.config.magentatv.receiver.ipAddress.label = IP-Adresse
|
||||
thing-type.config.magentatv.ipAddress.description = IP Adresse des Media Receivers
|
||||
thing-type.config.magentatv.receiver.userId.label = UID
|
||||
thing-type.config.magentatv.receiver.userId.description = Technische Benutzerkennung (User ID), siehe Dokumentation; wird automatisch gefüllt, wenn Login-Name und Passwort angegeben sind.
|
||||
thing-type.config.magentatv.receiver.userId.label = User ID
|
||||
thing-type.config.magentatv.receiver.userId.description = Technische Benutzerkennung, siehe Dokumentation
|
||||
thing-type.config.magentatv.receiver.accountName.label = Login-Name
|
||||
thing-type.config.magentatv.receiver.accountName.description = Login-Name (E-Mail) zur Anmeldung im Telekom Kundencenter
|
||||
thing-type.config.magentatv.receiver.accountPassword.label = Passwort
|
||||
|
4
bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/thing/thing-types.xml
Normal file → Executable file
4
bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/thing/thing-types.xml
Normal file → Executable file
@ -20,8 +20,8 @@
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
|
||||
<representation-property>macAddress</representation-property>
|
||||
|
||||
<config-description uri="thing-type:magentatv:receiver">
|
||||
<parameter name="ipAddress" type="text">
|
||||
<label>Device IP Address</label>
|
||||
@ -40,7 +40,7 @@
|
||||
</parameter>
|
||||
<parameter name="userId" type="text">
|
||||
<label>User ID</label>
|
||||
<description>Technical User ID required for pairing process, auto-filled when account credentials are given</description>
|
||||
<description>Technical User ID required for pairing process</description>
|
||||
</parameter>
|
||||
<parameter name="udn" type="text">
|
||||
<label>Unique Device Name</label>
|
||||
|
Loading…
Reference in New Issue
Block a user