shared quality fixes

This commit is contained in:
lakshyacis 2019-10-22 19:53:53 +05:30
parent 27be035e51
commit 6f91ba1b33
No known key found for this signature in database
GPG Key ID: D2C539C8EC63E9EB

View File

@ -1,21 +1,28 @@
from __future__ import division """
Some shared functions
.. deprecated:: 0.6.3
Should be moved to different places and this file removed,
but it needs refactoring.
"""
from __future__ import division
# Libraries. # Libraries.
import hashlib
import os import os
import sys import sys
import stat import stat
import threading import threading
import hashlib
import subprocess import subprocess
from binascii import hexlify from binascii import hexlify
from pyelliptic import arithmetic from pyelliptic import arithmetic
# Project imports. # Project imports.
import state
import highlevelcrypto import highlevelcrypto
import state
from addresses import decodeAddress, encodeVarint
from bmconfigparser import BMConfigParser from bmconfigparser import BMConfigParser
from debug import logger from debug import logger
from addresses import decodeAddress, encodeVarint
from helper_sql import sqlQuery from helper_sql import sqlQuery
@ -56,6 +63,7 @@ maximumLengthOfTimeToBotherResendingMessages = 0
def isAddressInMyAddressBook(address): def isAddressInMyAddressBook(address):
"""Is address in my addressbook?"""
queryreturn = sqlQuery( queryreturn = sqlQuery(
'''select address from addressbook where address=?''', '''select address from addressbook where address=?''',
address) address)
@ -64,6 +72,7 @@ def isAddressInMyAddressBook(address):
# At this point we should really just have a isAddressInMy(book, address)... # At this point we should really just have a isAddressInMy(book, address)...
def isAddressInMySubscriptionsList(address): def isAddressInMySubscriptionsList(address):
"""Am I subscribed to this address?"""
queryreturn = sqlQuery( queryreturn = sqlQuery(
'''select * from subscriptions where address=?''', '''select * from subscriptions where address=?''',
str(address)) str(address))
@ -71,6 +80,7 @@ def isAddressInMySubscriptionsList(address):
def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address):
"""Am I subscribed to this address, is it in my addressbook or whitelist?"""
if isAddressInMyAddressBook(address): if isAddressInMyAddressBook(address):
return True return True
@ -90,7 +100,8 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address):
return False return False
def decodeWalletImportFormat(WIFstring): def decodeWalletImportFormat(WIFstring): # pylint: disable=inconsistent-return-statements
"""Convert private key from base58 that's used in the config file to 8-bit binary string"""
fullString = arithmetic.changebase(WIFstring, 58, 256) fullString = arithmetic.changebase(WIFstring, 58, 256)
privkey = fullString[:-4] privkey = fullString[:-4]
if fullString[-4:] != \ if fullString[-4:] != \
@ -101,7 +112,7 @@ def decodeWalletImportFormat(WIFstring):
' 6 characters of the PRIVATE key: %s', ' 6 characters of the PRIVATE key: %s',
str(WIFstring)[:6] str(WIFstring)[:6]
) )
os._exit(0) os._exit(0) # pylint: disable=protected-access
# return "" # return ""
elif privkey[0] == '\x80': # checksum passed elif privkey[0] == '\x80': # checksum passed
return privkey[1:] return privkey[1:]
@ -111,10 +122,11 @@ def decodeWalletImportFormat(WIFstring):
' the checksum passed but the key doesn\'t begin with hex 80.' ' the checksum passed but the key doesn\'t begin with hex 80.'
' Here is the PRIVATE key: %s', WIFstring ' Here is the PRIVATE key: %s', WIFstring
) )
os._exit(0) os._exit(0) # pylint: disable=protected-access
def reloadMyAddressHashes(): def reloadMyAddressHashes():
"""Reinitialise runtime data (e.g. encryption objects, address hashes) from the config file"""
logger.debug('reloading keys from keys.dat file') logger.debug('reloading keys from keys.dat file')
myECCryptorObjects.clear() myECCryptorObjects.clear()
myAddressesByHash.clear() myAddressesByHash.clear()
@ -128,26 +140,21 @@ def reloadMyAddressHashes():
if isEnabled: if isEnabled:
hasEnabledKeys = True hasEnabledKeys = True
# status # status
_, addressVersionNumber, streamNumber, hash = \ addressVersionNumber, streamNumber, hashobj = decodeAddress(addressInKeysFile)[1:]
decodeAddress(addressInKeysFile)
if addressVersionNumber in (2, 3, 4): if addressVersionNumber in (2, 3, 4):
# Returns a simple 32 bytes of information encoded # Returns a simple 32 bytes of information encoded
# in 64 Hex characters, or null if there was an error. # in 64 Hex characters, or null if there was an error.
privEncryptionKey = hexlify(decodeWalletImportFormat( privEncryptionKey = hexlify(decodeWalletImportFormat(
BMConfigParser().get(addressInKeysFile, 'privencryptionkey')) BMConfigParser().get(addressInKeysFile, 'privencryptionkey')))
)
# It is 32 bytes encoded as 64 hex characters # It is 32 bytes encoded as 64 hex characters
if len(privEncryptionKey) == 64: if len(privEncryptionKey) == 64:
myECCryptorObjects[hash] = \ myECCryptorObjects[hashobj] = \
highlevelcrypto.makeCryptor(privEncryptionKey) highlevelcrypto.makeCryptor(privEncryptionKey)
myAddressesByHash[hash] = addressInKeysFile myAddressesByHash[hashobj] = addressInKeysFile
tag = hashlib.sha512(hashlib.sha512( tag = hashlib.sha512(hashlib.sha512(
encodeVarint(addressVersionNumber) + encodeVarint(addressVersionNumber) +
encodeVarint(streamNumber) + hash).digest() encodeVarint(streamNumber) + hashobj).digest()).digest()[32:]
).digest()[32:]
myAddressesByTag[tag] = addressInKeysFile myAddressesByTag[tag] = addressInKeysFile
else: else:
logger.error( logger.error(
'Error in reloadMyAddressHashes: Can\'t handle' 'Error in reloadMyAddressHashes: Can\'t handle'
@ -159,6 +166,7 @@ def reloadMyAddressHashes():
def reloadBroadcastSendersForWhichImWatching(): def reloadBroadcastSendersForWhichImWatching():
"""Reinitialise runtime data for the broadcasts I'm subscribed to from the config file"""
broadcastSendersForWhichImWatching.clear() broadcastSendersForWhichImWatching.clear()
MyECSubscriptionCryptorObjects.clear() MyECSubscriptionCryptorObjects.clear()
queryreturn = sqlQuery('SELECT address FROM subscriptions where enabled=1') queryreturn = sqlQuery('SELECT address FROM subscriptions where enabled=1')
@ -166,9 +174,9 @@ def reloadBroadcastSendersForWhichImWatching():
for row in queryreturn: for row in queryreturn:
address, = row address, = row
# status # status
_, addressVersionNumber, streamNumber, hash = decodeAddress(address) addressVersionNumber, streamNumber, hashobj = decodeAddress(address)[1:]
if addressVersionNumber == 2: if addressVersionNumber == 2:
broadcastSendersForWhichImWatching[hash] = 0 broadcastSendersForWhichImWatching[hashobj] = 0
# Now, for all addresses, even version 2 addresses, # Now, for all addresses, even version 2 addresses,
# we should create Cryptor objects in a dictionary which we will # we should create Cryptor objects in a dictionary which we will
# use to attempt to decrypt encrypted broadcast messages. # use to attempt to decrypt encrypted broadcast messages.
@ -176,14 +184,14 @@ def reloadBroadcastSendersForWhichImWatching():
if addressVersionNumber <= 3: if addressVersionNumber <= 3:
privEncryptionKey = hashlib.sha512( privEncryptionKey = hashlib.sha512(
encodeVarint(addressVersionNumber) + encodeVarint(addressVersionNumber) +
encodeVarint(streamNumber) + hash encodeVarint(streamNumber) + hashobj
).digest()[:32] ).digest()[:32]
MyECSubscriptionCryptorObjects[hash] = \ MyECSubscriptionCryptorObjects[hashobj] = \
highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))
else: else:
doubleHashOfAddressData = hashlib.sha512(hashlib.sha512( doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(
encodeVarint(addressVersionNumber) + encodeVarint(addressVersionNumber) +
encodeVarint(streamNumber) + hash encodeVarint(streamNumber) + hashobj
).digest()).digest() ).digest()).digest()
tag = doubleHashOfAddressData[32:] tag = doubleHashOfAddressData[32:]
privEncryptionKey = doubleHashOfAddressData[:32] privEncryptionKey = doubleHashOfAddressData[:32]
@ -192,21 +200,22 @@ def reloadBroadcastSendersForWhichImWatching():
def fixPotentiallyInvalidUTF8Data(text): def fixPotentiallyInvalidUTF8Data(text):
"""Sanitise invalid UTF-8 strings"""
try: try:
unicode(text, 'utf-8') unicode(text, 'utf-8')
return text return text
except: except:
return 'Part of the message is corrupt. The message cannot be' \ return 'Part of the message is corrupt. The message cannot be' \
' displayed the normal way.\n\n' + repr(text) ' displayed the normal way.\n\n' + repr(text)
# Checks sensitive file permissions for inappropriate umask
# during keys.dat creation. (Or unwise subsequent chmod.)
#
# Returns true iff file appears to have appropriate permissions.
def checkSensitiveFilePermissions(filename): def checkSensitiveFilePermissions(filename):
"""
:param str filename: path to the file
:return: True if file appears to have appropriate permissions.
"""
if sys.platform == 'win32': if sys.platform == 'win32':
# TODO: This might deserve extra checks by someone familiar with # .. todo:: This might deserve extra checks by someone familiar with
# Windows systems. # Windows systems.
return True return True
elif sys.platform[:7] == 'freebsd': elif sys.platform[:7] == 'freebsd':
@ -214,30 +223,30 @@ def checkSensitiveFilePermissions(filename):
present_permissions = os.stat(filename)[0] present_permissions = os.stat(filename)[0]
disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO
return present_permissions & disallowed_permissions == 0 return present_permissions & disallowed_permissions == 0
else: try:
try: # Skip known problems for non-Win32 filesystems
# Skip known problems for non-Win32 filesystems # without POSIX permissions.
# without POSIX permissions. fstype = subprocess.check_output(
fstype = subprocess.check_output( 'stat -f -c "%%T" %s' % (filename),
'stat -f -c "%%T" %s' % (filename), shell=True,
shell=True, stderr=subprocess.STDOUT
stderr=subprocess.STDOUT )
) if 'fuseblk' in fstype:
if 'fuseblk' in fstype: logger.info(
logger.info( 'Skipping file permissions check for %s.'
'Skipping file permissions check for %s.' ' Filesystem fuseblk detected.', filename)
' Filesystem fuseblk detected.', filename) return True
return True except:
except: # Swallow exception here, but we might run into trouble later!
# Swallow exception here, but we might run into trouble later! logger.error('Could not determine filesystem type. %s', filename)
logger.error('Could not determine filesystem type. %s', filename) present_permissions = os.stat(filename)[0]
present_permissions = os.stat(filename)[0] disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO
disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO return present_permissions & disallowed_permissions == 0
return present_permissions & disallowed_permissions == 0
# Fixes permissions on a sensitive file. # Fixes permissions on a sensitive file.
def fixSensitiveFilePermissions(filename, hasEnabledKeys): def fixSensitiveFilePermissions(filename, hasEnabledKeys):
"""Try to change file permissions to be more restrictive"""
if hasEnabledKeys: if hasEnabledKeys:
logger.warning( logger.warning(
'Keyfile had insecure permissions, and there were enabled' 'Keyfile had insecure permissions, and there were enabled'
@ -262,6 +271,7 @@ def fixSensitiveFilePermissions(filename, hasEnabledKeys):
def openKeysFile(): def openKeysFile():
"""Open keys file with an external editor"""
if 'linux' in sys.platform: if 'linux' in sys.platform:
subprocess.call(["xdg-open", state.appdata + 'keys.dat']) subprocess.call(["xdg-open", state.appdata + 'keys.dat'])
else: else: