added keymanager test
This commit is contained in:
parent
b24c683f5f
commit
ef6bb8c1e9
@ -18,6 +18,7 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
'''
|
'''
|
||||||
DENIABLE_PEER_ADDRESS = "OVPCZLOXD6DC5JHX4EQ3PSOGAZ3T24F75HQLIUZSDSMYPEOXCPFA===="
|
DENIABLE_PEER_ADDRESS = "OVPCZLOXD6DC5JHX4EQ3PSOGAZ3T24F75HQLIUZSDSMYPEOXCPFA===="
|
||||||
|
PASSWORD_LENGTH = 25
|
||||||
class OnionrValues:
|
class OnionrValues:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.passwordLength = 20
|
self.passwordLength = 20
|
||||||
|
@ -25,6 +25,7 @@ class KeyManager:
|
|||||||
self.keyFile = filepaths.keys_file
|
self.keyFile = filepaths.keys_file
|
||||||
|
|
||||||
def addKey(self, pubKey=None, privKey=None):
|
def addKey(self, pubKey=None, privKey=None):
|
||||||
|
'''Add a new key pair, either specified or none to generate a new pair automatically'''
|
||||||
if type(pubKey) is type(None) and type(privKey) is type(None):
|
if type(pubKey) is type(None) and type(privKey) is type(None):
|
||||||
pubKey, privKey = generate.generate_pub_key()
|
pubKey, privKey = generate.generate_pub_key()
|
||||||
pubKey = bytesconverter.bytes_to_str(pubKey)
|
pubKey = bytesconverter.bytes_to_str(pubKey)
|
||||||
@ -54,8 +55,11 @@ class KeyManager:
|
|||||||
def getPubkeyList(self):
|
def getPubkeyList(self):
|
||||||
'''Return a list of the user's keys'''
|
'''Return a list of the user's keys'''
|
||||||
keyList = []
|
keyList = []
|
||||||
with open(self.keyFile, "r") as keyFile:
|
try:
|
||||||
keyData = keyFile.read()
|
with open(self.keyFile, "r") as keyFile:
|
||||||
|
keyData = keyFile.read()
|
||||||
|
except FileNotFoundError:
|
||||||
|
keyData = ''
|
||||||
keyData = keyData.split('\n')
|
keyData = keyData.split('\n')
|
||||||
for pair in keyData:
|
for pair in keyData:
|
||||||
if len(pair) > 0: keyList.append(pair.split(',')[0])
|
if len(pair) > 0: keyList.append(pair.split(',')[0])
|
||||||
|
@ -77,10 +77,6 @@ class Onionr:
|
|||||||
# Load global configuration data
|
# Load global configuration data
|
||||||
data_exists = Onionr.setupConfig(self)
|
data_exists = Onionr.setupConfig(self)
|
||||||
|
|
||||||
# If block data folder does not exist
|
|
||||||
if not os.path.exists(self.dataDir + 'blocks/'):
|
|
||||||
os.mkdir(self.dataDir + 'blocks/')
|
|
||||||
|
|
||||||
# Copy default plugins into plugins folder
|
# Copy default plugins into plugins folder
|
||||||
if not os.path.exists(plugins.get_plugins_folder()):
|
if not os.path.exists(plugins.get_plugins_folder()):
|
||||||
if os.path.exists('static-data/default-plugins/'):
|
if os.path.exists('static-data/default-plugins/'):
|
||||||
|
@ -23,31 +23,35 @@ import logger, onionrexceptions
|
|||||||
from onionrutils import stringvalidators, bytesconverter
|
from onionrutils import stringvalidators, bytesconverter
|
||||||
from onionrusers import onionrusers, contactmanager
|
from onionrusers import onionrusers, contactmanager
|
||||||
from coredb import keydb
|
from coredb import keydb
|
||||||
|
import keymanager, onionrcrypto
|
||||||
import unpaddedbase32
|
import unpaddedbase32
|
||||||
|
from etc import onionrvalues
|
||||||
|
DETERMINISTIC_REQUIREMENT = onionrvalues.PASSWORD_LENGTH
|
||||||
def add_ID(o_inst):
|
def add_ID(o_inst):
|
||||||
|
key_manager = keymanager.KeyManager()
|
||||||
try:
|
try:
|
||||||
sys.argv[2]
|
sys.argv[2]
|
||||||
assert sys.argv[2] == 'true'
|
assert sys.argv[2] == 'true'
|
||||||
except (IndexError, AssertionError) as e:
|
except (IndexError, AssertionError) as e:
|
||||||
newID = o_inst.crypto.keyManager.addKey()[0]
|
newID = key_manager.addKey()[0]
|
||||||
else:
|
else:
|
||||||
logger.warn('Deterministic keys require random and long passphrases.', terminal=True)
|
logger.warn('Deterministic keys require random and long passphrases.', terminal=True)
|
||||||
logger.warn('If a good passphrase is not used, your key can be easily stolen.', terminal=True)
|
logger.warn('If a good passphrase is not used, your key can be easily stolen.', terminal=True)
|
||||||
logger.warn('You should use a series of hard to guess words, see this for reference: https://www.xkcd.com/936/', terminal=True)
|
logger.warn('You should use a series of hard to guess words, see this for reference: https://www.xkcd.com/936/', terminal=True)
|
||||||
pass1 = getpass.getpass(prompt='Enter at least %s characters: ' % (o_inst.crypto.deterministicRequirement,))
|
pass1 = getpass.getpass(prompt='Enter at least %s characters: ' % (DETERMINISTIC_REQUIREMENT,))
|
||||||
pass2 = getpass.getpass(prompt='Confirm entry: ')
|
pass2 = getpass.getpass(prompt='Confirm entry: ')
|
||||||
if o_inst.crypto.safeCompare(pass1, pass2):
|
if onionrcrypto.cryptoutils.safe_compare(pass1, pass2):
|
||||||
try:
|
try:
|
||||||
logger.info('Generating deterministic key. This can take a while.', terminal=True)
|
logger.info('Generating deterministic key. This can take a while.', terminal=True)
|
||||||
newID, privKey = o_inst.crypto.generateDeterministic(pass1)
|
newID, privKey = onionrcrypto.generate_deterministic(pass1)
|
||||||
except onionrexceptions.PasswordStrengthError:
|
except onionrexceptions.PasswordStrengthError:
|
||||||
logger.error('Passphrase must use at least %s characters.' % (o_inst.crypto.deterministicRequirement,), terminal=True)
|
logger.error('Passphrase must use at least %s characters.' % (DETERMINISTIC_REQUIREMENT,), terminal=True)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
logger.error('Passwords do not match.', terminal=True)
|
logger.error('Passwords do not match.', terminal=True)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
try:
|
try:
|
||||||
o_inst.crypto.keyManager.addKey(pubKey=newID,
|
key_manager.addKey(pubKey=newID,
|
||||||
privKey=privKey)
|
privKey=privKey)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.error('That ID is already available, you can change to it with the change-id command.', terminal=True)
|
logger.error('That ID is already available, you can change to it with the change-id command.', terminal=True)
|
||||||
@ -55,6 +59,7 @@ def add_ID(o_inst):
|
|||||||
logger.info('Added ID: %s' % (bytesconverter.bytes_to_str(newID),), terminal=True)
|
logger.info('Added ID: %s' % (bytesconverter.bytes_to_str(newID),), terminal=True)
|
||||||
|
|
||||||
def change_ID(o_inst):
|
def change_ID(o_inst):
|
||||||
|
key_manager = keymanager.KeyManager()
|
||||||
try:
|
try:
|
||||||
key = sys.argv[2]
|
key = sys.argv[2]
|
||||||
key = unpaddedbase32.repad(key.encode()).decode()
|
key = unpaddedbase32.repad(key.encode()).decode()
|
||||||
@ -62,7 +67,7 @@ def change_ID(o_inst):
|
|||||||
logger.warn('Specify pubkey to use', terminal=True)
|
logger.warn('Specify pubkey to use', terminal=True)
|
||||||
else:
|
else:
|
||||||
if stringvalidators.validate_pub_key(key):
|
if stringvalidators.validate_pub_key(key):
|
||||||
if key in o_inst.crypto.keyManager.getPubkeyList():
|
if key in key_manager.getPubkeyList():
|
||||||
o_inst.config.set('general.public_key', key)
|
o_inst.config.set('general.public_key', key)
|
||||||
o_inst.config.save()
|
o_inst.config.save()
|
||||||
logger.info('Set active key to: %s' % (key,), terminal=True)
|
logger.info('Set active key to: %s' % (key,), terminal=True)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import nacl.signing, nacl.encoding, nacl.pwhash
|
import nacl.signing, nacl.encoding, nacl.pwhash
|
||||||
import onionrexceptions
|
import onionrexceptions
|
||||||
from onionrutils import bytesconverter
|
from onionrutils import bytesconverter
|
||||||
|
from etc import onionrvalues
|
||||||
def generate_pub_key():
|
def generate_pub_key():
|
||||||
'''Generate a Ed25519 public key pair, return tuple of base32encoded pubkey, privkey'''
|
'''Generate a Ed25519 public key pair, return tuple of base32encoded pubkey, privkey'''
|
||||||
private_key = nacl.signing.SigningKey.generate()
|
private_key = nacl.signing.SigningKey.generate()
|
||||||
@ -9,7 +10,7 @@ def generate_pub_key():
|
|||||||
|
|
||||||
def generate_deterministic(passphrase, bypassCheck=False):
|
def generate_deterministic(passphrase, bypassCheck=False):
|
||||||
'''Generate a Ed25519 public key pair from a password'''
|
'''Generate a Ed25519 public key pair from a password'''
|
||||||
passStrength = 25
|
passStrength = onionrvalues.PASSWORD_LENGTH
|
||||||
passphrase = bytesconverter.str_to_bytes(passphrase) # Convert to bytes if not already
|
passphrase = bytesconverter.str_to_bytes(passphrase) # Convert to bytes if not already
|
||||||
# Validate passphrase length
|
# Validate passphrase length
|
||||||
if not bypassCheck:
|
if not bypassCheck:
|
||||||
|
39
onionr/tests/test_keymanager.py
Normal file
39
onionr/tests/test_keymanager.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys, os
|
||||||
|
sys.path.append(".")
|
||||||
|
import unittest, uuid
|
||||||
|
|
||||||
|
TEST_DIR = 'testdata/%s-%s' % (uuid.uuid4(), os.path.basename(__file__)) + '/'
|
||||||
|
print("Test directory:", TEST_DIR)
|
||||||
|
os.environ["ONIONR_HOME"] = TEST_DIR
|
||||||
|
from utils import createdirs
|
||||||
|
from coredb import keydb
|
||||||
|
import setupconfig, keymanager, filepaths
|
||||||
|
from onionrutils import stringvalidators
|
||||||
|
createdirs.create_dirs()
|
||||||
|
setupconfig.setup_config()
|
||||||
|
pub_key = keymanager.KeyManager().getPubkeyList()[0]
|
||||||
|
class KeyManagerTest(unittest.TestCase):
|
||||||
|
def test_sane_default(self):
|
||||||
|
self.assertGreaterEqual(len(pub_key), 52)
|
||||||
|
self.assertLessEqual(len(pub_key), 56)
|
||||||
|
self.assertEqual(pub_key, keymanager.KeyManager().getPubkeyList()[0])
|
||||||
|
stringvalidators.validate_pub_key(pub_key)
|
||||||
|
def test_change(self):
|
||||||
|
new_key = keymanager.KeyManager().addKey()[0]
|
||||||
|
self.assertNotEqual(new_key, pub_key)
|
||||||
|
self.assertEqual(new_key, keymanager.KeyManager().getPubkeyList()[1])
|
||||||
|
stringvalidators.validate_pub_key(new_key)
|
||||||
|
def test_remove(self):
|
||||||
|
manager = keymanager.KeyManager()
|
||||||
|
new_key = manager.addKey()[0]
|
||||||
|
priv_key = manager.getPrivkey(new_key)
|
||||||
|
self.assertIn(new_key, manager.getPubkeyList())
|
||||||
|
with open(filepaths.keys_file, 'r') as keyfile:
|
||||||
|
self.assertIn(new_key, keyfile.read())
|
||||||
|
manager.removeKey(new_key)
|
||||||
|
with open(filepaths.keys_file, 'r') as keyfile:
|
||||||
|
self.assertNotIn(new_key, keyfile.read())
|
||||||
|
|
||||||
|
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue
Block a user