103 |
105 |
104 def onChallenge(self, challenge): |
106 def onChallenge(self, challenge): |
105 if challenge.method == u"wampcra": |
107 if challenge.method == u"wampcra": |
106 if "secret" in self.config.extra: |
108 if "secret" in self.config.extra: |
107 secret = self.config.extra["secret"].encode('utf8') |
109 secret = self.config.extra["secret"].encode('utf8') |
108 signature = auth.compute_wcs(secret, challenge.extra['challenge'].encode('utf8')) |
110 signature = auth.compute_wcs( |
|
111 secret, challenge.extra['challenge'].encode('utf8')) |
109 return signature.decode("ascii") |
112 return signature.decode("ascii") |
110 else: |
113 else: |
111 raise Exception("no secret given for authentication") |
114 raise Exception("no secret given for authentication") |
112 else: |
115 else: |
113 raise Exception("don't know how to handle authmethod {}".format(challenge.method)) |
116 raise Exception( |
|
117 "don't know how to handle authmethod {}".format(challenge.method)) |
114 |
118 |
115 @inlineCallbacks |
119 @inlineCallbacks |
116 def onJoin(self, details): |
120 def onJoin(self, details): |
117 global _WampSession |
121 global _WampSession |
118 _WampSession = self |
122 _WampSession = self |
161 self.resetDelay() |
166 self.resetDelay() |
162 return ReconnectingClientFactory.buildProtocol(self, addr) |
167 return ReconnectingClientFactory.buildProtocol(self, addr) |
163 |
168 |
164 def clientConnectionFailed(self, connector, reason): |
169 def clientConnectionFailed(self, connector, reason): |
165 if self.continueTrying: |
170 if self.continueTrying: |
166 print(_("WAMP Client connection failed (%s) .. retrying ..") % time.ctime()) |
171 print(_("WAMP Client connection failed (%s) .. retrying ..") % |
167 super(ReconnectingWampWebSocketClientFactory, self).clientConnectionFailed(connector, reason) |
172 time.ctime()) |
|
173 super(ReconnectingWampWebSocketClientFactory, |
|
174 self).clientConnectionFailed(connector, reason) |
168 else: |
175 else: |
169 del connector |
176 del connector |
170 |
177 |
171 def clientConnectionLost(self, connector, reason): |
178 def clientConnectionLost(self, connector, reason): |
172 if self.continueTrying: |
179 if self.continueTrying: |
173 print(_("WAMP Client connection lost (%s) .. retrying ..") % time.ctime()) |
180 print(_("WAMP Client connection lost (%s) .. retrying ..") % |
174 super(ReconnectingWampWebSocketClientFactory, self).clientConnectionFailed(connector, reason) |
181 time.ctime()) |
|
182 super(ReconnectingWampWebSocketClientFactory, |
|
183 self).clientConnectionFailed(connector, reason) |
175 else: |
184 else: |
176 del connector |
185 del connector |
177 |
186 |
178 |
187 |
179 def CheckConfiguration(WampClientConf): |
188 def CheckConfiguration(WampClientConf): |
180 url = WampClientConf["url"] |
189 url = WampClientConf["url"] |
181 if not IsCorrectUri(url): |
190 if not IsCorrectUri(url): |
182 raise annotate.ValidateError( |
191 raise annotate.ValidateError( |
183 {"url":"Invalid URL: {}".format(url)}, |
192 {"url": "Invalid URL: {}".format(url)}, |
184 _("WAMP configuration error:")) |
193 _("WAMP configuration error:")) |
|
194 |
185 |
195 |
186 def GetConfiguration(): |
196 def GetConfiguration(): |
187 global lastKnownConfig |
197 global lastKnownConfig |
188 |
198 |
189 if os.path.exists(_WampConf): |
199 if os.path.exists(_WampConf): |
190 WampClientConf = json.load(open(_WampConf)) |
200 WampClientConf = json.load(open(_WampConf)) |
191 else: |
201 else: |
192 WampClientConf = defaultWampConfig.copy() |
202 WampClientConf = defaultWampConfig.copy() |
193 |
203 |
194 for itemName in mandatoryConfigItems: |
204 for itemName in mandatoryConfigItems: |
195 if WampClientConf.get(itemName, None) is None : |
205 if WampClientConf.get(itemName, None) is None: |
196 raise Exception(_("WAMP configuration error : missing '{}' parameter.").format(itemName)) |
206 raise Exception( |
|
207 _("WAMP configuration error : missing '{}' parameter.").format(itemName)) |
197 |
208 |
198 CheckConfiguration(WampClientConf) |
209 CheckConfiguration(WampClientConf) |
199 |
210 |
200 lastKnownConfig = WampClientConf.copy() |
211 lastKnownConfig = WampClientConf.copy() |
201 return WampClientConf |
212 return WampClientConf |
203 |
214 |
204 def SetWampSecret(wampSecret): |
215 def SetWampSecret(wampSecret): |
205 with open(os.path.realpath(_WampSecret), 'w') as f: |
216 with open(os.path.realpath(_WampSecret), 'w') as f: |
206 f.write(wampSecret) |
217 f.write(wampSecret) |
207 |
218 |
|
219 |
208 def SetConfiguration(WampClientConf): |
220 def SetConfiguration(WampClientConf): |
209 global lastKnownConfig |
221 global lastKnownConfig |
210 |
222 |
211 CheckConfiguration(WampClientConf) |
223 CheckConfiguration(WampClientConf) |
212 |
224 |
213 lastKnownConfig = WampClientConf.copy() |
225 lastKnownConfig = WampClientConf.copy() |
214 |
226 |
215 with open(os.path.realpath(_WampConf), 'w') as f: |
227 with open(os.path.realpath(_WampConf), 'w') as f: |
216 json.dump(WampClientConf, f, sort_keys=True, indent=4) |
228 json.dump(WampClientConf, f, sort_keys=True, indent=4) |
217 if 'active' in WampClientConf and WampClientConf['active']: |
229 if 'active' in WampClientConf and WampClientConf['active']: |
218 if _transportFactory and _WampSession: |
230 if _transportFactory and _WampSession: |
219 StopReconnectWampClient() |
231 StopReconnectWampClient() |
250 |
262 |
251 WampClientConf = GetConfiguration() |
263 WampClientConf = GetConfiguration() |
252 |
264 |
253 # set secret file path only if not already set |
265 # set secret file path only if not already set |
254 if _WampSecret is None: |
266 if _WampSecret is None: |
255 # default project's wamp secret also has precedance over commandline given |
267 # default project's wamp secret also |
|
268 # has precedance over commandline given |
256 if os.path.exists(_WampSecretDefault): |
269 if os.path.exists(_WampSecretDefault): |
257 _WampSecret = _WampSecretDefault |
270 _WampSecret = _WampSecretDefault |
258 else: |
271 else: |
259 _WampSecret = wampsecret |
272 _WampSecret = wampsecret |
260 |
273 |
261 if _WampSecret is not None: |
274 if _WampSecret is not None: |
262 WampClientConf["secret"] = LoadWampSecret(_WampSecret) |
275 WampClientConf["secret"] = LoadWampSecret(_WampSecret) |
263 else : |
276 else: |
264 print(_("WAMP authentication has no secret configured")) |
277 print(_("WAMP authentication has no secret configured")) |
265 _WampSecret = _WampSecretDefault |
278 _WampSecret = _WampSecretDefault |
266 |
279 |
267 if not WampClientConf["active"]: |
280 if not WampClientConf["active"]: |
268 print(_("WAMP deactivated in configuration")) |
281 print(_("WAMP deactivated in configuration")) |
283 url=WampClientConf["url"], |
296 url=WampClientConf["url"], |
284 serializers=[MsgPackSerializer()]) |
297 serializers=[MsgPackSerializer()]) |
285 |
298 |
286 # start the client from a Twisted endpoint |
299 # start the client from a Twisted endpoint |
287 if _transportFactory: |
300 if _transportFactory: |
288 conn = connectWS(_transportFactory) |
301 connectWS(_transportFactory) |
289 print(_("WAMP client connecting to :"), WampClientConf["url"]) |
302 print(_("WAMP client connecting to :"), WampClientConf["url"]) |
290 return True |
303 return True |
291 else: |
304 else: |
292 print(_("WAMP client can not connect to :"), WampClientConf["url"]) |
305 print(_("WAMP client can not connect to :"), WampClientConf["url"]) |
293 return False |
306 return False |
294 |
307 |
295 |
308 |
296 def StopReconnectWampClient(): |
309 def StopReconnectWampClient(): |
297 if _transportFactory is not None : |
310 if _transportFactory is not None: |
298 _transportFactory.stopTrying() |
311 _transportFactory.stopTrying() |
299 if _WampSession is not None : |
312 if _WampSession is not None: |
300 _WampSession.leave() |
313 _WampSession.leave() |
301 |
314 |
302 |
315 |
303 def StartReconnectWampClient(): |
316 def StartReconnectWampClient(): |
304 if _WampSession: |
317 if _WampSession: |
312 |
325 |
313 |
326 |
314 def GetSession(): |
327 def GetSession(): |
315 return _WampSession |
328 return _WampSession |
316 |
329 |
|
330 |
317 def getWampStatus(): |
331 def getWampStatus(): |
318 if _transportFactory is not None : |
332 if _transportFactory is not None: |
319 if _WampSession is not None : |
333 if _WampSession is not None: |
320 if _WampSession.is_attached() : |
334 if _WampSession.is_attached(): |
321 return "Attached" |
335 return "Attached" |
322 return "Established" |
336 return "Established" |
323 return "Connecting" |
337 return "Connecting" |
324 return "Disconnected" |
338 return "Disconnected" |
325 |
339 |
326 |
340 |
327 def SetServer(pysrv): |
341 def SetServer(pysrv): |
328 _PySrv = pysrv |
342 _PySrv = pysrv |
329 |
343 |
330 |
344 |
331 #### WEB CONFIGURATION INTERFACE #### |
345 # WEB CONFIGURATION INTERFACE |
332 WAMP_SECRET_URL = "secret" |
346 WAMP_SECRET_URL = "secret" |
333 webExposedConfigItems = ['active', 'url', 'ID'] |
347 webExposedConfigItems = ['active', 'url', 'ID'] |
334 |
348 |
335 def wampConfigDefault(ctx,argument): |
349 |
336 if lastKnownConfig is not None : |
350 def wampConfigDefault(ctx, argument): |
|
351 if lastKnownConfig is not None: |
337 return lastKnownConfig.get(argument.name, None) |
352 return lastKnownConfig.get(argument.name, None) |
|
353 |
338 |
354 |
339 def wampConfig(**kwargs): |
355 def wampConfig(**kwargs): |
340 secretfile_field = kwargs["secretfile"] |
356 secretfile_field = kwargs["secretfile"] |
341 if secretfile_field is not None: |
357 if secretfile_field is not None: |
342 secretfile = getattr(secretfile_field, "file", None) |
358 secretfile = getattr(secretfile_field, "file", None) |
345 SetWampSecret(secret) |
361 SetWampSecret(secret) |
346 |
362 |
347 newConfig = lastKnownConfig.copy() |
363 newConfig = lastKnownConfig.copy() |
348 for argname in webExposedConfigItems: |
364 for argname in webExposedConfigItems: |
349 arg = kwargs.get(argname, None) |
365 arg = kwargs.get(argname, None) |
350 if arg is not None : |
366 if arg is not None: |
351 newConfig[argname] = arg |
367 newConfig[argname] = arg |
352 |
368 |
353 SetConfiguration(newConfig) |
369 SetConfiguration(newConfig) |
|
370 |
354 |
371 |
355 class FileUploadDownload(annotate.FileUpload): |
372 class FileUploadDownload(annotate.FileUpload): |
356 pass |
373 pass |
357 |
374 |
358 |
375 |
359 class FileUploadDownloadRenderer(webform.FileUploadRenderer): |
376 class FileUploadDownloadRenderer(webform.FileUploadRenderer): |
|
377 |
360 def input(self, context, slot, data, name, value): |
378 def input(self, context, slot, data, name, value): |
|
379 # pylint: disable=expression-not-assigned |
361 slot[_("Upload:")] |
380 slot[_("Upload:")] |
362 slot = webform.FileUploadRenderer.input(self, context, slot, data, name, value) |
381 slot = webform.FileUploadRenderer.input( |
|
382 self, context, slot, data, name, value) |
363 download_url = data.typedValue.getAttribute('download_url') |
383 download_url = data.typedValue.getAttribute('download_url') |
364 return slot[tags.a(href=download_url)[_("Download")]] |
384 return slot[tags.a(href=download_url)[_("Download")]] |
365 |
385 |
366 registerAdapter(FileUploadDownloadRenderer, FileUploadDownload, formless.iformless.ITypedRenderer) |
386 registerAdapter(FileUploadDownloadRenderer, FileUploadDownload, |
367 |
387 formless.iformless.ITypedRenderer) |
|
388 |
|
389 |
368 def getDownloadUrl(ctx, argument): |
390 def getDownloadUrl(ctx, argument): |
369 if lastKnownConfig is not None : |
391 if lastKnownConfig is not None: |
370 return url.URL.fromContext(ctx).\ |
392 return url.URL.fromContext(ctx).\ |
371 child(WAMP_SECRET_URL).\ |
393 child(WAMP_SECRET_URL).\ |
372 child(lastKnownConfig["ID"]+".secret") |
394 child(lastKnownConfig["ID"] + ".secret") |
373 |
395 |
374 webFormInterface = [ |
396 webFormInterface = [ |
375 ("status", |
397 ("status", |
376 annotate.String(label=_("Current status"), |
398 annotate.String(label=_("Current status"), |
377 immutable = True, |
399 immutable=True, |
378 default = lambda *k:getWampStatus())), |
400 default=lambda *k:getWampStatus())), |
379 ("ID", |
401 ("ID", |
380 annotate.String(label=_("ID"), |
402 annotate.String(label=_("ID"), |
381 default = wampConfigDefault)), |
403 default=wampConfigDefault)), |
382 ("secretfile", |
404 ("secretfile", |
383 FileUploadDownload( |
405 FileUploadDownload(label=_("File containing secret for that ID"), |
384 label = _("File containing secret for that ID"), |
406 download_url=getDownloadUrl)), |
385 download_url = getDownloadUrl, |
|
386 )), |
|
387 ("active", |
407 ("active", |
388 annotate.Boolean(label=_("Enable WAMP connection"), |
408 annotate.Boolean(label=_("Enable WAMP connection"), |
389 default=wampConfigDefault)), |
409 default=wampConfigDefault)), |
390 ("url", |
410 ("url", |
391 annotate.String(label=_("WAMP Server URL"), |
411 annotate.String(label=_("WAMP Server URL"), |
392 default=wampConfigDefault))] |
412 default=wampConfigDefault))] |
393 |
413 |
394 |
414 |
395 def deliverWampSecret(ctx, segments): |
415 def deliverWampSecret(ctx, segments): |
396 filename = segments[1].decode('utf-8') |
416 # filename = segments[1].decode('utf-8') |
|
417 |
397 # FIXME: compare filename to ID+".secret" |
418 # FIXME: compare filename to ID+".secret" |
398 # for now all url under /secret returns the secret |
419 # for now all url under /secret returns the secret |
399 |
420 |
400 # TODO: make beutifull message in case of exception |
421 # TODO: make beautifull message in case of exception |
401 # while loading secret (if empty or dont exist) |
422 # while loading secret (if empty or dont exist) |
402 secret = LoadWampSecret(_WampSecret) |
423 secret = LoadWampSecret(_WampSecret) |
403 return static.Data(secret, 'application/octet-stream'),() |
424 return static.Data(secret, 'application/octet-stream'), () |
|
425 |
404 |
426 |
405 def RegisterWebSettings(NS): |
427 def RegisterWebSettings(NS): |
406 NS.ConfigurableSettings.addExtension( |
428 NS.ConfigurableSettings.addExtension( |
407 "wamp", |
429 "wamp", |
408 _("Wamp Settings"), |
430 _("Wamp Settings"), |
409 webFormInterface, |
431 webFormInterface, |
410 _("Set"), |
432 _("Set"), |
411 wampConfig) |
433 wampConfig) |
412 |
434 |
413 |
|
414 NS.customSettingsURLs[WAMP_SECRET_URL] = deliverWampSecret |
435 NS.customSettingsURLs[WAMP_SECRET_URL] = deliverWampSecret |
415 |
|