From 7c81755cda9bd1fb5d8f628d584ed580606e9601 Mon Sep 17 00:00:00 2001 From: Aman Tahiliani Date: Sat, 20 Apr 2024 15:10:06 -0400 Subject: [PATCH 1/2] File transfer trial --- peer_temp/abcd.txt | 1 + peer_temp/client_server.js | 45 ++++++++++++++ peer_temp/temp_requester.js | 84 +++++++++++++++++++++++++ peer_temp/temp_sender.js | 121 ++++++++++++++++++++++++++++++++++++ 4 files changed, 251 insertions(+) create mode 100644 peer_temp/abcd.txt create mode 100644 peer_temp/client_server.js create mode 100644 peer_temp/temp_requester.js create mode 100644 peer_temp/temp_sender.js diff --git a/peer_temp/abcd.txt b/peer_temp/abcd.txt new file mode 100644 index 0000000..5eaf5f5 --- /dev/null +++ b/peer_temp/abcd.txt @@ -0,0 +1 @@ +Hello Hi Test \ No newline at end of file diff --git a/peer_temp/client_server.js b/peer_temp/client_server.js new file mode 100644 index 0000000..8248b2f --- /dev/null +++ b/peer_temp/client_server.js @@ -0,0 +1,45 @@ + +const SimplePeer = require('simple-peer'); + +// Function to act as the file host +function hostFile() { + const peer = new SimplePeer({ initiator: true }); + + peer.on('signal', data => { + console.log('Share this data with the peer who wants to download the file:'); + console.log(JSON.stringify(data)); + }); + + peer.on('connect', () => { + console.log('Peer connected. Sending file...'); + const fileContent = 'This is the content of the file.'; + peer.send(fileContent); + }); +} + +// Function to act as the file requester +function requestFile() { + const peer = new SimplePeer(); + + peer.on('signal', data => { + console.log('Share this data with the file host:'); + console.log(JSON.stringify(data)); + }); + + peer.on('connect', () => { + console.log('Peer connected. Waiting for file...'); + }); + + peer.on('data', data => { + console.log(`File received: ${data}`); + }); +} + +// Decide whether to host the file or request it +const isHost = process.argv[2] === 'host'; + +if (isHost) { + hostFile(); +} else { + requestFile(); +} diff --git a/peer_temp/temp_requester.js b/peer_temp/temp_requester.js new file mode 100644 index 0000000..f522ae1 --- /dev/null +++ b/peer_temp/temp_requester.js @@ -0,0 +1,84 @@ +// // Requester Peer + +// const net = require('net'); + +// // IP address and port of the other peer +// const otherPeerIP = 'other_peer_ip_address'; +// const otherPeerPort = 12345; // Assuming this is the port the other peer is listening on + +// // File ID to request +// const fileId = 'file123'; + +// // Create a TCP socket to connect to the other peer +// const client = new net.Socket(); + +// client.connect(otherPeerPort, otherPeerIP, () => { +// console.log('Connected to peer'); + +// // Send the file ID as a request +// client.write(fileId); +// }); + +// // Listen for data (the requested file) from the other peer +// client.on('data', (data) => { +// console.log('Received file:', data.toString()); + +// // Close the connection after receiving the file +// client.end(); +// }); + +// // Handle connection errors +// client.on('error', (err) => { +// console.error('Connection error:', err); +// }); + + +// Requester Peer + +// const net = require('net'); + +// // IP address and port of the other peer +// const otherPeerIP = '127.0.0.1'; // Assuming both peers are running on the same machine +// const otherPeerPort = 12345; + +// File ID to request +const fileId = 'abcd.txt'; + +// Create a TCP server to handle incoming requests from the other peer + + +// Requester Peer + +const net = require('net'); + +// IP address and port of the receiving peer +const receiverIP = '127.0.0.1'; // Assuming both peers are running on the same machine +const receiverPort = 12345; + +// File ID to request +// const fileId = 'file123'; + +// Create a TCP client to connect to the receiving peer server +const client = new net.Socket(); + +// Handle connection to the receiving peer +client.connect(receiverPort, receiverIP, () => { + console.log('Connected to receiving peer server'); + + // Send the file ID as a request to the receiving peer + client.write(fileId); +}); + +// Listen for data (the requested file) from the receiving peer +client.on('data', (data) => { + console.log('Received file:', data.toString()); + + // Close the connection after receiving the file + client.end(); +}); + +// Handle connection errors +client.on('error', (err) => { + console.error('Connection error:', err); +}); + diff --git a/peer_temp/temp_sender.js b/peer_temp/temp_sender.js new file mode 100644 index 0000000..7e732b1 --- /dev/null +++ b/peer_temp/temp_sender.js @@ -0,0 +1,121 @@ +// // Receiving Peer + +// const net = require('net'); +// const fs = require('fs'); + +// // Port on which this peer will listen for requests +// const listenPort = 12345; + +// // Mapping of file IDs to file paths +// const filesMap = { +// 'file123': '/path/to/file.txt', +// // Add more file IDs and corresponding file paths as needed +// }; + +// // Create a server to listen for incoming requests +// const server = net.createServer((socket) => { +// console.log('Peer connected'); + +// // Handle data (file ID) received from the requester peer +// socket.on('data', (data) => { +// const fileId = data.toString(); +// console.log('Received request for file ID:', fileId); + +// // Look up the file path based on the file ID +// const filePath = filesMap[fileId]; + +// if (filePath) { +// // Read the file and send its contents back to the requester +// fs.readFile(filePath, (err, fileData) => { +// if (err) { +// console.error('Error reading file:', err); +// socket.end(); +// return; +// } + +// // Send the file data to the requester +// socket.write(fileData); + +// // Close the connection after sending the file +// socket.end(); +// }); +// } else { +// console.log('File ID not found'); +// socket.end(); +// } +// }); +// }); + +// // Start listening for incoming connections +// server.listen(listenPort, () => { +// console.log('Peer server listening on port', listenPort); +// }); + +// // Handle server errors +// server.on('error', (err) => { +// console.error('Server error:', err); +// }); + + +// Receiving Peer + +const net = require('net'); +const fs = require('fs'); + +// Port on which this peer will listen for requests +const listenPort = 12345; + +// Mapping of file IDs to file paths +const filesMap = { + 'abcd.txt': './abcd.txt', + // Add more file IDs and corresponding file paths as needed +}; + +// Create a TCP server to listen for incoming requests from other peers +const server = net.createServer((socket) => { + console.log('Receiving peer server connected'); + + // Handle data (file ID) received from the requester peer + socket.on('data', (data) => { + const fileId = data.toString(); + console.log('Received request for file ID:', fileId); + + // Look up the file path based on the file ID + const filePath = filesMap[fileId]; + + if (filePath) { + // Read the file and send its contents back to the requester + fs.readFile(filePath, (err, fileData) => { + if (err) { + console.error('Error reading file:', err); + socket.end(); + return; + } + + // Send the file data to the requester + socket.write(fileData); + + // Close the connection after sending the file + socket.end(); + }); + } else { + console.log('File ID not found'); + socket.end(); + } + }); + + // Handle connection errors + socket.on('error', (err) => { + console.error('Connection error:', err); + }); +}); + +// Start the server +server.listen(listenPort, () => { + console.log('Receiving peer server listening for incoming connections'); +}); + +// Handle server errors +server.on('error', (err) => { + console.error('Server error:', err); +}); From b9b405fba873725ad5f3918cc59af264bbf38266 Mon Sep 17 00:00:00 2001 From: Aman Tahiliani Date: Sat, 20 Apr 2024 20:10:40 -0400 Subject: [PATCH 2/2] Added changes for Malicious User reporting --- backend/api/migrations/0008_userreport.py | 57 ++++++++++++ backend/api/models.py | 20 ++++- backend/api/serializers.py | 15 +++- backend/api/urls.py | 1 + backend/api/user_login.py | 2 +- backend/api/utils/get_client_ip.py | 13 +++ backend/api/views.py | 100 ++++++++++++++++++---- 7 files changed, 186 insertions(+), 22 deletions(-) create mode 100644 backend/api/migrations/0008_userreport.py diff --git a/backend/api/migrations/0008_userreport.py b/backend/api/migrations/0008_userreport.py new file mode 100644 index 0000000..d51c971 --- /dev/null +++ b/backend/api/migrations/0008_userreport.py @@ -0,0 +1,57 @@ +# Generated by Django 4.2.11 on 2024-04-20 23:10 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("api", "0007_remove_file_points_file_downvotes_file_upvotes"), + ] + + operations = [ + migrations.CreateModel( + name="UserReport", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("description", models.TextField(max_length=300)), + ( + "file", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="file_report", + to="api.file", + ), + ), + ( + "reporting_user", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="user_report_generated", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "user", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="user_report", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/backend/api/models.py b/backend/api/models.py index 95ce20c..e4208e6 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -61,10 +61,28 @@ class File(models.Model): upvotes = models.ManyToManyField(PeerUser, related_name="upvoted_file") downvotes = models.ManyToManyField(PeerUser, related_name="downvoted_file") - @property def points(self): return self.upvotes.count() - self.downvotes.count() def __str__(self): return self.filename + + +class UserReport(models.Model): + user = models.ForeignKey( + PeerUser, on_delete=models.SET_NULL, null=True, related_name="user_report" + ) + reporting_user = models.ForeignKey( + PeerUser, + on_delete=models.SET_NULL, + null=True, + related_name="user_report_generated", + ) + description = models.TextField(blank=False, null=False, max_length=300) + file = models.ForeignKey( + File, on_delete=models.CASCADE, null=True, related_name="file_report" + ) + + def __str__(self) -> str: + return f"{self.user}:{self.file}:{self.reporting_user}" diff --git a/backend/api/serializers.py b/backend/api/serializers.py index b95a237..c369484 100644 --- a/backend/api/serializers.py +++ b/backend/api/serializers.py @@ -46,4 +46,17 @@ class FileSerializer(serializers.ModelSerializer): class Meta: model = File - fields = "__all__" + fields = [ + "id", + "filename", + "points", + "original_author", + "peer_users", + "topic", + "professor", + "semester", + "course", + "created_at", + "upvotes", + "downvotes", + ] diff --git a/backend/api/urls.py b/backend/api/urls.py index 5f57f26..2ecfb97 100644 --- a/backend/api/urls.py +++ b/backend/api/urls.py @@ -65,6 +65,7 @@ urlpatterns = [ name="downvote-file", ), path("api/files//", views.FileDetailAPIView.as_view(), name="file-detail"), + path("api/report_user/", views.ReportUserView.as_view(), name="report-user"), path("api/register/", views.RegisterFile.as_view(), name="file-register"), path("api/files/filter/", views.FileFilterView.as_view(), name="file-filter-view"), ] diff --git a/backend/api/user_login.py b/backend/api/user_login.py index f5da98f..c88a84d 100644 --- a/backend/api/user_login.py +++ b/backend/api/user_login.py @@ -6,7 +6,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated -from api.utils.get_client_ip import get_client_ip +from api.utils.get_client_ip import get_client_ip, PollMiddleware from django.utils import timezone diff --git a/backend/api/utils/get_client_ip.py b/backend/api/utils/get_client_ip.py index 6d65d6a..739a1e7 100644 --- a/backend/api/utils/get_client_ip.py +++ b/backend/api/utils/get_client_ip.py @@ -1,3 +1,4 @@ +from typing import Any from django.utils import timezone @@ -16,3 +17,15 @@ def update_user_ip(request): user.ip_address = ip_address user.last_poll = timezone.now() user.save() + + +class PollMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + print("Updating user last online and IP address") + update_user_ip(request) + response = self.get_response(request) + + return response diff --git a/backend/api/views.py b/backend/api/views.py index 05c3f7d..2569605 100644 --- a/backend/api/views.py +++ b/backend/api/views.py @@ -1,4 +1,4 @@ -from api.models import Course, File, Professor, Semester, Topic, PeerUser +from api.models import Course, File, Professor, Semester, Topic, PeerUser, UserReport from api.serializers import ( CourseSerializer, FileSerializer, @@ -7,13 +7,13 @@ from api.serializers import ( TopicSerializer, UserSerializer, ) -from datetime import datetime, timedelta +from datetime import timedelta from django.contrib.auth import authenticate from django.db import transaction +from django.db.models import Count, Value, F, IntegerField from django.utils import timezone from rest_framework import generics, status from rest_framework.authentication import TokenAuthentication -from rest_framework.authtoken.models import Token from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView @@ -123,7 +123,7 @@ class UpvoteFile(APIView): file.save() return Response( {"msg": f"Upvoted {file.filename}", "file_points": file.points}, - status=status.HTTP_200_OK, + status=status.HTTP_200_OK, ) except Exception as e: print(f"Error: {str(e)}") @@ -235,15 +235,6 @@ class RegisterFile(APIView): ) -from django.utils import timezone -from datetime import timedelta -from rest_framework.views import APIView -from rest_framework.response import Response -from rest_framework import status -from .models import File, PeerUser -from .serializers import FileSerializer - - class FileFilterView(APIView): authentication_classes = [TokenAuthentication] permission_classes = [IsAuthenticated] @@ -251,6 +242,7 @@ class FileFilterView(APIView): def get(self, request, format=None): try: # Extract filters from the query parameters + update_user_ip(request) topic_id = request.query_params.get("topic") professor_id = request.query_params.get("professor") course_id = request.query_params.get("course") @@ -291,19 +283,26 @@ class FileFilterView(APIView): if semester_id: queryset = queryset.filter(semester__id=semester_id) + queryset = queryset.annotate( + upvote_count=Count("upvotes"), downvote_count=Count("downvotes") + ).order_by(F("downvote_count") - F("upvote_count")) + # Filter files based on active peers in the past hour active_peer_ids = PeerUser.objects.filter( last_poll__gte=timezone.now() - timedelta(hours=1) ).values_list("id", flat=True) queryset = queryset.filter(peer_users__in=active_peer_ids).distinct() - # Sort files based on points column in descending order - queryset = queryset.order_by("-points") - - # Serialize files serializer = FileSerializer(queryset, many=True) # Loop through each serialized file to sort its peer_users - for file_data in serializer.data: + + try: + serialized_data = serializer.data + print(serialized_data) + except Exception as e: + print(str(e)) + for file_data in serialized_data: + print(file_data) file_obj = File.objects.get(id=file_data["id"]) sorted_peer_users = sorted( file_obj.peer_users.all(), key=lambda x: x.points, reverse=True @@ -312,9 +311,72 @@ class FileFilterView(APIView): sorted_peer_users, many=True ).data - return Response(serializer.data) + return Response(serialized_data) except Exception as e: return Response( {"error": f"Something went wrong: {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) + + +class ReportUserView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [IsAuthenticated] + + def post(self, request): + data = request.data + update_user_ip(request) + try: + assert "file_id" in data + assert "user_id" in data + assert "description" in data + except AssertionError as e: + return Response( + {"error": f"Missing Parameters. {str(e)}"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + try: + file = File.objects.get(id=data["file_id"]) + malicious_user = PeerUser.objects.get(id=data["user_id"]) + reporting_user = request.user + description = data["description"] + except Exception as e: + return Response( + {"error": f"Missing/Incorrect Parameters. {str(e)}"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + existing_user_report_queryset = UserReport.objects.filter( + user=malicious_user, file=file, reporting_user=reporting_user + ) + + if len(existing_user_report_queryset): + existing_report = existing_user_report_queryset.first() + existing_report.description = description + existing_report.save() + return Response( + { + "msg": "User report already exists for this file. Updated description" + }, + status=status.HTTP_208_ALREADY_REPORTED, + ) + + if ( + file not in malicious_user.owned_files.all() + or file not in malicious_user.shared_files.all() + ): + return Response( + {"error": "User does not own or host the file reported"}, + status=status.HTTP_404_NOT_FOUND, + ) + + UserReport.objects.create( + user=malicious_user, + reporting_user=reporting_user, + file=file, + description=description, + ) + malicious_user.points -= 1 + malicious_user.save() + return Response({"msg": "Report Created!"}, status=status.HTTP_201_CREATED)