Compare commits

..

4 Commits

Author SHA1 Message Date
Benjamin Loh a7c11477af updated readme
updated readme
2023-11-07 20:41:06 +08:00
Benjamin Loh 8e6c5789ef removed redundant yaml files
removed redundant yaml files
2023-11-07 20:22:22 +08:00
Devoalda 372825d662 fix(File save update):
Updated file saved to use uuid instead of original filename
Updated Download to use the original filename
2023-11-02 10:16:06 +08:00
Devoalda a5e409c2fd Updated Readme 2023-11-01 16:00:42 +08:00
4 changed files with 57 additions and 64 deletions

View File

@ -35,6 +35,23 @@ docker-compose up
``` ```
### Running Backend & Frontend Separately (Docker + Kubernetes) ### Running Backend & Frontend Separately (Docker + Kubernetes)
### Prerequisites
Before you begin, make sure you have:
- A Kubernetes cluster up and running.
- `kubectl` installed and configured to communicate with your cluster.
- Proper permissions to create Deployments, Services, Persistent Volumes, and other Kubernetes resources.
### Overview of Components
- `frontend_deployment.yaml`: Deployment for the SafeShare frontend.
- `frontend_service.yaml`: Service exposing the SafeShare frontend.
- `backend_deployment.yaml`: Deployment for the SafeShare backend.
- `backend_service.yaml`: Service exposing the SafeShare backend.
- `redis_deployment.yaml`: Setup for Redis with persistent storage.
```bash ```bash
# Run frontend using docker-compose # Run frontend using docker-compose
docker compose -f docker-compose-frontend.yml up -d docker compose -f docker-compose-frontend.yml up -d
@ -112,3 +129,15 @@ The files are deleted after a certain period of time (ttl).
The time period can be set in the `.env` file. (`TRASH_TIMEOUT`) The time period can be set in the `.env` file. (`TRASH_TIMEOUT`)
This service will periodically check redis for the files that have expired and delete them from the server's storage. This service will periodically check redis for the files that have expired and delete them from the server's storage.
## Test Files
Theoretically, the application can handle any type of file. However, we have tested the application with the following file types:
- Text-based `.txt`, `.py`, etc.
- Image-based `.png`, `.jpg`, etc.
- Video-based `.mp4`, etc.
- Executable `.exe`, etc.
The Virus file used for testing is generated with [metasploit](https://www.metasploit.com/) (msfvenom). ([VirusTotal Report](https://www.virustotal.com/gui/file/2fd0c13298f99d5ae10765ef65e1667e205e932376396d92e4343468abe0c541/detection))
It is a simple reverse shell payload that connects to the attacker's machine, Harmless since it is not connected to the attacker's machine. But **DO NOT** run it on your machine.

View File

@ -1,30 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: safeshare-frontend
labels:
app: safeshare
tier: frontend
spec:
replicas: 1
selector:
matchLabels:
app: safeshare
tier: frontend
template:
metadata:
labels:
app: safeshare
tier: frontend
spec:
containers:
- name: safeshare-frontend
image: amusement3004/safeshare-frontend
imagePullPolicy: IfNotPresent
env: # Add these environment variables
- name: REACT_APP_API_HOST
value: safeshare-backend-service # The name of the backend service
- name: REACT_APP_API_PORT
value: "8000" # The port the backend service listens on
ports:
- containerPort: 3000

View File

@ -1,15 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: safeshare-frontend-service
labels:
app: safeshare
tier: frontend
spec:
type: NodePort
ports:
- port: 3000
nodePort: 32000 # Optional: This is an example. Kubernetes will assign an available port if you don't specify this.
selector:
app: safeshare
tier: frontend

View File

@ -65,9 +65,9 @@ class ManageItemsView(APIView):
timeout_timer.cancel() timeout_timer.cancel()
def _save_file(self, file, ttl, responses): def _save_file(self, file, ttl, responses):
key = uuid.uuid4().hex generated_uuid = uuid.uuid4().hex # Generate a UUID
filename = file.name filename = file.name # Get the original filename
save_path = os.path.join(settings.MEDIA_ROOT, filename) save_path = os.path.join(settings.MEDIA_ROOT, generated_uuid) # Use the UUID as the new filename
hasher = hashlib.sha256() hasher = hashlib.sha256()
with open(save_path, 'wb') as destination: with open(save_path, 'wb') as destination:
@ -95,7 +95,7 @@ class ManageItemsView(APIView):
logger.warning(f'File {filename} is infected with a virus') logger.warning(f'File {filename} is infected with a virus')
return return
# Determine the MIME type of the file using python-magic # Determine the MIME type of the file using python-magic
try: try:
file_type = magic.Magic() file_type = magic.Magic()
mime_type = file_type.from_file(save_path) mime_type = file_type.from_file(save_path)
@ -103,21 +103,22 @@ class ManageItemsView(APIView):
logger.warning(f'Error detecting MIME type: {str(e)}') logger.warning(f'Error detecting MIME type: {str(e)}')
mime_type = 'application/octet-stream' mime_type = 'application/octet-stream'
# Store the file path, filename, MIME type, and other information in the cache # Store the file path, generated UUID, original filename, MIME type, and other information in the cache
cache.set(key, { cache.set(generated_uuid, {
'filename': filename, 'filename': filename, # Original filename
'generated_uuid': generated_uuid, # Generated UUID
'path': save_path, 'path': save_path,
'mime_type': mime_type, # Store the MIME type 'mime_type': mime_type,
}, timeout=ttl) }, timeout=ttl)
response = { response = {
'key': key, 'key': generated_uuid, # Return the generated UUID
'filename': filename, 'filename': filename, # Return the original filename
'mime_type': mime_type, # Include the MIME type in the response 'mime_type': mime_type,
'msg': f"{key} successfully set to {filename} with TTL {ttl} seconds", 'msg': f"{generated_uuid} successfully set to {filename} with TTL {ttl} seconds",
} }
responses.append(response) responses.append(response)
logger.info(f'File {filename} successfully saved to cache with key {key} and TTL {ttl} seconds') logger.info(f'File {filename} successfully saved to cache with key {generated_uuid} and TTL {ttl} seconds')
class ManageItemView(APIView): class ManageItemView(APIView):
@ -147,7 +148,8 @@ class ManageItemView(APIView):
response = HttpResponse(file_data, content_type=mime_type) response = HttpResponse(file_data, content_type=mime_type)
# Set the Content-Disposition with the original filename # Set the Content-Disposition with the original filename
response['Content-Disposition'] = f'attachment; filename="{quote(os.path.basename(file_path))}"' original_filename = value.get('filename', 'file') # Get the original filename from the cache
response['Content-Disposition'] = f'attachment; filename="{quote(original_filename)}"'
logger.info(f'File {file_path} successfully retrieved from cache with key {key}') logger.info(f'File {file_path} successfully retrieved from cache with key {key}')
return response return response
@ -174,7 +176,13 @@ PRIVATE_IPS_PREFIX = ('10.', '172.', '192.')
def get_client_ip(request): def get_client_ip(request):
""" """
Get Client's IP Get the client's IP address from the request.
This function extracts the client's IP address from various request headers,
taking into account possible proxy servers.
:param request: The HTTP request object.
:return: The client's IP address.
""" """
remote_address = request.META.get('HTTP_X_FORWARDED_FOR') or request.META.get('REMOTE_ADDR') remote_address = request.META.get('HTTP_X_FORWARDED_FOR') or request.META.get('REMOTE_ADDR')
ip = remote_address ip = remote_address
@ -183,8 +191,9 @@ def get_client_ip(request):
if x_forwarded_for: if x_forwarded_for:
proxies = x_forwarded_for.split(',') proxies = x_forwarded_for.split(',')
while len(proxies) > 0 and proxies[0].startswith(PRIVATE_IPS_PREFIX): while proxies and proxies[0].startswith(PRIVATE_IPS_PREFIX):
proxies.pop(0) proxies.pop(0)
if len(proxies) > 0: if proxies:
ip = proxies[0] ip = proxies[0]
return ip return ip