Skip to content

Commit

Permalink
Sanitize topic lists for XML conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
FlyingDiver committed Feb 7, 2024
1 parent 37e034a commit ac961c4
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 33 deletions.
2 changes: 1 addition & 1 deletion MQTT Connector.indigoPlugin/Contents/Info.plist
Expand Up @@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>PluginVersion</key>
<string>2023.2.0</string>
<string>2023.2.1</string>
<key>ServerApiVersion</key>
<string>3.4</string>
<key>IwsApiVersion</key>
Expand Down
Expand Up @@ -91,7 +91,7 @@
</Field>
<Field id="subscriptions_items" type="list" rows="10" visibleBindingId="section" visibleBindingValue="subscriptions">
<Label>Subscribed Topics:</Label>
<List class="self" method="subscribedList" dynamicReload="true"/>
<List class="self" method="subscribedListConfigUI" dynamicReload="true"/>
</Field>
<Field id="subscriptions_deleteSubscriptions" type="button" visibleBindingId="section" visibleBindingValue="subscriptions">
<Label/>
Expand Down
Expand Up @@ -5,6 +5,7 @@
import time
import logging
import indigo
import urllib.parse

from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient

Expand Down Expand Up @@ -87,9 +88,9 @@ def onConnect(self, mid, rc):
device.updateStateImageOnServer(indigo.kStateImageSel.SensorOn)

# Subscribing in onConnect() means that if we lose the connection and reconnect then subscriptions will be renewed.
subs = device.pluginProps.get(u'subscriptions', None)
if subs:
for s in subs:
if subs := device.pluginProps.get('subscriptions'):
for sub in subs:
s = urllib.parse.unquote(sub)
qos = int(s[0:1])
topic = s[2:]
self.subscribe(topic, qos)
Expand Down
11 changes: 6 additions & 5 deletions MQTT Connector.indigoPlugin/Contents/Server Plugin/dxl_broker.py
Expand Up @@ -5,6 +5,7 @@
import time
import logging
import indigo
import urllib.parse

from dxlclient.client import DxlClient
from dxlclient.client_config import DxlClientConfig
Expand Down Expand Up @@ -53,11 +54,11 @@ def __init__(self, device):
device.updateStateOnServer(key="status", value="Connected")
device.updateStateImageOnServer(indigo.kStateImageSel.SensorOn)

subs = device.pluginProps.get(u'subscriptions', None)
if subs:
for topic in subs:
self.dxl_client.add_event_callback(topic, self.MyEventCallback(self))
self.logger.info(u"{}: Subscribing to: {}".format(device.name, topic))
if subs := device.pluginProps.get('subscriptions'):
for sub in subs:
s = urllib.parse.unquote(sub)
self.dxl_client.add_event_callback(s, self.MyEventCallback(self))
self.logger.info(f"{device.name}: Subscribing to: {s}")

def disconnect(self):
device = indigo.devices[self.deviceID]
Expand Down
Expand Up @@ -7,7 +7,7 @@
import indigo
import threading
from os.path import exists

import urllib.parse
import paho.mqtt.client as mqtt


Expand Down Expand Up @@ -111,21 +111,21 @@ def on_connect(self, client, userdata, flags, rc):
self.logger.debug(f"{device.name}: Connected with result code {rc}")

# Subscribing in on_connect() means that if we lose the connection and reconnect then subscriptions will be renewed.
subs = device.pluginProps.get('subscriptions', None)
if subs:
for s in subs:
if subs := device.pluginProps.get('subscriptions'):
for sub in subs:
s = urllib.parse.unquote(sub)
qos = int(s[0:1])
topic = s[2:]
self.logger.info(f"{device.name}: Subscribing to: {topic} ({qos})")
client.subscribe(topic, qos)

device.updateStateOnServer(key="status", value="Connected {}".format(rc))
device.updateStateOnServer(key="status", value=f"Connected {rc}")
device.updateStateImageOnServer(indigo.kStateImageSel.SensorOn)

def on_disconnect(self, client, userdata, rc):
device = indigo.devices[self.deviceID]
self.logger.error(f"{device.name}: Disconnected with result code {rc}")
device.updateStateOnServer(key="status", value="Disconnected {}".format(rc))
device.updateStateOnServer(key="status", value=f"Disconnected {rc}")
device.updateStateImageOnServer(indigo.kStateImageSel.SensorTripped)

def on_message(self, client, userdata, msg):
Expand Down
54 changes: 37 additions & 17 deletions MQTT Connector.indigoPlugin/Contents/Server Plugin/plugin.py
Expand Up @@ -6,6 +6,8 @@
import plistlib
import json
import logging
import urllib.parse

import pystache
import re
import base64
Expand All @@ -17,7 +19,7 @@
from mqtt_broker import MQTTBroker
from aiot_broker import AIoTBroker

