Skip to content

Commit

Permalink
Remove old implementation with new one
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanDeveloper committed Oct 16, 2024
1 parent 8ae7353 commit 3abd7f8
Show file tree
Hide file tree
Showing 12 changed files with 819 additions and 1,065 deletions.
25 changes: 0 additions & 25 deletions src/__init__.py
Original file line number Diff line number Diff line change
@@ -1,25 +0,0 @@
CONFIG_SCHEMA = {
"name": {"required": True, "type": "string"},
"containers": {"required": True, "type": "list"},
"users": {"required": True, "type": "list"},
"identityFile": {"required": True, "type": "list"},
"hosts": {"required": True, "type": "list"},
"metrics": {
"required": True,
"type": "dict",
"schema": {
"percentage": {
"required": True,
"type": "dict",
"schema": {
"value": {"required": True, "type": "number", "min": 0, "max": 100},
"trend": {
"type": "string",
"nullable": True,
"regex": "^(?i)(down|equal|up)$",
},
},
}
},
},
}
154 changes: 154 additions & 0 deletions src/ctf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@

import os
import sys
from typing import List
import yamale
import click
import pathlib

from ipaddress import ip_network
from yamale import YamaleError
from yamale.validators import DefaultValidators

sys.path.append(os.getcwd())
from src.host import Host
from src.log_config import get_logger
from src.utils import Path


logger = get_logger("ctf_creator.ctf")

class CTFCreator():
def __init__(self, config: str, save_path: str) -> None:
self.config = self._get_config(config)
logger.info(f"Containers: {self.config.get('containers')}")
logger.info(f"Users: {self.config.get('users')}")
logger.info(f"Key: {self.config.get('key')}")
logger.info(f"Hosts: {self.config.get('hosts')}")
logger.info(
f"IP-Address Subnet-base: {self.config.get('subnet')} "
)

self.save_path = save_path
self.subnet = ip_network(self.config.get("subnet"))

def _get_config(self, config: dict) -> dict:
try:
validators = DefaultValidators.copy() # This is a dictionary
validators[Path.tag] = Path
schema = yamale.make_schema(f'{pathlib.Path(__file__).parent.resolve()}/schema.yaml', validators=validators)
# Create a Data object
data = yamale.make_data(content=config)
# Validate data against the schema. Throws a ValueError if data is invalid.
yamale.validate(schema, data)

logger.info("YAML file loaded successfully.")

return data[0][0]
except YamaleError as e:
logger.error('Validation failed!\n')
for result in e.results:
logger.error("Error validating data '%s' with '%s'\n\t" % (result.data, result.schema))
for error in result.errors:
logger.error('\t%s' % error)
exit(1)

def _get_hosts(self) -> List:
hosts = []
for host in self.config.get('hosts'):
host_object = Host(host=host, save_path=self.save_path)
hosts.append(host_object)
host_object.clean_up()
return hosts

def _extract_ovpn_info(self, file_path):
"""
Extracts the host IP address, port number, and subnet from an OpenVPN configuration file.
Args:
file_path (str): Path to the OpenVPN configuration file.
Returns:
tuple: A tuple containing:
- host_ip_address (str): The IP address found after the 'remote' keyword.
- port_number (int): The port number found after the IP address on the 'remote' line.
"""
if not os.path.exists(file_path):
logger.error(f"File {file_path} does not exist.")
return None

host_ip_address = None
port_number = None

with open(file_path, "r") as file:
lines = file.readlines()

for line in lines:
if line.startswith("remote "):
parts = line.split()
if len(parts) == 3:
host_ip_address = parts[1]
port_number = int(parts[2])

if host_ip_address and port_number:
return host_ip_address, port_number
else:
logger.error("Failed to extract all necessary information.")
return None

def create_challenge(self):
logger.info("Set up hosts.")
self.hosts = self._get_hosts()
logger.info("Begin set up of challenge.")

http_port = 40000
openvpn_port = 50000
challenge_counter = 1
next_network = self.subnet

# TODO Handle issue, when address for OpenVPN or HTTP Port is already in use.
for idx, user in enumerate(self.config.get("users")):
if os.path.exists(f"{self.save_path}/data/{user}"):
logger.info(f"OpenVPN data exists for the user: {user}")
logger.info(f"Data for the user: {user} will NOT be changed. Starting OVPN Docker container with existing data.")
ip, openvpn_port = self._extract_ovpn_info(f"{self.save_path}/data/{user}/client.ovpn")

logger.info(f"Get host with IP {ip}")
host: Host = [d for d in self.hosts if str(d.ip) == ip][0]

host.send_and_extract_tar(user=user)
host.start_openvpn(user, openvpn_port, http_port, next_network)
else:
logger.info(
f"For the user: {user}, an OpenVPN configuration file will be generated!"
)
host: Host = self.hosts[idx % len(self.hosts)]
host.start_openvpn(user, openvpn_port + challenge_counter, http_port + challenge_counter, next_network)

# TODO handle start containers
# host.start_containers(user, self.config.get("containers"))

next_network = ip_network((int(next_network.network_address) + next_network.num_addresses), strict=False)
challenge_counter += 1


@click.command()
@click.option(
"--config",
required=True,
help="The path to the .yaml configuration file for the CTF-Creator.",
type=click.File('r', encoding='utf8'),
)
@click.option(
"--save",
required=True,
help="The path where you want to save the user data for the CTF-Creator. E.g. /home/nick/ctf-creator",
type=click.Path(writable=True),
)
def main(config, save):
ctfcreator = CTFCreator(config=config.read(), save_path=save)
ctfcreator.create_challenge()


if __name__ == "__main__":
main()
Loading

0 comments on commit 3abd7f8

Please sign in to comment.