Add TLS support (#14331)

Fixes #14309

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
Jacob Laursen 2023-02-04 13:08:41 +01:00 committed by GitHub
parent c4c89d3c29
commit 8a4033c95f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 52 additions and 19 deletions

View File

@ -36,11 +36,12 @@ WebOS TV has three configuration parameters.
Parameters: Parameters:
| Name | Description | | Name | Description |
|------------|-----------------------------------------------------------------------------------------------------| |------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| host | Hostname or IP address of TV | | host | Hostname or IP address of TV |
| key | Key exchanged with TV after pairing (enter it after you paired the device) | | key | Key exchanged with TV after pairing (enter it after you paired the device) |
| macAddress | The MAC address of your TV to turn on via Wake On Lan (WOL). The binding will attempt to detect it. | | macAddress | The MAC address of your TV to turn on via Wake On Lan (WOL). The binding will attempt to detect it. |
| useTLS | Enable Transport Layer Security. This is required by latest firmware versions and should work with older versions as well. In case of compatibility issues it can be disabled. |
### Configuration in .things file ### Configuration in .things file

View File

@ -68,4 +68,7 @@ public class LGWebOSBindingConstants {
public static final String CHANNEL_MEDIA_STOP = "mediaStop"; public static final String CHANNEL_MEDIA_STOP = "mediaStop";
public static final String CHANNEL_APP_LAUNCHER = "appLauncher"; public static final String CHANNEL_APP_LAUNCHER = "appLauncher";
public static final String CHANNEL_RCBUTTON = "rcButton"; public static final String CHANNEL_RCBUTTON = "rcButton";
public static final int DEFAULT_WS_PORT = 3000;
public static final int DEFAULT_WSS_PORT = 3001;
} }

View File

