mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-25 14:55:55 +01:00
[vizio] Improve handling of TV's self-signed certificate (#14429)
Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
This commit is contained in:
parent
8c56a0f0b3
commit
7c20a4804a
@ -134,7 +134,7 @@ If an app that is in the JSON database fails to start when selected, try adjusti
|
|||||||
A current list of `APP_ID`'s can be found at http://hometest.buddytv.netdna-cdn.com/appservice/vizio_apps_prod.json
|
A current list of `APP_ID`'s can be found at http://hometest.buddytv.netdna-cdn.com/appservice/vizio_apps_prod.json
|
||||||
and `NAME_SPACE` & `MESSAGE` values needed can be found at http://hometest.buddytv.netdna-cdn.com/appservice/app_availability_prod.json
|
and `NAME_SPACE` & `MESSAGE` values needed can be found at http://hometest.buddytv.netdna-cdn.com/appservice/app_availability_prod.json
|
||||||
|
|
||||||
If there is an error in the user supplied `appListJson`, the thing will fail to start and display a CONFIGURATION_PENDING message.
|
If there is an error in the user supplied `appListJson`, the thing will fail to start and display a CONFIGURATION_ERROR message.
|
||||||
If all text in `appListJson` is removed (set to null) and the thing configuration saved, the binding will restore `appListJson` from the binding's JSON db.
|
If all text in `appListJson` is removed (set to null) and the thing configuration saved, the binding will restore `appListJson` from the binding's JSON db.
|
||||||
|
|
||||||
## Full Example
|
## Full Example
|
||||||
|
@ -16,7 +16,6 @@ import static org.openhab.binding.vizio.internal.VizioBindingConstants.SUPPORTED
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
|
||||||
import org.openhab.binding.vizio.internal.appdb.VizioAppDbService;
|
import org.openhab.binding.vizio.internal.appdb.VizioAppDbService;
|
||||||
import org.openhab.binding.vizio.internal.handler.VizioHandler;
|
import org.openhab.binding.vizio.internal.handler.VizioHandler;
|
||||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||||
@ -39,7 +38,7 @@ import org.osgi.service.component.annotations.Reference;
|
|||||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.vizio")
|
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.vizio")
|
||||||
public class VizioHandlerFactory extends BaseThingHandlerFactory {
|
public class VizioHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
|
||||||
private final HttpClient httpClient;
|
private final HttpClientFactory httpClientFactory;
|
||||||
private final VizioStateDescriptionOptionProvider stateDescriptionProvider;
|
private final VizioStateDescriptionOptionProvider stateDescriptionProvider;
|
||||||
private final String vizioAppsJson;
|
private final String vizioAppsJson;
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ public class VizioHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
public VizioHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
|
public VizioHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
|
||||||
final @Reference VizioStateDescriptionOptionProvider provider,
|
final @Reference VizioStateDescriptionOptionProvider provider,
|
||||||
final @Reference VizioAppDbService vizioAppDbService) {
|
final @Reference VizioAppDbService vizioAppDbService) {
|
||||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
this.httpClientFactory = httpClientFactory;
|
||||||
this.stateDescriptionProvider = provider;
|
this.stateDescriptionProvider = provider;
|
||||||
this.vizioAppsJson = vizioAppDbService.getVizioAppsJson();
|
this.vizioAppsJson = vizioAppDbService.getVizioAppsJson();
|
||||||
}
|
}
|
||||||
@ -62,7 +61,7 @@ public class VizioHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||||
|
|
||||||
if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
|
if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
|
||||||
VizioHandler handler = new VizioHandler(thing, httpClient, stateDescriptionProvider, vizioAppsJson);
|
VizioHandler handler = new VizioHandler(thing, httpClientFactory, stateDescriptionProvider, vizioAppsJson);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ public class VizioCommunicator {
|
|||||||
* @throws VizioException
|
* @throws VizioException
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public PairingStart starPairing(String deviceName, int deviceId) throws VizioException {
|
public PairingStart startPairing(String deviceName, int deviceId) throws VizioException {
|
||||||
return fromJson(
|
return fromJson(
|
||||||
putCommand(urlStartPairing,
|
putCommand(urlStartPairing,
|
||||||
String.format("{ \"DEVICE_NAME\": \"%s\", \"DEVICE_ID\": \"%d\" }", deviceName, deviceId)),
|
String.format("{ \"DEVICE_NAME\": \"%s\", \"DEVICE_ID\": \"%d\" }", deviceName, deviceId)),
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.vizio.internal.communication;
|
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
|
|
||||||
import javax.net.ssl.X509ExtendedTrustManager;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
|
||||||
import org.openhab.core.io.net.http.PEMTrustManager;
|
|
||||||
import org.openhab.core.io.net.http.TlsTrustManagerProvider;
|
|
||||||
import org.openhab.core.io.net.http.TrustAllTrustManager;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a {@link PEMTrustManager} to allow secure connections to a Vizio TV that uses self signed
|
|
||||||
* certificates.
|
|
||||||
*
|
|
||||||
* @author Christoph Weitkamp - Initial Contribution
|
|
||||||
* @author Michael Lobstein - Adapted for Vizio binding
|
|
||||||
*/
|
|
||||||
@NonNullByDefault
|
|
||||||
public class VizioTlsTrustManagerProvider implements TlsTrustManagerProvider {
|
|
||||||
private final String hostname;
|
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(VizioTlsTrustManagerProvider.class);
|
|
||||||
|
|
||||||
public VizioTlsTrustManagerProvider(String hostname) {
|
|
||||||
this.hostname = hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getHostName() {
|
|
||||||
return hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public X509ExtendedTrustManager getTrustManager() {
|
|
||||||
try {
|
|
||||||
logger.trace("Use self-signed certificate downloaded from Vizio TV.");
|
|
||||||
return PEMTrustManager.getInstanceFromServer("https://" + getHostName());
|
|
||||||
} catch (CertificateException | MalformedURLException e) {
|
|
||||||
logger.debug("An unexpected exception occurred - returning a TrustAllTrustManager: {}", e.getMessage(), e);
|
|
||||||
}
|
|
||||||
return TrustAllTrustManager.getInstance();
|
|
||||||
}
|
|
||||||
}
|
|
@ -107,7 +107,7 @@ public class VizioCommandExtension extends AbstractConsoleCommandExtension {
|
|||||||
Random rng = new Random();
|
Random rng = new Random();
|
||||||
|
|
||||||
int pairingDeviceId = rng.nextInt(100000);
|
int pairingDeviceId = rng.nextInt(100000);
|
||||||
int pairingToken = communicator.starPairing(args[2], pairingDeviceId).getItem()
|
int pairingToken = communicator.startPairing(args[2], pairingDeviceId).getItem()
|
||||||
.getPairingReqToken();
|
.getPairingReqToken();
|
||||||
if (pairingToken != -1) {
|
if (pairingToken != -1) {
|
||||||
handler.setPairingDeviceId(pairingDeviceId);
|
handler.setPairingDeviceId(pairingDeviceId);
|
||||||
|
@ -25,11 +25,11 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.openhab.binding.vizio.internal.VizioConfiguration;
|
import org.openhab.binding.vizio.internal.VizioConfiguration;
|
||||||
import org.openhab.binding.vizio.internal.VizioException;
|
import org.openhab.binding.vizio.internal.VizioException;
|
||||||
import org.openhab.binding.vizio.internal.VizioStateDescriptionOptionProvider;
|
import org.openhab.binding.vizio.internal.VizioStateDescriptionOptionProvider;
|
||||||
import org.openhab.binding.vizio.internal.communication.VizioCommunicator;
|
import org.openhab.binding.vizio.internal.communication.VizioCommunicator;
|
||||||
import org.openhab.binding.vizio.internal.communication.VizioTlsTrustManagerProvider;
|
|
||||||
import org.openhab.binding.vizio.internal.dto.app.CurrentApp;
|
import org.openhab.binding.vizio.internal.dto.app.CurrentApp;
|
||||||
import org.openhab.binding.vizio.internal.dto.applist.VizioApp;
|
import org.openhab.binding.vizio.internal.dto.applist.VizioApp;
|
||||||
import org.openhab.binding.vizio.internal.dto.applist.VizioApps;
|
import org.openhab.binding.vizio.internal.dto.applist.VizioApps;
|
||||||
@ -40,7 +40,7 @@ import org.openhab.binding.vizio.internal.dto.inputlist.InputList;
|
|||||||
import org.openhab.binding.vizio.internal.dto.power.PowerMode;
|
import org.openhab.binding.vizio.internal.dto.power.PowerMode;
|
||||||
import org.openhab.binding.vizio.internal.enums.KeyCommand;
|
import org.openhab.binding.vizio.internal.enums.KeyCommand;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.io.net.http.TlsTrustManagerProvider;
|
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||||
import org.openhab.core.library.types.NextPreviousType;
|
import org.openhab.core.library.types.NextPreviousType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.library.types.PercentType;
|
import org.openhab.core.library.types.PercentType;
|
||||||
@ -53,12 +53,11 @@ import org.openhab.core.thing.Thing;
|
|||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
import org.openhab.core.thing.ThingStatusDetail;
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||||
|
import org.openhab.core.thing.util.ThingWebClientUtil;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
import org.openhab.core.types.StateOption;
|
import org.openhab.core.types.StateOption;
|
||||||
import org.openhab.core.types.UnDefType;
|
import org.openhab.core.types.UnDefType;
|
||||||
import org.osgi.framework.FrameworkUtil;
|
|
||||||
import org.osgi.framework.ServiceRegistration;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -74,11 +73,11 @@ import com.google.gson.JsonSyntaxException;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class VizioHandler extends BaseThingHandler {
|
public class VizioHandler extends BaseThingHandler {
|
||||||
private final Logger logger = LoggerFactory.getLogger(VizioHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(VizioHandler.class);
|
||||||
private final HttpClient httpClient;
|
private final HttpClientFactory httpClientFactory;
|
||||||
|
private @Nullable HttpClient httpClient;
|
||||||
private final VizioStateDescriptionOptionProvider stateDescriptionProvider;
|
private final VizioStateDescriptionOptionProvider stateDescriptionProvider;
|
||||||
private final String dbAppsJson;
|
private final String dbAppsJson;
|
||||||
|
|
||||||
private @Nullable ServiceRegistration<?> serviceRegistration;
|
|
||||||
private @Nullable ScheduledFuture<?> refreshJob;
|
private @Nullable ScheduledFuture<?> refreshJob;
|
||||||
private @Nullable ScheduledFuture<?> metadataRefreshJob;
|
private @Nullable ScheduledFuture<?> metadataRefreshJob;
|
||||||
|
|
||||||
@ -97,13 +96,13 @@ public class VizioHandler extends BaseThingHandler {
|
|||||||
private boolean powerOn = false;
|
private boolean powerOn = false;
|
||||||
private boolean debounce = true;
|
private boolean debounce = true;
|
||||||
|
|
||||||
public VizioHandler(Thing thing, HttpClient httpClient,
|
public VizioHandler(Thing thing, HttpClientFactory httpClientFactory,
|
||||||
VizioStateDescriptionOptionProvider stateDescriptionProvider, String vizioAppsJson) {
|
VizioStateDescriptionOptionProvider stateDescriptionProvider, String vizioAppsJson) {
|
||||||
super(thing);
|
super(thing);
|
||||||
this.httpClient = httpClient;
|
this.httpClientFactory = httpClientFactory;
|
||||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||||
this.dbAppsJson = vizioAppsJson;
|
this.dbAppsJson = vizioAppsJson;
|
||||||
this.communicator = new VizioCommunicator(httpClient, EMPTY, -1, EMPTY);
|
this.communicator = new VizioCommunicator(httpClientFactory.getCommonHttpClient(), EMPTY, -1, EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -127,13 +126,22 @@ public class VizioHandler extends BaseThingHandler {
|
|||||||
host = "[" + host + "]";
|
host = "[" + host + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.communicator = new VizioCommunicator(httpClient, host, config.port, authToken != null ? authToken : EMPTY);
|
final String httpClientName = ThingWebClientUtil.buildWebClientConsumerName(thing.getUID(), null);
|
||||||
|
try {
|
||||||
// register trustmanager service to allow httpClient to accept self signed cert from the Vizio TV
|
httpClient = httpClientFactory.createHttpClient(httpClientName, new SslContextFactory.Client(true));
|
||||||
VizioTlsTrustManagerProvider tlsTrustManagerProvider = new VizioTlsTrustManagerProvider(
|
final HttpClient localHttpClient = this.httpClient;
|
||||||
host + ":" + config.port);
|
if (localHttpClient != null) {
|
||||||
serviceRegistration = FrameworkUtil.getBundle(getClass()).getBundleContext()
|
localHttpClient.start();
|
||||||
.registerService(TlsTrustManagerProvider.class.getName(), tlsTrustManagerProvider, null);
|
this.communicator = new VizioCommunicator(localHttpClient, host, config.port,
|
||||||
|
authToken != null ? authToken : EMPTY);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(
|
||||||
|
"Long running HttpClient for Vizio handler {} cannot be started. Creating Handler failed. Exception: {}",
|
||||||
|
httpClientName, e.getMessage(), e);
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (authToken == null) {
|
if (authToken == null) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
|
||||||
@ -363,11 +371,14 @@ public class VizioHandler extends BaseThingHandler {
|
|||||||
this.metadataRefreshJob = null;
|
this.metadataRefreshJob = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceRegistration<?> localServiceRegistration = serviceRegistration;
|
try {
|
||||||
if (localServiceRegistration != null) {
|
HttpClient localHttpClient = this.httpClient;
|
||||||
// remove trustmanager service
|
if (localHttpClient != null) {
|
||||||
localServiceRegistration.unregister();
|
localHttpClient.stop();
|
||||||
serviceRegistration = null;
|
}
|
||||||
|
this.httpClient = null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("Unable to stop Vizio httpClient. Exception: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user