Skip to content
Snippets Groups Projects
Commit a62fb6a3 authored by Martinz, David's avatar Martinz, David
Browse files

added descriptions

parent 6de1a802
No related branches found
No related tags found
No related merge requests found
......@@ -28,6 +28,61 @@ Each branch contains a specific **hacklet** demonstrating a unique security vuln
---
### 📂 **Directory Structure**
```bash
.
├── app # Main application directory
│ ├── __init__.py # App initialization (Flask app factory)
│ ├── routes # Contains Flask route handlers (blueprints)
│ │ ├── auth.py # Authentication routes (login, register)
│ │ ├── messaging.py # Messaging routes (chats, file uploads)
│ │ └── __pycache__ # Compiled Python files (ignored by git)
│ └── uploads # Directory to store uploaded files
│ ├── etc # Directory for uploaded system files (exploit testing)
│ └── malicious.sh # Example malicious file uploaded by an attacker
├── docker-compose.yml # Docker Compose configuration for running the app
├── Dockerfile # Dockerfile to build the container image
├── host_etc # Host directory bind-mounted to the container (used in hacklet)
├── malicious.sh # Exploit script for CVE-2024-21626 (container breakout)
├── requirements.txt # Python dependencies for the app
├── run.py # Main entry point to run the Flask app
├── templates # HTML templates for the web app
│ ├── base.html # Base template (common layout for all pages)
│ ├── chats.html # Template for the chats page
│ ├── conversation.html# Template for conversation/chat window
│ ├── index.html # Homepage template
│ ├── login.html # Login page template
│ ├── macros.html # Reusable UI components (e.g., flash messages)
│ ├── register.html # Registration page template
│ └── send_file.html # Template for sending files
└── uploads # Directory to store user-uploaded files
├── malicious.sh # Uploaded malicious shell script
└── reverse_shell.sh # Reverse shell script uploaded by the attacker
```
---
### 🛠️ **How to Run the Web App**
1. Clone the repository:
```bash
git clone https://github.com/DFS-group/security-in-container-environments.git
cd security-in-container-environments/messaging-app
```
2. Build and run the Docker container:
```bash
docker-compose up --build
```
3. Access the web app at:
```
http://localhost:5000
```
---
## 🛠️ **Tools and Techniques Used**
| **Tool** | **Purpose** |
......
......@@ -2,12 +2,17 @@ from flask import Blueprint, render_template, request, redirect, url_for, flash
from flask_login import login_user, logout_user, current_user, UserMixin
from app import login_manager
# Define the authentication blueprint
# This blueprint handles routes related to user authentication (login, logout, registration)
auth_bp = Blueprint('auth', __name__)
# In-memory user data
# In-memory user data storage
# This dictionary stores user information (username, ID, and password)
# Example: {"david": {"id": 1, "password": "1234"}}
users = {}
# User class
# Define a custom User class that extends Flask-Login's UserMixin
# This class represents a logged-in user
class User(UserMixin):
def __init__(self, id, username, password):
self.id = id
......@@ -15,48 +20,76 @@ class User(UserMixin):
self.password = password
# User loader function for Flask-Login
# Flask-Login requires this function to retrieve the user object based on their ID
@login_manager.user_loader
def load_user(user_id):
"""
This function loads a user from the in-memory users dictionary
based on the user ID provided by Flask-Login.
"""
for username, user in users.items():
if user['id'] == int(user_id):
return User(user['id'], username, user['password'])
return None
# Registration route
# Route to handle user registration
# Users can register by providing a username and password
@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
"""
Handles user registration.
- GET request: Displays the registration form.
- POST request: Processes the registration form and creates a new user.
"""
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if username in users:
# If the username already exists, show an error message
flash('Username already exists', 'register-danger')
else:
# If the username is new, add the user to the in-memory users dictionary
user_id = len(users) + 1
users[username] = {'id': user_id, 'password': password}
flash('Registration successful! Please log in.', 'login-success')
return redirect(url_for('auth.login'))
# Render the registration page
return render_template('register.html')
# Login route
# Route to handle user login
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
"""
Handles user login.
- GET request: Displays the login form.
- POST request: Processes the login form and logs in the user if credentials are valid.
"""
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
# Check if the provided username and password match an existing user
if username in users and users[username]['password'] == password:
# Create a User object and log the user in
user = User(users[username]['id'], username, password)
login_user(user)
flash('Login successful!', 'index-success')
return redirect(url_for('messaging.index'))
else:
# If login fails, show an error message
flash('Invalid username or password', 'login-danger')
# Render the login page
return render_template('login.html')
# Logout route
# Route to handle user logout
@auth_bp.route('/logout')
def logout():
"""
Logs out the current user and redirects them to the login page.
"""
logout_user()
flash('You have been logged out.', 'login-info')
return redirect(url_for('auth.login'))
......@@ -3,38 +3,53 @@ from flask_login import login_required, current_user
import os
from app.routes.auth import users
# Define the messaging blueprint for handling chat-related routes
messaging_bp = Blueprint('messaging', __name__)
# Mock database for messages
# In-memory dictionary to store chat messages between users
# Format: {("user1", "user2"): [("sender", "message"), ...]}
messages = {}
# Directory to store uploaded files
UPLOAD_FOLDER = './uploads'
# Ensure the upload folder exists when the app starts
if not os.path.exists(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
# Route for the homepage
@messaging_bp.route('/')
def index():
"""Render the homepage."""
return render_template('index.html')
# Route to view and manage chats
@messaging_bp.route('/chats', methods=['GET', 'POST'])
@login_required
def view_chats():
user_chats = set()
"""
Displays a list of active conversations for the current user.
Allows starting a new conversation by selecting a user from a dropdown list.
"""
user_chats = set() # Stores the usernames of users the current user has chatted with
# Loop through all message participants to find active chats for the current user
for participants in messages.keys():
if current_user.username in participants:
other_user = participants[1] if participants[0] == current_user.username else participants[0]
user_chats.add(other_user)
# Handle form submission to start a new chat
if request.method == 'POST':
new_chat_user = request.form.get('username')
if new_chat_user:
if new_chat_user == current_user.username:
# Prevent starting a chat with yourself
flash('You cannot start a conversation with yourself!', 'chats-danger')
return redirect(url_for('messaging.view_chats'))
if new_chat_user in users:
# Create a new conversation if it doesn't already exist
participants = tuple(sorted((current_user.username, new_chat_user)))
if participants not in messages:
messages[participants] = []
......@@ -44,16 +59,25 @@ def view_chats():
flash('User not found!', 'chats-danger')
return redirect(url_for('messaging.view_chats'))
# Render the chats template with the list of users and active chats
return render_template('chats.html', users=users.keys(), chats=list(user_chats))
# Route to view a specific conversation between the current user and another user
@messaging_bp.route('/conversation/<username>', methods=['GET', 'POST'])
@login_required
def view_conversation(username):
"""
Displays the chat history between the current user and the specified user.
Allows the current user to send new messages.
"""
# Sort participants alphabetically to create a unique key for the conversation
participants = tuple(sorted((current_user.username, username)))
# Initialize a new conversation if it doesn't exist
if participants not in messages:
messages[participants] = []
# Handle new message submission
if request.method == 'POST':
new_message = request.form.get('message')
if new_message:
......@@ -61,10 +85,16 @@ def view_conversation(username):
flash('Message sent!', 'conversation-success')
return redirect(url_for('messaging.view_conversation', username=username))
# Render the conversation template with chat history
chat_history = messages[participants]
return render_template('conversation.html', username=username, chat_history=chat_history)
# Route to download a file from the uploads folder
@messaging_bp.route('/uploads/<filename>')
@login_required
def download_file(filename):
"""
Serves a file from the uploads directory.
Ensures that only authenticated users can download files.
"""
return send_from_directory(UPLOAD_FOLDER, filename)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment