mirror of
https://github.com/iio612/DEFENDER.git
synced 2026-02-13 19:24:23 +00:00
Updating mod_clone by adding action on groups. reloading the module is now using Settings.set_cache and get_cache
This commit is contained in:
@@ -186,7 +186,7 @@ class Base:
|
|||||||
# Sort to reload submodules before parent modules
|
# Sort to reload submodules before parent modules
|
||||||
for name, module in sorted(modules_to_reload, key=lambda x: x[0], reverse=True):
|
for name, module in sorted(modules_to_reload, key=lambda x: x[0], reverse=True):
|
||||||
try:
|
try:
|
||||||
if 'mod_' not in name:
|
if 'mod_' not in name and 'schemas' not in name:
|
||||||
importlib.reload(module)
|
importlib.reload(module)
|
||||||
self.logs.debug(f'[LOAD_MODULE] Module {module} success')
|
self.logs.debug(f'[LOAD_MODULE] Module {module} success')
|
||||||
|
|
||||||
|
|||||||
59
core/classes/commands.py
Normal file
59
core/classes/commands.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
from core.definition import MCommand
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.base import Base
|
||||||
|
|
||||||
|
class Command:
|
||||||
|
|
||||||
|
DB_COMMANDS: list['MCommand'] = []
|
||||||
|
|
||||||
|
def __init__(self, base: 'Base'):
|
||||||
|
self.Base = base
|
||||||
|
|
||||||
|
def build(self, new_command_obj: MCommand) -> bool:
|
||||||
|
|
||||||
|
command = self.get_command(new_command_obj.command_name, new_command_obj.module_name)
|
||||||
|
if command is None:
|
||||||
|
self.DB_COMMANDS.append(new_command_obj)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Update command if it exist
|
||||||
|
# Removing the object
|
||||||
|
if self.drop_command(command.command_name, command.module_name):
|
||||||
|
# Add the new object
|
||||||
|
self.DB_COMMANDS.append(new_command_obj)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_command(self, command_name: str, module_name: str) -> Optional[MCommand]:
|
||||||
|
|
||||||
|
for command in self.DB_COMMANDS:
|
||||||
|
if command.command_name.lower() == command_name and command.module_name == module_name:
|
||||||
|
return command
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def drop_command(self, command_name: str, module_name: str) -> bool:
|
||||||
|
|
||||||
|
cmd = self.get_command(command_name, module_name)
|
||||||
|
if cmd is not None:
|
||||||
|
self.DB_COMMANDS.remove(cmd)
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_ordered_commands(self) -> list[MCommand]:
|
||||||
|
return sorted(self.DB_COMMANDS, key=lambda c: (c.command_level, c.module_name))
|
||||||
|
|
||||||
|
def get_commands_by_level(self, level: int = 0) -> Optional[list[MCommand]]:
|
||||||
|
|
||||||
|
cmd_list = self.get_ordered_commands()
|
||||||
|
new_list: list[MCommand] = []
|
||||||
|
|
||||||
|
for cmd in cmd_list:
|
||||||
|
if cmd.command_level <= level:
|
||||||
|
new_list.append(cmd)
|
||||||
|
|
||||||
|
return new_list
|
||||||
@@ -337,7 +337,6 @@ class Unrealircd6:
|
|||||||
def send_quit(self, uid: str, reason: str, print_log: True) -> None:
|
def send_quit(self, uid: str, reason: str, print_log: True) -> None:
|
||||||
"""Send quit message
|
"""Send quit message
|
||||||
- Delete uid from User object
|
- Delete uid from User object
|
||||||
- Delete uid from Clone object
|
|
||||||
- Delete uid from Reputation object
|
- Delete uid from Reputation object
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -345,16 +344,12 @@ class Unrealircd6:
|
|||||||
reason (str): The reason for the quit
|
reason (str): The reason for the quit
|
||||||
"""
|
"""
|
||||||
user_obj = self.__Irc.User.get_User(uidornickname=uid)
|
user_obj = self.__Irc.User.get_User(uidornickname=uid)
|
||||||
clone_obj = self.__Irc.Clone.get_clone(uidornickname=uid)
|
|
||||||
reputationObj = self.__Irc.Reputation.get_Reputation(uidornickname=uid)
|
reputationObj = self.__Irc.Reputation.get_Reputation(uidornickname=uid)
|
||||||
|
|
||||||
if not user_obj is None:
|
if not user_obj is None:
|
||||||
self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log)
|
self.send2socket(f":{user_obj.uid} QUIT :{reason}", print_log=print_log)
|
||||||
self.__Irc.User.delete(user_obj.uid)
|
self.__Irc.User.delete(user_obj.uid)
|
||||||
|
|
||||||
if not clone_obj is None:
|
|
||||||
self.__Irc.Clone.delete(clone_obj.uid)
|
|
||||||
|
|
||||||
if not reputationObj is None:
|
if not reputationObj is None:
|
||||||
self.__Irc.Reputation.delete(reputationObj.uid)
|
self.__Irc.Reputation.delete(reputationObj.uid)
|
||||||
|
|
||||||
@@ -569,7 +564,6 @@ class Unrealircd6:
|
|||||||
self.__Irc.User.delete(uid_who_quit)
|
self.__Irc.User.delete(uid_who_quit)
|
||||||
self.__Irc.Client.delete(uid_who_quit)
|
self.__Irc.Client.delete(uid_who_quit)
|
||||||
self.__Irc.Reputation.delete(uid_who_quit)
|
self.__Irc.Reputation.delete(uid_who_quit)
|
||||||
self.__Irc.Clone.delete(uid_who_quit)
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
|
'''This class should never be reloaded.
|
||||||
|
'''
|
||||||
from threading import Timer, Thread, RLock
|
from threading import Timer, Thread, RLock
|
||||||
from socket import socket
|
from socket import socket
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
|
"""This Class will never be reloaded.
|
||||||
|
Means that the variables are available during
|
||||||
|
the whole life of the app
|
||||||
|
"""
|
||||||
|
|
||||||
RUNNING_TIMERS: list[Timer] = []
|
RUNNING_TIMERS: list[Timer] = []
|
||||||
RUNNING_THREADS: list[Thread] = []
|
RUNNING_THREADS: list[Thread] = []
|
||||||
@@ -13,3 +20,29 @@ class Settings:
|
|||||||
|
|
||||||
PROTOCTL_USER_MODES: list[str] = []
|
PROTOCTL_USER_MODES: list[str] = []
|
||||||
PROTOCTL_PREFIX: list[str] = []
|
PROTOCTL_PREFIX: list[str] = []
|
||||||
|
|
||||||
|
__CACHE: dict[str, Any] = {}
|
||||||
|
"""Use set_cache or get_cache instead"""
|
||||||
|
|
||||||
|
def set_cache(self, key: str, value_to_cache: Any):
|
||||||
|
"""When you want to store a variable
|
||||||
|
Ex.
|
||||||
|
```python
|
||||||
|
set_cache('MY_KEY', {'key1': 'value1', 'key2', 'value2'})
|
||||||
|
```
|
||||||
|
Args:
|
||||||
|
key (str): The key you want to add.
|
||||||
|
value_to_cache (Any): The Value you want to store.
|
||||||
|
"""
|
||||||
|
self.__CACHE[key] = value_to_cache
|
||||||
|
|
||||||
|
def get_cache(self, key) -> Any:
|
||||||
|
"""It returns the value associated to the key and finally it removes the entry"""
|
||||||
|
if self.__CACHE.get(key):
|
||||||
|
return self.__CACHE.pop(key)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_cache_size(self) -> int:
|
||||||
|
return len(self.__CACHE)
|
||||||
|
|
||||||
@@ -334,3 +334,10 @@ class MClone(MainModel):
|
|||||||
umodes: str = None
|
umodes: str = None
|
||||||
remote_ip: str = '127.0.0.1'
|
remote_ip: str = '127.0.0.1'
|
||||||
group: str = 'Default'
|
group: str = 'Default'
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MCommand(MainModel):
|
||||||
|
module_name: str = None
|
||||||
|
command_name: str = None
|
||||||
|
description: str = None
|
||||||
|
command_level: int = 0
|
||||||
|
|||||||
83
core/irc.py
83
core/irc.py
@@ -8,9 +8,10 @@ import time
|
|||||||
import traceback
|
import traceback
|
||||||
from ssl import SSLSocket
|
from ssl import SSLSocket
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import Union
|
from typing import Optional, Union
|
||||||
from core.loader import Loader
|
from core.loader import Loader
|
||||||
from core.classes.protocol import Protocol
|
from core.classes.protocol import Protocol
|
||||||
|
from core.classes.commands import Command
|
||||||
|
|
||||||
class Irc:
|
class Irc:
|
||||||
_instance = None
|
_instance = None
|
||||||
@@ -67,9 +68,6 @@ class Irc:
|
|||||||
# Use Channel Instance
|
# Use Channel Instance
|
||||||
self.Channel = self.Loader.Channel
|
self.Channel = self.Loader.Channel
|
||||||
|
|
||||||
# Use Clones Instance
|
|
||||||
self.Clone = self.Loader.Clone
|
|
||||||
|
|
||||||
# Use Reputation Instance
|
# Use Reputation Instance
|
||||||
self.Reputation = self.Loader.Reputation
|
self.Reputation = self.Loader.Reputation
|
||||||
|
|
||||||
@@ -83,7 +81,11 @@ class Irc:
|
|||||||
self.first_connexion_ip: str = None
|
self.first_connexion_ip: str = None
|
||||||
|
|
||||||
# Define the dict that will contain all loaded modules
|
# Define the dict that will contain all loaded modules
|
||||||
self.loaded_classes:dict[str, 'Irc'] = {} # Definir la variable qui contiendra la liste modules chargés
|
self.loaded_classes:dict[str, 'Irc'] = {}
|
||||||
|
|
||||||
|
# Load Commands Utils
|
||||||
|
self.Commands = self.Loader.Commands
|
||||||
|
"""Command utils"""
|
||||||
|
|
||||||
# Global full module commands that contains level, module name, commands and description
|
# Global full module commands that contains level, module name, commands and description
|
||||||
self.module_commands: dict[int, dict[str, dict[str, str]]] = {}
|
self.module_commands: dict[int, dict[str, dict[str, str]]] = {}
|
||||||
@@ -341,9 +343,71 @@ class Irc:
|
|||||||
self.module_commands.setdefault(level, {}).setdefault(module_name, {}).update({command_name: command_description})
|
self.module_commands.setdefault(level, {}).setdefault(module_name, {}).update({command_name: command_description})
|
||||||
self.module_commands_list.append(command_name)
|
self.module_commands_list.append(command_name)
|
||||||
|
|
||||||
|
# Build Model.
|
||||||
|
self.Commands.build(self.Loader.Definition.MCommand(module_name, command_name, command_description, level))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def generate_help_menu(self, nickname: str) -> None:
|
def generate_help_menu(self, nickname: str, module: Optional[str] = None) -> None:
|
||||||
|
|
||||||
|
# Check if the nickname is an admin
|
||||||
|
p = self.Protocol
|
||||||
|
admin_obj = self.Admin.get_Admin(nickname)
|
||||||
|
dnickname = self.Config.SERVICE_NICKNAME
|
||||||
|
color_bold = self.Config.COLORS.bold
|
||||||
|
color_nogc = self.Config.COLORS.nogc
|
||||||
|
color_blue = self.Config.COLORS.blue
|
||||||
|
color_black = self.Config.COLORS.black
|
||||||
|
color_underline = self.Config.COLORS.underline
|
||||||
|
current_level = 0
|
||||||
|
count = 0
|
||||||
|
if admin_obj is not None:
|
||||||
|
current_level = admin_obj.level
|
||||||
|
|
||||||
|
p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" ***************** LISTE DES COMMANDES *****************")
|
||||||
|
header = f" {'Level':<8}| {'Command':<25}| {'Module':<15}| {'Description':<35}"
|
||||||
|
line = "-"*75
|
||||||
|
p.send_notice(nick_from=dnickname,nick_to=nickname, msg=header)
|
||||||
|
p.send_notice(nick_from=dnickname,nick_to=nickname, msg=f" {line}")
|
||||||
|
for cmd in self.Commands.get_commands_by_level(current_level):
|
||||||
|
if module is None or cmd.module_name.lower() == module.lower():
|
||||||
|
p.send_notice(
|
||||||
|
nick_from=dnickname,
|
||||||
|
nick_to=nickname,
|
||||||
|
msg=f" {color_black}{cmd.command_level:<8}{color_nogc}| {cmd.command_name:<25}| {cmd.module_name:<15}| {cmd.description:<35}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
for level, modules in self.module_commands.items():
|
||||||
|
if level > current_level:
|
||||||
|
break
|
||||||
|
|
||||||
|
if count > 0:
|
||||||
|
p.send_notice(nick_from=dnickname, nick_to=nickname, msg=" ")
|
||||||
|
|
||||||
|
p.send_notice(
|
||||||
|
nick_from=dnickname,
|
||||||
|
nick_to=nickname,
|
||||||
|
msg=f"{color_blue}{color_bold}Level {level}:{color_nogc}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for module_name, commands in modules.items():
|
||||||
|
if module is None or module.lower() == module_name.lower():
|
||||||
|
p.send_notice(
|
||||||
|
nick_from=dnickname,
|
||||||
|
nick_to=nickname,
|
||||||
|
msg=f"{color_black} {color_underline}Module: {module_name}{color_nogc}"
|
||||||
|
)
|
||||||
|
for command, description in commands.items():
|
||||||
|
p.send_notice(nick_from=dnickname, nick_to=nickname, msg=f" {command:<20}: {description}")
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
p.send_notice(nick_from=dnickname,nick_to=nickname,msg=f" ***************** FIN DES COMMANDES *****************")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def generate_help_menu_bakcup(self, nickname: str) -> None:
|
||||||
|
|
||||||
# Check if the nickname is an admin
|
# Check if the nickname is an admin
|
||||||
admin_obj = self.Admin.get_Admin(nickname)
|
admin_obj = self.Admin.get_Admin(nickname)
|
||||||
@@ -578,6 +642,7 @@ class Irc:
|
|||||||
channel=self.Config.SERVICE_CHANLOG
|
channel=self.Config.SERVICE_CHANLOG
|
||||||
)
|
)
|
||||||
self.Base.db_delete_module(module_name)
|
self.Base.db_delete_module(module_name)
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
def unload_module(self, mod_name: str) -> bool:
|
def unload_module(self, mod_name: str) -> bool:
|
||||||
"""Unload a module
|
"""Unload a module
|
||||||
@@ -1387,8 +1452,12 @@ class Irc:
|
|||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} <account>")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} {command.upper()} <account>")
|
||||||
|
|
||||||
case 'help':
|
case 'help':
|
||||||
|
# Syntax. !help [module_name]
|
||||||
|
module_name = str(cmd[1]) if len(cmd) == 2 else None
|
||||||
|
self.generate_help_menu(nickname=fromuser, module=module_name)
|
||||||
|
|
||||||
self.generate_help_menu(nickname=fromuser)
|
for com in self.Commands.get_ordered_commands():
|
||||||
|
print(com)
|
||||||
|
|
||||||
case 'load':
|
case 'load':
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from core.classes import user, admin, client, channel, clone, reputation, settings
|
from core.classes import user, admin, client, channel, reputation, settings, commands
|
||||||
import core.definition as df
|
import core.definition as df
|
||||||
import core.base as baseModule
|
import core.base as baseModule
|
||||||
import core.classes.config as confModule
|
import core.classes.config as confModule
|
||||||
@@ -15,7 +15,7 @@ class Loader:
|
|||||||
self.BaseModule: baseModule = baseModule
|
self.BaseModule: baseModule = baseModule
|
||||||
|
|
||||||
# Load Classes
|
# Load Classes
|
||||||
self.Settings: settings = settings.Settings()
|
self.Settings: settings.Settings = settings.Settings()
|
||||||
|
|
||||||
self.Config: df.MConfig = self.ConfModule.Configuration().ConfigObject
|
self.Config: df.MConfig = self.ConfModule.Configuration().ConfigObject
|
||||||
|
|
||||||
@@ -29,6 +29,6 @@ class Loader:
|
|||||||
|
|
||||||
self.Channel: channel.Channel = channel.Channel(self.Base)
|
self.Channel: channel.Channel = channel.Channel(self.Base)
|
||||||
|
|
||||||
self.Clone: clone.Clone = clone.Clone(self.Base)
|
|
||||||
|
|
||||||
self.Reputation: reputation.Reputation = reputation.Reputation(self.Base)
|
self.Reputation: reputation.Reputation = reputation.Reputation(self.Base)
|
||||||
|
|
||||||
|
self.Commands: commands.Command = commands.Command(self.Base)
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
|
from typing import Optional, TYPE_CHECKING
|
||||||
from core.definition import MClone
|
from core.definition import MClone
|
||||||
from typing import Any, Optional
|
|
||||||
from core.base import Base
|
|
||||||
|
|
||||||
class Clone:
|
if TYPE_CHECKING:
|
||||||
|
from mods.clone.mod_clone import Clone
|
||||||
|
|
||||||
|
class CloneManager:
|
||||||
|
|
||||||
UID_CLONE_DB: list[MClone] = []
|
UID_CLONE_DB: list[MClone] = []
|
||||||
|
|
||||||
def __init__(self, base: Base):
|
def __init__(self, uplink: 'Clone'):
|
||||||
|
|
||||||
self.Logs = base.logs
|
self.Logs = uplink.Logs
|
||||||
|
|
||||||
def insert(self, new_clone_object: MClone) -> bool:
|
def insert(self, new_clone_object: MClone) -> bool:
|
||||||
"""Create new Clone object
|
"""Create new Clone object
|
||||||
@@ -61,7 +63,7 @@ class Clone:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def exists(self, nickname: str) -> bool:
|
def nickname_exists(self, nickname: str) -> bool:
|
||||||
"""Check if the nickname exist
|
"""Check if the nickname exist
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -91,6 +93,21 @@ class Clone:
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def group_exists(self, groupname: str) -> bool:
|
||||||
|
"""Verify if a group exist
|
||||||
|
|
||||||
|
Args:
|
||||||
|
groupname (str): The group name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: _description_
|
||||||
|
"""
|
||||||
|
for clone in self.UID_CLONE_DB:
|
||||||
|
if clone.group.strip().lower() == groupname.strip().lower():
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def get_clone(self, uidornickname: str) -> Optional[MClone]:
|
def get_clone(self, uidornickname: str) -> Optional[MClone]:
|
||||||
"""Get MClone object or None
|
"""Get MClone object or None
|
||||||
|
|
||||||
@@ -108,6 +125,24 @@ class Clone:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_clones_from_groupname(self, groupname: str) -> list[MClone]:
|
||||||
|
"""Get list of clone objects by group name
|
||||||
|
|
||||||
|
Args:
|
||||||
|
groupname (str): The group name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[MClone]: List of clones in the group
|
||||||
|
"""
|
||||||
|
group_of_clone: list[MClone] = []
|
||||||
|
|
||||||
|
if self.group_exists(groupname):
|
||||||
|
for clone in self.UID_CLONE_DB:
|
||||||
|
if clone.group.strip().lower() == groupname.strip().lower():
|
||||||
|
group_of_clone.append(clone)
|
||||||
|
|
||||||
|
return group_of_clone
|
||||||
|
|
||||||
def get_uid(self, uidornickname: str) -> Optional[str]:
|
def get_uid(self, uidornickname: str) -> Optional[str]:
|
||||||
"""Get the UID of the clone starting from the UID or the Nickname
|
"""Get the UID of the clone starting from the UID or the Nickname
|
||||||
|
|
||||||
@@ -125,15 +160,6 @@ class Clone:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_clone_asdict(self, uidornickname: str) -> Optional[dict[str, Any]]:
|
|
||||||
|
|
||||||
clone_obj = self.get_clone(uidornickname=uidornickname)
|
|
||||||
|
|
||||||
if clone_obj is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return clone_obj.to_dict()
|
|
||||||
|
|
||||||
def kill(self, nickname:str) -> bool:
|
def kill(self, nickname:str) -> bool:
|
||||||
|
|
||||||
response = False
|
response = False
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
from dataclasses import dataclass
|
import time, logging
|
||||||
import random, faker, time, logging
|
from typing import TYPE_CHECKING, Optional
|
||||||
from typing import TYPE_CHECKING
|
from faker import Faker
|
||||||
|
import mods.clone.utils as utils
|
||||||
|
import mods.clone.threads as thds
|
||||||
|
import mods.clone.schemas as schemas
|
||||||
|
from mods.clone.clone_manager import CloneManager
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from core.irc import Irc
|
from core.irc import Irc
|
||||||
|
|
||||||
class Clone():
|
class Clone():
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ModConfModel:
|
|
||||||
clone_nicknames: list[str]
|
|
||||||
|
|
||||||
def __init__(self, ircInstance: 'Irc') -> None:
|
def __init__(self, ircInstance: 'Irc') -> None:
|
||||||
|
|
||||||
# Module name (Mandatory)
|
# Module name (Mandatory)
|
||||||
@@ -37,11 +37,28 @@ class Clone():
|
|||||||
# Add Channel object to the module (Mandatory)
|
# Add Channel object to the module (Mandatory)
|
||||||
self.Channel = ircInstance.Channel
|
self.Channel = ircInstance.Channel
|
||||||
|
|
||||||
# Add clone object to the module (Optionnal)
|
# Add global definitions
|
||||||
self.Clone = ircInstance.Clone
|
|
||||||
|
|
||||||
self.Definition = ircInstance.Loader.Definition
|
self.Definition = ircInstance.Loader.Definition
|
||||||
|
|
||||||
|
# The Global Settings
|
||||||
|
self.Settings = ircInstance.Loader.Settings
|
||||||
|
|
||||||
|
self.Schemas = schemas
|
||||||
|
|
||||||
|
self.Utils = utils
|
||||||
|
|
||||||
|
self.Threads = thds
|
||||||
|
|
||||||
|
self.Faker: Optional['Faker'] = self.Utils.create_faker_object('en_GB')
|
||||||
|
|
||||||
|
self.Clone = CloneManager(self)
|
||||||
|
|
||||||
|
metadata = self.Settings.get_cache('UID_CLONE_DB')
|
||||||
|
|
||||||
|
if metadata is not None:
|
||||||
|
self.Clone.UID_CLONE_DB = metadata
|
||||||
|
self.Logs.debug(f"Cache Size = {self.Settings.get_cache_size()}")
|
||||||
|
|
||||||
# Créer les nouvelles commandes du module
|
# Créer les nouvelles commandes du module
|
||||||
self.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones')
|
self.Irc.build_command(1, self.module_name, 'clone', 'Connect, join, part, kill and say clones')
|
||||||
|
|
||||||
@@ -57,10 +74,6 @@ class Clone():
|
|||||||
self.__create_tables()
|
self.__create_tables()
|
||||||
|
|
||||||
self.stop = False
|
self.stop = False
|
||||||
logging.getLogger('faker').setLevel(logging.CRITICAL)
|
|
||||||
|
|
||||||
self.fakeEN = faker.Faker('en_GB')
|
|
||||||
self.fakeFR = faker.Faker('fr_FR')
|
|
||||||
|
|
||||||
# Load module configuration (Mandatory)
|
# Load module configuration (Mandatory)
|
||||||
self.__load_module_configuration()
|
self.__load_module_configuration()
|
||||||
@@ -99,9 +112,7 @@ class Clone():
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Variable qui va contenir les options de configuration du module Defender
|
# Variable qui va contenir les options de configuration du module Defender
|
||||||
self.ModConfig = self.ModConfModel(
|
self.ModConfig = self.Schemas.ModConfModel()
|
||||||
clone_nicknames=[]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Sync the configuration with core configuration (Mandatory)
|
# Sync the configuration with core configuration (Mandatory)
|
||||||
# self.Base.db_sync_core_config(self.module_name, self.ModConfig)
|
# self.Base.db_sync_core_config(self.module_name, self.ModConfig)
|
||||||
@@ -115,6 +126,8 @@ class Clone():
|
|||||||
"""Cette methode sera executée a chaque désactivation ou
|
"""Cette methode sera executée a chaque désactivation ou
|
||||||
rechargement de module
|
rechargement de module
|
||||||
"""
|
"""
|
||||||
|
# Store Clones DB into the global Settings to retrieve it after the reload.
|
||||||
|
self.Settings.set_cache('UID_CLONE_DB', self.Clone.UID_CLONE_DB)
|
||||||
|
|
||||||
self.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL)
|
self.Channel.db_query_channel(action='del', module_name=self.module_name, channel_name=self.Config.CLONE_CHANNEL)
|
||||||
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -nts")
|
self.Protocol.send2socket(f":{self.Config.SERVICE_NICKNAME} MODE {self.Config.CLONE_CHANNEL} -nts")
|
||||||
@@ -123,175 +136,40 @@ class Clone():
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def generate_vhost(self) -> str:
|
def cmd(self, data:list):
|
||||||
|
|
||||||
fake = self.fakeEN
|
|
||||||
|
|
||||||
rand_1 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
|
||||||
rand_2 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
|
||||||
rand_3 = fake.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
|
||||||
|
|
||||||
vhost = ''.join(rand_1) + '.' + ''.join(rand_2) + '.' + ''.join(rand_3) + '.IP'
|
|
||||||
return vhost
|
|
||||||
|
|
||||||
def generate_clones(self, group: str = 'Default', auto_remote_ip: bool = False) -> None:
|
|
||||||
try:
|
try:
|
||||||
|
if not data or len(data) < 2:
|
||||||
|
return
|
||||||
|
|
||||||
fakeEN = self.fakeEN
|
cmd = data.copy() if isinstance(data, list) else list(data).copy()
|
||||||
fakeFR = self.fakeFR
|
index, command = self.Irc.Protocol.get_ircd_protocol_poisition(cmd)
|
||||||
unixtime = self.Base.get_unixtime()
|
if index == -1:
|
||||||
|
return
|
||||||
|
|
||||||
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
match command:
|
||||||
generate_uid = fakeEN.random_sample(chaine, 6)
|
|
||||||
uid = self.Config.SERVEUR_ID + ''.join(generate_uid)
|
|
||||||
|
|
||||||
umodes = self.Config.CLONE_UMODES
|
|
||||||
|
|
||||||
# Generate Username
|
|
||||||
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
||||||
new_username = fakeEN.random_sample(chaine, 9)
|
|
||||||
username = ''.join(new_username)
|
|
||||||
|
|
||||||
# Create realname XX F|M Department
|
|
||||||
gender = fakeEN.random_choices(['F','M'], 1)
|
|
||||||
gender = ''.join(gender)
|
|
||||||
|
|
||||||
if gender == 'F':
|
|
||||||
nickname = fakeEN.first_name_female()
|
|
||||||
elif gender == 'M':
|
|
||||||
nickname = fakeEN.first_name_male()
|
|
||||||
else:
|
|
||||||
nickname = fakeEN.first_name()
|
|
||||||
|
|
||||||
age = random.randint(20, 60)
|
|
||||||
department = fakeFR.department_name()
|
|
||||||
realname = f'{age} {gender} {department}'
|
|
||||||
|
|
||||||
decoded_ip = fakeEN.ipv4_private() if auto_remote_ip else '127.0.0.1'
|
|
||||||
hostname = fakeEN.hostname()
|
|
||||||
|
|
||||||
vhost = self.generate_vhost()
|
|
||||||
|
|
||||||
checkNickname = self.Clone.exists(nickname=nickname)
|
|
||||||
checkUid = self.Clone.uid_exists(uid=uid)
|
|
||||||
|
|
||||||
while checkNickname:
|
|
||||||
caracteres = '0123456789'
|
|
||||||
randomize = ''.join(random.choice(caracteres) for _ in range(2))
|
|
||||||
nickname = nickname + str(randomize)
|
|
||||||
checkNickname = self.Clone.exists(nickname=nickname)
|
|
||||||
|
|
||||||
while checkUid:
|
|
||||||
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
|
||||||
generate_uid = fakeEN.random_sample(chaine, 6)
|
|
||||||
uid = self.Config.SERVEUR_ID + ''.join(generate_uid)
|
|
||||||
checkUid = self.Clone.uid_exists(uid=uid)
|
|
||||||
|
|
||||||
clone = self.Definition.MClone(
|
|
||||||
connected=False,
|
|
||||||
nickname=nickname,
|
|
||||||
username=username,
|
|
||||||
realname=realname,
|
|
||||||
hostname=hostname,
|
|
||||||
umodes=umodes,
|
|
||||||
uid=uid,
|
|
||||||
remote_ip=decoded_ip,
|
|
||||||
vhost=vhost,
|
|
||||||
group=group,
|
|
||||||
channels=[]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.Clone.insert(clone)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
except AttributeError as ae:
|
|
||||||
self.Logs.error(f'Attribute Error : {ae}')
|
|
||||||
except Exception as err:
|
|
||||||
self.Logs.error(f"General Error: {err}")
|
|
||||||
|
|
||||||
def thread_connect_clones(self, number_of_clones:int , group: str = 'Default', auto_remote_ip: bool = False, interval: float = 0.2) -> None:
|
|
||||||
|
|
||||||
for i in range(0, number_of_clones):
|
|
||||||
self.generate_clones(group=group, auto_remote_ip=auto_remote_ip)
|
|
||||||
|
|
||||||
for clone in self.Clone.UID_CLONE_DB:
|
|
||||||
|
|
||||||
if self.stop:
|
|
||||||
print(f"Stop creating clones ...")
|
|
||||||
self.stop = False
|
|
||||||
break
|
|
||||||
|
|
||||||
if not clone.connected:
|
|
||||||
self.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False)
|
|
||||||
self.Protocol.send_join_chan(uidornickname=clone.uid, channel=self.Config.CLONE_CHANNEL, password=self.Config.CLONE_CHANNEL_PASSWORD, print_log=False)
|
|
||||||
|
|
||||||
time.sleep(interval)
|
|
||||||
clone.connected = True
|
|
||||||
|
|
||||||
def thread_kill_clones(self, fromuser: str) -> None:
|
|
||||||
|
|
||||||
clone_to_kill: list[str] = []
|
|
||||||
for clone in self.Clone.UID_CLONE_DB:
|
|
||||||
clone_to_kill.append(clone.uid)
|
|
||||||
|
|
||||||
for clone_uid in clone_to_kill:
|
|
||||||
self.Protocol.send_quit(clone_uid, 'Gooood bye', print_log=False)
|
|
||||||
|
|
||||||
del clone_to_kill
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def cmd(self, data:list) -> None:
|
|
||||||
try:
|
|
||||||
service_id = self.Config.SERVICE_ID # Defender serveur id
|
|
||||||
cmd = list(data).copy()
|
|
||||||
|
|
||||||
if len(cmd) < 2:
|
|
||||||
return None
|
|
||||||
|
|
||||||
match cmd[1]:
|
|
||||||
|
|
||||||
case 'REPUTATION':
|
|
||||||
pass
|
|
||||||
|
|
||||||
if len(cmd) < 3:
|
|
||||||
return None
|
|
||||||
|
|
||||||
match cmd[2]:
|
|
||||||
case 'PRIVMSG':
|
case 'PRIVMSG':
|
||||||
# print(cmd)
|
return self.Utils.handle_on_privmsg(self, cmd)
|
||||||
uid_sender = self.User.clean_uid(cmd[1])
|
|
||||||
senderObj = self.User.get_User(uid_sender)
|
|
||||||
|
|
||||||
if senderObj.hostname in self.Config.CLONE_LOG_HOST_EXEMPT:
|
case 'QUIT':
|
||||||
return None
|
return
|
||||||
|
|
||||||
if not senderObj is None:
|
case _:
|
||||||
senderMsg = ' '.join(cmd[4:])
|
return
|
||||||
clone_obj = self.Clone.get_clone(cmd[3])
|
|
||||||
|
|
||||||
if clone_obj is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if clone_obj.uid != self.Config.SERVICE_ID:
|
|
||||||
final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}"
|
|
||||||
self.Protocol.send_priv_msg(
|
|
||||||
nick_from=clone_obj.uid,
|
|
||||||
msg=final_message,
|
|
||||||
channel=self.Config.CLONE_CHANNEL
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'General Error: {err}')
|
self.Logs.error(f'General Error: {err}', exc_info=True)
|
||||||
|
|
||||||
def hcmds(self, user: str, channel: any, cmd: list, fullcmd: list = []) -> None:
|
def hcmds(self, user: str, channel: any, cmd: list, fullcmd: list = []) -> None:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
if len(cmd) < 1:
|
||||||
|
return
|
||||||
|
|
||||||
command = str(cmd[0]).lower()
|
command = str(cmd[0]).lower()
|
||||||
fromuser = user
|
fromuser = user
|
||||||
|
dnickname = self.Config.SERVICE_NICKNAME
|
||||||
dnickname = self.Config.SERVICE_NICKNAME # Defender nickname
|
|
||||||
|
|
||||||
match command:
|
match command:
|
||||||
|
|
||||||
@@ -303,6 +181,7 @@ class Clone():
|
|||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | nickname] #channel")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | nickname] #channel")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list")
|
||||||
|
return None
|
||||||
|
|
||||||
option = str(cmd[1]).lower()
|
option = str(cmd[1]).lower()
|
||||||
|
|
||||||
@@ -317,8 +196,8 @@ class Clone():
|
|||||||
connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.2
|
connection_interval = int(cmd[4]) if len(cmd) == 5 else 0.2
|
||||||
|
|
||||||
self.Base.create_thread(
|
self.Base.create_thread(
|
||||||
func=self.thread_connect_clones,
|
func=self.Threads.thread_connect_clones,
|
||||||
func_args=(number_of_clones, group, False, connection_interval)
|
func_args=(self, number_of_clones, group, False, connection_interval)
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@@ -328,18 +207,28 @@ class Clone():
|
|||||||
|
|
||||||
case 'kill':
|
case 'kill':
|
||||||
try:
|
try:
|
||||||
# clone kill [all | nickname]
|
# clone kill [ALL | group name | nickname]
|
||||||
self.stop = True
|
self.stop = True
|
||||||
clone_name = str(cmd[2])
|
option = str(cmd[2])
|
||||||
clone_to_kill: list[str] = []
|
|
||||||
|
|
||||||
if clone_name.lower() == 'all':
|
if option.lower() == 'all':
|
||||||
self.Base.create_thread(func=self.thread_kill_clones, func_args=(fromuser, ))
|
self.Base.create_thread(func=self.Threads.thread_kill_clones, func_args=(self, ))
|
||||||
|
|
||||||
|
elif self.Clone.group_exists(option):
|
||||||
|
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||||
|
|
||||||
|
if len(list_of_clones_in_group) > 0:
|
||||||
|
self.Logs.debug(f"[Clone Kill Group] - Killing {len(list_of_clones_in_group)} clones in the group {option}")
|
||||||
|
|
||||||
|
for clone in list_of_clones_in_group:
|
||||||
|
self.Protocol.send_quit(clone.uid, "Now i am leaving irc but i'll come back soon ...", print_log=False)
|
||||||
|
self.Clone.delete(clone.uid)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
clone_obj = self.Clone.get_clone(clone_name)
|
clone_obj = self.Clone.get_clone(option)
|
||||||
if not clone_obj is None:
|
if not clone_obj is None:
|
||||||
self.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False)
|
self.Protocol.send_quit(clone_obj.uid, 'Goood bye', print_log=False)
|
||||||
|
self.Clone.delete(clone_obj.uid)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.Logs.error(f'{err}')
|
||||||
@@ -348,19 +237,28 @@ class Clone():
|
|||||||
|
|
||||||
case 'join':
|
case 'join':
|
||||||
try:
|
try:
|
||||||
# clone join [all | nickname] #channel
|
# clone join [all | group name | nickname] #channel
|
||||||
clone_name = str(cmd[2])
|
option = str(cmd[2])
|
||||||
clone_channel_to_join = str(cmd[3])
|
clone_channel_to_join = str(cmd[3])
|
||||||
|
|
||||||
if clone_name.lower() == 'all':
|
if option.lower() == 'all':
|
||||||
|
|
||||||
for clone in self.Clone.UID_CLONE_DB:
|
for clone in self.Clone.UID_CLONE_DB:
|
||||||
self.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False)
|
self.Protocol.send_join_chan(uidornickname=clone.uid, channel=clone_channel_to_join, print_log=False)
|
||||||
|
|
||||||
|
elif self.Clone.group_exists(option):
|
||||||
|
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||||
|
|
||||||
|
if len(list_of_clones_in_group) > 0:
|
||||||
|
self.Logs.debug(f"[Clone Join Group] - Joining {len(list_of_clones_in_group)} clones from group {option} in the channel {clone_channel_to_join}")
|
||||||
|
|
||||||
|
for clone in list_of_clones_in_group:
|
||||||
|
self.Protocol.send_join_chan(uidornickname=clone.nickname, channel=clone_channel_to_join, print_log=False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if self.Clone.exists(clone_name):
|
if self.Clone.nickname_exists(option):
|
||||||
if not self.Clone.get_uid(clone_name) is None:
|
clone_uid = self.Clone.get_clone(option).uid
|
||||||
self.Protocol.send_join_chan(uidornickname=clone_name, channel=clone_channel_to_join, print_log=False)
|
self.Protocol.send_join_chan(uidornickname=clone_uid, channel=clone_channel_to_join, print_log=False)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'{err}')
|
self.Logs.error(f'{err}')
|
||||||
@@ -370,17 +268,26 @@ class Clone():
|
|||||||
case 'part':
|
case 'part':
|
||||||
try:
|
try:
|
||||||
# clone part [all | nickname] #channel
|
# clone part [all | nickname] #channel
|
||||||
clone_name = str(cmd[2])
|
option = str(cmd[2])
|
||||||
clone_channel_to_part = str(cmd[3])
|
clone_channel_to_part = str(cmd[3])
|
||||||
|
|
||||||
if clone_name.lower() == 'all':
|
if option.lower() == 'all':
|
||||||
|
|
||||||
for clone in self.Clone.UID_CLONE_DB:
|
for clone in self.Clone.UID_CLONE_DB:
|
||||||
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
||||||
|
|
||||||
|
elif self.Clone.group_exists(option):
|
||||||
|
list_of_clones_in_group = self.Clone.get_clones_from_groupname(option)
|
||||||
|
|
||||||
|
if len(list_of_clones_in_group) > 0:
|
||||||
|
self.Logs.debug(f"[Clone Part Group] - Part {len(list_of_clones_in_group)} clones from group {option} from the channel {clone_channel_to_part}")
|
||||||
|
|
||||||
|
for clone in list_of_clones_in_group:
|
||||||
|
self.Protocol.send_part_chan(uidornickname=clone.uid, channel=clone_channel_to_part, print_log=False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if self.Clone.exists(clone_name):
|
if self.Clone.nickname_exists(option):
|
||||||
clone_uid = self.Clone.get_uid(clone_name)
|
clone_uid = self.Clone.get_uid(option)
|
||||||
if not clone_uid is None:
|
if not clone_uid is None:
|
||||||
self.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False)
|
self.Protocol.send_part_chan(uidornickname=clone_uid, channel=clone_channel_to_part, print_log=False)
|
||||||
|
|
||||||
@@ -407,7 +314,7 @@ class Clone():
|
|||||||
|
|
||||||
final_message = ' '.join(cmd[4:])
|
final_message = ' '.join(cmd[4:])
|
||||||
|
|
||||||
if clone_channel is None or not self.Clone.exists(clone_name):
|
if clone_channel is None or not self.Clone.nickname_exists(clone_name):
|
||||||
self.Protocol.send_notice(
|
self.Protocol.send_notice(
|
||||||
nick_from=dnickname,
|
nick_from=dnickname,
|
||||||
nick_to=fromuser,
|
nick_to=fromuser,
|
||||||
@@ -415,7 +322,7 @@ class Clone():
|
|||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if self.Clone.exists(clone_name):
|
if self.Clone.nickname_exists(clone_name):
|
||||||
self.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel)
|
self.Protocol.send_priv_msg(nick_from=clone_name, msg=final_message, channel=clone_channel)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@@ -428,12 +335,12 @@ class Clone():
|
|||||||
|
|
||||||
case _:
|
case _:
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone connect NUMBER GROUP_NAME INTERVAL")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | nickname]")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone kill [all | group name | nickname]")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | nickname] #channel")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone join [all | group name | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | nickname] #channel")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone part [all | group name | nickname] #channel")
|
||||||
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list")
|
self.Protocol.send_notice(nick_from=dnickname, nick_to=fromuser, msg=f"/msg {dnickname} clone list")
|
||||||
|
|
||||||
except IndexError as ie:
|
except IndexError as ie:
|
||||||
self.Logs.error(f'Index Error: {ie}')
|
self.Logs.error(f'Index Error: {ie}')
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
self.Logs.error(f'Index Error: {err}')
|
self.Logs.error(f'General Error: {err}')
|
||||||
|
|||||||
22
mods/clone/schemas.py
Normal file
22
mods/clone/schemas.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from core.definition import MainModel, dataclass, field
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ModConfModel(MainModel):
|
||||||
|
clone_nicknames: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MClone(MainModel):
|
||||||
|
"""Model Clone"""
|
||||||
|
connected: bool = False
|
||||||
|
uid: str = None
|
||||||
|
nickname: str = None
|
||||||
|
username: str = None
|
||||||
|
realname: str = None
|
||||||
|
channels: list = field(default_factory=list)
|
||||||
|
vhost: str = None
|
||||||
|
hostname: str = 'localhost'
|
||||||
|
umodes: str = None
|
||||||
|
remote_ip: str = '127.0.0.1'
|
||||||
|
group: str = 'Default'
|
||||||
|
|
||||||
|
DB_CLONES: list[MClone] = []
|
||||||
39
mods/clone/threads.py
Normal file
39
mods/clone/threads.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from mods.clone.mod_clone import Clone
|
||||||
|
|
||||||
|
def thread_connect_clones(uplink: 'Clone',
|
||||||
|
number_of_clones:int ,
|
||||||
|
group: str = 'Default',
|
||||||
|
auto_remote_ip: bool = False,
|
||||||
|
interval: float = 0.2
|
||||||
|
):
|
||||||
|
|
||||||
|
for i in range(0, number_of_clones):
|
||||||
|
uplink.Utils.create_new_clone(uplink, uplink.Faker, group=group, auto_remote_ip=auto_remote_ip)
|
||||||
|
|
||||||
|
for clone in uplink.Clone.UID_CLONE_DB:
|
||||||
|
|
||||||
|
if uplink.stop:
|
||||||
|
print(f"Stop creating clones ...")
|
||||||
|
uplink.stop = False
|
||||||
|
break
|
||||||
|
|
||||||
|
if not clone.connected:
|
||||||
|
uplink.Protocol.send_uid(clone.nickname, clone.username, clone.hostname, clone.uid, clone.umodes, clone.vhost, clone.remote_ip, clone.realname, print_log=False)
|
||||||
|
uplink.Protocol.send_join_chan(uidornickname=clone.uid, channel=uplink.Config.CLONE_CHANNEL, password=uplink.Config.CLONE_CHANNEL_PASSWORD, print_log=False)
|
||||||
|
|
||||||
|
sleep(interval)
|
||||||
|
clone.connected = True
|
||||||
|
|
||||||
|
def thread_kill_clones(uplink: 'Clone'):
|
||||||
|
|
||||||
|
clone_to_kill = uplink.Clone.UID_CLONE_DB.copy()
|
||||||
|
|
||||||
|
for clone in clone_to_kill:
|
||||||
|
uplink.Protocol.send_quit(clone.uid, 'Gooood bye', print_log=False)
|
||||||
|
uplink.Clone.delete(clone.uid)
|
||||||
|
|
||||||
|
del clone_to_kill
|
||||||
198
mods/clone/utils.py
Normal file
198
mods/clone/utils.py
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
import logging
|
||||||
|
import random
|
||||||
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
from faker import Faker
|
||||||
|
|
||||||
|
logging.getLogger('faker').setLevel(logging.CRITICAL)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from mods.clone.mod_clone import Clone
|
||||||
|
|
||||||
|
def create_faker_object(faker_local: Optional[str] = 'en_GB') -> Faker:
|
||||||
|
"""Create a new faker object
|
||||||
|
|
||||||
|
Args:
|
||||||
|
faker_local (Optional[str], optional): _description_. Defaults to 'en_GB'.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Faker: The Faker Object
|
||||||
|
"""
|
||||||
|
if faker_local not in ['en_GB', 'fr_FR']:
|
||||||
|
faker_local = 'en_GB'
|
||||||
|
|
||||||
|
return Faker(faker_local)
|
||||||
|
|
||||||
|
def generate_uid_for_clone(faker_instance: 'Faker', server_id: str) -> str:
|
||||||
|
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||||
|
return server_id + ''.join(faker_instance.random_sample(chaine, 6))
|
||||||
|
|
||||||
|
def generate_vhost_for_clone(faker_instance: 'Faker') -> str:
|
||||||
|
"""Generate new vhost for the clone
|
||||||
|
|
||||||
|
Args:
|
||||||
|
faker_instance (Faker): The Faker instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: _description_
|
||||||
|
"""
|
||||||
|
rand_1 = faker_instance.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||||
|
rand_2 = faker_instance.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||||
|
rand_3 = faker_instance.random_elements(['A','B','C','D','E','F','0','1','2','3','4','5','6','7','8','9'], unique=True, length=8)
|
||||||
|
|
||||||
|
vhost = ''.join(rand_1) + '.' + ''.join(rand_2) + '.' + ''.join(rand_3) + '.IP'
|
||||||
|
return vhost
|
||||||
|
|
||||||
|
def generate_username_for_clone(faker_instance: 'Faker') -> str:
|
||||||
|
"""Generate vhosts for clones
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The vhost
|
||||||
|
"""
|
||||||
|
chaine = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||||
|
return ''.join(faker_instance.random_sample(chaine, 9))
|
||||||
|
|
||||||
|
def generate_realname_for_clone(faker_instance: 'Faker') -> tuple[int, str, str]:
|
||||||
|
"""Generate realname for clone
|
||||||
|
Ex: XX F|M Department
|
||||||
|
Args:
|
||||||
|
faker_instance (Faker): _description_
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: Age | Gender | Department
|
||||||
|
"""
|
||||||
|
# Create realname XX F|M Department
|
||||||
|
gender = faker_instance.random_choices(['F','M'], 1)
|
||||||
|
gender = ''.join(gender)
|
||||||
|
age = random.randint(20, 60)
|
||||||
|
if faker_instance.locales[0] == 'fr_FR':
|
||||||
|
department = faker_instance.department_name()
|
||||||
|
else:
|
||||||
|
department = faker_instance.city()
|
||||||
|
|
||||||
|
return (age, gender, department)
|
||||||
|
|
||||||
|
def generate_nickname_for_clone(faker_instance: 'Faker', gender: Optional[str] = 'AUTO') -> str:
|
||||||
|
"""Generate nickname for clone
|
||||||
|
|
||||||
|
Args:
|
||||||
|
faker_instance (Faker): The Faker Instance
|
||||||
|
gender (str): The Gender.Default F
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Nickname Based on the Gender
|
||||||
|
"""
|
||||||
|
if gender.upper() == 'AUTO' or gender.upper() not in ['F', 'M']:
|
||||||
|
# Generate new gender
|
||||||
|
gender = faker_instance.random_choices(['F','M'], 1)
|
||||||
|
gender = ''.join(gender)
|
||||||
|
|
||||||
|
if gender.upper() == 'F':
|
||||||
|
return faker_instance.first_name_female()
|
||||||
|
elif gender.upper() == 'M':
|
||||||
|
return faker_instance.first_name_male()
|
||||||
|
|
||||||
|
def generate_ipv4_for_clone(faker_instance: 'Faker', auto: bool = True) -> str:
|
||||||
|
"""Generate remote ipv4 for clone
|
||||||
|
|
||||||
|
Args:
|
||||||
|
faker_instance (Faker): The Faker Instance
|
||||||
|
auto (bool): Set auto generation of ip or 127.0.0.1 will be returned
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Remote IPV4
|
||||||
|
"""
|
||||||
|
return faker_instance.ipv4_private() if auto else '127.0.0.1'
|
||||||
|
|
||||||
|
def generate_hostname_for_clone(faker_instance: 'Faker') -> str:
|
||||||
|
"""Generate hostname for clone
|
||||||
|
|
||||||
|
Args:
|
||||||
|
faker_instance (Faker): The Faker Instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: New hostname
|
||||||
|
"""
|
||||||
|
return faker_instance.hostname()
|
||||||
|
|
||||||
|
def create_new_clone(uplink: 'Clone', faker_instance: 'Faker', group: str = 'Default', auto_remote_ip: bool = False) -> bool:
|
||||||
|
"""Create a new Clone object in the DB_CLONES.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
faker_instance (Faker): The Faker instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if it was created
|
||||||
|
"""
|
||||||
|
faker = faker_instance
|
||||||
|
|
||||||
|
uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID)
|
||||||
|
umodes = uplink.Config.CLONE_UMODES
|
||||||
|
|
||||||
|
# Generate Username
|
||||||
|
username = generate_username_for_clone(faker)
|
||||||
|
|
||||||
|
# Generate realname (XX F|M Department)
|
||||||
|
age, gender, department = generate_realname_for_clone(faker)
|
||||||
|
realname = f'{age} {gender} {department}'
|
||||||
|
|
||||||
|
# Generate nickname
|
||||||
|
nickname = generate_nickname_for_clone(faker, gender)
|
||||||
|
|
||||||
|
# Generate decoded ipv4 and hostname
|
||||||
|
decoded_ip = generate_ipv4_for_clone(faker, auto_remote_ip)
|
||||||
|
hostname = generate_hostname_for_clone(faker)
|
||||||
|
vhost = generate_vhost_for_clone(faker)
|
||||||
|
|
||||||
|
checkNickname = uplink.Clone.nickname_exists(nickname)
|
||||||
|
checkUid = uplink.Clone.uid_exists(uid=uid)
|
||||||
|
|
||||||
|
while checkNickname:
|
||||||
|
caracteres = '0123456789'
|
||||||
|
randomize = ''.join(random.choice(caracteres) for _ in range(2))
|
||||||
|
nickname = nickname + str(randomize)
|
||||||
|
checkNickname = uplink.Clone.nickname_exists(nickname)
|
||||||
|
|
||||||
|
while checkUid:
|
||||||
|
uid = generate_uid_for_clone(faker, uplink.Config.SERVEUR_ID)
|
||||||
|
checkUid = uplink.Clone.uid_exists(uid=uid)
|
||||||
|
|
||||||
|
clone = uplink.Definition.MClone(
|
||||||
|
connected=False,
|
||||||
|
nickname=nickname,
|
||||||
|
username=username,
|
||||||
|
realname=realname,
|
||||||
|
hostname=hostname,
|
||||||
|
umodes=umodes,
|
||||||
|
uid=uid,
|
||||||
|
remote_ip=decoded_ip,
|
||||||
|
vhost=vhost,
|
||||||
|
group=group,
|
||||||
|
channels=[]
|
||||||
|
)
|
||||||
|
|
||||||
|
uplink.Clone.insert(clone)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def handle_on_privmsg(uplink: 'Clone', srvmsg: list[str]):
|
||||||
|
|
||||||
|
uid_sender = uplink.User.clean_uid(srvmsg[1])
|
||||||
|
senderObj = uplink.User.get_User(uid_sender)
|
||||||
|
|
||||||
|
if senderObj.hostname in uplink.Config.CLONE_LOG_HOST_EXEMPT:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not senderObj is None:
|
||||||
|
senderMsg = ' '.join(srvmsg[4:])
|
||||||
|
clone_obj = uplink.Clone.get_clone(srvmsg[3])
|
||||||
|
|
||||||
|
if clone_obj is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if clone_obj.uid != uplink.Config.SERVICE_ID:
|
||||||
|
final_message = f"{senderObj.nickname}!{senderObj.username}@{senderObj.hostname} > {senderMsg.lstrip(':')}"
|
||||||
|
uplink.Protocol.send_priv_msg(
|
||||||
|
nick_from=clone_obj.uid,
|
||||||
|
msg=final_message,
|
||||||
|
channel=uplink.Config.CLONE_CHANNEL
|
||||||
|
)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "6.1.4",
|
"version": "6.2.0",
|
||||||
|
|
||||||
"requests": "2.32.3",
|
"requests": "2.32.3",
|
||||||
"psutil": "6.0.0",
|
"psutil": "6.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user