kCurDevVersCount = 0 # current version of plugin devices
kCurDevVersCount = 1 # current version of plugin devices


# normally used for file system paths, but will work for slash separated topics
Expand Down Expand Up @@ -198,6 +200,14 @@ def deviceStartComm(self, device):
elif instanceVers < kCurDevVersCount:
newProps = device.pluginProps
newProps["devVersCount"] = kCurDevVersCount

new_subs = list()
if 'subscriptions' in device.pluginProps:
for topic in device.pluginProps['subscriptions']:
new_subs.append(urllib.parse.quote(topic))
newProps['subscriptions'] = new_subs
self.logger.debug(f"deviceStartComm: subscriptions updated to {new_subs=}")

device.replacePluginPropsOnServer(newProps)
self.logger.debug(f"{device.name}: Updated device version: {instanceVers} -> {kCurDevVersCount}")
else:
Expand Down Expand Up @@ -458,25 +468,26 @@ def addTopic(self, valuesDict, typeId, deviceId):

if typeId == 'dxlBroker':
if topic not in topicList:
topicList.append(topic)
topicList.append(urllib.parse.quote(topic))

elif typeId == 'mqttBroker':
s = "{}:{}".format(qos, topic)
s = f"{qos}:{topic}"
if s not in topicList:
topicList.append(s)
topicList.append(urllib.parse.quote(s))

elif typeId == 'aIoTBroker':
s = "{}:{}".format(qos, topic)
s = f"{qos}:{topic}"
if s not in topicList:
topicList.append(s)
topicList.append(urllib.parse.quote(s))
else:
self.logger.warning(f"addTopic: Invalid device type: {typeId} for device {deviceId}")

valuesDict['subscriptions'] = topicList
return valuesDict

@staticmethod
def deleteSubscriptions(valuesDict, typeId, deviceId):
def deleteSubscriptions(self, valuesDict, typeId, deviceId):
self.logger.debug(f"deleteSubscriptions: {list(valuesDict['subscriptions'])=}")
self.logger.debug(f"deleteSubscriptions: {list(valuesDict['subscriptions_items'])=}")
topicList = list()
if 'subscriptions' in valuesDict:
for t in valuesDict['subscriptions']:
Expand All @@ -487,12 +498,22 @@ def deleteSubscriptions(valuesDict, typeId, deviceId):
valuesDict['subscriptions'] = topicList
return valuesDict

@staticmethod
def subscribedList(ifilter, valuesDict, typeId, deviceId):
def subscribedList(self, ifilter, valuesDict, typeId, deviceId):
returnList = list()
if 'subscriptions' in valuesDict:
for topic in valuesDict['subscriptions']:
self.logger.debug(f"subscribedList: {topic=}")
returnList.append(topic)
self.logger.debug(f"subscribedList: {returnList=}")
return returnList

def subscribedListConfigUI(self, ifilter, valuesDict, typeId, deviceId):
returnList = list()
if 'subscriptions' in valuesDict:
for topic in valuesDict['subscriptions']:
self.logger.debug(f"subscribedListConfigUI: {topic=}")
returnList.append((topic, urllib.parse.unquote(topic)))
self.logger.debug(f"subscribedListConfigUI: {returnList=}")
return returnList

########################################
Expand Down Expand Up @@ -590,8 +611,6 @@ def validateDeviceConfigUi(self, valuesDict, typeId, deviceId):
if typeId == "mqttBroker":
broker = self.brokers.get(deviceId, None)

# test the templates to make sure they return valid data

# if the subscription list changes, calc changes and update the broker

if 'subscriptions' not in valuesDict:
Expand All @@ -600,14 +619,16 @@ def validateDeviceConfigUi(self, valuesDict, typeId, deviceId):
valuesDict['old_subscriptions'] = indigo.List()

# unsubscribe first in case the QoS changed
for s in valuesDict['old_subscriptions']:
if s not in valuesDict['subscriptions']:
for sub in valuesDict['old_subscriptions']:
if sub not in valuesDict['subscriptions']:
s = urllib.parse.unquote(sub)
topic = s[2:]
if broker:
broker.unsubscribe(topic=topic)

for s in valuesDict['subscriptions']:
if s not in valuesDict['old_subscriptions']:
for sub in valuesDict['subscriptions']:
if sub not in valuesDict['old_subscriptions']:
s = urllib.parse.unquote(sub)
qos = int(s[0:1])
topic = s[2:]
if broker:
Expand Down Expand Up @@ -930,7 +951,6 @@ def fetchQueuedMessageAction(self, action, device, callerWaitingForResult):
message['payload'] = base64.b64encode(message['payload'])
return message


########################################################################

def getBrokerDevices(self, ifilter="", valuesDict=None, typeId="", targetId=0):
Expand Down

0 comments on commit ac961c4

Please sign in to comment.