tfc-mirror/tests/mock_classes.py

501 lines
17 KiB
Python

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-
"""
TFC - Onion-routed, endpoint secure messaging system
Copyright (C) 2013-2020 Markus Ottela
This file is part of TFC.
TFC 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.
TFC 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 TFC. If not, see <https://www.gnu.org/licenses/>.
"""
import getpass
import time
from datetime import datetime
from typing import Any, Callable, Generator, Iterable, List, Sized
import nacl.signing
from src.common.database import TFCUnencryptedDatabase
from src.common.db_contacts import Contact
from src.common.db_groups import Group
from src.common.db_keys import KeySet
from src.common.db_contacts import ContactList as OrigContactList
from src.common.db_groups import GroupList as OrigGroupList
from src.common.db_onion import OnionService as OrigOnionService
from src.common.db_keys import KeyList as OrigKeyList
from src.common.db_masterkey import MasterKey as OrigMasterKey
from src.common.gateway import Gateway as OrigGateway
from src.common.gateway import GatewaySettings as OrigGatewaySettings
from src.common.db_settings import Settings as OrigSettings
from src.common.encoding import pub_key_to_onion_address, pub_key_to_short_address
from src.common.misc import calculate_race_condition_delay
from src.common.reed_solomon import RSCodec
from src.common.statics import (DIR_USER_DATA, FINGERPRINT_LENGTH, INITIAL_HARAC, KEX_STATUS_VERIFIED, LOCAL_ID,
LOCAL_NICK, LOCAL_PUBKEY, ONION_SERVICE_PRIVATE_KEY_LENGTH, SYMMETRIC_KEY_LENGTH,
TX, WIN_TYPE_GROUP, WIN_UID_COMMAND)
from src.transmitter.windows import TxWindow as OrigTxWindow
from src.receiver.packet import PacketList as OrigPacketList
from src.receiver.windows import RxWindow as OrigRxWindow
from tests.utils import nick_to_pub_key, group_name_to_group_id
def create_contact(nick: str,
tx_fingerprint: bytes = FINGERPRINT_LENGTH * b'\x01',
rx_fingerprint: bytes = FINGERPRINT_LENGTH * b'\x02',
kex_status: bytes = KEX_STATUS_VERIFIED,
log_messages: bool = True,
file_reception: bool = True,
notifications: bool = True
) -> Contact:
"""Create a mock contact object."""
if nick == LOCAL_ID:
pub_key = LOCAL_PUBKEY
nick = LOCAL_NICK
else:
pub_key = nick_to_pub_key(nick)
return Contact(pub_key, nick,
tx_fingerprint, rx_fingerprint, kex_status,
log_messages, file_reception, notifications)
def create_group(name: str, nick_list: List[str] = None) -> Group:
"""Create a mock group object."""
if nick_list is None:
nick_list = ['Alice', 'Bob']
settings = Settings()
members = [create_contact(n) for n in nick_list]
return Group(name, group_name_to_group_id(name), False, False, members, settings, lambda: None)
def create_keyset(nick: str,
tx_key: bytes = SYMMETRIC_KEY_LENGTH * b'\x01',
tx_hek: bytes = SYMMETRIC_KEY_LENGTH * b'\x01',
rx_key: bytes = SYMMETRIC_KEY_LENGTH * b'\x01',
rx_hek: bytes = SYMMETRIC_KEY_LENGTH * b'\x01',
tx_harac: int = INITIAL_HARAC,
rx_harac: int = INITIAL_HARAC,
store_f: Callable[..., None] = None) -> KeySet:
"""Create a mock keyset object."""
pub_key = LOCAL_PUBKEY if nick == LOCAL_ID else nick_to_pub_key(nick)
return KeySet(pub_key, tx_key, tx_hek, rx_key, rx_hek, tx_harac, rx_harac,
store_keys=lambda: None if store_f is None else store_f)
def create_rx_window(nick: str = 'Alice') -> OrigRxWindow:
"""Create a mock Rx-window object."""
pub_key = LOCAL_PUBKEY if nick == LOCAL_ID else nick_to_pub_key(nick)
return RxWindow(uid=pub_key)
# Common
class ContactList(OrigContactList, Iterable, Sized):
"""Mock the object for unit testing."""
def __init__(self, nicks=None, **kwargs) -> None:
self.master_key = MasterKey()
self.settings = Settings()
self.contacts = [] if nicks is None else [create_contact(n) for n in nicks]
for key, value in kwargs.items():
setattr(self, key, value)
def __iter__(self) -> Generator:
yield from self.contacts
def store_contacts(self, replace: bool = True):
"""Mock method."""
def load_contacts(self) -> None:
"""Mock method."""
def print_contacts(self) -> None:
"""Mock method."""
class Gateway(OrigGateway):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
self.packets = []
self.settings = GatewaySettings(**kwargs)
self.rs = RSCodec(2 * self.settings.serial_error_correction)
def write(self, output: str) -> None:
"""Mock method."""
self.packets.append(output)
class GroupList(OrigGroupList, Iterable, Sized):
"""Mock the object for unit testing."""
def __init__(self, groups: List[str] = None, **kwargs) -> None:
self.master_key = MasterKey()
self.settings = Settings()
self.contact_list = ContactList()
self.groups = [] if groups is None else [(create_group(g)) for g in groups] # type: List[Group]
self.store_groups_called = False
for key, value in kwargs.items():
setattr(self, key, value)
def __iter__(self) -> Generator:
"""Mock method."""
yield from self.groups
def __len__(self) -> int:
"""Mock method."""
return len(self.groups)
def store_groups(self, replace: bool = True):
"""Mock method."""
self.store_groups_called = True
def load_groups(self) -> None:
"""Mock method."""
def print_groups(self) -> None:
"""Mock method."""
class KeyList(OrigKeyList):
"""Mock the object for unit testing."""
def __init__(self, nicks: List[str] = None, **kwargs) -> None:
self.master_key = MasterKey()
self.settings = Settings()
self.keysets = [] if nicks is None else [create_keyset(n) for n in nicks]
self.store_keys_called = False
for key, value in kwargs.items():
setattr(self, key, value)
def store_keys(self, replace: bool = True):
"""Mock method."""
self.store_keys_called = True
def load_keys(self) -> None:
"""Mock method."""
class MasterKey(OrigMasterKey):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
"""Create new MasterKey mock object."""
self.local_test = False
self.master_key = bytes(SYMMETRIC_KEY_LENGTH)
self.file_name = f'{DIR_USER_DATA}{TX}_login_data'
self.database = TFCUnencryptedDatabase(self.file_name)
for key, value in kwargs.items():
setattr(self, key, value)
def load_master_key(self) -> bytes:
"""Create mock master key bytes."""
if getpass.getpass() == 'test_password':
return self.master_key
return SYMMETRIC_KEY_LENGTH * b'f'
class OnionService(OrigOnionService):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
"""Create new OnionService mock object."""
self.onion_private_key = ONION_SERVICE_PRIVATE_KEY_LENGTH*b'a'
self.conf_code = b'a'
self.public_key = bytes(nacl.signing.SigningKey(seed=self.onion_private_key).verify_key)
self.user_onion_address = pub_key_to_onion_address(self.public_key)
self.user_short_address = pub_key_to_short_address(self.public_key)
self.is_delivered = False
for key, value in kwargs.items():
setattr(self, key, value)
# Transmitter Program
class Settings(OrigSettings):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
"""Create new Settings mock object."""
self.disable_gui_dialog = False
self.max_number_of_group_members = 50
self.max_number_of_groups = 50
self.max_number_of_contacts = 50
self.log_messages_by_default = False
self.accept_files_by_default = False
self.show_notifications_by_default = True
self.log_file_masking = False
self.ask_password_for_log_access = True
# Transmitter settings
self.nc_bypass_messages = False
self.confirm_sent_files = True
self.double_space_exits = False
self.traffic_masking = False
self.tm_static_delay = 2.0
self.tm_random_delay = 2.0
# Relay settings
self.allow_contact_requests = True
# Receiver settings
self.new_message_notify_preview = False
self.new_message_notify_duration = 1.0
self.max_decompress_size = 100_000_000
self.master_key = MasterKey()
self.software_operation = TX
self.local_testing_mode = False
self.all_keys = list(vars(self).keys())
self.key_list = self.all_keys[:self.all_keys.index('master_key')]
self.defaults = {k: self.__dict__[k] for k in self.key_list}
# Override defaults with specified kwargs
for key, value in kwargs.items():
setattr(self, key, value)
def store_settings(self, replace: bool = True):
"""Mock method."""
def load_settings(self) -> None:
"""Mock method."""
@staticmethod
def validate_key_value_pair(key: str,
value: str,
contact_list: 'ContactList',
group_list: 'GroupList'
) -> None:
"""Mock method."""
# Transmitter Program
class GatewaySettings(OrigGatewaySettings):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
"""Create new GatewaySettings mock object."""
self.serial_baudrate = 19200
self.serial_error_correction = 5
self.use_serial_usb_adapter = True
self.built_in_serial_interface = 'ttyS0'
self.software_operation = TX
self.local_testing_mode = False
self.data_diode_sockets = False
self.all_keys = list(vars(self).keys())
self.key_list = self.all_keys[:self.all_keys.index('software_operation')]
self.defaults = {k: self.__dict__[k] for k in self.key_list}
self.session_serial_error_correction = self.serial_error_correction
self.session_serial_baudrate = self.serial_baudrate
self.session_usb_serial_adapter = self.use_serial_usb_adapter
self.tx_inter_packet_delay = 0.0
self.rx_receive_timeout = 0.0
self.race_condition_delay = calculate_race_condition_delay(self.session_serial_error_correction,
self.serial_baudrate)
# Override defaults with specified kwargs
for key, value in kwargs.items():
setattr(self, key, value)
def store_settings(self) -> None:
"""Mock method."""
def load_settings(self) -> None:
"""Mock method."""
class TxWindow(OrigTxWindow):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
"""Create new TxWindow mock object."""
self.contact_list = ContactList()
self.group_list = GroupList()
self.window_contacts = []
self.group = None
self.contact = None
self.name = None
self.type = None
self.uid = None
self.group_id = None
self.imc_name = None
for key, value in kwargs.items():
setattr(self, key, value)
class UserInput(object):
"""Mock the object for unit testing."""
def __init__(self, plaintext: str = None, **kwargs: Any) -> None:
"""Create new UserInput mock object."""
self.plaintext = plaintext
self.type = None
for key, value in kwargs.items():
setattr(self, key, value)
# Receiver Program
class Packet(object):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
"""Create new Pack mock object."""
self.account = None
self.contact = None
self.origin = None
self.type = None
self.settings = None
self.f_name = None
self.f_size = None
self.f_packets = None
self.f_eta = None
self.lt_active = False
self.is_complete = False
self.assembly_pt_list = []
self.payload = None # Unittest mock return value
for key, value in kwargs.items():
setattr(self, key, value)
def add_packet(self, packet: bytes) -> None:
"""Mock method."""
def assemble_message_packet(self) -> None:
"""Mock method."""
return self.payload
def assemble_and_store_file(self) -> None:
"""Mock method."""
return self.payload
def assemble_command_packet(self) -> None:
"""Mock method."""
return self.payload
class PacketList(OrigPacketList):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
self.settings = Settings()
self.contact_list = ContactList()
self.packets = []
for key, value in kwargs.items():
setattr(self, key, value)
class RxWindow(OrigRxWindow):
"""Mock the object for unit testing."""
def __init__(self, **kwargs: Any) -> None:
self.uid = None
self.contact_list = ContactList()
self.group_list = GroupList()
self.settings = Settings()
self.packet_list = PacketList()
self.is_active = False
self.group_timestamp = time.time() * 1000
self.group = None
self.window_contacts = []
self.message_log = []
self.handle_dict = dict()
self.previous_msg_ts = datetime.now()
self.unread_messages = 0
self.type = None
self.type_print = None
self.name = None
for key, value in kwargs.items():
setattr(self, key, value)
class WindowList(object):
"""Mock the object for unit testing."""
def __init__(self, nicks: List[str] = None, **kwargs: Any) -> None:
"""Create new WindowList mock object."""
self.contact_list = ContactList()
self.group_list = GroupList()
self.packet_list = PacketList()
self.settings = Settings()
self.windows = [] if nicks is None else [create_rx_window(n) for n in nicks]
self.active_win = None
for key, value in kwargs.items():
setattr(self, key, value)
def __len__(self) -> int:
return len(self.windows)
def __iter__(self) -> RxWindow:
yield from self.windows
def group_windows(self) -> List[RxWindow]:
"""Mock method."""
return [w for w in self.windows if w.type == WIN_TYPE_GROUP]
def set_active_rx_window(self, name: bytes) -> None:
"""Mock method."""
if self.active_win is not None:
self.active_win.is_active = False
self.active_win = self.get_window(name)
self.active_win.is_active = True
def has_window(self, name: bytes) -> bool:
"""Mock method."""
return name in self.get_list_of_window_names()
def get_list_of_window_names(self) -> List[bytes]:
"""Mock method."""
return [w.uid for w in self.windows]
def get_command_window(self) -> RxWindow:
"""Mock method."""
return self.get_window(WIN_UID_COMMAND)
def remove_window(self, uid: bytes) -> None:
"""Mock method."""
for i, w in enumerate(self.windows):
if uid == w.uid:
del self.windows[i]
break
def get_window(self, uid: bytes) -> RxWindow:
"""Mock method."""
if not self.has_window(uid):
self.windows.append(RxWindow(uid=uid,
contact_list=self.contact_list,
group_list =self.group_list,
settings =self.settings,
packet_list =self.packet_list))
return next(w for w in self.windows if w.uid == uid)