From c79636863d8bae013e929c0ab842fd40d0cd13c2 Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Thu, 5 Dec 2019 18:17:35 +0200
Subject: [PATCH 01/13] If tray is not available, disable settings group "Tray"
and related checkboxes; set checkBoxMinimizeToTray to false by default
---
src/bitmessageqt/settings.py | 39 +++++++++++++++++++++++++-----------
src/bitmessageqt/settings.ui | 2 +-
2 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py
index 982328cc..7fb0ea91 100644
--- a/src/bitmessageqt/settings.py
+++ b/src/bitmessageqt/settings.py
@@ -47,20 +47,33 @@ class SettingsDialog(QtGui.QDialog):
def adjust_from_config(self, config):
"""Adjust all widgets state according to config settings"""
# pylint: disable=too-many-branches,too-many-statements
- self.checkBoxStartOnLogon.setChecked(
- config.getboolean('bitmessagesettings', 'startonlogon'))
- self.checkBoxMinimizeToTray.setChecked(
- config.getboolean('bitmessagesettings', 'minimizetotray'))
- self.checkBoxTrayOnClose.setChecked(
- config.safeGetBoolean('bitmessagesettings', 'trayonclose'))
+ if not self.parent.tray.isSystemTrayAvailable():
+ self.groupBoxTray.setEnabled(False)
+ self.groupBoxTray.setTitle(_translate(
+ "MainWindow", "Tray (not available in your system)"))
+ for setting in (
+ 'minimizetotray', 'trayonclose', 'startintray'):
+ config.set('bitmessagesettings', setting, 'false')
+ else:
+ self.checkBoxMinimizeToTray.setChecked(
+ config.getboolean('bitmessagesettings', 'minimizetotray'))
+ self.checkBoxTrayOnClose.setChecked(
+ config.safeGetBoolean('bitmessagesettings', 'trayonclose'))
+ self.checkBoxStartInTray.setChecked(
+ config.getboolean('bitmessagesettings', 'startintray'))
+
self.checkBoxHideTrayConnectionNotifications.setChecked(
- config.getboolean("bitmessagesettings", "hidetrayconnectionnotifications"))
+ config.getboolean(
+ 'bitmessagesettings', 'hidetrayconnectionnotifications'))
self.checkBoxShowTrayNotifications.setChecked(
config.getboolean('bitmessagesettings', 'showtraynotifications'))
- self.checkBoxStartInTray.setChecked(
- config.getboolean('bitmessagesettings', 'startintray'))
+
+ self.checkBoxStartOnLogon.setChecked(
+ config.getboolean('bitmessagesettings', 'startonlogon'))
+
self.checkBoxWillinglySendToMobile.setChecked(
- config.safeGetBoolean('bitmessagesettings', 'willinglysendtomobile'))
+ config.safeGetBoolean(
+ 'bitmessagesettings', 'willinglysendtomobile'))
self.checkBoxUseIdenticons.setChecked(
config.safeGetBoolean('bitmessagesettings', 'useidenticons'))
self.checkBoxReplyBelow.setChecked(
@@ -82,10 +95,12 @@ class SettingsDialog(QtGui.QDialog):
"MainWindow", "Start-on-login not yet supported on your OS."))
self.checkBoxMinimizeToTray.setDisabled(True)
self.checkBoxMinimizeToTray.setText(_translate(
- "MainWindow", "Minimize-to-tray not yet supported on your OS."))
+ "MainWindow",
+ "Minimize-to-tray not yet supported on your OS."))
self.checkBoxShowTrayNotifications.setDisabled(True)
self.checkBoxShowTrayNotifications.setText(_translate(
- "MainWindow", "Tray notifications not yet supported on your OS."))
+ "MainWindow",
+ "Tray notifications not yet supported on your OS."))
elif 'linux' in sys.platform:
self.checkBoxStartOnLogon.setDisabled(True)
self.checkBoxStartOnLogon.setText(_translate(
diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui
index 963f2e64..33278e94 100644
--- a/src/bitmessageqt/settings.ui
+++ b/src/bitmessageqt/settings.ui
@@ -75,7 +75,7 @@
Minimize to tray
- true
+ false
From 5a35de6bca4385431905be5a59f004f7bfd2896c Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Fri, 20 Dec 2019 15:20:14 +0200
Subject: [PATCH 02/13] Fix sendOnionPeerObj() broken in 9923e97
---
src/class_singleWorker.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py
index a275b79d..d035c092 100644
--- a/src/class_singleWorker.py
+++ b/src/class_singleWorker.py
@@ -467,8 +467,8 @@ class singleWorker(StoppableThread):
def sendOnionPeerObj(self, peer=None):
"""Send onionpeer object representing peer"""
if not peer: # find own onionhostname
- for peer_ in state.ownAddresses:
- if peer_.host.endswith('.onion'):
+ for peer in state.ownAddresses:
+ if peer.host.endswith('.onion'):
break
else:
return
From 03316496b7c3380c5ac408f86d049855dbcedac6 Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Sat, 14 Dec 2019 12:53:51 +0200
Subject: [PATCH 03/13] Stop UDPSocket on socket.error 101 (Network is
unreachable)
---
src/network/udp.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/network/udp.py b/src/network/udp.py
index cf694567..d8c5f340 100644
--- a/src/network/udp.py
+++ b/src/network/udp.py
@@ -146,6 +146,9 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes
retval = self.socket.sendto(
self.write_buf, ('', self.port))
except socket.error as e:
- logger.error("socket error on sendato: %s", e)
+ logger.error("socket error on sendto: %s", e)
+ if e.errno == 101:
+ self.announcing = False
+ self.socket.close()
retval = 0
self.slice_write_buf(retval)
From 9119507b033372cdca432eb45c3d3d897455bd4b Mon Sep 17 00:00:00 2001
From: sandakersmann
Date: Fri, 27 Dec 2019 18:23:02 +0100
Subject: [PATCH 04/13] Changed copyright year to 2020
---
COPYING | 2 +-
LICENSE | 2 +-
src/api.py | 2 +-
src/bitmessagemain.py | 2 +-
src/bitmessageqt/about.ui | 2 +-
src/bitmessageqt/dialogs.py | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/COPYING b/COPYING
index 2e0ae6c1..078bf213 100644
--- a/COPYING
+++ b/COPYING
@@ -1,5 +1,5 @@
Copyright (c) 2012-2016 Jonathan Warren
-Copyright (c) 2012-2019 The Bitmessage Developers
+Copyright (c) 2012-2020 The Bitmessage Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/LICENSE b/LICENSE
index 3be738c0..6bb86242 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2012-2016 Jonathan Warren
-Copyright (c) 2012-2019 The Bitmessage Developers
+Copyright (c) 2012-2020 The Bitmessage Developers
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/src/api.py b/src/api.py
index f9d0a518..3201fba5 100644
--- a/src/api.py
+++ b/src/api.py
@@ -2,7 +2,7 @@
# pylint: disable=too-many-statements
# Copyright (c) 2012-2016 Jonathan Warren
-# Copyright (c) 2012-2019 The Bitmessage developers
+# Copyright (c) 2012-2020 The Bitmessage developers
"""
This is not what you run to run the Bitmessage API. Instead, enable the API
diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py
index 176125cc..96885b5e 100755
--- a/src/bitmessagemain.py
+++ b/src/bitmessagemain.py
@@ -3,7 +3,7 @@
The PyBitmessage startup script
"""
# Copyright (c) 2012-2016 Jonathan Warren
-# Copyright (c) 2012-2019 The Bitmessage developers
+# Copyright (c) 2012-2020 The Bitmessage developers
# Distributed under the MIT/X11 software license. See the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bitmessageqt/about.ui b/src/bitmessageqt/about.ui
index a912927a..7073bbd1 100644
--- a/src/bitmessageqt/about.ui
+++ b/src/bitmessageqt/about.ui
@@ -46,7 +46,7 @@
-
- <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2012-2019 The Bitmessage Developers</p></body></html>
+ <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2012-2020 The Bitmessage Developers</p></body></html>
Qt::AlignLeft
diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py
index b4bcd2fd..c667edb1 100644
--- a/src/bitmessageqt/dialogs.py
+++ b/src/bitmessageqt/dialogs.py
@@ -47,7 +47,7 @@ class AboutDialog(QtGui.QDialog, RetranslateMixin):
try:
self.label_2.setText(
self.label_2.text().replace(
- '2019', str(last_commit.get('time').year)
+ '2020', str(last_commit.get('time').year)
))
except AttributeError:
pass
From 168c4a5696510bb3c6256b519352a6b0413dd713 Mon Sep 17 00:00:00 2001
From: Peter Surda
Date: Tue, 3 Dec 2019 12:59:27 +0100
Subject: [PATCH 05/13] Checkdeps fix
- an exception can be triggered if too many requirements are fulfilled
---
checkdeps.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/checkdeps.py b/checkdeps.py
index 03782037..45dc2fc9 100755
--- a/checkdeps.py
+++ b/checkdeps.py
@@ -164,7 +164,7 @@ if (not compiler or prereqs) and OPSYS in PACKAGE_MANAGER:
if not compiler:
compilerToPackages()
prereqToPackages()
- if mandatory:
+ if prereqs and mandatory:
sys.exit(1)
else:
print("All the dependencies satisfied, you can install PyBitmessage")
From c35f48bd0bdd7581571be6ee111d6530c00246b8 Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Sun, 22 Sep 2019 15:35:10 +0300
Subject: [PATCH 06/13] Fix setting socksproxytype and return in
proxyconfig_stem:
socksproxytype is set to SOCKS5 temporary if proxyconfig succeeds.
---
src/plugins/proxyconfig_stem.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py
index bdbfe8ca..e56aecc6 100644
--- a/src/plugins/proxyconfig_stem.py
+++ b/src/plugins/proxyconfig_stem.py
@@ -43,6 +43,7 @@ def connect_plugin(config): # pylint: disable=too-many-branches
):
# remote proxy is choosen for outbound connections,
# nothing to do here, but need to set socksproxytype to SOCKS5!
+ config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
logwrite(
'sockshostname is set to remote address,'
' aborting stem proxy configuration')
@@ -77,6 +78,8 @@ def connect_plugin(config): # pylint: disable=too-many-branches
logwrite('Started tor on port %s' % port)
break
+ config.setTemp('bitmessagesettings', 'socksproxytype', 'SOCKS5')
+
if config.safeGetBoolean('bitmessagesettings', 'sockslisten'):
# need a hidden service for inbound connections
try:
@@ -117,6 +120,5 @@ def connect_plugin(config): # pylint: disable=too-many-branches
config.set(
onionhostname, 'keytype', response.private_key_type)
config.save()
- config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
- return True
+ return True
From 44cb975a611dcca0f40f328f44f517962f013a52 Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Fri, 18 Oct 2019 17:52:00 +0300
Subject: [PATCH 07/13] Fixed bug in plugin.get_plugins(), edited docstrings
---
src/plugins/__init__.py | 7 +++++++
src/plugins/plugin.py | 27 ++++++++++++++++++++-------
2 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/src/plugins/__init__.py b/src/plugins/__init__.py
index e69de29b..285009df 100644
--- a/src/plugins/__init__.py
+++ b/src/plugins/__init__.py
@@ -0,0 +1,7 @@
+"""
+Simple plugin system based on setuptools
+----------------------------------------
+
+
+"""
+# .. include:: pybitmessage.plugins.plugin.rst
diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py
index e671a73f..629de0a6 100644
--- a/src/plugins/plugin.py
+++ b/src/plugins/plugin.py
@@ -1,19 +1,28 @@
# -*- coding: utf-8 -*-
"""
-src/plugins/plugin.py
-===================================
+Operating with plugins
"""
+import logging
+
import pkg_resources
+logger = logging.getLogger('default')
+
+
def get_plugins(group, point='', name=None, fallback=None):
"""
- Iterate through plugins (`connect_plugin` attribute of entry point)
- which name starts with `point` or equals to `name`.
- If `fallback` kwarg specified, plugin with that name yield last.
+ :param str group: plugin group
+ :param str point: plugin name prefix
+ :param name: exact plugin name
+ :param fallback: fallback plugin name
+
+ Iterate through plugins (``connect_plugin`` attribute of entry point)
+ which name starts with ``point`` or equals to ``name``.
+ If ``fallback`` kwarg specified, plugin with that name yield last.
"""
for ep in pkg_resources.iter_entry_points('bitmessage.' + group):
- if name and ep.name == name or ep.name.startswith(point):
+ if name and ep.name == name or not point or ep.name.startswith(point):
try:
plugin = ep.load().connect_plugin
if ep.name == fallback:
@@ -25,6 +34,8 @@ def get_plugins(group, point='', name=None, fallback=None):
ValueError,
pkg_resources.DistributionNotFound,
pkg_resources.UnknownExtra):
+ logger.debug(
+ 'Problem while loading %s', ep.name, exc_info=True)
continue
try:
yield _fallback
@@ -33,6 +44,8 @@ def get_plugins(group, point='', name=None, fallback=None):
def get_plugin(*args, **kwargs):
- """Returns first available plugin `from get_plugins()` if any."""
+ """
+ :return: first available plugin from :func:`get_plugins` if any.
+ """
for plugin in get_plugins(*args, **kwargs):
return plugin
From 5160a68c28a3493e4c0bb55a4169cef350e2058e Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Fri, 18 Oct 2019 17:52:44 +0300
Subject: [PATCH 08/13] Moved start_proxyconfig to helper_startup;
no more prints in helper_startup
---
src/bitmessagemain.py | 32 ++++++----------------------
src/helper_startup.py | 49 ++++++++++++++++++++++++++++++++++++-------
src/tests/core.py | 9 ++++----
3 files changed, 51 insertions(+), 39 deletions(-)
diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py
index 96885b5e..48ed9738 100755
--- a/src/bitmessagemain.py
+++ b/src/bitmessagemain.py
@@ -39,7 +39,8 @@ import shutdown
from bmconfigparser import BMConfigParser
from debug import logger # this should go before any threads
from helper_startup import (
- isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections
+ isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections,
+ start_proxyconfig
)
from inventory import Inventory
from knownnodes import readKnownNodes
@@ -168,30 +169,9 @@ def signal_handler(signum, frame):
class Main(object):
"""Main PyBitmessage class"""
- @staticmethod
- def start_proxyconfig(config):
- """Check socksproxytype and start any proxy configuration plugin"""
- proxy_type = config.safeGet('bitmessagesettings', 'socksproxytype')
- if proxy_type not in ('none', 'SOCKS4a', 'SOCKS5'):
- # pylint: disable=relative-import
- from plugins.plugin import get_plugin
- try:
- proxyconfig_start = time.time()
- if not get_plugin('proxyconfig', name=proxy_type)(config):
- raise TypeError
- except TypeError:
- logger.error(
- 'Failed to run proxy config plugin %s',
- proxy_type, exc_info=True)
- shutdown.doCleanShutdown()
- sys.exit(2)
- else:
- logger.info(
- 'Started proxy config plugin %s in %s sec',
- proxy_type, time.time() - proxyconfig_start)
-
- def start(self): # pylint: disable=too-many-statements, too-many-branches, too-many-locals
+ def start(self):
"""Start main application"""
+ # pylint: disable=too-many-statements,too-many-branches,too-many-locals
_fixSocket()
config = BMConfigParser()
@@ -350,7 +330,7 @@ class Main(object):
# start network components if networking is enabled
if state.enableNetwork:
- self.start_proxyconfig(config)
+ start_proxyconfig()
BMConnectionPool()
asyncoreThread = BMNetworkThread()
asyncoreThread.daemon = True
@@ -410,7 +390,7 @@ class Main(object):
self.stop()
elif not state.enableGUI:
from tests import core as test_core # pylint: disable=relative-import
- test_core_result = test_core.run(self)
+ test_core_result = test_core.run()
state.enableGUI = True
self.stop()
test_core.cleanup()
diff --git a/src/helper_startup.py b/src/helper_startup.py
index 9aaad5ef..9711c339 100644
--- a/src/helper_startup.py
+++ b/src/helper_startup.py
@@ -2,11 +2,12 @@
Startup operations.
"""
# pylint: disable=too-many-branches,too-many-statements
-from __future__ import print_function
+import logging
import os
import platform
import sys
+import time
from distutils.version import StrictVersion
import defaults
@@ -15,6 +16,13 @@ import paths
import state
from bmconfigparser import BMConfigParser
+try:
+ from plugins.plugin import get_plugin
+except ImportError:
+ get_plugin = None
+
+
+logger = logging.getLogger('default')
# The user may de-select Portable Mode in the settings if they want
# the config files to stay in the application data folder.
@@ -30,14 +38,14 @@ def loadConfig():
needToCreateKeysFile = config.safeGet(
'bitmessagesettings', 'settingsversion') is None
if not needToCreateKeysFile:
- print(
+ logger.info(
'Loading config files from directory specified'
- ' on startup: %s' % state.appdata)
+ ' on startup: %s', state.appdata)
else:
config.read(paths.lookupExeFolder() + 'keys.dat')
try:
config.get('bitmessagesettings', 'settingsversion')
- print('Loading config files from same directory as program.')
+ logger.info('Loading config files from same directory as program.')
needToCreateKeysFile = False
state.appdata = paths.lookupExeFolder()
except:
@@ -48,7 +56,8 @@ def loadConfig():
needToCreateKeysFile = config.safeGet(
'bitmessagesettings', 'settingsversion') is None
if not needToCreateKeysFile:
- print('Loading existing config files from', state.appdata)
+ logger.info(
+ 'Loading existing config files from %s', state.appdata)
if needToCreateKeysFile:
@@ -103,9 +112,10 @@ def loadConfig():
# Just use the same directory as the program and forget about
# the appdata folder
state.appdata = ''
- print('Creating new config files in same directory as program.')
+ logger.info(
+ 'Creating new config files in same directory as program.')
else:
- print('Creating new config files in', state.appdata)
+ logger.info('Creating new config files in %s', state.appdata)
if not os.path.exists(state.appdata):
os.makedirs(state.appdata)
if not sys.platform.startswith('win'):
@@ -255,7 +265,7 @@ def updateConfig():
'bitmessagesettings', 'hidetrayconnectionnotifications', 'false')
if config.safeGetInt('bitmessagesettings', 'maxoutboundconnections') < 1:
config.set('bitmessagesettings', 'maxoutboundconnections', '8')
- print('WARNING: your maximum outbound connections must be a number.')
+ logger.warning('Your maximum outbound connections must be a number.')
# TTL is now user-specifiable. Let's add an option to save
# whatever the user selects.
@@ -278,3 +288,26 @@ def isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections():
return False
except Exception:
pass
+
+
+def start_proxyconfig():
+ """Check socksproxytype and start any proxy configuration plugin"""
+ if not get_plugin:
+ return
+ config = BMConfigParser()
+ proxy_type = config.safeGet('bitmessagesettings', 'socksproxytype')
+ if proxy_type and proxy_type not in ('none', 'SOCKS4a', 'SOCKS5'):
+ try:
+ proxyconfig_start = time.time()
+ if not get_plugin('proxyconfig', name=proxy_type)(config):
+ raise TypeError()
+ except TypeError:
+ # cannot import shutdown here ):
+ logger.error(
+ 'Failed to run proxy config plugin %s',
+ proxy_type, exc_info=True)
+ os._exit(0) # pylint: disable=protected-access
+ else:
+ logger.info(
+ 'Started proxy config plugin %s in %s sec',
+ proxy_type, time.time() - proxyconfig_start)
diff --git a/src/tests/core.py b/src/tests/core.py
index d2456064..84971dc5 100644
--- a/src/tests/core.py
+++ b/src/tests/core.py
@@ -14,6 +14,7 @@ import unittest
import knownnodes
import state
from bmconfigparser import BMConfigParser
+from helper_startup import start_proxyconfig
from helper_msgcoding import MsgEncode, MsgDecode
from network import asyncore_pollchoose as asyncore
from network.connectionpool import BMConnectionPool
@@ -21,8 +22,8 @@ from network.node import Peer
from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection
from queues import excQueue
+
knownnodes_file = os.path.join(state.appdata, 'knownnodes.dat')
-program = None
def pickle_knownnodes():
@@ -196,14 +197,12 @@ class TestCore(unittest.TestCase):
self._check_bootstrap()
self._initiate_bootstrap()
BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'stem')
- program.start_proxyconfig(BMConfigParser())
+ start_proxyconfig()
self._check_bootstrap()
-def run(prog):
+def run():
"""Starts all tests defined in this module"""
- global program # pylint: disable=global-statement
- program = prog
loader = unittest.TestLoader()
loader.sortTestMethodsUsing = None
suite = loader.loadTestsFromTestCase(TestCore)
From e3ccc3c7c8e4d3662adb8e20e20f1d8a32687e83 Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Thu, 3 Oct 2019 18:34:27 +0300
Subject: [PATCH 09/13] Support for socksproxytype plugins in Settings dialog
---
src/bitmessageqt/settings.py | 64 +++++++++++++++++++-----------------
src/bitmessageqt/settings.ui | 4 +--
2 files changed, 35 insertions(+), 33 deletions(-)
diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py
index 7fb0ea91..8fe1ecba 100644
--- a/src/bitmessageqt/settings.py
+++ b/src/bitmessageqt/settings.py
@@ -1,3 +1,4 @@
+import ConfigParser
import os
import sys
@@ -16,6 +17,7 @@ import tempfile
import widgets
from bmconfigparser import BMConfigParser
from helper_sql import sqlExecute, sqlStoredProcedure
+from helper_startup import start_proxyconfig
from network.asyncore_pollchoose import set_rates
from tr import _translate
@@ -32,6 +34,16 @@ class SettingsDialog(QtGui.QDialog):
self.net_restart_needed = False
self.timer = QtCore.QTimer()
+ try:
+ import pkg_resources
+ except ImportError:
+ pass
+ else:
+ # Append proxy types defined in plugins
+ for ep in pkg_resources.iter_entry_points(
+ 'bitmessage.proxyconfig'):
+ self.comboBoxProxyType.addItem(ep.name)
+
self.lineEditMaxOutboundConnections.setValidator(
QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections))
@@ -117,21 +129,16 @@ class SettingsDialog(QtGui.QDialog):
self.checkBoxOnionOnly.setChecked(
config.safeGetBoolean('bitmessagesettings', 'onionservicesonly'))
- proxy_type = config.safeGet(
- 'bitmessagesettings', 'socksproxytype', 'none')
- if proxy_type == 'none':
- self.comboBoxProxyType.setCurrentIndex(0)
- self.lineEditSocksHostname.setEnabled(False)
- self.lineEditSocksPort.setEnabled(False)
- self.lineEditSocksUsername.setEnabled(False)
- self.lineEditSocksPassword.setEnabled(False)
- self.checkBoxAuthentication.setEnabled(False)
- self.checkBoxSocksListen.setEnabled(False)
- self.checkBoxOnionOnly.setEnabled(False)
- elif proxy_type == 'SOCKS4a':
- self.comboBoxProxyType.setCurrentIndex(1)
- elif proxy_type == 'SOCKS5':
- self.comboBoxProxyType.setCurrentIndex(2)
+ try:
+ # Get real value, not temporary
+ self._proxy_type = ConfigParser.SafeConfigParser.get(
+ config, 'bitmessagesettings', 'socksproxytype')
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ self._proxy_type = 'none'
+ self.comboBoxProxyType.setCurrentIndex(
+ 0 if self._proxy_type == 'none'
+ else self.comboBoxProxyType.findText(self._proxy_type))
+ self.comboBoxProxyTypeChanged(self.comboBoxProxyType.currentIndex())
self.lineEditSocksHostname.setText(
config.get('bitmessagesettings', 'sockshostname'))
@@ -219,7 +226,7 @@ class SettingsDialog(QtGui.QDialog):
self.checkBoxAuthentication.setEnabled(False)
self.checkBoxSocksListen.setEnabled(False)
self.checkBoxOnionOnly.setEnabled(False)
- elif comboBoxIndex in (1, 2):
+ else:
self.lineEditSocksHostname.setEnabled(True)
self.lineEditSocksPort.setEnabled(True)
self.checkBoxAuthentication.setEnabled(True)
@@ -321,27 +328,22 @@ class SettingsDialog(QtGui.QDialog):
upnpThread = upnp.uPnPThread()
upnpThread.start()
- proxy_type = self.config.safeGet(
- 'bitmessagesettings', 'socksproxytype', 'none')
- if (
- proxy_type == 'none' and
- self.comboBoxProxyType.currentText()[0:5] == 'SOCKS' and
- shared.statusIconColor != 'red'
- ):
- self.net_restart_needed = True
- if (
- proxy_type[0:5] == 'SOCKS' and
- self.comboBoxProxyType.currentText()[0:5] != 'SOCKS'
- ):
+ proxytype_index = self.comboBoxProxyType.currentIndex()
+ if proxytype_index == 0:
+ if self._proxy_type != 'none' and shared.statusIconColor != 'red':
+ self.net_restart_needed = True
+ elif self.comboBoxProxyType.currentText() != self._proxy_type:
self.net_restart_needed = True
self.parent.statusbar.clearMessage()
self.config.set(
'bitmessagesettings', 'socksproxytype',
- str(self.comboBoxProxyType.currentText())
- if self.comboBoxProxyType.currentText()[0:5] == 'SOCKS'
- else 'none'
+ 'none' if self.comboBoxProxyType.currentIndex() == 0
+ else str(self.comboBoxProxyType.currentText())
)
+ if proxytype_index > 2: # last literal proxytype in ui
+ start_proxyconfig()
+
self.config.set('bitmessagesettings', 'socksauthentication', str(
self.checkBoxAuthentication.isChecked()))
self.config.set('bitmessagesettings', 'sockshostname', str(
diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui
index 33278e94..0ffbf442 100644
--- a/src/bitmessageqt/settings.ui
+++ b/src/bitmessageqt/settings.ui
@@ -419,12 +419,12 @@
-
- SOCKS4a
+ SOCKS4a
-
- SOCKS5
+ SOCKS5
From 2bddae511a84fae6c4830ce7903e442c77de5673 Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Mon, 21 Oct 2019 15:20:29 +0300
Subject: [PATCH 10/13] Fixed some mistakes in tor dependent tests and marked
them
for skipping until the finish of debug.
---
requirements.txt | 1 -
src/tests/core.py | 48 +++++++++++++++++++++++++++++++----------------
2 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/requirements.txt b/requirements.txt
index be429a9f..c55e5cf1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,3 @@
python_prctl
psutil
pycrypto
-stem
diff --git a/src/tests/core.py b/src/tests/core.py
index 84971dc5..d56076c3 100644
--- a/src/tests/core.py
+++ b/src/tests/core.py
@@ -14,14 +14,19 @@ import unittest
import knownnodes
import state
from bmconfigparser import BMConfigParser
-from helper_startup import start_proxyconfig
from helper_msgcoding import MsgEncode, MsgDecode
+from helper_startup import start_proxyconfig
from network import asyncore_pollchoose as asyncore
from network.connectionpool import BMConnectionPool
from network.node import Peer
from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection
from queues import excQueue
+try:
+ import stem.version as stem_version
+except ImportError:
+ stem_version = None
+
knownnodes_file = os.path.join(state.appdata, 'knownnodes.dat')
@@ -171,12 +176,29 @@ class TestCore(unittest.TestCase):
self.assertIsInstance(con, connection_base)
self.assertNotEqual(peer.host, '127.0.0.1')
return
- else: # pylint: disable=useless-else-on-loop
- self.fail(
- 'Failed to connect during %s sec' % (time.time() - _started))
+ self.fail(
+ 'Failed to connect during %s sec' % (time.time() - _started))
- def test_onionservicesonly(self):
- """test onionservicesonly networking mode"""
+ def test_bootstrap(self):
+ """test bootstrapping"""
+ self._initiate_bootstrap()
+ self._check_bootstrap()
+
+ @unittest.skipUnless(stem_version, 'No stem, skipping tor dependent test')
+ def test_bootstrap_tor(self):
+ """test bootstrapping with tor"""
+ self._initiate_bootstrap()
+ BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'stem')
+ start_proxyconfig()
+ self._check_bootstrap()
+
+ @unittest.skipUnless(stem_version, 'No stem, skipping tor dependent test')
+ def test_onionservicesonly(self): # this should start after bootstrap
+ """
+ set onionservicesonly, wait for 3 connections and check them all
+ are onions
+ """
+ BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
BMConfigParser().set('bitmessagesettings', 'onionservicesonly', 'true')
self._initiate_bootstrap()
BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
@@ -185,21 +207,15 @@ class TestCore(unittest.TestCase):
for n, peer in enumerate(BMConnectionPool().outboundConnections):
if n > 2:
return
- if not peer.host.endswith('.onion'):
+ if (
+ not peer.host.endswith('.onion')
+ and not peer.host.startswith('bootstrap')
+ ):
self.fail(
'Found non onion hostname %s in outbound connections!'
% peer.host)
self.fail('Failed to connect to at least 3 nodes within 360 sec')
- def test_bootstrap(self):
- """test bootstrapping"""
- self._initiate_bootstrap()
- self._check_bootstrap()
- self._initiate_bootstrap()
- BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'stem')
- start_proxyconfig()
- self._check_bootstrap()
-
def run():
"""Starts all tests defined in this module"""
From 52d5c1ff03707829b5055ef71015c0da369fb09d Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Tue, 22 Oct 2019 10:10:41 +0300
Subject: [PATCH 11/13] Document proxyconfig_stem
---
src/plugins/proxyconfig_stem.py | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py
index e56aecc6..cbc6395d 100644
--- a/src/plugins/proxyconfig_stem.py
+++ b/src/plugins/proxyconfig_stem.py
@@ -1,7 +1,15 @@
# -*- coding: utf-8 -*-
"""
-src/plugins/proxyconfig_stem.py
-===================================
+Configure tor proxy and hidden service with
+`stem `_ depending on *bitmessagesettings*:
+
+ * try to start own tor instance on *socksport* if *sockshostname*
+ is unset or set to localhost;
+ * if *socksport* is already in use that instance is used only for
+ hidden service (if *sockslisten* is also set True);
+ * create ephemeral hidden service v3 if there is already *onionhostname*;
+ * otherwise use stem's 'BEST' version and save onion keys to the new
+ section using *onionhostname* as name for future use.
"""
import os
import logging
@@ -36,10 +44,16 @@ class DebugLogger(object):
def connect_plugin(config): # pylint: disable=too-many-branches
- """Run stem proxy configurator"""
+ """
+ Run stem proxy configurator
+
+ :param config: current configuration instance
+ :type config: :class:`pybitmessage.bmconfigparser.BMConfigParser`
+ :return: True if configuration was done successfully
+ """
logwrite = DebugLogger()
- if config.safeGet('bitmessagesettings', 'sockshostname') not in (
- 'localhost', '127.0.0.1', ''
+ if config.safeGet('bitmessagesettings', 'sockshostname', '') not in (
+ 'localhost', '127.0.0.1', ''
):
# remote proxy is choosen for outbound connections,
# nothing to do here, but need to set socksproxytype to SOCKS5!
From 1c4d7655c3a58e067db4a872b747fe5a39c3c181 Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Sat, 7 Dec 2019 21:33:30 +0200
Subject: [PATCH 12/13] Fix socksproxytype in the support message,
made that a separate function getSOCKSProxyType(config) in the settings.
---
src/bitmessageqt/settings.py | 24 ++++++++++++++++--------
src/bitmessageqt/support.py | 4 ++--
2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py
index 8fe1ecba..011d38ed 100644
--- a/src/bitmessageqt/settings.py
+++ b/src/bitmessageqt/settings.py
@@ -22,6 +22,19 @@ from network.asyncore_pollchoose import set_rates
from tr import _translate
+def getSOCKSProxyType(config):
+ """Get user socksproxytype setting from *config*"""
+ try:
+ result = ConfigParser.SafeConfigParser.get(
+ config, 'bitmessagesettings', 'socksproxytype')
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ return
+ else:
+ if result.lower() in ('', 'none', 'false'):
+ result = None
+ return result
+
+
class SettingsDialog(QtGui.QDialog):
"""The "Settings" dialog"""
def __init__(self, parent=None, firstrun=False):
@@ -129,14 +142,9 @@ class SettingsDialog(QtGui.QDialog):
self.checkBoxOnionOnly.setChecked(
config.safeGetBoolean('bitmessagesettings', 'onionservicesonly'))
- try:
- # Get real value, not temporary
- self._proxy_type = ConfigParser.SafeConfigParser.get(
- config, 'bitmessagesettings', 'socksproxytype')
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- self._proxy_type = 'none'
+ self._proxy_type = getSOCKSProxyType(config)
self.comboBoxProxyType.setCurrentIndex(
- 0 if self._proxy_type == 'none'
+ 0 if not self._proxy_type
else self.comboBoxProxyType.findText(self._proxy_type))
self.comboBoxProxyTypeChanged(self.comboBoxProxyType.currentIndex())
@@ -330,7 +338,7 @@ class SettingsDialog(QtGui.QDialog):
proxytype_index = self.comboBoxProxyType.currentIndex()
if proxytype_index == 0:
- if self._proxy_type != 'none' and shared.statusIconColor != 'red':
+ if self._proxy_type and shared.statusIconColor != 'red':
self.net_restart_needed = True
elif self.comboBoxProxyType.currentText() != self._proxy_type:
self.net_restart_needed = True
diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py
index 2a1ddb18..d6d4543d 100644
--- a/src/bitmessageqt/support.py
+++ b/src/bitmessageqt/support.py
@@ -15,6 +15,7 @@ from openclpow import openclAvailable, openclEnabled
import paths
import proofofwork
from pyelliptic.openssl import OpenSSL
+from settings import getSOCKSProxyType
import queues
import network.stats
import state
@@ -118,8 +119,7 @@ def createSupportMessage(myapp):
BMConfigParser().safeGet('bitmessagesettings', 'opencl')
) if openclEnabled() else "None"
locale = getTranslationLanguage()
- socks = BMConfigParser().safeGet(
- 'bitmessagesettings', 'socksproxytype', "N/A")
+ socks = getSOCKSProxyType(BMConfigParser()) or "N/A"
upnp = BMConfigParser().safeGet('bitmessagesettings', 'upnp', "N/A")
connectedhosts = len(network.stats.connectedHostsList())
From 61f64f72c36b315ef8663176d6cc2474af4457ea Mon Sep 17 00:00:00 2001
From: Dmitri Bogomolov <4glitch@gmail.com>
Date: Fri, 20 Dec 2019 10:53:31 +0200
Subject: [PATCH 13/13] Fixing port for hidden service
---
src/plugins/proxyconfig_stem.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/plugins/proxyconfig_stem.py b/src/plugins/proxyconfig_stem.py
index cbc6395d..494519f2 100644
--- a/src/plugins/proxyconfig_stem.py
+++ b/src/plugins/proxyconfig_stem.py
@@ -112,7 +112,8 @@ def connect_plugin(config): # pylint: disable=too-many-branches
onionkeytype = config.safeGet(onionhostname, 'keytype')
response = controller.create_ephemeral_hidden_service(
- config.safeGetInt('bitmessagesettings', 'onionport', 8444),
+ {config.safeGetInt('bitmessagesettings', 'onionport', 8444):
+ config.safeGetInt('bitmessagesettings', 'port', 8444)},
key_type=(onionkeytype or 'NEW'),
key_content=(onionkey or onionhostname and 'ED25519-V3' or 'BEST')
)