commit after conflicts
This commit is contained in:
parent
102ea32d28
commit
e436b8ecf6
2
COPYING
2
COPYING
|
@ -1,5 +1,5 @@
|
||||||
Copyright (c) 2012-2016 Jonathan Warren
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
Copyright (c) 2012-2016 Jonathan Warren
|
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
|
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
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
|
|
@ -164,7 +164,7 @@ if (not compiler or prereqs) and OPSYS in PACKAGE_MANAGER:
|
||||||
if not compiler:
|
if not compiler:
|
||||||
compilerToPackages()
|
compilerToPackages()
|
||||||
prereqToPackages()
|
prereqToPackages()
|
||||||
if mandatory:
|
if prereqs and mandatory:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
print("All the dependencies satisfied, you can install PyBitmessage")
|
print("All the dependencies satisfied, you can install PyBitmessage")
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
python_prctl
|
python_prctl
|
||||||
psutil
|
psutil
|
||||||
pycrypto
|
pycrypto
|
||||||
stem
|
|
||||||
|
|
|
@ -30,7 +30,8 @@ import queues
|
||||||
import shared
|
import shared
|
||||||
import shutdown
|
import shutdown
|
||||||
import state
|
import state
|
||||||
from addresses import addBMIfNotPresent, calculateInventoryHash, decodeAddress, decodeVarint, varintDecodeError
|
|
||||||
|
from addresses import addBMIfNotPresent, calculateInventoryHash, decodeAddress, decodeVarint, varintDecodeError
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from helper_ackPayload import genAckPayload
|
from helper_ackPayload import genAckPayload
|
||||||
|
|
|
@ -1303,6 +1303,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
"""Method builds the widget"""
|
"""Method builds the widget"""
|
||||||
|
print(os.path.join(os.path.dirname(__file__), 'main.kv'))
|
||||||
main_widget = Builder.load_file(
|
main_widget = Builder.load_file(
|
||||||
os.path.join(os.path.dirname(__file__), 'main.kv'))
|
os.path.join(os.path.dirname(__file__), 'main.kv'))
|
||||||
self.nav_drawer = Navigatorss()
|
self.nav_drawer = Navigatorss()
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
The PyBitmessage startup script
|
The PyBitmessage startup script
|
||||||
"""
|
"""
|
||||||
# Copyright (c) 2012-2016 Jonathan Warren
|
# 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
|
# Distributed under the MIT/X11 software license. See the accompanying
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@ from bmconfigparser import BMConfigParser
|
||||||
# this should go before any threads
|
# this should go before any threads
|
||||||
from debug import logger
|
from debug import logger
|
||||||
from helper_startup import (
|
from helper_startup import (
|
||||||
isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections
|
isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections,
|
||||||
|
start_proxyconfig
|
||||||
)
|
)
|
||||||
from inventory import Inventory
|
from inventory import Inventory
|
||||||
from knownnodes import readKnownNodes
|
from knownnodes import readKnownNodes
|
||||||
|
@ -188,10 +189,9 @@ class Main(object):
|
||||||
logger.info(
|
logger.info(
|
||||||
'Started proxy config plugin %s in %s sec',
|
'Started proxy config plugin %s in %s sec',
|
||||||
proxy_type, time.time() - proxyconfig_start)
|
proxy_type, time.time() - proxyconfig_start)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Start main application"""
|
"""Start main application"""
|
||||||
# pylint: disable=too-many-statements, too-many-branches, too-many-locals
|
# pylint: disable=too-many-statements,too-many-branches,too-many-locals
|
||||||
_fixSocket()
|
_fixSocket()
|
||||||
|
|
||||||
config = BMConfigParser()
|
config = BMConfigParser()
|
||||||
|
@ -268,11 +268,10 @@ class Main(object):
|
||||||
|
|
||||||
set_thread_name("PyBitmessage")
|
set_thread_name("PyBitmessage")
|
||||||
|
|
||||||
state.dandelion = config.safeGetInt('network', 'dandelion')
|
state.dandelion = config.safeGet('network', 'dandelion')
|
||||||
# dandelion requires outbound connections, without them,
|
# dandelion requires outbound connections, without them,
|
||||||
# stem objects will get stuck forever
|
# stem objects will get stuck forever
|
||||||
if state.dandelion and not config.safeGetBoolean(
|
if state.dandelion and not (config.safeGet('bitmessagesettings', 'sendoutgoingconnections') == 'True'):
|
||||||
'bitmessagesettings', 'sendoutgoingconnections'):
|
|
||||||
state.dandelion = 0
|
state.dandelion = 0
|
||||||
|
|
||||||
if state.testmode or config.safeGetBoolean(
|
if state.testmode or config.safeGetBoolean(
|
||||||
|
@ -350,7 +349,7 @@ class Main(object):
|
||||||
singleAPIThread.start()
|
singleAPIThread.start()
|
||||||
# start network components if networking is enabled
|
# start network components if networking is enabled
|
||||||
if state.enableNetwork:
|
if state.enableNetwork:
|
||||||
self.start_proxyconfig(config)
|
start_proxyconfig()
|
||||||
BMConnectionPool()
|
BMConnectionPool()
|
||||||
asyncoreThread = BMNetworkThread()
|
asyncoreThread = BMNetworkThread()
|
||||||
asyncoreThread.daemon = True
|
asyncoreThread.daemon = True
|
||||||
|
@ -408,9 +407,8 @@ class Main(object):
|
||||||
if (state.testmode and time.time() - state.last_api_response >= 30):
|
if (state.testmode and time.time() - state.last_api_response >= 30):
|
||||||
self.stop()
|
self.stop()
|
||||||
elif not state.enableGUI:
|
elif not state.enableGUI:
|
||||||
# pylint: disable=relative-import
|
from tests import core as test_core # pylint: disable=relative-import
|
||||||
from tests import core as test_core
|
test_core_result = test_core.run()
|
||||||
test_core_result = test_core.run(self)
|
|
||||||
state.enableGUI = True
|
state.enableGUI = True
|
||||||
self.stop()
|
self.stop()
|
||||||
test_core.cleanup()
|
test_core.cleanup()
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
<item alignment="Qt::AlignLeft">
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2012-2019 The Bitmessage Developers</p></body></html></string>
|
<string><html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2012-2020 The Bitmessage Developers</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignLeft</set>
|
<set>Qt::AlignLeft</set>
|
||||||
|
|
|
@ -47,7 +47,7 @@ class AboutDialog(QtGui.QDialog, RetranslateMixin):
|
||||||
try:
|
try:
|
||||||
self.label_2.setText(
|
self.label_2.setText(
|
||||||
self.label_2.text().replace(
|
self.label_2.text().replace(
|
||||||
'2019', str(last_commit.get('time').year)
|
'2020', str(last_commit.get('time').year)
|
||||||
))
|
))
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import ConfigParser
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -16,10 +17,24 @@ import tempfile
|
||||||
import widgets
|
import widgets
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from helper_sql import sqlExecute, sqlStoredProcedure
|
from helper_sql import sqlExecute, sqlStoredProcedure
|
||||||
|
from helper_startup import start_proxyconfig
|
||||||
from network.asyncore_pollchoose import set_rates
|
from network.asyncore_pollchoose import set_rates
|
||||||
from tr import _translate
|
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):
|
class SettingsDialog(QtGui.QDialog):
|
||||||
"""The "Settings" dialog"""
|
"""The "Settings" dialog"""
|
||||||
def __init__(self, parent=None, firstrun=False):
|
def __init__(self, parent=None, firstrun=False):
|
||||||
|
@ -32,6 +47,16 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
self.net_restart_needed = False
|
self.net_restart_needed = False
|
||||||
self.timer = QtCore.QTimer()
|
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(
|
self.lineEditMaxOutboundConnections.setValidator(
|
||||||
QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections))
|
QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections))
|
||||||
|
|
||||||
|
@ -47,20 +72,33 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
def adjust_from_config(self, config):
|
def adjust_from_config(self, config):
|
||||||
"""Adjust all widgets state according to config settings"""
|
"""Adjust all widgets state according to config settings"""
|
||||||
# pylint: disable=too-many-branches,too-many-statements
|
# pylint: disable=too-many-branches,too-many-statements
|
||||||
self.checkBoxStartOnLogon.setChecked(
|
if not self.parent.tray.isSystemTrayAvailable():
|
||||||
config.getboolean('bitmessagesettings', 'startonlogon'))
|
self.groupBoxTray.setEnabled(False)
|
||||||
self.checkBoxMinimizeToTray.setChecked(
|
self.groupBoxTray.setTitle(_translate(
|
||||||
config.getboolean('bitmessagesettings', 'minimizetotray'))
|
"MainWindow", "Tray (not available in your system)"))
|
||||||
self.checkBoxTrayOnClose.setChecked(
|
for setting in (
|
||||||
config.safeGetBoolean('bitmessagesettings', 'trayonclose'))
|
'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(
|
self.checkBoxHideTrayConnectionNotifications.setChecked(
|
||||||
config.getboolean("bitmessagesettings", "hidetrayconnectionnotifications"))
|
config.getboolean(
|
||||||
|
'bitmessagesettings', 'hidetrayconnectionnotifications'))
|
||||||
self.checkBoxShowTrayNotifications.setChecked(
|
self.checkBoxShowTrayNotifications.setChecked(
|
||||||
config.getboolean('bitmessagesettings', 'showtraynotifications'))
|
config.getboolean('bitmessagesettings', 'showtraynotifications'))
|
||||||
self.checkBoxStartInTray.setChecked(
|
|
||||||
config.getboolean('bitmessagesettings', 'startintray'))
|
self.checkBoxStartOnLogon.setChecked(
|
||||||
|
config.getboolean('bitmessagesettings', 'startonlogon'))
|
||||||
|
|
||||||
self.checkBoxWillinglySendToMobile.setChecked(
|
self.checkBoxWillinglySendToMobile.setChecked(
|
||||||
config.safeGetBoolean('bitmessagesettings', 'willinglysendtomobile'))
|
config.safeGetBoolean(
|
||||||
|
'bitmessagesettings', 'willinglysendtomobile'))
|
||||||
self.checkBoxUseIdenticons.setChecked(
|
self.checkBoxUseIdenticons.setChecked(
|
||||||
config.safeGetBoolean('bitmessagesettings', 'useidenticons'))
|
config.safeGetBoolean('bitmessagesettings', 'useidenticons'))
|
||||||
self.checkBoxReplyBelow.setChecked(
|
self.checkBoxReplyBelow.setChecked(
|
||||||
|
@ -82,10 +120,12 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
"MainWindow", "Start-on-login not yet supported on your OS."))
|
"MainWindow", "Start-on-login not yet supported on your OS."))
|
||||||
self.checkBoxMinimizeToTray.setDisabled(True)
|
self.checkBoxMinimizeToTray.setDisabled(True)
|
||||||
self.checkBoxMinimizeToTray.setText(_translate(
|
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.setDisabled(True)
|
||||||
self.checkBoxShowTrayNotifications.setText(_translate(
|
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:
|
elif 'linux' in sys.platform:
|
||||||
self.checkBoxStartOnLogon.setDisabled(True)
|
self.checkBoxStartOnLogon.setDisabled(True)
|
||||||
self.checkBoxStartOnLogon.setText(_translate(
|
self.checkBoxStartOnLogon.setText(_translate(
|
||||||
|
@ -102,21 +142,11 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
self.checkBoxOnionOnly.setChecked(
|
self.checkBoxOnionOnly.setChecked(
|
||||||
config.safeGetBoolean('bitmessagesettings', 'onionservicesonly'))
|
config.safeGetBoolean('bitmessagesettings', 'onionservicesonly'))
|
||||||
|
|
||||||
proxy_type = config.safeGet(
|
self._proxy_type = getSOCKSProxyType(config)
|
||||||
'bitmessagesettings', 'socksproxytype', 'none')
|
self.comboBoxProxyType.setCurrentIndex(
|
||||||
if proxy_type == 'none':
|
0 if not self._proxy_type
|
||||||
self.comboBoxProxyType.setCurrentIndex(0)
|
else self.comboBoxProxyType.findText(self._proxy_type))
|
||||||
self.lineEditSocksHostname.setEnabled(False)
|
self.comboBoxProxyTypeChanged(self.comboBoxProxyType.currentIndex())
|
||||||
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)
|
|
||||||
|
|
||||||
self.lineEditSocksHostname.setText(
|
self.lineEditSocksHostname.setText(
|
||||||
config.get('bitmessagesettings', 'sockshostname'))
|
config.get('bitmessagesettings', 'sockshostname'))
|
||||||
|
@ -204,7 +234,7 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
self.checkBoxAuthentication.setEnabled(False)
|
self.checkBoxAuthentication.setEnabled(False)
|
||||||
self.checkBoxSocksListen.setEnabled(False)
|
self.checkBoxSocksListen.setEnabled(False)
|
||||||
self.checkBoxOnionOnly.setEnabled(False)
|
self.checkBoxOnionOnly.setEnabled(False)
|
||||||
elif comboBoxIndex in (1, 2):
|
else:
|
||||||
self.lineEditSocksHostname.setEnabled(True)
|
self.lineEditSocksHostname.setEnabled(True)
|
||||||
self.lineEditSocksPort.setEnabled(True)
|
self.lineEditSocksPort.setEnabled(True)
|
||||||
self.checkBoxAuthentication.setEnabled(True)
|
self.checkBoxAuthentication.setEnabled(True)
|
||||||
|
@ -306,27 +336,22 @@ class SettingsDialog(QtGui.QDialog):
|
||||||
upnpThread = upnp.uPnPThread()
|
upnpThread = upnp.uPnPThread()
|
||||||
upnpThread.start()
|
upnpThread.start()
|
||||||
|
|
||||||
proxy_type = self.config.safeGet(
|
proxytype_index = self.comboBoxProxyType.currentIndex()
|
||||||
'bitmessagesettings', 'socksproxytype', 'none')
|
if proxytype_index == 0:
|
||||||
if (
|
if self._proxy_type and shared.statusIconColor != 'red':
|
||||||
proxy_type == 'none' and
|
self.net_restart_needed = True
|
||||||
self.comboBoxProxyType.currentText()[0:5] == 'SOCKS' and
|
elif self.comboBoxProxyType.currentText() != self._proxy_type:
|
||||||
shared.statusIconColor != 'red'
|
|
||||||
):
|
|
||||||
self.net_restart_needed = True
|
|
||||||
if (
|
|
||||||
proxy_type[0:5] == 'SOCKS' and
|
|
||||||
self.comboBoxProxyType.currentText()[0:5] != 'SOCKS'
|
|
||||||
):
|
|
||||||
self.net_restart_needed = True
|
self.net_restart_needed = True
|
||||||
self.parent.statusbar.clearMessage()
|
self.parent.statusbar.clearMessage()
|
||||||
|
|
||||||
self.config.set(
|
self.config.set(
|
||||||
'bitmessagesettings', 'socksproxytype',
|
'bitmessagesettings', 'socksproxytype',
|
||||||
str(self.comboBoxProxyType.currentText())
|
'none' if self.comboBoxProxyType.currentIndex() == 0
|
||||||
if self.comboBoxProxyType.currentText()[0:5] == 'SOCKS'
|
else str(self.comboBoxProxyType.currentText())
|
||||||
else 'none'
|
|
||||||
)
|
)
|
||||||
|
if proxytype_index > 2: # last literal proxytype in ui
|
||||||
|
start_proxyconfig()
|
||||||
|
|
||||||
self.config.set('bitmessagesettings', 'socksauthentication', str(
|
self.config.set('bitmessagesettings', 'socksauthentication', str(
|
||||||
self.checkBoxAuthentication.isChecked()))
|
self.checkBoxAuthentication.isChecked()))
|
||||||
self.config.set('bitmessagesettings', 'sockshostname', str(
|
self.config.set('bitmessagesettings', 'sockshostname', str(
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
<string>Minimize to tray</string>
|
<string>Minimize to tray</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -419,12 +419,12 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>SOCKS4a</string>
|
<string notr="true">SOCKS4a</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>SOCKS5</string>
|
<string notr="true">SOCKS5</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -15,6 +15,7 @@ from openclpow import openclAvailable, openclEnabled
|
||||||
import paths
|
import paths
|
||||||
import proofofwork
|
import proofofwork
|
||||||
from pyelliptic.openssl import OpenSSL
|
from pyelliptic.openssl import OpenSSL
|
||||||
|
from settings import getSOCKSProxyType
|
||||||
import queues
|
import queues
|
||||||
import network.stats
|
import network.stats
|
||||||
import state
|
import state
|
||||||
|
@ -118,8 +119,7 @@ def createSupportMessage(myapp):
|
||||||
BMConfigParser().safeGet('bitmessagesettings', 'opencl')
|
BMConfigParser().safeGet('bitmessagesettings', 'opencl')
|
||||||
) if openclEnabled() else "None"
|
) if openclEnabled() else "None"
|
||||||
locale = getTranslationLanguage()
|
locale = getTranslationLanguage()
|
||||||
socks = BMConfigParser().safeGet(
|
socks = getSOCKSProxyType(BMConfigParser()) or "N/A"
|
||||||
'bitmessagesettings', 'socksproxytype', "N/A")
|
|
||||||
upnp = BMConfigParser().safeGet('bitmessagesettings', 'upnp', "N/A")
|
upnp = BMConfigParser().safeGet('bitmessagesettings', 'upnp', "N/A")
|
||||||
connectedhosts = len(network.stats.connectedHostsList())
|
connectedhosts = len(network.stats.connectedHostsList())
|
||||||
|
|
||||||
|
|
|
@ -141,13 +141,13 @@ class objectProcessor(threading.Thread):
|
||||||
# bypass nonce and time, retain object type/version/stream + body
|
# bypass nonce and time, retain object type/version/stream + body
|
||||||
readPosition = 16
|
readPosition = 16
|
||||||
|
|
||||||
if data[readPosition:] in shared.ackdataForWhichImWatching:
|
if bytes(data[readPosition:]) in shared.ackdataForWhichImWatching:
|
||||||
logger.info('This object is an acknowledgement bound for me.')
|
logger.info('This object is an acknowledgement bound for me.')
|
||||||
del shared.ackdataForWhichImWatching[data[readPosition:]]
|
del shared.ackdataForWhichImWatching[data[readPosition:]]
|
||||||
sqlExecute(
|
sqlExecute(
|
||||||
'UPDATE sent SET status=?, lastactiontime=?'
|
'UPDATE sent SET status=?, lastactiontime=?'
|
||||||
' WHERE ackdata=?',
|
' WHERE ackdata=?',
|
||||||
'ackreceived', int(time.time()), data[readPosition:])
|
' ackreceived', int(time.time()), data[readPosition:])
|
||||||
queues.UISignalQueue.put((
|
queues.UISignalQueue.put((
|
||||||
'updateSentItemStatusByAckdata',
|
'updateSentItemStatusByAckdata',
|
||||||
(data[readPosition:],
|
(data[readPosition:],
|
||||||
|
@ -221,7 +221,7 @@ class objectProcessor(threading.Thread):
|
||||||
'the hash requested in this getpubkey request is: %s',
|
'the hash requested in this getpubkey request is: %s',
|
||||||
hexlify(requestedHash))
|
hexlify(requestedHash))
|
||||||
# if this address hash is one of mine
|
# if this address hash is one of mine
|
||||||
if requestedHash in shared.myAddressesByHash:
|
if bytes(requestedHash) in shared.myAddressesByHash:
|
||||||
myAddress = shared.myAddressesByHash[requestedHash]
|
myAddress = shared.myAddressesByHash[requestedHash]
|
||||||
elif requestedAddressVersionNumber >= 4:
|
elif requestedAddressVersionNumber >= 4:
|
||||||
requestedTag = data[readPosition:readPosition + 32]
|
requestedTag = data[readPosition:readPosition + 32]
|
||||||
|
@ -233,7 +233,7 @@ class objectProcessor(threading.Thread):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'the tag requested in this getpubkey request is: %s',
|
'the tag requested in this getpubkey request is: %s',
|
||||||
hexlify(requestedTag))
|
hexlify(requestedTag))
|
||||||
if requestedTag in shared.myAddressesByTag:
|
if bytes(requestedTag) in shared.myAddressesByTag:
|
||||||
myAddress = shared.myAddressesByTag[requestedTag]
|
myAddress = shared.myAddressesByTag[requestedTag]
|
||||||
|
|
||||||
if myAddress == '':
|
if myAddress == '':
|
||||||
|
@ -328,7 +328,7 @@ class objectProcessor(threading.Thread):
|
||||||
dataToStore = data[20:readPosition]
|
dataToStore = data[20:readPosition]
|
||||||
sha = hashlib.new('sha512')
|
sha = hashlib.new('sha512')
|
||||||
sha.update(
|
sha.update(
|
||||||
'\x04' + publicSigningKey + '\x04' + publicEncryptionKey)
|
'\x04'.encode() + publicSigningKey + '\x04'.encode() + publicEncryptionKey)
|
||||||
ripe = RIPEMD160Hash(sha.digest()).digest()
|
ripe = RIPEMD160Hash(sha.digest()).digest()
|
||||||
|
|
||||||
if logger.isEnabledFor(logging.DEBUG):
|
if logger.isEnabledFor(logging.DEBUG):
|
||||||
|
@ -367,9 +367,9 @@ class objectProcessor(threading.Thread):
|
||||||
' Sanity check failed.')
|
' Sanity check failed.')
|
||||||
return
|
return
|
||||||
readPosition += 4
|
readPosition += 4
|
||||||
publicSigningKey = '\x04' + data[readPosition:readPosition + 64]
|
publicSigningKey = ('\x04').encode() + data[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
publicEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
|
publicEncryptionKey = ('\x04').encode() + data[readPosition:readPosition + 64]
|
||||||
readPosition += 64
|
readPosition += 64
|
||||||
_, specifiedNonceTrialsPerByteLength = decodeVarint(
|
_, specifiedNonceTrialsPerByteLength = decodeVarint(
|
||||||
data[readPosition:readPosition + 10])
|
data[readPosition:readPosition + 10])
|
||||||
|
@ -433,7 +433,7 @@ class objectProcessor(threading.Thread):
|
||||||
return
|
return
|
||||||
|
|
||||||
tag = data[readPosition:readPosition + 32]
|
tag = data[readPosition:readPosition + 32]
|
||||||
if tag not in state.neededPubkeys:
|
if tag not in bytes(state.neededPubkeys):
|
||||||
logger.info(
|
logger.info(
|
||||||
'We don\'t need this v4 pubkey. We didn\'t ask for it.')
|
'We don\'t need this v4 pubkey. We didn\'t ask for it.')
|
||||||
return
|
return
|
||||||
|
@ -866,7 +866,7 @@ class objectProcessor(threading.Thread):
|
||||||
elif broadcastVersion == 5:
|
elif broadcastVersion == 5:
|
||||||
embeddedTag = data[readPosition:readPosition + 32]
|
embeddedTag = data[readPosition:readPosition + 32]
|
||||||
readPosition += 32
|
readPosition += 32
|
||||||
if embeddedTag not in shared.MyECSubscriptionCryptorObjects:
|
if bytes(embeddedTag) not in shared.MyECSubscriptionCryptorObjects:
|
||||||
logger.debug('We\'re not interested in this broadcast.')
|
logger.debug('We\'re not interested in this broadcast.')
|
||||||
return
|
return
|
||||||
# We are interested in this broadcast because of its tag.
|
# We are interested in this broadcast because of its tag.
|
||||||
|
|
|
@ -471,8 +471,8 @@ class singleWorker(StoppableThread):
|
||||||
def sendOnionPeerObj(self, peer=None):
|
def sendOnionPeerObj(self, peer=None):
|
||||||
"""Send onionpeer object representing peer"""
|
"""Send onionpeer object representing peer"""
|
||||||
if not peer: # find own onionhostname
|
if not peer: # find own onionhostname
|
||||||
for peer_ in state.ownAddresses:
|
for peer in state.ownAddresses:
|
||||||
if peer_.host.endswith('.onion'):
|
if peer.host.endswith('.onion'):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
Startup operations.
|
Startup operations.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=too-many-branches,too-many-statements
|
# pylint: disable=too-many-branches,too-many-statements
|
||||||
from __future__ import print_function
|
# import configparser
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
|
|
||||||
import defaults
|
import defaults
|
||||||
|
@ -15,6 +16,13 @@ import paths
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import BMConfigParser
|
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 user may de-select Portable Mode in the settings if they want
|
||||||
# the config files to stay in the application data folder.
|
# the config files to stay in the application data folder.
|
||||||
|
@ -31,14 +39,14 @@ def loadConfig():
|
||||||
needToCreateKeysFile = config.safeGet(
|
needToCreateKeysFile = config.safeGet(
|
||||||
'bitmessagesettings', 'settingsversion') is None
|
'bitmessagesettings', 'settingsversion') is None
|
||||||
if not needToCreateKeysFile:
|
if not needToCreateKeysFile:
|
||||||
print(
|
logger.info(
|
||||||
'Loading config files from directory specified'
|
'Loading config files from directory specified'
|
||||||
' on startup: %s' % state.appdata)
|
' on startup: %s', state.appdata)
|
||||||
else:
|
else:
|
||||||
config.read(paths.lookupExeFolder() + 'keys.dat')
|
config.read(paths.lookupExeFolder() + 'keys.dat')
|
||||||
try:
|
try:
|
||||||
config.get('bitmessagesettings', 'settingsversion')
|
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
|
needToCreateKeysFile = False
|
||||||
state.appdata = paths.lookupExeFolder()
|
state.appdata = paths.lookupExeFolder()
|
||||||
except:
|
except:
|
||||||
|
@ -49,7 +57,8 @@ def loadConfig():
|
||||||
needToCreateKeysFile = config.safeGet(
|
needToCreateKeysFile = config.safeGet(
|
||||||
'bitmessagesettings', 'settingsversion') is None
|
'bitmessagesettings', 'settingsversion') is None
|
||||||
if not needToCreateKeysFile:
|
if not needToCreateKeysFile:
|
||||||
print('Loading existing config files from', state.appdata)
|
logger.info(
|
||||||
|
'Loading existing config files from %s', state.appdata)
|
||||||
|
|
||||||
if needToCreateKeysFile:
|
if needToCreateKeysFile:
|
||||||
|
|
||||||
|
@ -104,9 +113,10 @@ def loadConfig():
|
||||||
# Just use the same directory as the program and forget about
|
# Just use the same directory as the program and forget about
|
||||||
# the appdata folder
|
# the appdata folder
|
||||||
state.appdata = ''
|
state.appdata = ''
|
||||||
print('Creating new config files in same directory as program.')
|
logger.info(
|
||||||
|
'Creating new config files in same directory as program.')
|
||||||
else:
|
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):
|
if not os.path.exists(state.appdata):
|
||||||
os.makedirs(state.appdata)
|
os.makedirs(state.appdata)
|
||||||
if not sys.platform.startswith('win'):
|
if not sys.platform.startswith('win'):
|
||||||
|
@ -258,7 +268,7 @@ def updateConfig():
|
||||||
'bitmessagesettings', 'hidetrayconnectionnotifications', 'false')
|
'bitmessagesettings', 'hidetrayconnectionnotifications', 'false')
|
||||||
if config.safeGetInt('bitmessagesettings', 'maxoutboundconnections') < 1:
|
if config.safeGetInt('bitmessagesettings', 'maxoutboundconnections') < 1:
|
||||||
config.set('bitmessagesettings', 'maxoutboundconnections', '8')
|
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
|
# TTL is now user-specifiable. Let's add an option to save
|
||||||
# whatever the user selects.
|
# whatever the user selects.
|
||||||
|
@ -281,3 +291,26 @@ def isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections():
|
||||||
return False
|
return False
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
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)
|
||||||
|
|
|
@ -22,7 +22,7 @@ def assemble_addr(peerList):
|
||||||
len(peerList[i:i + MAX_ADDR_COUNT]))
|
len(peerList[i:i + MAX_ADDR_COUNT]))
|
||||||
for stream, peer, timestamp in peerList[i:i + MAX_ADDR_COUNT]:
|
for stream, peer, timestamp in peerList[i:i + MAX_ADDR_COUNT]:
|
||||||
payload += struct.pack(
|
payload += struct.pack(
|
||||||
'>Q', timestamp) # 64-bit time
|
'>Q', int(timestamp)) # 64-bit time
|
||||||
payload += struct.pack('>I', stream)
|
payload += struct.pack('>I', stream)
|
||||||
payload += struct.pack(
|
payload += struct.pack(
|
||||||
'>q', 1) # service bit flags offered by this node
|
'>q', 1) # service bit flags offered by this node
|
||||||
|
|
|
@ -172,9 +172,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
except BMObjectAlreadyHaveError:
|
except BMObjectAlreadyHaveError:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'%(host)s:%(port)i already got object, skipping',
|
'%(host)s:%(port)i already got object, skipping',
|
||||||
self.destination._asdict())
|
self.destinaestion._asdict())
|
||||||
except struct.error:
|
except struct.error:
|
||||||
logger.debug('decoding error, skipping')
|
logger.debug('decoding error, skipping')
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
elif self.socket.type == socket.SOCK_DGRAM:
|
elif self.socket.type == socket.SOCK_DGRAM:
|
||||||
# broken read, ignore
|
# broken read, ignore
|
||||||
pass
|
pass
|
||||||
|
@ -206,9 +208,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
"""Decode node details from the payload"""
|
"""Decode node details from the payload"""
|
||||||
# protocol.checkIPAddress()
|
# protocol.checkIPAddress()
|
||||||
services, host, port = self.decode_payload_content("Q16sH")
|
services, host, port = self.decode_payload_content("Q16sH")
|
||||||
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
|
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF'.encode('raw_unicode_escape'):
|
||||||
host = socket.inet_ntop(socket.AF_INET, host[12:16])
|
host = socket.inet_ntop(socket.AF_INET, host[12:16])
|
||||||
elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43':
|
elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43'.encode('raw_unicode_escape'):
|
||||||
# Onion, based on BMD/bitcoind
|
# Onion, based on BMD/bitcoind
|
||||||
host = base64.b32encode(host[6:]).lower() + ".onion"
|
host = base64.b32encode(host[6:]).lower() + ".onion"
|
||||||
else:
|
else:
|
||||||
|
@ -385,7 +387,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
if dandelion and not state.dandelion:
|
if dandelion and not state.dandelion:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
for i in map(str, items):
|
for i in map(bytes, items):
|
||||||
if i in Inventory() and not Dandelion().hasHash(i):
|
if i in Inventory() and not Dandelion().hasHash(i):
|
||||||
continue
|
continue
|
||||||
if dandelion and not Dandelion().hasHash(i):
|
if dandelion and not Dandelion().hasHash(i):
|
||||||
|
@ -438,7 +440,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
try:
|
try:
|
||||||
self.object.checkObjectByType()
|
self.object.checkObjectByType()
|
||||||
objectProcessorQueue.put((
|
objectProcessorQueue.put((
|
||||||
self.object.objectType, buffer(self.object.data)))
|
self.object.objectType, memoryview(self.object.data)))
|
||||||
except BMObjectInvalidError:
|
except BMObjectInvalidError:
|
||||||
BMProto.stopDownloadingObject(self.object.inventoryHash, True)
|
BMProto.stopDownloadingObject(self.object.inventoryHash, True)
|
||||||
else:
|
else:
|
||||||
|
@ -449,12 +451,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
|
||||||
|
|
||||||
if self.object.inventoryHash in Inventory() and Dandelion().hasHash(self.object.inventoryHash):
|
if self.object.inventoryHash in Inventory() and Dandelion().hasHash(self.object.inventoryHash):
|
||||||
Dandelion().removeHash(self.object.inventoryHash, "cycle detection")
|
Dandelion().removeHash(self.object.inventoryHash, "cycle detection")
|
||||||
|
[self.object.inventoryHash] = (
|
||||||
Inventory()[self.object.inventoryHash] = (
|
|
||||||
self.object.objectType, self.object.streamNumber,
|
self.object.objectType, self.object.streamNumber,
|
||||||
buffer(self.payload[objectOffset:]), self.object.expiresTime,
|
memoryview(self.payload[objectOffset:]), self.object.expiresTime,
|
||||||
buffer(self.object.tag)
|
memoryview(self.object.tag)
|
||||||
)
|
)
|
||||||
|
Inventory()[self.object.inventoryHash]
|
||||||
self.handleReceivedObject(
|
self.handleReceivedObject(
|
||||||
self.object.streamNumber, self.object.inventoryHash)
|
self.object.streamNumber, self.object.inventoryHash)
|
||||||
invQueue.put((
|
invQueue.put((
|
||||||
|
|
|
@ -149,6 +149,9 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes
|
||||||
retval = self.socket.sendto(
|
retval = self.socket.sendto(
|
||||||
self.write_buf, ('<broadcast>', self.port))
|
self.write_buf, ('<broadcast>', self.port))
|
||||||
except socket.error as e:
|
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
|
retval = 0
|
||||||
self.slice_write_buf(retval)
|
self.slice_write_buf(retval)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
"""
|
||||||
|
Simple plugin system based on setuptools
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
# .. include:: pybitmessage.plugins.plugin.rst
|
|
@ -1,19 +1,28 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
src/plugins/plugin.py
|
Operating with plugins
|
||||||
===================================
|
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger('default')
|
||||||
|
|
||||||
|
|
||||||
def get_plugins(group, point='', name=None, fallback=None):
|
def get_plugins(group, point='', name=None, fallback=None):
|
||||||
"""
|
"""
|
||||||
Iterate through plugins (`connect_plugin` attribute of entry point)
|
:param str group: plugin group
|
||||||
which name starts with `point` or equals to `name`.
|
:param str point: plugin name prefix
|
||||||
If `fallback` kwarg specified, plugin with that name yield last.
|
: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):
|
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:
|
try:
|
||||||
plugin = ep.load().connect_plugin
|
plugin = ep.load().connect_plugin
|
||||||
if ep.name == fallback:
|
if ep.name == fallback:
|
||||||
|
@ -25,6 +34,8 @@ def get_plugins(group, point='', name=None, fallback=None):
|
||||||
ValueError,
|
ValueError,
|
||||||
pkg_resources.DistributionNotFound,
|
pkg_resources.DistributionNotFound,
|
||||||
pkg_resources.UnknownExtra):
|
pkg_resources.UnknownExtra):
|
||||||
|
logger.debug(
|
||||||
|
'Problem while loading %s', ep.name, exc_info=True)
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
yield _fallback
|
yield _fallback
|
||||||
|
@ -33,6 +44,8 @@ def get_plugins(group, point='', name=None, fallback=None):
|
||||||
|
|
||||||
|
|
||||||
def get_plugin(*args, **kwargs):
|
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):
|
for plugin in get_plugins(*args, **kwargs):
|
||||||
return plugin
|
return plugin
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
src/plugins/proxyconfig_stem.py
|
Configure tor proxy and hidden service with
|
||||||
===================================
|
`stem <https://stem.torproject.org/>`_ 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 os
|
||||||
import logging
|
import logging
|
||||||
|
@ -36,13 +44,20 @@ class DebugLogger(object):
|
||||||
|
|
||||||
|
|
||||||
def connect_plugin(config): # pylint: disable=too-many-branches
|
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()
|
logwrite = DebugLogger()
|
||||||
if config.safeGet('bitmessagesettings', 'sockshostname') not in (
|
if config.safeGet('bitmessagesettings', 'sockshostname', '') not in (
|
||||||
'localhost', '127.0.0.1', ''
|
'localhost', '127.0.0.1', ''
|
||||||
):
|
):
|
||||||
# remote proxy is choosen for outbound connections,
|
# remote proxy is choosen for outbound connections,
|
||||||
# nothing to do here, but need to set socksproxytype to SOCKS5!
|
# nothing to do here, but need to set socksproxytype to SOCKS5!
|
||||||
|
config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
|
||||||
logwrite(
|
logwrite(
|
||||||
'sockshostname is set to remote address,'
|
'sockshostname is set to remote address,'
|
||||||
' aborting stem proxy configuration')
|
' aborting stem proxy configuration')
|
||||||
|
@ -77,6 +92,8 @@ def connect_plugin(config): # pylint: disable=too-many-branches
|
||||||
logwrite('Started tor on port %s' % port)
|
logwrite('Started tor on port %s' % port)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
config.setTemp('bitmessagesettings', 'socksproxytype', 'SOCKS5')
|
||||||
|
|
||||||
if config.safeGetBoolean('bitmessagesettings', 'sockslisten'):
|
if config.safeGetBoolean('bitmessagesettings', 'sockslisten'):
|
||||||
# need a hidden service for inbound connections
|
# need a hidden service for inbound connections
|
||||||
try:
|
try:
|
||||||
|
@ -95,7 +112,8 @@ def connect_plugin(config): # pylint: disable=too-many-branches
|
||||||
onionkeytype = config.safeGet(onionhostname, 'keytype')
|
onionkeytype = config.safeGet(onionhostname, 'keytype')
|
||||||
|
|
||||||
response = controller.create_ephemeral_hidden_service(
|
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_type=(onionkeytype or 'NEW'),
|
||||||
key_content=(onionkey or onionhostname and 'ED25519-V3' or 'BEST')
|
key_content=(onionkey or onionhostname and 'ED25519-V3' or 'BEST')
|
||||||
)
|
)
|
||||||
|
@ -117,6 +135,5 @@ def connect_plugin(config): # pylint: disable=too-many-branches
|
||||||
config.set(
|
config.set(
|
||||||
onionhostname, 'keytype', response.private_key_type)
|
onionhostname, 'keytype', response.private_key_type)
|
||||||
config.save()
|
config.save()
|
||||||
config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -278,14 +278,13 @@ def isProofOfWorkSufficient(
|
||||||
|
|
||||||
def CreatePacket(command, payload=''):
|
def CreatePacket(command, payload=''):
|
||||||
"""Construct and return a number of bytes from a payload"""
|
"""Construct and return a number of bytes from a payload"""
|
||||||
payload = payload if type(payload) == bytes else payload.encode()
|
payload = payload if type(payload) in [bytes,bytearray] else payload.encode()
|
||||||
|
|
||||||
payload_length = len(payload)
|
payload_length = len(payload)
|
||||||
checksum = hashlib.sha512(payload).digest()[0:4]
|
checksum = hashlib.sha512(payload).digest()[0:4]
|
||||||
byte = bytearray(Header.size + payload_length)
|
byte = bytearray(Header.size + payload_length)
|
||||||
Header.pack_into(byte, 0, 0xE9BEB4D9, command.encode(), payload_length, checksum)
|
Header.pack_into(byte, 0, 0xE9BEB4D9, command.encode(), payload_length, checksum)
|
||||||
byte[Header.size:] = payload
|
byte[Header.size:] = payload
|
||||||
return byte
|
return bytes(byte)
|
||||||
|
|
||||||
|
|
||||||
def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server=False, nodeid=None):
|
def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server=False, nodeid=None):
|
||||||
|
@ -325,10 +324,8 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server=
|
||||||
(NODE_DANDELION if state.dandelion else 0)
|
(NODE_DANDELION if state.dandelion else 0)
|
||||||
)
|
)
|
||||||
# = 127.0.0.1. This will be ignored by the remote host. The actual remote connected IP will be used.
|
# = 127.0.0.1. This will be ignored by the remote host. The actual remote connected IP will be used.
|
||||||
|
#python3 need to check
|
||||||
# python3 need to check
|
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF'.encode('raw_unicode_escape') + pack('>L', 2130706433)
|
||||||
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF'.encode() + pack('>L', 2130706433)
|
|
||||||
|
|
||||||
# we have a separate extPort and incoming over clearnet
|
# we have a separate extPort and incoming over clearnet
|
||||||
# or outgoing through clearnet
|
# or outgoing through clearnet
|
||||||
extport = BMConfigParser().safeGetInt('bitmessagesettings', 'extport')
|
extport = BMConfigParser().safeGetInt('bitmessagesettings', 'extport')
|
||||||
|
|
|
@ -39,15 +39,20 @@ class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __getitem__(self, hash_):
|
def __getitem__(self, hash_):
|
||||||
print('----------__getitem__------------------')
|
if hash_ == 0:
|
||||||
|
hash_ = bytes()
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if hash_ in self._inventory:
|
try:
|
||||||
return self._inventory[hash_]
|
if hash_ in self._inventory:
|
||||||
rows = sqlQuery(
|
return self._inventory[hash_]
|
||||||
'SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?',
|
rows = sqlQuery(
|
||||||
sqlite3.Binary(hash_))
|
'SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?',
|
||||||
if not rows:
|
sqlite3.Binary(hash_))
|
||||||
raise KeyError(hash_)
|
if not rows:
|
||||||
|
pass
|
||||||
|
# raise KeyError(hash_)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
return InventoryItem(*rows[0])
|
return InventoryItem(*rows[0])
|
||||||
|
|
||||||
def __setitem__(self, hash_, value):
|
def __setitem__(self, hash_, value):
|
||||||
|
|
|
@ -15,14 +15,20 @@ import knownnodes
|
||||||
import state
|
import state
|
||||||
from bmconfigparser import BMConfigParser
|
from bmconfigparser import BMConfigParser
|
||||||
from helper_msgcoding import MsgEncode, MsgDecode
|
from helper_msgcoding import MsgEncode, MsgDecode
|
||||||
|
from helper_startup import start_proxyconfig
|
||||||
from network import asyncore_pollchoose as asyncore
|
from network import asyncore_pollchoose as asyncore
|
||||||
from network.connectionpool import BMConnectionPool
|
from network.connectionpool import BMConnectionPool
|
||||||
from network.node import Peer
|
from network.node import Peer
|
||||||
from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection
|
from network.tcp import Socks4aBMConnection, Socks5BMConnection, TCPConnection
|
||||||
from queues import excQueue
|
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')
|
knownnodes_file = os.path.join(state.appdata, 'knownnodes.dat')
|
||||||
program = None
|
|
||||||
|
|
||||||
|
|
||||||
def pickle_knownnodes():
|
def pickle_knownnodes():
|
||||||
|
@ -170,12 +176,29 @@ class TestCore(unittest.TestCase):
|
||||||
self.assertIsInstance(con, connection_base)
|
self.assertIsInstance(con, connection_base)
|
||||||
self.assertNotEqual(peer.host, '127.0.0.1')
|
self.assertNotEqual(peer.host, '127.0.0.1')
|
||||||
return
|
return
|
||||||
else: # pylint: disable=useless-else-on-loop
|
self.fail(
|
||||||
self.fail(
|
'Failed to connect during %s sec' % (time.time() - _started))
|
||||||
'Failed to connect during %s sec' % (time.time() - _started))
|
|
||||||
|
|
||||||
def test_onionservicesonly(self):
|
def test_bootstrap(self):
|
||||||
"""test onionservicesonly networking mode"""
|
"""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')
|
BMConfigParser().set('bitmessagesettings', 'onionservicesonly', 'true')
|
||||||
self._initiate_bootstrap()
|
self._initiate_bootstrap()
|
||||||
BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
|
BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
|
||||||
|
@ -184,26 +207,18 @@ class TestCore(unittest.TestCase):
|
||||||
for n, peer in enumerate(BMConnectionPool().outboundConnections):
|
for n, peer in enumerate(BMConnectionPool().outboundConnections):
|
||||||
if n > 2:
|
if n > 2:
|
||||||
return
|
return
|
||||||
if not peer.host.endswith('.onion'):
|
if (
|
||||||
|
not peer.host.endswith('.onion')
|
||||||
|
and not peer.host.startswith('bootstrap')
|
||||||
|
):
|
||||||
self.fail(
|
self.fail(
|
||||||
'Found non onion hostname %s in outbound connections!'
|
'Found non onion hostname %s in outbound connections!'
|
||||||
% peer.host)
|
% peer.host)
|
||||||
self.fail('Failed to connect to at least 3 nodes within 360 sec')
|
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')
|
|
||||||
program.start_proxyconfig(BMConfigParser())
|
|
||||||
self._check_bootstrap()
|
|
||||||
|
|
||||||
|
def run():
|
||||||
def run(prog):
|
|
||||||
"""Starts all tests defined in this module"""
|
"""Starts all tests defined in this module"""
|
||||||
global program # pylint: disable=global-statement
|
|
||||||
program = prog
|
|
||||||
loader = unittest.TestLoader()
|
loader = unittest.TestLoader()
|
||||||
loader.sortTestMethodsUsing = None
|
loader.sortTestMethodsUsing = None
|
||||||
suite = loader.loadTestsFromTestCase(TestCore)
|
suite = loader.loadTestsFromTestCase(TestCore)
|
||||||
|
|
Reference in New Issue
Block a user