Include mod_jsonrpc

This commit is contained in:
adator
2024-09-22 22:23:13 +02:00
parent 7e5e2d4643
commit 11eedbb191
6 changed files with 276 additions and 2 deletions

1
.gitignore vendored
View File

@@ -2,7 +2,6 @@
db/
logs/
__pycache__/
mods/mod_jsonrpc.py
configuration.json
*.log
test.py

View File

@@ -157,6 +157,12 @@ Pour Les prochains lancement de defender vous devez utiliser la commande suivant
"OWNER": "TON_NICK_NAME",
"PASSWORD": "TON_PASSWORD",
"JSONRPC_URL": "https://your.domaine.com:8600/api",
"JSONRPC_PATH_TO_SOCKET_FILE": "/PATH/TO/YOUR/IRCD/data/rpc.socket",
"JSONRPC_METHOD": "socket",
"JSONRPC_USER": "YOUR_RPC_USER",
"JSONRPC_PASSWORD": "YOUR_RPC_PASSWORD",
"SALON_JAIL": "#jail",
"SALON_JAIL_MODES": "sS",
"SALON_LIBERER": "#welcome",

View File

@@ -22,6 +22,12 @@
"OWNER": "TON_NICK_NAME",
"PASSWORD": "TON_PASSWORD",
"JSONRPC_URL": "https://your.domaine.com:8600/api",
"JSONRPC_PATH_TO_SOCKET_FILE": "/PATH/TO/YOUR/IRCD/data/rpc.socket",
"JSONRPC_METHOD": "socket",
"JSONRPC_USER": "YOUR_RPC_USER",
"JSONRPC_PASSWORD": "YOUR_RPC_PASSWORD",
"SALON_JAIL": "#jail",
"SALON_JAIL_MODES": "sS",
"SALON_LIBERER": "#welcome",

View File

@@ -64,7 +64,7 @@ class Install:
defender_install_folder=defender_install_folder,
venv_folder=venv_folder,
venv_cmd_installation=['python3', '-m', 'venv', venv_folder],
venv_cmd_requirements=['sqlalchemy','psutil','requests','faker'],
venv_cmd_requirements=['sqlalchemy','psutil','requests','faker','unrealircd_rpc_py'],
venv_pip_executable=f'{os.path.join(defender_install_folder, venv_folder, "bin")}{os.sep}pip',
venv_python_executable=f'{os.path.join(defender_install_folder, venv_folder, "bin")}{os.sep}python'
)

View File

@@ -84,6 +84,12 @@ class ConfigDataModel:
PASSWORD: str
"""The password of the admin of the service"""
JSONRPC_URL: str
JSONRPC_PATH_TO_SOCKET_FILE: str
JSONRPC_METHOD: str
JSONRPC_USER: str
JSONRPC_PASSWORD: str
SALON_JAIL: str
"""The JAIL channel (ex. #jail)"""
@@ -208,13 +214,22 @@ class Config:
SERVICE_PREFIX=import_config["SERVICE_PREFIX"] if "SERVICE_PREFIX" in import_config else '!',
OWNER=import_config["OWNER"] if "OWNER" in import_config else 'admin',
PASSWORD=import_config["PASSWORD"] if "PASSWORD" in import_config else 'admin',
JSONRPC_METHOD=import_config["JSONRPC_METHOD"] if "JSONRPC_METHOD" in import_config else 'socket',
JSONRPC_URL=import_config["JSONRPC_URL"] if "JSONRPC_URL" in import_config else None,
JSONRPC_PATH_TO_SOCKET_FILE=import_config["JSONRPC_PATH_TO_SOCKET_FILE"] if "JSONRPC_PATH_TO_SOCKET_FILE" in import_config else None,
JSONRPC_USER=import_config["JSONRPC_USER"] if "JSONRPC_USER" in import_config else None,
JSONRPC_PASSWORD=import_config["JSONRPC_PASSWORD"] if "JSONRPC_PASSWORD" in import_config else None,
SALON_JAIL=import_config["SALON_JAIL"] if "SALON_JAIL" in import_config else '#jail',
SALON_JAIL_MODES=import_config["SALON_JAIL_MODES"] if "SALON_JAIL_MODES" in import_config else 'sS',
SALON_LIBERER=import_config["SALON_LIBERER"] if "SALON_LIBERER" in import_config else '#welcome',
CLONE_CHANNEL=import_config["CLONE_CHANNEL"] if "CLONE_CHANNEL" in import_config else '#clones',
CLONE_CMODES=import_config["CLONE_CMODES"] if "CLONE_CMODES" in import_config else '+nts',
CLONE_LOG_HOST_EXEMPT=import_config["CLONE_LOG_HOST_EXEMPT"] if "CLONE_LOG_HOST_EXEMPT" in import_config else [],
CLONE_CHANNEL_PASSWORD=import_config["CLONE_CHANNEL_PASSWORD"] if "CLONE_CHANNEL_PASSWORD" in import_config else "clone_Password_1234",
API_TIMEOUT=import_config["API_TIMEOUT"] if "API_TIMEOUT" in import_config else 2,
PORTS_TO_SCAN=import_config["PORTS_TO_SCAN"] if "PORTS_TO_SCAN" in import_config else [],
WHITELISTED_IP=import_config["WHITELISTED_IP"] if "WHITELISTED_IP" in import_config else ['127.0.0.1'],