@ -16,6 +16,8 @@ import static org.openhab.binding.lgwebos.internal.LGWebOSBindingConstants.*;
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.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.client.WebSocketClient; import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.openhab.binding.lgwebos.internal.handler.LGWebOSHandler; import org.openhab.binding.lgwebos.internal.handler.LGWebOSHandler;
import org.openhab.core.io.net.http.WebSocketFactory; import org.openhab.core.io.net.http.WebSocketFactory;
@ -53,7 +55,8 @@ public class LGWebOSHandlerFactory extends BaseThingHandlerFactory {
* Cannot use openHAB's shared web socket client (webSocketFactory.getCommonWebSocketClient()) as we have to * Cannot use openHAB's shared web socket client (webSocketFactory.getCommonWebSocketClient()) as we have to
* change client settings. * change client settings.
*/ */
this.webSocketClient = webSocketFactory.createWebSocketClient("lgwebos"); var httpClient = new HttpClient(new SslContextFactory.Client(true));
this.webSocketClient = new WebSocketClient(httpClient);
this.stateDescriptionProvider = stateDescriptionProvider; this.stateDescriptionProvider = stateDescriptionProvider;
} }
@ -74,9 +77,6 @@ public class LGWebOSHandlerFactory extends BaseThingHandlerFactory {
@Override @Override
protected void activate(ComponentContext componentContext) { protected void activate(ComponentContext componentContext) {
super.activate(componentContext); super.activate(componentContext);
// LGWebOS TVs only support WEAK cipher suites, thus not using SSL.
// SslContextFactory sslContextFactory = new SslContextFactory(true);
// sslContextFactory.addExcludeProtocols("tls/1.3");
// reduce timeout from default 15sec // reduce timeout from default 15sec
this.webSocketClient.setConnectTimeout(1000); this.webSocketClient.setConnectTimeout(1000);

View File

@ -25,11 +25,11 @@ import org.eclipse.jdt.annotation.Nullable;
public class LGWebOSConfiguration { public class LGWebOSConfiguration {
@Nullable @Nullable
String host; // name has to match LGWebOSBindingConstants.CONFIG_HOST String host; // name has to match LGWebOSBindingConstants.CONFIG_HOST
int port = 3000; // 3001 for TLS
@Nullable @Nullable
String key; // name has to match LGWebOSBindingConstants.CONFIG_KEY String key; // name has to match LGWebOSBindingConstants.CONFIG_KEY
@Nullable @Nullable
String macAddress; // name has to match LGWebOSBindingConstants.CONFIG_MAC_ADDRESS String macAddress; // name has to match LGWebOSBindingConstants.CONFIG_MAC_ADDRESS
boolean useTLS = true;
public String getHost() { public String getHost() {
String h = host; String h = host;
@ -41,8 +41,8 @@ public class LGWebOSConfiguration {
return k == null ? "" : k; return k == null ? "" : k;
} }
public int getPort() { public boolean getUseTLS() {
return port; return useTLS;
} }
public String getMacAddress() { public String getMacAddress() {
@ -52,7 +52,7 @@ public class LGWebOSConfiguration {
@Override @Override
public String toString() { public String toString() {
return "WebOSConfiguration [host=" + host + ", port=" + port + ", key.length=" + getKey().length() return "WebOSConfiguration [host=" + host + ", useTLS=" + useTLS + ", key.length=" + getKey().length()
+ ", macAddress=" + macAddress + "]"; + ", macAddress=" + macAddress + "]";
} }
} }

View File

@ -135,7 +135,7 @@ public class LGWebOSHandler extends BaseThingHandler
return; return;
} }
LGWebOSTVSocket s = new LGWebOSTVSocket(webSocketClient, this, host, c.getPort(), scheduler); LGWebOSTVSocket s = new LGWebOSTVSocket(webSocketClient, this, host, c.getUseTLS(), scheduler);
s.setListener(this); s.setListener(this);
socket = s; socket = s;

View File

@ -116,6 +116,7 @@ public class LGWebOSTVSocket {
private final URI destUri; private final URI destUri;
private final LGWebOSTVKeyboardInput keyboardInput; private final LGWebOSTVKeyboardInput keyboardInput;
private final ScheduledExecutorService scheduler; private final ScheduledExecutorService scheduler;
private final Protocol protocol;
public enum State { public enum State {
DISCONNECTING, DISCONNECTING,
@ -125,6 +126,19 @@ public class LGWebOSTVSocket {
REGISTERED REGISTERED
} }
private enum Protocol {
WEB_SOCKET("ws", DEFAULT_WS_PORT),
WEB_SOCKET_SECURE("wss", DEFAULT_WSS_PORT);
private Protocol(String name, int port) {
this.name = name;
this.port = port;
}
public String name;
public int port;
}
private State state = State.DISCONNECTED; private State state = State.DISCONNECTED;
private @Nullable Session session; private @Nullable Session session;
@ -140,14 +154,15 @@ public class LGWebOSTVSocket {
private @Nullable ScheduledFuture<?> disconnectingJob; private @Nullable ScheduledFuture<?> disconnectingJob;
public LGWebOSTVSocket(WebSocketClient client, ConfigProvider config, String host, int port, public LGWebOSTVSocket(WebSocketClient client, ConfigProvider config, String host, boolean useTLS,
ScheduledExecutorService scheduler) { ScheduledExecutorService scheduler) {
this.config = config; this.config = config;
this.client = client; this.client = client;
this.keyboardInput = new LGWebOSTVKeyboardInput(this); this.keyboardInput = new LGWebOSTVKeyboardInput(this);
this.protocol = useTLS ? Protocol.WEB_SOCKET_SECURE : Protocol.WEB_SOCKET;
try { try {
this.destUri = new URI("ws://" + host + ":" + port); this.destUri = new URI(protocol.name + "://" + host + ":" + protocol.port);
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
throw new IllegalArgumentException("IP address or hostname provided is invalid: " + host); throw new IllegalArgumentException("IP address or hostname provided is invalid: " + host);
} }
@ -916,8 +931,13 @@ public class LGWebOSTVSocket {
@Override @Override
public void onSuccess(@Nullable JsonObject jsonObj) { public void onSuccess(@Nullable JsonObject jsonObj) {
if (jsonObj != null) { if (jsonObj != null) {
String socketPath = jsonObj.get("socketPath").getAsString().replace("wss:", "ws:").replace(":3001/", String socketPath = jsonObj.get("socketPath").getAsString();
":3000/"); if (protocol == Protocol.WEB_SOCKET) {
socketPath = socketPath
.replace(Protocol.WEB_SOCKET_SECURE.name + ":", Protocol.WEB_SOCKET.name + ":")
.replace(":" + Protocol.WEB_SOCKET_SECURE.port + "/",
":" + Protocol.WEB_SOCKET.port + "/");
}
try { try {
mouseSocket.connect(new URI(socketPath)); mouseSocket.connect(new URI(socketPath));
} catch (URISyntaxException e) { } catch (URISyntaxException e) {

View File

@ -22,6 +22,13 @@
(WOL) when it receives command ON on channel power. Accepted value is six groups of two hexadecimal digits, (WOL) when it receives command ON on channel power. Accepted value is six groups of two hexadecimal digits,
separated by hyphens or colons, e.g '3c:cd:93:c2:20:e0'.</description> separated by hyphens or colons, e.g '3c:cd:93:c2:20:e0'.</description>
</parameter> </parameter>
<parameter name="useTLS" type="boolean" required="false">
<label>Use TLS</label>
<description>Enable Transport Layer Security. This is required by latest firmware versions and should work with older
versions as well. In case of compatibility issues it can be disabled.</description>
<advanced>true</advanced>
<default>true</default>
</parameter>
</config-description> </config-description>
</config-description:config-descriptions> </config-description:config-descriptions>

View File

@ -16,6 +16,8 @@ thing-type.config.lgwebos.WebOSTV.key.label = Access Key
thing-type.config.lgwebos.WebOSTV.key.description = Key exchanged with TV after pairing. thing-type.config.lgwebos.WebOSTV.key.description = Key exchanged with TV after pairing.
thing-type.config.lgwebos.WebOSTV.macAddress.label = MAC Address thing-type.config.lgwebos.WebOSTV.macAddress.label = MAC Address
thing-type.config.lgwebos.WebOSTV.macAddress.description = If MAC Address of TV is entered here, the binding will attempt to power on the device via Wake On Lan (WOL) when it receives command ON on channel power. Accepted value is six groups of two hexadecimal digits, separated by hyphens or colons, e.g '3c:cd:93:c2:20:e0'. thing-type.config.lgwebos.WebOSTV.macAddress.description = If MAC Address of TV is entered here, the binding will attempt to power on the device via Wake On Lan (WOL) when it receives command ON on channel power. Accepted value is six groups of two hexadecimal digits, separated by hyphens or colons, e.g '3c:cd:93:c2:20:e0'.
thing-type.config.lgwebos.WebOSTV.useTLS.label = Use TLS
thing-type.config.lgwebos.WebOSTV.useTLS.description = Enable Transport Layer Security. This is required by latest firmware versions and should work with older versions as well. In case of compatibility issues it can be disabled.
# channel types # channel types
@ -69,7 +71,7 @@ actionShowToastWithIconDesc = Sends a toast message to a WebOS device with custo
actionShowToastInputIconLabel = Icon actionShowToastInputIconLabel = Icon
actionShowToastInputIconDesc = The URL to the icon to display actionShowToastInputIconDesc = The URL to the icon to display
# Thing status descriptions # thing status descriptions
offline.config-error-unknown-host = Missing parameter "host" offline.config-error-unknown-host = Missing parameter "host"
offline.comm-error-connexion-failed = Connection Failed: {0} offline.comm-error-connexion-failed = Connection Failed: {0}