From c8a983b78ed6e9cf5e144ffb2e837448d81a49b6 Mon Sep 17 00:00:00 2001 From: Richie <2837357W@student.gla.ac.uk> Date: Thu, 26 Oct 2023 16:20:15 +0800 Subject: [PATCH 1/4] integrate totalvirus api --- safeshare/safeshare_vdb/__init__.py | 0 safeshare/safeshare_vdb/client.py | 6 +-- safeshare/safeshare_vdb/env | 1 + safeshare/safeshare_vdb/server.py | 70 +++++++++++++++++++++-------- 4 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 safeshare/safeshare_vdb/__init__.py create mode 100644 safeshare/safeshare_vdb/env diff --git a/safeshare/safeshare_vdb/__init__.py b/safeshare/safeshare_vdb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/safeshare/safeshare_vdb/client.py b/safeshare/safeshare_vdb/client.py index 0c3b5f5..8e42fee 100644 --- a/safeshare/safeshare_vdb/client.py +++ b/safeshare/safeshare_vdb/client.py @@ -8,11 +8,11 @@ class Client: self.stub = pb2_grpc.Dynamo_DBStub(self.channel) def CheckFile(self, sha_256_id: str): - response = self.stub.CheckFile(pb2.Request(file_hash=sha_256_id)) + response = self.stub.CheckHash(pb2.Request(file_hash=sha_256_id)) print(response) def UpdateFile(self, sha_256_id: str): - response = self.stub.UpdateFile(pb2.Request(file_hash=sha_256_id)) + response = self.stub.UpdateHash(pb2.Request(file_hash=sha_256_id)) print(response) @@ -20,4 +20,4 @@ if __name__ == "__main__": client = Client() id = "15e4313dddb45875ed67d1ab25f1f5b76f0b3a23e4fa9308c521e3fb30068028" client.CheckFile(id) - client.UpdateFile(id) + # client.UpdateFile(id) diff --git a/safeshare/safeshare_vdb/env b/safeshare/safeshare_vdb/env new file mode 100644 index 0000000..c65e6b3 --- /dev/null +++ b/safeshare/safeshare_vdb/env @@ -0,0 +1 @@ +API_TOKEN= \ No newline at end of file diff --git a/safeshare/safeshare_vdb/server.py b/safeshare/safeshare_vdb/server.py index e8a875a..bee491e 100644 --- a/safeshare/safeshare_vdb/server.py +++ b/safeshare/safeshare_vdb/server.py @@ -4,6 +4,9 @@ import re import grpc import dynamo_pb2 as pb2 import dynamo_pb2_grpc as pb2_grpc +import environ +import os +import requests import boto3 as boto # 1.28.68 @@ -13,23 +16,68 @@ sha256_table = dynamodb.Table('safeshare_sha256') sha1_table = dynamodb.Table('safeshare_sha1') md5_table = dynamodb.Table('safeshare_md5') +# TotalVirus API key +environ.Env.read_env('./.env') +api = environ.Env().str('API_TOKEN') + +headers = { + "accept": "application/json", + "x-apikey": api +} + # hash hex_pattern = re.compile("^[a-fA-F0-9]+$") +def upload(hash_val): + if not hex_pattern.match(hash_val): + return False + else: + length = len(hash_val) + if length == 64: + sha256_table.put_item(Item={'sha256': hash_val}) + elif length == 40: + sha1_table.put_item(Item={'sha1': hash_val}) + elif length == 32: + md5_table.put_item(Item={'md5': hash_val}) + else: + return False + + return True + + +def scan(hash_val): + url = "https://www.virustotal.com/api/v3/files/" + hash_val + response = requests.get(url, headers=headers) + if response.status_code == 200: + data = response.json()["data"] + return data["attributes"]["last_analysis_stats"]["malicious"] > 0 + else: + return False + + def check_sha256(sha256): response = sha256_table.get_item(Key={'sha256': sha256}) - return 'Item' in response + if "Item" not in response: + return upload(sha256) if scan(sha256) else False + else: + return True def check_sha1(sha1): response = sha1_table.get_item(Key={'sha1': sha1}) - return 'Item' in response + if "Item" not in response: + return upload(sha1) if scan(sha1) else False + else: + return True def check_md5(md5): response = md5_table.get_item(Key={'md5': md5}) - return 'Item' in response + if "Item" not in response: + return upload(md5) if scan(md5) else False + else: + return True class Dynamo(pb2_grpc.Dynamo_DBServicer): @@ -48,21 +96,7 @@ class Dynamo(pb2_grpc.Dynamo_DBServicer): return pb2.Response(is_exist=False) def UpdateHash(self, request, context): - if not hex_pattern.match(request.file_hash): - return pb2.Response(is_exist=False) - else: - length = len(request.file_hash) - if length == 64: - sha256_table.put_item(Item={'sha256': request.file_hash}) - return pb2.Response(is_exist=True) - elif length == 40: - sha1_table.put_item(Item={'sha1': request.file_hash}) - return pb2.Response(is_exist=True) - elif length == 32: - md5_table.put_item(Item={'md5': request.file_hash}) - return pb2.Response(is_exist=True) - else: - return pb2.Response(is_exist=False) + return pb2.Response(is_exist=upload(request.file_hash)) def serve(): From eddb7a7bc908f5f93267c5b1f717b8fa12a76892 Mon Sep 17 00:00:00 2001 From: Devoalda Date: Thu, 26 Oct 2023 16:28:10 +0800 Subject: [PATCH 2/4] feature(File Virus Check): Backend virus check update --- .../safeshare-frontend/src/pages/shareFile.js | 5 ++-- safeshare/safeshare_app/views/file.py | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/safeshare/safeshare-frontend/src/pages/shareFile.js b/safeshare/safeshare-frontend/src/pages/shareFile.js index a18f5d1..2cc6118 100644 --- a/safeshare/safeshare-frontend/src/pages/shareFile.js +++ b/safeshare/safeshare-frontend/src/pages/shareFile.js @@ -28,7 +28,10 @@ function ShareFile() { // If data is an array, take the first item if (Array.isArray(data)) { const passcode = data[0].key; + const baseUrl = 'http://localhost:8000/api/files/'; + setPasscode(passcode); + setShareableLink(baseUrl + passcode); // Copy the passcode to the clipboard navigator.clipboard.writeText(passcode).then(() => { // Show a notification @@ -40,8 +43,6 @@ function ShareFile() { // Handle errors here console.error('File upload failed', error); }); - const baseUrl = 'http://localhost:3000/download/'; - setShareableLink(baseUrl); } }; diff --git a/safeshare/safeshare_app/views/file.py b/safeshare/safeshare_app/views/file.py index 8530e11..0873cfa 100644 --- a/safeshare/safeshare_app/views/file.py +++ b/safeshare/safeshare_app/views/file.py @@ -1,7 +1,9 @@ import threading import uuid import os +import hashlib +from safeshare.safeshare_vdb.client import Client from django.core.cache import cache from rest_framework.decorators import api_view from rest_framework.response import Response @@ -43,11 +45,32 @@ def manage_items(request): # Define the path to save the file locally save_path = os.path.join(settings.MEDIA_ROOT, filename) + # Hash the file + hasher = hashlib.sha256() + # Save the file locally with open(save_path, 'wb') as destination: for chunk in file.chunks(): + hasher.update(chunk) destination.write(chunk) + # Get the hash signature + hash_signature = hasher.hexdigest() + print(f"Hash signature: {hash_signature}") + + # Call RPC For virus scan + client = Client() + result = client.CheckFile(hash_signature) + + # If infected, delete the file and return an error + if result: + response = { + 'msg': f"File {filename} is infected with a virus" + } + os.remove(save_path) + responses.append(response) + return Response(responses, status=400) + # Store the file path in the cache with the provided TTL cache.set(key, { From 75d7f23e2c7b7d001a04a96e4c92ca1d742fdc05 Mon Sep 17 00:00:00 2001 From: Richie <2837357W@student.gla.ac.uk> Date: Thu, 26 Oct 2023 16:30:27 +0800 Subject: [PATCH 3/4] change return to t/f --- safeshare/safeshare_vdb/client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/safeshare/safeshare_vdb/client.py b/safeshare/safeshare_vdb/client.py index 8e42fee..86735f8 100644 --- a/safeshare/safeshare_vdb/client.py +++ b/safeshare/safeshare_vdb/client.py @@ -9,15 +9,15 @@ class Client: def CheckFile(self, sha_256_id: str): response = self.stub.CheckHash(pb2.Request(file_hash=sha_256_id)) - print(response) + return response.is_exist def UpdateFile(self, sha_256_id: str): response = self.stub.UpdateHash(pb2.Request(file_hash=sha_256_id)) - print(response) + return response.is_exist if __name__ == "__main__": client = Client() id = "15e4313dddb45875ed67d1ab25f1f5b76f0b3a23e4fa9308c521e3fb30068028" - client.CheckFile(id) + print(client.CheckFile(id)) # client.UpdateFile(id) From c55e3df669817bedf93d41bd1c9675523386171a Mon Sep 17 00:00:00 2001 From: xrando <2837341L@student.gla.ac.uk> Date: Thu, 26 Oct 2023 16:41:43 +0800 Subject: [PATCH 4/4] added text input to take in ttl added text input to take in ttl --- .../safeshare-frontend/src/pages/shareFile.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/safeshare/safeshare-frontend/src/pages/shareFile.js b/safeshare/safeshare-frontend/src/pages/shareFile.js index 2cc6118..ce68ce8 100644 --- a/safeshare/safeshare-frontend/src/pages/shareFile.js +++ b/safeshare/safeshare-frontend/src/pages/shareFile.js @@ -6,6 +6,7 @@ import { Link } from 'react-router-dom'; function ShareFile() { const [file, setFile] = useState(null); const [passcode, setPasscode] = useState(''); + const [ttl, setTtl] = useState(''); const [shareableLink, setShareableLink] = useState(''); const [notification, setNotification] = useState(''); @@ -16,7 +17,7 @@ function ShareFile() { if (file) { const formData = new FormData(); formData.append('file', file); - //formData.append('ttl', "60"); + formData.append('ttl', ttl * 24 * 60 * 60); // Send POST request to the backend API using Axios axios @@ -62,7 +63,23 @@ function ShareFile() { Back

Share a file with others!

+ + {/* TTL Input */} +
+ + setTtl(e.target.value)} + className="mt-1 p-2 w-full border rounded-md focus:ring focus:ring-opacity-50" + /> +
+ + {passcode && (