248
mods/mod_jsonrpc.py Normal file
View File

@@ -0,0 +1,248 @@
from dataclasses import dataclass
from core.irc import Irc
from unrealircd_rpc_py.Live import Live
from unrealircd_rpc_py.Loader import Loader
class Jsonrpc():
@dataclass
class ModConfModel:
"""The Model containing the module parameters
"""
param_exemple1: str
param_exemple2: int
def __init__(self, ircInstance:Irc) -> None:
# Module name (Mandatory)
self.module_name = 'mod_' + str(self.__class__.__name__).lower()
# Add Irc Object to the module (Mandatory)
self.Irc = ircInstance
# Add Global Configuration to the module (Mandatory)
self.Config = ircInstance.Config
# Add Base object to the module (Mandatory)
self.Base = ircInstance.Base
# Add logs object to the module (Mandatory)
self.Logs = ircInstance.Base.logs
# Add User object to the module (Mandatory)
self.User = ircInstance.User
# Add Channel object to the module (Mandatory)
self.Channel = ircInstance.Channel
# Create module commands (Mandatory)
self.commands_level = {
1: ['jsonrpc', 'jruser']
}
# Init the module
self.__init_module()
# Log the module
self.Logs.debug(f'Module {self.module_name} loaded ...')
def __init_module(self) -> None:
# Insert module commands into the core one (Mandatory)
self.__set_commands(self.commands_level)
# Create you own tables (Mandatory)
# self.__create_tables()
# Load module configuration and sync with core one (Mandatory)
self.__load_module_configuration()
# End of mandatory methods you can start your customization #
self.UnrealIrcdRpcLive: Live = None
self.Rpc: Loader = Loader(
req_method=self.Config.JSONRPC_METHOD,
url=self.Config.JSONRPC_URL,
username=self.Config.JSONRPC_USER,
password=self.Config.JSONRPC_PASSWORD
)
if self.Rpc.Error.code != -1:
self.Base.db_delete_module(module_name=self.module_name)
return None
def __set_commands(self, commands:dict[int, list[str]]) -> None:
"""### Rajoute les commandes du module au programme principal
Args:
commands (list): Liste des commandes du module
"""
for level, com in commands.items():
for c in commands[level]:
if not c in self.Irc.commands:
self.Irc.commands_level[level].append(c)
self.Irc.commands.append(c)
return None
def __create_tables(self) -> None:
"""Methode qui va créer la base de donnée si elle n'existe pas.
Une Session unique pour cette classe sera crée, qui sera utilisé dans cette classe / module
Args:
database_name (str): Nom de la base de données ( pas d'espace dans le nom )
Returns:
None: Aucun retour n'es attendu
"""
table_logs = '''CREATE TABLE IF NOT EXISTS test_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
datetime TEXT,
server_msg TEXT
)
'''
self.Base.db_execute_query(table_logs)
return None
def callback_sent_to_irc(self, json_response: str):
dnickname = self.Config.SERVICE_NICKNAME
dchanlog = self.Config.SERVICE_CHANLOG
self.Irc.sendPrivMsg(msg=json_response, channel=dchanlog)
def thread_start_jsonrpc(self):
self.UnrealIrcdRpcLive = Live(path_to_socket_file=self.Config.JSONRPC_PATH_TO_SOCKET_FILE,
callback_object_instance=self,
callback_method_name='callback_sent_to_irc'
)
self.UnrealIrcdRpcLive.subscribe()
def __load_module_configuration(self) -> None:
"""### Load Module Configuration
"""
try:
# Build the default configuration model (Mandatory)
self.ModConfig = self.ModConfModel(param_exemple1='param value 1', param_exemple2=1)
# Sync the configuration with core configuration (Mandatory)
#self.Base.db_sync_core_config(self.module_name, self.ModConfig)
return None
except TypeError as te:
self.Logs.critical(te)
def __update_configuration(self, param_key: str, param_value: str):
"""Update the local and core configuration
Args:
param_key (str): The parameter key
param_value (str): The parameter value
"""
self.Base.db_update_core_config(self.module_name, self.ModConfig, param_key, param_value)
def unload(self) -> None:
return None
def cmd(self, data:list) -> None:
return None
def _hcmds(self, user:str, channel: any, cmd: list, fullcmd: list = []) -> None:
command = str(cmd[0]).lower()
dnickname = self.Config.SERVICE_NICKNAME
fromuser = user
fromchannel = str(channel) if not channel is None else None
match command:
case 'jsonrpc':
try:
option = str(cmd[1]).lower()
if len(command) == 1:
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} jsonrpc on')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} jsonrpc off')
match option:
case 'on':
self.Base.create_thread(self.thread_start_jsonrpc, run_once=True)
case 'off':
self.UnrealIrcdRpcLive.unsubscribe()
except IndexError as ie:
self.Logs.error(ie)
case 'jruser':
try:
option = str(cmd[1]).lower()
if len(command) == 1:
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :/msg {dnickname} jruser get nickname')
match option:
case 'get':
nickname = str(cmd[2])
uid_to_get = self.User.get_uid(nickname)
if uid_to_get is None:
return None
rpc = Loader(
req_method=self.Config.JSONRPC_METHOD,
url=self.Config.JSONRPC_URL,
username=self.Config.JSONRPC_USER,
password=self.Config.JSONRPC_PASSWORD
)
UserInfo = rpc.User.get(uid_to_get)
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :UID : {UserInfo.id}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :NICKNAME : {UserInfo.name}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :USERNAME : {UserInfo.username}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :REALNAME : {UserInfo.realname}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CHANNELS : {UserInfo.channels}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :SECURITY GROUP : {UserInfo.security_groups}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :REPUTATION : {UserInfo.reputation}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :IP : {UserInfo.ip}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :COUNTRY CODE : {UserInfo.country_code}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :ASN : {UserInfo.asn}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :ASNAME : {UserInfo.asname}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CLOAKED HOST : {UserInfo.cloakedhost}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :HOSTNAME : {UserInfo.hostname}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :VHOST : {UserInfo.vhost}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CLIENT PORT : {UserInfo.client_port}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :SERVER PORT : {UserInfo.server_port}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :IDLE SINCE : {UserInfo.idle_since}')
self.Irc.send2socket(f':{dnickname} NOTICE {fromuser} :CONNECTED SINCE : {UserInfo.connected_since}')
except IndexError as ie:
self.Logs.error(ie)
case 'ia':
try:
self.Base.create_thread(self.thread_ask_ia, ('',))
self.Irc.send2socket(f":{dnickname} NOTICE {fromuser} : This is a notice to the sender ...")
self.Irc.send2socket(f":{dnickname} PRIVMSG {fromuser} : This is private message to the sender ...")
if not fromchannel is None:
self.Irc.send2socket(f":{dnickname} PRIVMSG {fromchannel} : This is channel message to the sender ...")
# How to update your module configuration
self.__update_configuration('param_exemple2', 7)
# Log if you want the result
self.Logs.debug(f"Test logs ready")
except Exception as err:
self.Logs.error(f"Unknown Error: {err}")