From 7b76b77c64e2a42a90d5e49d5822433ee2cf6c67 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Mar 2017 15:57:39 +0100 Subject: [PATCH] Bitmessage Plugin - allows sending messages through Bitmessage API - no folder listing / message retrieving yet - no address selection yet, uses the "zeronet-test" chan both for sending and receiving - API configured through command line / zeronet.conf - should reuse the xmlrpc socket and be thread-safe - test site: http://127.0.0.1:43110/1EEx89QjgGgNd9qRDErswEHb82bqWYcPuz --- plugins/Bitmessage/BMAPI.py | 44 ++++++++++++++++++++++++ plugins/Bitmessage/BMIO.py | 7 ++++ plugins/Bitmessage/BitmessagePlugin.py | 46 ++++++++++++++++++++++++++ plugins/Bitmessage/Singleton.py | 7 ++++ plugins/Bitmessage/Test/TestMessage.py | 11 ++++++ plugins/Bitmessage/Test/conftest.py | 1 + plugins/Bitmessage/Test/pytest.ini | 5 +++ plugins/Bitmessage/__init__.py | 1 + 8 files changed, 122 insertions(+) create mode 100644 plugins/Bitmessage/BMAPI.py create mode 100644 plugins/Bitmessage/BMIO.py create mode 100644 plugins/Bitmessage/BitmessagePlugin.py create mode 100644 plugins/Bitmessage/Singleton.py create mode 100644 plugins/Bitmessage/Test/TestMessage.py create mode 100644 plugins/Bitmessage/Test/conftest.py create mode 100644 plugins/Bitmessage/Test/pytest.ini create mode 100644 plugins/Bitmessage/__init__.py diff --git a/plugins/Bitmessage/BMAPI.py b/plugins/Bitmessage/BMAPI.py new file mode 100644 index 000000000..9cecf4c9a --- /dev/null +++ b/plugins/Bitmessage/BMAPI.py @@ -0,0 +1,44 @@ +import json +import threading +import traceback +import xmlrpclib + +from Singleton import Singleton +from Config import config + +@Singleton +class BMAPI(object): + thrdata = None + def __init__(self): + self.thrdata = threading.local() + self.connect() + + def check_connection(self): + if not (hasattr(self.thrdata, 'con') and self.thrdata.con is not None): + self.connect() + return self.thrdata.con + + def connect(self): + try: + self.thrdata.con = xmlrpclib.ServerProxy( + 'http://' + + config.bitmessage_username + ':' + + config.bitmessage_password + '@' + + config.bitmessage_host + ':' + + config.bitmessage_port + '/') + except: + traceback.print_exc() + try: + response = self.thrdata.con.add(2, 2) + except: + self.thrdata.con = None + traceback.print_exc() + if self.thrdata.con is not None: + return self.thrdata.con + return False + + def disconnect(self): + self.thrdata.con = None + + def conn(self): + return self.check_connection() diff --git a/plugins/Bitmessage/BMIO.py b/plugins/Bitmessage/BMIO.py new file mode 100644 index 000000000..a861b9f30 --- /dev/null +++ b/plugins/Bitmessage/BMIO.py @@ -0,0 +1,7 @@ +from base64 import b64encode + +from BMAPI import BMAPI + +def sendMessage(sender, recipient, subject, body): + ackData = BMAPI().conn().sendMessage(recipient, sender, b64encode(subject), b64encode(body), 2) + return ackData diff --git a/plugins/Bitmessage/BitmessagePlugin.py b/plugins/Bitmessage/BitmessagePlugin.py new file mode 100644 index 000000000..d29ed1d32 --- /dev/null +++ b/plugins/Bitmessage/BitmessagePlugin.py @@ -0,0 +1,46 @@ +from Plugin import PluginManager + +import BMIO +from BMAPI import BMAPI + +@PluginManager.registerTo("UiWebsocket") +class UiWebsocketPlugin(object): + def actionSendBitmessage(self, to, text, publickey=0): + if type(publickey) is int: # Encrypt using user's publickey + publickey = self.user.getBitmessage(self.site.address, publickey) + if type(to) is int: # Encrypt using user's publickey + to2 = self.user.getBitmessage(self.site.address, to) + else: + to2 = to + BMAPI().check_connection() + ackData = BMIO.sendMessage(publickey, to2, "ZeroNet message", text) + self.response(to, ackData) + + +@PluginManager.registerTo("User") +class UserPlugin(object): + def getBitmessage(self, address, param_index=0): + assert param_index >= 0 and param_index <= 1000 + site_data = self.getSiteData(address) + + if site_data.get("cert"): # Different privatekey for different cert provider + index = param_index + self.getAddressAuthIndex(site_data["cert"]) + else: + index = param_index + + if "bitmessage_%s" % index not in site_data: + site_data["bitmessage_%s" % index] = "BM-2cVuNdpRNKaPmPCroMxrzS14RXbXZhxPrx" + self.log.debug("New bitmessage address generated for %s:%s" % (address, index)) + return site_data["bitmessage_%s" % index] + + +@PluginManager.registerTo("ConfigPlugin") +class ConfigPlugin(object): + def createArguments(self): + group = self.parser.add_argument_group("Bitmessage plugin") + group.add_argument('--bitmessage_username', help='Username for Bitmessage API', default=None, metavar="username") + group.add_argument('--bitmessage_password', help='Password for Bitmessage API', default=None, metavar="password") + group.add_argument('--bitmessage_host', help='Host for Bitmessage API', default="127.0.0.1", metavar="host") + group.add_argument('--bitmessage_port', help='Port for Bitmessage API', default="8445", metavar="port") + + return super(ConfigPlugin, self).createArguments() diff --git a/plugins/Bitmessage/Singleton.py b/plugins/Bitmessage/Singleton.py new file mode 100644 index 000000000..1eef08e1b --- /dev/null +++ b/plugins/Bitmessage/Singleton.py @@ -0,0 +1,7 @@ +def Singleton(cls): + instances = {} + def getinstance(): + if cls not in instances: + instances[cls] = cls() + return instances[cls] + return getinstance diff --git a/plugins/Bitmessage/Test/TestMessage.py b/plugins/Bitmessage/Test/TestMessage.py new file mode 100644 index 000000000..a3c1e36de --- /dev/null +++ b/plugins/Bitmessage/Test/TestMessage.py @@ -0,0 +1,11 @@ +import pytest + +from binascii import unhexlify + +@pytest.mark.usefixtures("resetSettings") +class TestMessage: + def testSend(self, ui_websocket): + ui_websocket.actionSendBitmessage('BM-2cVuNdpRNKaPmPCroMxrzS14RXbXZhxPrx', "TestMessage", 0) + result = ui_websocket.ws.result + + assert len(unhexlify(result)) == 32 # random 32 bytes hexencoded diff --git a/plugins/Bitmessage/Test/conftest.py b/plugins/Bitmessage/Test/conftest.py new file mode 100644 index 000000000..8c1df5b29 --- /dev/null +++ b/plugins/Bitmessage/Test/conftest.py @@ -0,0 +1 @@ +from src.Test.conftest import * \ No newline at end of file diff --git a/plugins/Bitmessage/Test/pytest.ini b/plugins/Bitmessage/Test/pytest.ini new file mode 100644 index 000000000..d09210d1d --- /dev/null +++ b/plugins/Bitmessage/Test/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +python_files = Test*.py +addopts = -rsxX -v --durations=6 +markers = + webtest: mark a test as a webtest. \ No newline at end of file diff --git a/plugins/Bitmessage/__init__.py b/plugins/Bitmessage/__init__.py new file mode 100644 index 000000000..f088e574d --- /dev/null +++ b/plugins/Bitmessage/__init__.py @@ -0,0 +1 @@ +import BitmessagePlugin