--- a/connectors/WAMP/__init__.py Sat Mar 01 12:30:04 2025 +0100
+++ b/connectors/WAMP/__init__.py Tue Mar 04 14:00:41 2025 +0100
@@ -24,21 +24,25 @@
from functools import partial
from threading import Thread, Event
from twisted.internet import reactor, threads
from twisted.internet._sslverify import OpenSSLCertificateAuthorities
+from twisted.internet.ssl import optionsForClientTLS from autobahn.twisted import wamp
from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS
from autobahn.wamp import types, auth
from autobahn.wamp.exception import TransportLost
from autobahn.wamp.serializer import MsgPackSerializer
+from OpenSSL import crypto from ProjectController import ToDoBeforeQuit
from connectors.ConnectorBase import ConnectorBase
import PSKManagement as PSK
+import CertManagement as Cert @@ -104,11 +108,10 @@
urlprefix = {"WAMP": "ws",
url = urlprefix+"://"+urlpath
+ CN = urlpath.split("/")[0].split(":")[0] secret = PSK.GetSecret(confnodesroot.ProjectPath, ID)
- # TODO: add x509 certificate management together with PSK management.
+ trust_store = Cert.GetCertPath(confnodesroot.ProjectPath, CN) confnodesroot.logger.write_error(
_("Connection to {loc} failed with exception {ex}\n").format(
@@ -139,9 +142,16 @@
if transport_factory.isSecure:
- contextFactory = MakeSecureContextFactory(
- trust_store=trust_store)
+ if not os.path.exists(trust_store): + raise Exception("Wamp trust store not found") + cert = crypto.load_certificate( + open(trust_store, 'rb').read() + trustRoot=OpenSSLCertificateAuthorities([cert]) + contextFactory = optionsForClientTLS(transport_factory.host, trustRoot=trustRoot) # start the client from a Twisted endpoint
conn = connectWS(transport_factory, contextFactory)
--- a/runtime/WampClient.py Sat Mar 01 12:30:04 2025 +0100
+++ b/runtime/WampClient.py Tue Mar 04 14:00:41 2025 +0100
@@ -33,7 +33,7 @@
from autobahn.wamp.serializer import MsgPackSerializer
from twisted.internet.protocol import ReconnectingClientFactory
from twisted.python.components import registerAdapter
-from twisted.internet.ssl import optionsForClientTLS, CertificateOptions
+from twisted.internet.ssl import optionsForClientTLS from twisted.internet._sslverify import OpenSSLCertificateAuthorities
from OpenSSL import crypto
@@ -51,6 +51,7 @@
# Find pre-existing project WAMP config file
@@ -143,7 +144,7 @@
registerOptions = types.RegisterOptions(**kwargs)
- print(_("TypeError register option: {}".format(e)))
+ print("TypeError register option: {}".format(e)) self.register(GetCallee(name), '.'.join((ID, name)), registerOptions)
@@ -153,7 +154,7 @@
- print(_('WAMP session joined (%s) by:' % time.ctime()), ID)
+ print('WAMP session joined (%s) by: %s' % (time.ctime(), ID)) def onLeave(self, details):
global _WampSession, _transportFactory
@@ -185,7 +186,7 @@
self.setProtocolOptions(**protocolOptions)
- print(_("Custom protocol options failed :"), e)
+ print("Custom protocol options failed :", e) def setClientFactoryOptions(self, options):
@@ -198,13 +199,13 @@
return ReconnectingClientFactory.buildProtocol(self, addr)
def clientConnectionFailed(self, connector, reason):
- print(_("WAMP Client connection failed (%s) .. retrying ..") %
+ print("WAMP Client connection failed (%s) .. retrying .." % super(ReconnectingWampWebSocketClientFactory,
self).clientConnectionFailed(connector, reason)
def clientConnectionLost(self, connector, reason):
- print(_("WAMP Client connection lost (%s) .. retrying ..") %
+ print("WAMP Client connection lost (%s) .. retrying .." % super(ReconnectingWampWebSocketClientFactory,
self).clientConnectionFailed(connector, reason)
@@ -266,7 +267,7 @@
def LoadWampSecret(secretfname):
WSClientWampSecret = open(secretfname, 'rb').read()
if len(WSClientWampSecret) == 0:
- raise Exception(_("WAMP secret empty"))
+ raise Exception(_("WAMP secret is empty")) return WSClientWampSecret
@@ -275,7 +276,8 @@
def RegisterWampClient(wampconf=None, wampsecret=None, ConfDir=None, KeyStore=None, servicename=None):
- global _WampConf, _WampSecret, _WampTrust, defaultWampConfig
+ from twisted.internet import reactor + global _WampConf, _WampSecret, _WampSercretFile, _WampTrust, defaultWampConfig defaultWampConfig["ID"] = servicename
@@ -299,32 +301,37 @@
WampClientConf = GetConfiguration()
+ if not WampClientConf["active"]: + print("WAMP deactivated in configuration") # set secret file path only if not already set
- if _WampSecret is None:
+ if _WampSercretFile is None: # default project's wamp secret also
# has precedance over commandline given
if os.path.exists(_WampSecretDefault):
- _WampSecret = _WampSecretDefault
+ _WampSercretFile = _WampSecretDefault - _WampSecret = wampsecret
+ _WampSercretFile = wampsecret - if _WampSecret is not None:
- if _WampSecret == _WampSecretDefault:
+ if _WampSercretFile is not None: + if _WampSercretFile == _WampSecretDefault: # secret from project dir is raw (no ID prefix)
- secret = LoadWampSecret(_WampSecret)
+ _WampSecret = LoadWampSecret(_WampSercretFile) # secret from command line is formated ID:PSK
# fall back to PSK data (works because wampsecret is PSKpath)
- _ID, secret = getPSKID()
- WampClientConf["secret"] = secret
+ _ID, _WampSecret = getPSKID() raise Exception(_("WAMP no secret file given"))
- if not WampClientConf["active"]:
- print(_("WAMP deactivated in configuration"))
+ reactor.callInThread(_RegisterWampClient) +def _RegisterWampClient(): + WampClientConf = GetConfiguration() + WampClientConf["secret"] = _WampSecret # create a WAMP application session factory
component_config = types.ComponentConfig(
@@ -348,11 +355,9 @@
contextFactory = MakeSecureContextFactory(WampClientConf["verifyHostname"])
connectWS(_transportFactory, contextFactory)
- print(_("WAMP client connecting to :"), WampClientConf["url"])
+ print("WAMP client connecting to :", WampClientConf["url"]) - print(_("WAMP client can not connect to :"), WampClientConf["url"])
+ print("WAMP client can not connect to :", WampClientConf["url"]) def MakeSecureContextFactory(verifyHostname):
@@ -382,7 +387,7 @@
@@ -440,7 +445,7 @@
if secretfile_field is not None:
secretfile = getattr(secretfile_field, "file", None)
if secretfile is not None:
- with open(os.path.realpath(_WampSecret), 'w') as destfd:
+ with open(os.path.realpath(_WampSercretFile), 'w') as destfd: shutil.copyfileobj(secretfile,destfd)
@@ -574,7 +579,7 @@
# TODO: make beautifull message in case of exception
# while loading secret (if empty or dont exist)
- secret = LoadWampSecret(_WampSecret)
+ secret = LoadWampSecret(_WampSercretFile) return static.Data(secret, 'application/octet-stream'), ()
def deleteTrustStore(ctx, segments):