tfc-mirror/src/receiver/commands_g.py

219 lines
8.6 KiB
Python

#!/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 typing
from src.common.encoding import b58encode
from src.common.exceptions import FunctionReturn
from src.common.misc import separate_header, split_byte_string, validate_group_name
from src.common.output import group_management_print, m_print
from src.common.statics import *
if typing.TYPE_CHECKING:
from datetime import datetime
from src.common.db_contacts import ContactList
from src.common.db_groups import GroupList
from src.common.db_settings import Settings
from src.receiver.windows import WindowList
def group_create(cmd_data: bytes,
ts: 'datetime',
window_list: 'WindowList',
contact_list: 'ContactList',
group_list: 'GroupList',
settings: 'Settings'
) -> None:
"""Create a new group."""
group_id, variable_len_data = separate_header(cmd_data, GROUP_ID_LENGTH)
group_name_bytes, ser_members = variable_len_data.split(US_BYTE, 1)
group_name = group_name_bytes.decode()
purp_pub_keys = set(split_byte_string(ser_members, ONION_SERVICE_PUBLIC_KEY_LENGTH))
pub_keys = set(contact_list.get_list_of_pub_keys())
accepted = list(purp_pub_keys & pub_keys)
rejected = list(purp_pub_keys - pub_keys)
if len(accepted) > settings.max_number_of_group_members:
raise FunctionReturn(f"Error: TFC settings only allow {settings.max_number_of_group_members} "
f"members per group.")
if len(group_list) == settings.max_number_of_groups:
raise FunctionReturn(f"Error: TFC settings only allow {settings.max_number_of_groups} groups.")
accepted_contacts = [contact_list.get_contact_by_pub_key(k) for k in accepted]
group_list.add_group(group_name,
group_id,
settings.log_messages_by_default,
settings.show_notifications_by_default,
accepted_contacts)
group = group_list.get_group(group_name)
window = window_list.get_window(group.group_id)
window.window_contacts = accepted_contacts
window.message_log = []
window.unread_messages = 0
window.create_handle_dict()
group_management_print(NEW_GROUP, accepted, contact_list, group_name)
group_management_print(UNKNOWN_ACCOUNTS, rejected, contact_list, group_name)
local_win = window_list.get_window(WIN_UID_LOCAL)
local_win.add_new(ts, f"Created new group {group_name}.")
def group_add(cmd_data: bytes,
ts: 'datetime',
window_list: 'WindowList',
contact_list: 'ContactList',
group_list: 'GroupList',
settings: 'Settings'
) -> None:
"""Add member(s) to group."""
group_id, ser_members = separate_header(cmd_data, GROUP_ID_LENGTH)
purp_pub_keys = set(split_byte_string(ser_members, ONION_SERVICE_PUBLIC_KEY_LENGTH))
try:
group_name = group_list.get_group_by_id(group_id).name
except StopIteration:
raise FunctionReturn(f"Error: No group with ID '{b58encode(group_id)}' found.")
pub_keys = set(contact_list.get_list_of_pub_keys())
before_adding = set(group_list.get_group(group_name).get_list_of_member_pub_keys())
ok_accounts = set(pub_keys & purp_pub_keys)
new_in_group_set = set(ok_accounts - before_adding)
end_assembly = list(before_adding | new_in_group_set)
already_in_g = list(purp_pub_keys & before_adding)
rejected = list(purp_pub_keys - pub_keys)
new_in_group = list(new_in_group_set)
if len(end_assembly) > settings.max_number_of_group_members:
raise FunctionReturn(f"Error: TFC settings only allow {settings.max_number_of_group_members} "
f"members per group.")
group = group_list.get_group(group_name)
group.add_members([contact_list.get_contact_by_pub_key(k) for k in new_in_group])
window = window_list.get_window(group.group_id)
window.add_contacts(new_in_group)
window.create_handle_dict()
group_management_print(ADDED_MEMBERS, new_in_group, contact_list, group_name)
group_management_print(ALREADY_MEMBER, already_in_g, contact_list, group_name)
group_management_print(UNKNOWN_ACCOUNTS, rejected, contact_list, group_name)
local_win = window_list.get_window(WIN_UID_LOCAL)
local_win.add_new(ts, f"Added members to group {group_name}.")
def group_remove(cmd_data: bytes,
ts: 'datetime',
window_list: 'WindowList',
contact_list: 'ContactList',
group_list: 'GroupList'
) -> None:
"""Remove member(s) from the group."""
group_id, ser_members = separate_header(cmd_data, GROUP_ID_LENGTH)
purp_pub_keys = set(split_byte_string(ser_members, ONION_SERVICE_PUBLIC_KEY_LENGTH))
try:
group_name = group_list.get_group_by_id(group_id).name
except StopIteration:
raise FunctionReturn(f"Error: No group with ID '{b58encode(group_id)}' found.")
pub_keys = set(contact_list.get_list_of_pub_keys())
before_removal = set(group_list.get_group(group_name).get_list_of_member_pub_keys())
ok_accounts_set = set(purp_pub_keys & pub_keys)
removable_set = set(before_removal & ok_accounts_set)
not_in_group = list(ok_accounts_set - before_removal)
rejected = list(purp_pub_keys - pub_keys)
removable = list(removable_set)
group = group_list.get_group(group_name)
group.remove_members(removable)
window = window_list.get_window(group.group_id)
window.remove_contacts(removable)
group_management_print(REMOVED_MEMBERS, removable, contact_list, group_name)
group_management_print(NOT_IN_GROUP, not_in_group, contact_list, group_name)
group_management_print(UNKNOWN_ACCOUNTS, rejected, contact_list, group_name)
local_win = window_list.get_window(WIN_UID_LOCAL)
local_win.add_new(ts, f"Removed members from group {group_name}.")
def group_delete(group_id: bytes,
ts: 'datetime',
window_list: 'WindowList',
group_list: 'GroupList'
) -> None:
"""Remove the group."""
if not group_list.has_group_id(group_id):
raise FunctionReturn(f"Error: No group with ID '{b58encode(group_id)}' found.")
name = group_list.get_group_by_id(group_id).name
window_list.remove_window(group_id)
group_list.remove_group_by_id(group_id)
message = f"Removed group '{name}'."
m_print(message, bold=True, head=1, tail=1)
local_win = window_list.get_window(WIN_UID_LOCAL)
local_win.add_new(ts, message)
def group_rename(cmd_data: bytes,
ts: 'datetime',
window_list: 'WindowList',
contact_list: 'ContactList',
group_list: 'GroupList'
) -> None:
"""Rename the group."""
group_id, new_name_bytes = separate_header(cmd_data, GROUP_ID_LENGTH)
try:
group = group_list.get_group_by_id(group_id)
except StopIteration:
raise FunctionReturn(f"Error: No group with ID '{b58encode(group_id)}' found.")
try:
new_name = new_name_bytes.decode()
except UnicodeError:
raise FunctionReturn(f"Error: New name for group '{group.name}' was invalid.")
error_msg = validate_group_name(new_name, contact_list, group_list)
if error_msg:
raise FunctionReturn(error_msg)
old_name = group.name
group.name = new_name
group_list.store_groups()
window = window_list.get_window(group.group_id)
window.name = new_name
message = f"Renamed group '{old_name}' to '{new_name}'."
local_win = window_list.get_window(WIN_UID_LOCAL)
local_win.add_new(ts, message, output=True)