commit after conflicts

This commit is contained in:
lakshyacis 2020-01-06 16:44:13 +05:30
parent 102ea32d28
commit e436b8ecf6
No known key found for this signature in database
GPG Key ID: D2C539C8EC63E9EB
24 changed files with 262 additions and 146 deletions

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -1,4 +1,3 @@
python_prctl
psutil
pycrypto
stem

View File

@ -30,7 +30,8 @@ import queues
import shared
import shutdown
import state
from addresses import addBMIfNotPresent, calculateInventoryHash, decodeAddress, decodeVarint, varintDecodeError
from addresses import addBMIfNotPresent, calculateInventoryHash, decodeAddress, decodeVarint, varintDecodeError
from bmconfigparser import BMConfigParser
from debug import logger
from helper_ackPayload import genAckPayload

View File

@ -1303,6 +1303,7 @@ class NavigateApp(App): # pylint: disable=too-many-public-methods
def build(self):
"""Method builds the widget"""
print(os.path.join(os.path.dirname(__file__), 'main.kv'))
main_widget = Builder.load_file(
os.path.join(os.path.dirname(__file__), 'main.kv'))
self.nav_drawer = Navigatorss()

View File

@ -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.
@ -32,7 +32,8 @@ from bmconfigparser import BMConfigParser
# this should go before any threads
from debug import logger
from helper_startup import (
isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections
isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections,
start_proxyconfig
)
from inventory import Inventory
from knownnodes import readKnownNodes
@ -188,10 +189,9 @@ class Main(object):
logger.info(
'Started proxy config plugin %s in %s sec',
proxy_type, time.time() - proxyconfig_start)
def start(self):
"""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()
config = BMConfigParser()
@ -268,11 +268,10 @@ class Main(object):
set_thread_name("PyBitmessage")
state.dandelion = config.safeGetInt('network', 'dandelion')
state.dandelion = config.safeGet('network', 'dandelion')
# dandelion requires outbound connections, without them,
# stem objects will get stuck forever
if state.dandelion and not config.safeGetBoolean(
'bitmessagesettings', 'sendoutgoingconnections'):
if state.dandelion and not (config.safeGet('bitmessagesettings', 'sendoutgoingconnections') == 'True'):
state.dandelion = 0
if state.testmode or config.safeGetBoolean(
@ -350,7 +349,7 @@ class Main(object):
singleAPIThread.start()
# start network components if networking is enabled
if state.enableNetwork:
self.start_proxyconfig(config)
start_proxyconfig()
BMConnectionPool()
asyncoreThread = BMNetworkThread()
asyncoreThread.daemon = True
@ -408,9 +407,8 @@ class Main(object):
if (state.testmode and time.time() - state.last_api_response >= 30):
self.stop()
elif not state.enableGUI:
# pylint: disable=relative-import
from tests import core as test_core
test_core_result = test_core.run(self)
from tests import core as test_core # pylint: disable=relative-import
test_core_result = test_core.run()
state.enableGUI = True
self.stop()
test_core.cleanup()

View File

@ -46,7 +46,7 @@
<item alignment="Qt::AlignLeft">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Copyright © 2012-2016 Jonathan Warren&lt;br/&gt;Copyright © 2012-2019 The Bitmessage Developers&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Copyright © 2012-2016 Jonathan Warren&lt;br/&gt;Copyright © 2012-2020 The Bitmessage Developers&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeft</set>

View File

@ -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

View File

@ -1,3 +1,4 @@
import ConfigParser
import os
import sys
@ -16,10 +17,24 @@ 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
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):
@ -32,6 +47,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))
@ -47,20 +72,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 +120,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(
@ -102,21 +142,11 @@ 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)
self._proxy_type = getSOCKSProxyType(config)
self.comboBoxProxyType.setCurrentIndex(
0 if not self._proxy_type
else self.comboBoxProxyType.findText(self._proxy_type))
self.comboBoxProxyTypeChanged(self.comboBoxProxyType.currentIndex())
self.lineEditSocksHostname.setText(
config.get('bitmessagesettings', 'sockshostname'))
@ -204,7 +234,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)
@ -306,27 +336,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 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(

View File

@ -75,7 +75,7 @@
<string>Minimize to tray</string>
</property>
<property name="checked">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
@ -419,12 +419,12 @@
</item>
<item>
<property name="text">
<string>SOCKS4a</string>
<string notr="true">SOCKS4a</string>
</property>
</item>
<item>
<property name="text">
<string>SOCKS5</string>
<string notr="true">SOCKS5</string>
</property>
</item>
</widget>

View File

@ -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())

View File

@ -141,13 +141,13 @@ class objectProcessor(threading.Thread):
# bypass nonce and time, retain object type/version/stream + body
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.')
del shared.ackdataForWhichImWatching[data[readPosition:]]
sqlExecute(
'UPDATE sent SET status=?, lastactiontime=?'
' WHERE ackdata=?',
'ackreceived', int(time.time()), data[readPosition:])
' ackreceived', int(time.time()), data[readPosition:])
queues.UISignalQueue.put((
'updateSentItemStatusByAckdata',
(data[readPosition:],
@ -221,7 +221,7 @@ class objectProcessor(threading.Thread):
'the hash requested in this getpubkey request is: %s',
hexlify(requestedHash))
# if this address hash is one of mine
if requestedHash in shared.myAddressesByHash:
if bytes(requestedHash) in shared.myAddressesByHash:
myAddress = shared.myAddressesByHash[requestedHash]
elif requestedAddressVersionNumber >= 4:
requestedTag = data[readPosition:readPosition + 32]
@ -233,7 +233,7 @@ class objectProcessor(threading.Thread):
logger.debug(
'the tag requested in this getpubkey request is: %s',
hexlify(requestedTag))
if requestedTag in shared.myAddressesByTag:
if bytes(requestedTag) in shared.myAddressesByTag:
myAddress = shared.myAddressesByTag[requestedTag]
if myAddress == '':
@ -328,7 +328,7 @@ class objectProcessor(threading.Thread):
dataToStore = data[20:readPosition]
sha = hashlib.new('sha512')
sha.update(
'\x04' + publicSigningKey + '\x04' + publicEncryptionKey)
'\x04'.encode() + publicSigningKey + '\x04'.encode() + publicEncryptionKey)
ripe = RIPEMD160Hash(sha.digest()).digest()
if logger.isEnabledFor(logging.DEBUG):
@ -367,9 +367,9 @@ class objectProcessor(threading.Thread):
' Sanity check failed.')
return
readPosition += 4
publicSigningKey = '\x04' + data[readPosition:readPosition + 64]
publicSigningKey = ('\x04').encode() + data[readPosition:readPosition + 64]
readPosition += 64
publicEncryptionKey = '\x04' + data[readPosition:readPosition + 64]
publicEncryptionKey = ('\x04').encode() + data[readPosition:readPosition + 64]
readPosition += 64
_, specifiedNonceTrialsPerByteLength = decodeVarint(
data[readPosition:readPosition + 10])
@ -433,7 +433,7 @@ class objectProcessor(threading.Thread):
return
tag = data[readPosition:readPosition + 32]
if tag not in state.neededPubkeys:
if tag not in bytes(state.neededPubkeys):
logger.info(
'We don\'t need this v4 pubkey. We didn\'t ask for it.')
return
@ -866,7 +866,7 @@ class objectProcessor(threading.Thread):
elif broadcastVersion == 5:
embeddedTag = data[readPosition: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.')
return
# We are interested in this broadcast because of its tag.

View File

@ -471,8 +471,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

View File

@ -2,11 +2,12 @@
Startup operations.
"""
# pylint: disable=too-many-branches,too-many-statements
from __future__ import print_function
# import configparser
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.
@ -31,14 +39,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:
@ -49,7 +57,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:
@ -104,9 +113,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'):
@ -258,7 +268,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.
@ -281,3 +291,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)

