Mostly finished with wot command processing

This commit is contained in:
Kevin F 2022-09-23 17:31:34 -04:00
parent d915a2aaed
commit a517ad3aee
15 changed files with 122 additions and 207 deletions

View File

@ -1,13 +1,8 @@
PyNaCl==1.5.0
PySocks==1.7.1
stem==1.8.0
unpaddedbase32==0.2.0
niceware==0.2.1
psutil==5.9.1
filenuke==0.0.0
ujson==5.4.0
cffi==1.15.1
onionrblocks==7.0.0
ordered-set==4.1.0
cherrypy==18.8.0
json-rpc==1.13.0

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python3
"""Generate a 16 word passphase with 256 bits of entropy.
Specify true to reduce to 128 bits"""
import sys
import niceware
byte_count = 32 # 256 bits of entropy with niceware
arg = False
try:
arg = sys.argv[1].lower()
if arg == 'true':
byte_count = 16
except IndexError: pass
print(' '.join(niceware.generate_passphrase(byte_count)))

View File

@ -1,95 +0,0 @@
"""Onionr - Private P2P Communication.
This module defines user ID-related CLI commands
"""
import sys
import getpass
import unpaddedbase32
import niceware
import logger
import onionrexceptions
from onionrutils import stringvalidators, bytesconverter
import config
import keymanager
import onionrcrypto
import onionrvalues
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
DETERMINISTIC_REQUIREMENT = onionrvalues.PASSWORD_LENGTH
def add_ID():
"""Command to create a new user ID key pair."""
key_manager = keymanager.KeyManager()
pw = ""
try:
sys.argv[2] # pylint: disable=W0104
if not sys.argv[2].lower() == 'true':
raise ValueError
except (IndexError, ValueError):
newID = key_manager.addKey()[0]
else:
pw = "-".join(niceware.generate_passphrase(32))
newID, privKey = onionrcrypto.generate_deterministic(pw)
try:
key_manager.addKey(pubKey=newID,
privKey=privKey)
except ValueError:
logger.error(
'That ID is already available, you can change to it ' +
'with the change-id command.', terminal=True)
return
if pw:
print("Phrase to restore ID:", pw)
logger.info('Added ID: %s' %
(bytesconverter.bytes_to_str(newID.replace('=', '')),), terminal=True)
add_ID.onionr_help = "If the first argument is true, " # type: ignore
add_ID.onionr_help += "Onionr will show a deterministic " # type: ignore
add_ID.onionr_help += "generation prompt. Otherwise it will " # type: ignore
add_ID.onionr_help += "generate & save a new random key pair." # type: ignore
def change_ID():
"""Command to change active ID from argv or stdin."""
key_manager = keymanager.KeyManager()
try:
key = sys.argv[2]
key = unpaddedbase32.repad(key.encode()).decode()
except IndexError:
logger.warn('Specify pubkey to use', terminal=True)
else:
if stringvalidators.validate_pub_key(key):
key_list = key_manager.getPubkeyList()
if key in key_list or key.replace('=', '') in key_list:
config.set('general.public_key', key)
config.save()
logger.info('Set active key to: %s' % (key,), terminal=True)
logger.info('Restart Onionr if it is running.', terminal=True)
else:
logger.warn('That key does not exist', terminal=True)
else:
logger.warn('Invalid key %s' % (key,), terminal=True)
change_ID.onionr_help = "<pubkey>: Switches Onionr to " # type: ignore
change_ID.onionr_help += "use a different user ID key. " # type: ignore
change_ID.onionr_help += "You should immediately restart " # type: ignore
change_ID.onionr_help += "Onionr if it is running." # type: ignore

View File

@ -1,42 +0,0 @@
"""
Onionr - Private P2P Communication
validate various string data types
"""
import base64
import string
import unpaddedbase32, nacl.signing, nacl.encoding
from onionrutils import bytesconverter
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
def validate_pub_key(key):
"""Validate if a string is a valid base32 encoded Ed25519 key"""
if type(key) is type(None):
return False
# Accept keys that have no = padding
key = unpaddedbase32.repad(bytesconverter.str_to_bytes(key))
retVal = False
try:
nacl.signing.SigningKey(seed=key, encoder=nacl.encoding.Base32Encoder)
except nacl.exceptions.ValueError:
pass
except base64.binascii.Error as _:
pass
else:
retVal = True
return retVal

View File

