154 lines
5.9 KiB
Python
Executable File
154 lines
5.9 KiB
Python
Executable File
#!/usr/bin/env python3.6
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
TFC - Onion-routed, endpoint secure messaging system
|
|
Copyright (C) 2013-2019 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 os
|
|
import sys
|
|
import time
|
|
import typing
|
|
|
|
from typing import Dict, List, Tuple
|
|
|
|
from src.common.exceptions import FunctionReturn
|
|
from src.common.output import clear_screen
|
|
from src.common.statics import *
|
|
|
|
from src.receiver.commands import process_command
|
|
from src.receiver.files import new_file, process_file
|
|
from src.receiver.key_exchanges import process_local_key
|
|
from src.receiver.messages import process_message
|
|
from src.receiver.packet import PacketList
|
|
from src.receiver.windows import WindowList
|
|
|
|
if typing.TYPE_CHECKING:
|
|
from datetime import datetime
|
|
from multiprocessing import Queue
|
|
from src.common.db_contacts import ContactList
|
|
from src.common.db_groups import GroupList
|
|
from src.common.db_keys import KeyList
|
|
from src.common.db_masterkey import MasterKey
|
|
from src.common.db_settings import Settings
|
|
from src.common.gateway import Gateway
|
|
|
|
|
|
def output_loop(queues: Dict[bytes, 'Queue'],
|
|
gateway: 'Gateway',
|
|
settings: 'Settings',
|
|
contact_list: 'ContactList',
|
|
key_list: 'KeyList',
|
|
group_list: 'GroupList',
|
|
master_key: 'MasterKey',
|
|
stdin_fd: int,
|
|
unittest: bool = False
|
|
) -> None:
|
|
"""Process packets in message queues according to their priority."""
|
|
l_queue = queues[LOCAL_KEY_DATAGRAM_HEADER]
|
|
m_queue = queues[MESSAGE_DATAGRAM_HEADER]
|
|
f_queue = queues[FILE_DATAGRAM_HEADER]
|
|
c_queue = queues[COMMAND_DATAGRAM_HEADER]
|
|
e_queue = queues[EXIT_QUEUE]
|
|
|
|
sys.stdin = os.fdopen(stdin_fd)
|
|
packet_buf = dict() # type: Dict[bytes, List[Tuple[datetime, bytes]]]
|
|
file_buf = dict() # type: Dict[bytes, Tuple[datetime, bytes]]
|
|
file_keys = dict() # type: Dict[bytes, bytes]
|
|
|
|
kdk_hashes = [] # type: List[bytes]
|
|
packet_hashes = [] # type: List[bytes]
|
|
|
|
packet_list = PacketList(settings, contact_list)
|
|
window_list = WindowList(settings, contact_list, group_list, packet_list)
|
|
|
|
clear_screen()
|
|
while True:
|
|
try:
|
|
if l_queue.qsize() != 0:
|
|
ts, packet = l_queue.get()
|
|
process_local_key(ts, packet, window_list, contact_list, key_list,
|
|
settings, kdk_hashes, packet_hashes, l_queue)
|
|
continue
|
|
|
|
if not contact_list.has_local_contact():
|
|
time.sleep(0.1)
|
|
continue
|
|
|
|
# Commands
|
|
if c_queue.qsize() != 0:
|
|
ts, packet = c_queue.get()
|
|
process_command(ts, packet, window_list, packet_list, contact_list, key_list,
|
|
group_list, settings, master_key, gateway, e_queue)
|
|
continue
|
|
|
|
# File window refresh
|
|
if window_list.active_win is not None and window_list.active_win.uid == WIN_UID_FILE:
|
|
window_list.active_win.redraw_file_win()
|
|
|
|
# Cached message packets
|
|
for onion_pub_key in packet_buf:
|
|
if (contact_list.has_pub_key(onion_pub_key)
|
|
and key_list.has_rx_mk(onion_pub_key)
|
|
and packet_buf[onion_pub_key]):
|
|
ts, packet = packet_buf[onion_pub_key].pop(0)
|
|
process_message(ts, packet, window_list, packet_list, contact_list, key_list,
|
|
group_list, settings, master_key, file_keys)
|
|
continue
|
|
|
|
# New messages
|
|
if m_queue.qsize() != 0:
|
|
ts, packet = m_queue.get()
|
|
onion_pub_key = packet[:ONION_SERVICE_PUBLIC_KEY_LENGTH]
|
|
|
|
if contact_list.has_pub_key(onion_pub_key) and key_list.has_rx_mk(onion_pub_key):
|
|
process_message(ts, packet, window_list, packet_list, contact_list, key_list,
|
|
group_list, settings, master_key, file_keys)
|
|
else:
|
|
packet_buf.setdefault(onion_pub_key, []).append((ts, packet))
|
|
continue
|
|
|
|
# Cached files
|
|
if file_buf:
|
|
for k in file_buf:
|
|
key_to_remove = b''
|
|
try:
|
|
if k in file_keys:
|
|
key_to_remove = k
|
|
ts_, file_ct = file_buf[k]
|
|
dec_key = file_keys[k]
|
|
onion_pub_key = k[:ONION_SERVICE_PUBLIC_KEY_LENGTH]
|
|
process_file(ts_, onion_pub_key, file_ct, dec_key, contact_list, window_list, settings)
|
|
finally:
|
|
if key_to_remove:
|
|
file_buf.pop(k)
|
|
file_keys.pop(k)
|
|
break
|
|
|
|
# New files
|
|
if f_queue.qsize() != 0:
|
|
ts, packet = f_queue.get()
|
|
new_file(ts, packet, file_keys, file_buf, contact_list, window_list, settings)
|
|
|
|
time.sleep(0.01)
|
|
|
|
if unittest and queues[UNITTEST_QUEUE].qsize() != 0:
|
|
break
|
|
|
|
except (FunctionReturn, KeyError, KeyboardInterrupt):
|
|
pass
|