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)
### 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
# Run frontend using docker-compose
docker compose -f docker-compose-frontend.yml up -d
@ -111,4 +128,16 @@ The application provides an automated cleaning service for the files that are up
The files are deleted after a certain period of time (ttl).
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()
def _save_file(self, file, ttl, responses):
key = uuid.uuid4().hex
filename = file.name
save_path = os.path.join(settings.MEDIA_ROOT, filename)
generated_uuid = uuid.uuid4().hex # Generate a UUID
filename = file.name # Get the original filename
save_path = os.path.join(settings.MEDIA_ROOT, generated_uuid) # Use the UUID as the new filename
hasher = hashlib.sha256()
with open(save_path, 'wb') as destination:
@ -95,7 +95,7 @@ class ManageItemsView(APIView):
logger.warning(f'File {filename} is infected with a virus')
return
# Determine the MIME type of the file using python-magic
# Determine the MIME type of the file using python-magic
try:
file_type = magic.Magic()
mime_type = file_type.from_file(save_path)
@ -103,21 +103,22 @@ class ManageItemsView(APIView):
logger.warning(f'Error detecting MIME type: {str(e)}')
mime_type = 'application/octet-stream'
# Store the file path, filename, MIME type, and other information in the cache
cache.set(key, {
'filename': filename,
# Store the file path, generated UUID, original filename, MIME type, and other information in the cache
cache.set(generated_uuid, {
'filename': filename, # Original filename
'generated_uuid': generated_uuid, # Generated UUID
'path': save_path,
'mime_type': mime_type, # Store the MIME type
'mime_type': mime_type,
}, timeout=ttl)
response = {
'key': key,
'filename': filename,
'mime_type': mime_type, # Include the MIME type in the response
'msg': f"{key} successfully set to {filename} with TTL {ttl} seconds",
'key': generated_uuid, # Return the generated UUID
'filename': filename, # Return the original filename
'mime_type': mime_type,
'msg': f"{generated_uuid} successfully set to {filename} with TTL {ttl} seconds",
}
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):
@ -147,7 +148,8 @@ class ManageItemView(APIView):
response = HttpResponse(file_data, content_type=mime_type)
# 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}')
return response
@ -174,7 +176,13 @@ PRIVATE_IPS_PREFIX = ('10.', '172.', '192.')
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')
ip = remote_address
@ -183,8 +191,9 @@ def get_client_ip(request):
if x_forwarded_for:
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)
if len(proxies) > 0:
ip = proxies[0]
if proxies:
ip = proxies[0]
return ip