@ -3,7 +3,6 @@
size related utilities
"""
import os
from onionrutils import stringvalidators
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -7,9 +7,6 @@ from nacl.signing import SigningKey, VerifyKey
from nacl.encoding import Base32Encoder
from nacl.exceptions import BadSignatureError
from wot.identity.processtrustsignature import process_trust_signature
from wot.identity.processrevokesignature import process_revoke_signature
from wot.identity.processidentityannounce import process_identity_announce
from wot.identity.name import IdentityName
from wot.identity.name import max_len as max_name_len
from wot.identity.identityset import IdentitySet, identities

View File

@ -1,28 +0,0 @@
import logger
from nacl.signing import VerifyKey
from wot.blockprocessingevent import WotCommand
from wot.identity.identityset import identities
def process_identity_announce(identity_announce_payload):
if len(identity_announce_payload) != 97:
logger.warn(
f'Identity announce signature size is invalid',
terminal=True)
# verify that this is a signature for an announce command
if identity_announce_payload[0] != WotCommand.ANNOUNCE:
logger.warn(
f'Invalid command in signature' , terminal=True)
return
# signer is first 32 bytes
signer = identity_announce_payload[1:33]
# signature is last 64 bytes
signature = identity_announce_payload[33:]
# If bad signature, it raises nacl.exceptions.BadSignatureError
VerifyKey(signer).verify(identity_announce_payload[0] + signer, signature)
# noop if already announced
identities.add

View File

@ -0,0 +1,4 @@
from .processidentityannounce import process_identity_announce
from .processrevokesignature import process_revoke_signature
from .processtrustsignature import process_trust_signature
from .processrevokeidentity import process_identity_revoke

View File

@ -0,0 +1,17 @@
import logger
from nacl.signing import VerifyKey
from wot.blockprocessingevent import WotCommand
from wot.identity import Identity
from wot.identity.identityset import identities
def process_identity_announce(identity_announce_payload):
# verify that this is a signature for an announce command
if identity_announce_payload[0] != WotCommand.ANNOUNCE:
logger.warn(
f'Invalid command in signature' , terminal=True)
return
iden = Identity.deserialize(identity_announce_payload[1:])
identities.add(iden)

View File

@ -0,0 +1,21 @@
import logger
from nacl.signing import VerifyKey
from wot.blockprocessingevent import WotCommand
from wot.identity import Identity
from wot.identity.identityset import identities
def process_identity_revoke(revoke_payload: bytes):
wot_cmd = revoke_payload[0].to_bytes(1, 'big')
if revoke_payload[0] != WotCommand.REVOKE:
logger.warn(
f'Invalid command in signature', terminal=True)
return
revoked_identity = revoke_payload[1:33]
signature = revoke_payload[33:]
# raises nacl.exceptions.BadSignatureError if bad signature
VerifyKey(revoked_identity).verify(wot_cmd + revoked_identity, signature)
identities.remove(Identity(revoked_identity, "etc"))

View File

@ -11,6 +11,7 @@ def process_trust_signature(sig_payload: bytes):
if len(sig_payload) != 129:
logger.warn(
f'Signature size is invalid for a signed identity')
return
# verify that this is a signature for a trust command
if sig_payload[0] != WotCommand.TRUST:

View File

@ -15,10 +15,11 @@ os.environ["ONIONR_HOME"] = TEST_DIR
import unittest
import sys
sys.path.append(".")
sys.path.append('static-data/default-plugins/wot/wot')
sys.path.append('static-data/default-plugins/wot/')
sys.path.append("src/")
import identity
from identity.identityset import identities
from wot.identityprocessing import process_identity_announce
from wot import identity
from wot.identity.identityset import identities
class WotCommand(IntEnum):
@ -34,16 +35,14 @@ class TestAnnounceIdentityPayload(unittest.TestCase):
identities.clear()
signing_key = SigningKey.generate()
main_iden = identity.Identity(signing_key.verify_key, "test")
main_iden = identity.Identity(signing_key, "test")
wot_cmd = int(WotCommand.ANNOUNCE).to_bytes(1, 'big')
announce_signature = signing_key.sign(wot_cmd + bytes(main_iden))
announce_signature_payload = wot_cmd + bytes(signing_key.verify_key) + \
bytes(announce_signature)
serialized_iden = wot_cmd + main_iden.serialize()
identity.process_identity_announce(announce_signature_payload)
process_identity_announce(serialized_iden)
self.assertEqual(main_iden, identities[0])
self.assertEqual(bytes(main_iden.key), bytes(list(identities)[0].key))
self.assertEqual(len(identities), 1)
self.assertEqual(len(main_iden.trusted), 0)

View File

@ -0,0 +1,68 @@
import os, uuid
from random import randint
from time import sleep
from enum import IntEnum, auto
from nacl.signing import SigningKey, VerifyKey
from nacl.exceptions import BadSignatureError
import nacl
import secrets
import onionrblocks
TEST_DIR = 'testdata/%s-%s' % (str(uuid.uuid4())[:6], os.path.basename(__file__)) + '/'
print("Test directory:", TEST_DIR)
os.environ["ONIONR_HOME"] = TEST_DIR
import unittest
import sys
sys.path.append(".")
sys.path.append('static-data/default-plugins/wot/')
sys.path.append("src/")
from wot.identityprocessing import process_identity_revoke
from wot import identity
from wot.identity.identityset import identities
class WotCommand(IntEnum):
TRUST = 1
REVOKE_TRUST = auto()
ANNOUNCE = auto()
REVOKE = auto()
class TestRevokeIdentityPayload(unittest.TestCase):
def test_revoke_identity_invalid(self):
identities.clear()
signing_key = SigningKey.generate()
main_iden = identity.Identity(signing_key, "test")
identities.add(main_iden)
wot_cmd = int(WotCommand.REVOKE).to_bytes(1, 'big')
signed = signing_key.sign(wot_cmd + bytes(main_iden.key))
revoke_payload = wot_cmd + bytes(signing_key.verify_key) + signed.signature
self.assertRaises(nacl.exceptions.Inv process_identity_revoke(revoke_payload)
self.assertEqual(len(identities), 1)
def test_revoke_identity_payload(self):
identities.clear()
signing_key = SigningKey.generate()
main_iden = identity.Identity(signing_key, "test")
identities.add(main_iden)
wot_cmd = int(WotCommand.REVOKE).to_bytes(1, 'big')
signed = signing_key.sign(wot_cmd + bytes(main_iden.key))
revoke_payload = wot_cmd + bytes(signing_key.verify_key) + signed.signature
process_identity_revoke(revoke_payload)
self.assertEqual(len(identities), 0)
unittest.main()

View File

@ -15,10 +15,10 @@ os.environ["ONIONR_HOME"] = TEST_DIR
import unittest
import sys
sys.path.append(".")
sys.path.append('static-data/default-plugins/wot/wot')
sys.path.append('static-data/default-plugins/wot/')
sys.path.append("src/")
import identity
from identity.identityset import identities
from wot import identity
from wot.identity.identityset import identities
class WotCommand(IntEnum):