View File

@ -22,7 +22,7 @@ def assemble_addr(peerList):
len(peerList[i:i + MAX_ADDR_COUNT]))
for stream, peer, timestamp in peerList[i:i + MAX_ADDR_COUNT]:
payload += struct.pack(
'>Q', timestamp) # 64-bit time
'>Q', int(timestamp)) # 64-bit time
payload += struct.pack('>I', stream)
payload += struct.pack(
'>q', 1) # service bit flags offered by this node

View File

@ -172,9 +172,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
except BMObjectAlreadyHaveError:
logger.debug(
'%(host)s:%(port)i already got object, skipping',
self.destination._asdict())
self.destinaestion._asdict())
except struct.error:
logger.debug('decoding error, skipping')
except ValueError:
pass
elif self.socket.type == socket.SOCK_DGRAM:
# broken read, ignore
pass
@ -206,9 +208,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
"""Decode node details from the payload"""
# protocol.checkIPAddress()
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])
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
host = base64.b32encode(host[6:]).lower() + ".onion"
else:
@ -385,7 +387,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
if dandelion and not state.dandelion:
return True
for i in map(str, items):
for i in map(bytes, items):
if i in Inventory() and not Dandelion().hasHash(i):
continue
if dandelion and not Dandelion().hasHash(i):
@ -438,7 +440,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
try:
self.object.checkObjectByType()
objectProcessorQueue.put((
self.object.objectType, buffer(self.object.data)))
self.object.objectType, memoryview(self.object.data)))
except BMObjectInvalidError:
BMProto.stopDownloadingObject(self.object.inventoryHash, True)
else:
@ -449,12 +451,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker):
if self.object.inventoryHash in Inventory() and Dandelion().hasHash(self.object.inventoryHash):
Dandelion().removeHash(self.object.inventoryHash, "cycle detection")
Inventory()[self.object.inventoryHash] = (
[self.object.inventoryHash] = (
self.object.objectType, self.object.streamNumber,
buffer(self.payload[objectOffset:]), self.object.expiresTime,
buffer(self.object.tag)
memoryview(self.payload[objectOffset:]), self.object.expiresTime,
memoryview(self.object.tag)
)
Inventory()[self.object.inventoryHash]
self.handleReceivedObject(
self.object.streamNumber, self.object.inventoryHash)
invQueue.put((

View File

@ -149,6 +149,9 @@ class UDPSocket(BMProto): # pylint: disable=too-many-instance-attributes
retval = self.socket.sendto(
self.write_buf, ('<broadcast>', 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)

View File

@ -0,0 +1,7 @@
"""
Simple plugin system based on setuptools
----------------------------------------
"""
# .. include:: pybitmessage.plugins.plugin.rst

View File

@ -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

View File

@ -1,7 +1,15 @@
# -*- 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 logging
@ -36,13 +44,20 @@ 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!
config.set('bitmessagesettings', 'socksproxytype', 'SOCKS5')
logwrite(
'sockshostname is set to remote address,'
' aborting stem proxy configuration')
@ -77,6 +92,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:
@ -95,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')
)
@ -117,6 +135,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

View File

@ -278,14 +278,13 @@ def isProofOfWorkSufficient(
def CreatePacket(command, 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)
checksum = hashlib.sha512(payload).digest()[0:4]
byte = bytearray(Header.size + payload_length)
Header.pack_into(byte, 0, 0xE9BEB4D9, command.encode(), payload_length, checksum)
byte[Header.size:] = payload
return byte
return bytes(byte)
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)
)
# = 127.0.0.1. This will be ignored by the remote host. The actual remote connected IP will be used.
# python3 need to check
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF'.encode() + pack('>L', 2130706433)
#python3 need to check
payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF'.encode('raw_unicode_escape') + pack('>L', 2130706433)
# we have a separate extPort and incoming over clearnet
# or outgoing through clearnet
extport = BMConfigParser().safeGetInt('bitmessagesettings', 'extport')

View File

@ -39,15 +39,20 @@ class SqliteInventory(InventoryStorage): # pylint: disable=too-many-ancestors
return True
def __getitem__(self, hash_):
print('----------__getitem__------------------')
if hash_ == 0:
hash_ = bytes()
with self.lock:
if hash_ in self._inventory:
return self._inventory[hash_]
rows = sqlQuery(
'SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?',
sqlite3.Binary(hash_))
if not rows:
raise KeyError(hash_)
try:
if hash_ in self._inventory:
return self._inventory[hash_]
rows = sqlQuery(
'SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?',
sqlite3.Binary(hash_))
if not rows:
pass
# raise KeyError(hash_)
except:
pass
return InventoryItem(*rows[0])
def __setitem__(self, hash_, value):

View File

@ -15,14 +15,20 @@ import knownnodes
import state
from bmconfigparser import BMConfigParser
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')
program = None
def pickle_knownnodes():
@ -170,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')
@ -184,26 +207,18 @@ 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')
program.start_proxyconfig(BMConfigParser())
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)