--- a/Beremiz_service.py Tue Jul 10 12:51:28 2018 +0200
+++ b/Beremiz_service.py Tue Jul 10 12:54:05 2018 +0200
@@ -592,19 +592,11 @@
NS.WorkingDir = WorkingDir
- # Find pre-existing project WAMP config file
- _wampconf = os.path.join(WorkingDir, "wampconf.json")
- # If project's WAMP config file exits, override default (-c)
- if os.path.exists(_wampconf):
- if wampconf is not None:
- import runtime.WampClient as WC # pylint: disable=ungrouped-imports
- LogMessageAndException(_("WAMP import failed :"))
+ import runtime.WampClient as WC # pylint: disable=ungrouped-imports + WC.WorkingDir = WorkingDir + LogMessageAndException(_("WAMP import failed :")) for extention_file, extension_folder in extensions:
@@ -621,12 +613,11 @@
LogMessageAndException(_("Nevow Web service failed. "))
- if wampconf is not None:
- WC.SetServer(pyroserver)
- WC.RegisterWampClient(wampconf, wampsecret)
- LogMessageAndException(_("WAMP client startup failed. "))
+ WC.SetServer(pyroserver) + WC.RegisterWampClient(wampconf, wampsecret) + LogMessageAndException(_("WAMP client startup failed. ")) pyro_thread_started = Lock()
pyro_thread_started.acquire()
--- a/runtime/WampClient.py Tue Jul 10 12:51:28 2018 +0200
+++ b/runtime/WampClient.py Tue Jul 10 12:54:05 2018 +0200
@@ -34,16 +34,22 @@
from autobahn.wamp.serializer import MsgPackSerializer
from twisted.internet.defer import inlineCallbacks
from twisted.internet.protocol import ReconnectingClientFactory
+from twisted.python.components import registerAdapter import runtime.NevowServer as NS
-from formless import annotate
+from formless import annotate, webform +from nevow import tags, url, static mandatoryConfigItems = ["ID", "active", "realm", "url"]
+# Find pre-existing project WAMP config file @@ -61,6 +67,14 @@
+# de-activated dumb wamp config + "url": "ws://127.0.0.1:8888" # Those two lists are meant to be filled by customized runtime
@@ -164,8 +178,8 @@
-def CheckConfiguration(WSClientConf):
- url = WSClientConf["url"]
+def CheckConfiguration(WampClientConf): + url = WampClientConf["url"] if not IsCorrectUri(url):
raise annotate.ValidateError(
{"url":"Invalid URL: {}".format(url)},
@@ -174,34 +188,42 @@
- WSClientConf = json.load(open(_WampConf))
+ if os.path.exists(_WampConf): + WampClientConf = json.load(open(_WampConf)) + WampClientConf = defaultWampConfig for itemName in mandatoryConfigItems:
- if WSClientConf.get(itemName, None) is None :
+ if WampClientConf.get(itemName, None) is None : raise Exception(_("WAMP configuration error : missing '{}' parameter.").format(itemName))
- CheckConfiguration(WSClientConf)
+ CheckConfiguration(WampClientConf) - lastKnownConfig = WSClientConf.copy()
+ lastKnownConfig = WampClientConf.copy() -def SetConfiguration(WSClientConf):
+def SetWampSecret(wampSecret): + with open(os.path.realpath(_WampSecret), 'w') as f: +def SetConfiguration(WampClientConf): - CheckConfiguration(WSClientConf)
+ CheckConfiguration(WampClientConf) - lastKnownConfig = WSClientConf.copy()
+ lastKnownConfig = WampClientConf.copy() with open(os.path.realpath(_WampConf), 'w') as f:
- json.dump(WSClientConf, f, sort_keys=True, indent=4)
- if 'active' in WSClientConf and WSClientConf['active']:
+ json.dump(WampClientConf, f, sort_keys=True, indent=4) + if 'active' in WampClientConf and WampClientConf['active']: if _transportFactory and _WampSession:
StopReconnectWampClient()
StartReconnectWampClient()
StopReconnectWampClient()
def LoadWampSecret(secretfname):
@@ -217,24 +239,35 @@
def RegisterWampClient(wampconf=None, wampsecret=None):
global _WampConf, _WampSecret
- _WampSecret = wampsecret
+ _WampConfDefault = os.path.join(WorkingDir, "wampconf.json") + _WampSecretDefault = os.path.join(WorkingDir, "wamp.secret") + # default project's wampconf has precedance over commandline given + if os.path.exists(_WampConfDefault) or wampconf is None: + _WampConf = _WampConfDefault - WSClientConf = GetConfiguration()
+ WampClientConf = GetConfiguration() - if not WSClientConf["active"]:
+ if wampsecret is not None: + WampClientConf["secret"] = LoadWampSecret(wampsecret) + _WampSecret = wampsecret + if os.path.exists(_WampSecretDefault): + WampClientConf["secret"] = LoadWampSecret(_WampSecretDefault) + print(_("WAMP authentication has no secret configured")) + _WampSecret = _WampSecretDefault + if not WampClientConf["active"]: print(_("WAMP deactivated in configuration"))
- if _WampSecret is not None:
- WSClientConf["secret"] = LoadWampSecret(_WampSecret)
# create a WAMP application session factory
component_config = types.ComponentConfig(
- realm=WSClientConf["realm"],
+ realm=WampClientConf["realm"], session_factory = wamp.ApplicationSessionFactory(
session_factory.session = WampSession
@@ -243,16 +276,16 @@
ReconnectingWampWebSocketClientFactory(
- url=WSClientConf["url"],
+ url=WampClientConf["url"], serializers=[MsgPackSerializer()])
# start the client from a Twisted endpoint
conn = connectWS(_transportFactory)
- print(_("WAMP client connecting to :"), WSClientConf["url"])
+ print(_("WAMP client connecting to :"), WampClientConf["url"]) - print(_("WAMP client can not connect to :"), WSClientConf["url"])
+ print(_("WAMP client can not connect to :"), WampClientConf["url"]) @@ -292,7 +325,7 @@
#### WEB CONFIGURATION INTERFACE ####
+WAMP_SECRET_URL = "secret" webExposedConfigItems = ['active', 'url', 'ID']
def wampConfigDefault(ctx,argument):
@@ -300,12 +333,37 @@
return lastKnownConfig.get(argument.name, None)
def wampConfig(**kwargs):
+ secretfile_field = kwargs["secretfile"] + if secretfile_field is not None: + secret = secretfile_field.file.read() newConfig = lastKnownConfig.copy()
for argname in webExposedConfigItems:
newConfig[argname] = kwargs[argname]
SetConfiguration(newConfig)
+class FileUploadDownload(annotate.FileUpload): +class FileUploadDownloadRenderer(webform.FileUploadRenderer): + def input(self, context, slot, data, name, value): + slot = webform.FileUploadRenderer.input(self, context, slot, data, name, value) + download_url = data.typedValue.getAttribute('download_url') + return slot[tags.a(href=download_url)[_("Download")]] +registerAdapter(FileUploadDownloadRenderer, FileUploadDownload, formless.iformless.ITypedRenderer) +def getDownloadUrl(ctx, argument): + if lastKnownConfig is not None : + currentID = lastKnownConfig.get("ID", None) + return url.URL.fromContext(ctx).\ + child(WAMP_SECRET_URL).\ + child(lastKnownConfig["ID"]+".secret") annotate.String(label=_("Current status"),
@@ -314,6 +372,11 @@
annotate.String(label=_("ID"),
default = wampConfigDefault)),
+ label = _("File containing secret for that ID"), + download_url = getDownloadUrl, annotate.Boolean(label=_("Enable WAMP connection"),
default=wampConfigDefault)),
@@ -328,3 +391,13 @@
+def deliverWampSecret(ctx, segments): + filename = segments[1].decode('utf-8') + # TODO : SECURITY compare filename to ID and blah... + secret = LoadWampSecret(_WampSecret) + return static.Data(secret, 'application/octet-stream'),() +NS.customSettingsURLs[WAMP_SECRET_URL] = deliverWampSecret