From 311b9fc03b504c609655f9d61333cba29ec9f755 Mon Sep 17 00:00:00 2001 From: Ambuj Raj Date: Sat, 11 May 2024 22:59:14 +0530 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20No=20user=20related=20info=20fro?= =?UTF-8?q?m=20user=20or=20UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- middleware/app/api/routes/download.py | 9 ++-- middleware/app/api/routes/upload.py | 40 +++++----------- middleware/app/api/services/download.py | 6 +-- middleware/app/api/services/upload.py | 30 +++++------- middleware/app/{api => utils}/auth.py | 48 +++++++++++++++---- .../app/(pages)/(protected)/history/page.tsx | 13 ++--- ui/src/app/(pages)/page.tsx | 4 -- ui/src/app/(pages)/share/[uploadId]/page.tsx | 17 +++++-- 8 files changed, 87 insertions(+), 80 deletions(-) rename middleware/app/{api => utils}/auth.py (51%) diff --git a/middleware/app/api/routes/download.py b/middleware/app/api/routes/download.py index 8465161..662beab 100644 --- a/middleware/app/api/routes/download.py +++ b/middleware/app/api/routes/download.py @@ -2,7 +2,8 @@ import api.services.download as download_service import utils.logger as logger -from fastapi import APIRouter +from fastapi import APIRouter, Depends +from utils.auth import optional_authenticate router = APIRouter() @@ -16,7 +17,9 @@ class StatusEnum(PythonEnum): @router.get("/{upload_id}") -def get_file_url_return_name_link(upload_id: str, user_id: str | None = None): +def get_file_url_return_name_link( + upload_id: str, token_data: None = Depends(optional_authenticate) +): """ Get download url from Storage. Checks for the expires at, download count < max download and updates the count in DB @@ -31,7 +34,7 @@ def get_file_url_return_name_link(upload_id: str, user_id: str | None = None): FUNCTION_NAME = "get_file_url_return_name_link()" log.info("Entering {}".format(FUNCTION_NAME)) - response = download_service.get_file_url_return_name_link(upload_id, user_id) + response = download_service.get_file_url_return_name_link(token_data, upload_id) log.info("Exiting {}".format(FUNCTION_NAME)) return response diff --git a/middleware/app/api/routes/upload.py b/middleware/app/api/routes/upload.py index a31e470..a8de862 100644 --- a/middleware/app/api/routes/upload.py +++ b/middleware/app/api/routes/upload.py @@ -3,9 +3,9 @@ import api.services.upload as upload_service import utils.logger as logger -from api.auth import authenticate from fastapi import APIRouter, Depends, Request from pydantic import BaseModel +from utils.auth import authenticate router = APIRouter() @@ -20,25 +20,16 @@ class StatusEnum(PythonEnum): class InitiateUpload(BaseModel): file_names: List[str] - creator_id: str - creator_email: str - creator_ip: str share_email_as_source: bool class FinaliseUpload(BaseModel): file_names: list receiver_email: str - sender_name: str class EditTitle(BaseModel): title: str - user_id: str - - -class DeleteUpload(BaseModel): - user_id: str @router.post("/initiate") @@ -54,8 +45,6 @@ def initiate_upload( Parameters: - file_names: list of name of the file to be uploaded - - creator_email: email of the creator - - creator_ip: ip address of the creator - File-Length: total file size of the uploaded file Returns: @@ -64,7 +53,7 @@ def initiate_upload( FUNCTION_NAME = "initiate_upload()" log.info("Entering {}".format(FUNCTION_NAME)) - response = upload_service.initiate_upload(body, request) + response = upload_service.initiate_upload(token_data, body, request) log.info("Exiting {}".format(FUNCTION_NAME)) return response @@ -82,7 +71,6 @@ def post_upload_return_link_qr( - upload_id: upload id of the upload process - file_name: name of the file uploaded - receiver_email: receiver email address - - user_id: user id of the sender Returns: - Sharable Link and QR code of frontend page @@ -90,22 +78,19 @@ def post_upload_return_link_qr( FUNCTION_NAME = "post_upload_return_link_qr()" log.info("Entering {}".format(FUNCTION_NAME)) - response = upload_service.post_upload_return_link_qr(body, upload_id) + response = upload_service.post_upload_return_link_qr(token_data, body, upload_id) log.info("Exiting {}".format(FUNCTION_NAME)) return response @router.delete("/{upload_id}") -def delete_upload_return_done( - upload_id: str, body: DeleteUpload, token_data: None = Depends(authenticate) -): +def delete_upload_return_done(upload_id: str, token_data: None = Depends(authenticate)): """ Delete the upload of the user Reads the DB to find the upload and deletes. Parameters: - - user_id: user id - upload_id: upload id to be deleted Returns: @@ -114,7 +99,7 @@ def delete_upload_return_done( FUNCTION_NAME = "delete_upload_return_done()" log.info("Entering {}".format(FUNCTION_NAME)) - response = upload_service.delete_upload_return_done(upload_id, body) + response = upload_service.delete_upload_return_done(token_data, upload_id) log.info("Exiting {}".format(FUNCTION_NAME)) return response @@ -130,7 +115,6 @@ def update_upload_title_return_done( Parameters: - title: new title - - user_id: user id - upload_id: upload id to be edited Returns: @@ -139,22 +123,22 @@ def update_upload_title_return_done( FUNCTION_NAME = "update_upload_title_return_done()" log.info("Entering {}".format(FUNCTION_NAME)) - response = upload_service.update_upload_title_return_done(body, upload_id) + response = upload_service.update_upload_title_return_done( + token_data, body, upload_id + ) log.info("Exiting {}".format(FUNCTION_NAME)) return response -@router.get("/history/{user_id}") -def get_history_return_all_shares_list( - user_id: str, token_data: None = Depends(authenticate) -): +@router.get("/history") +def get_history_return_all_shares_list(token_data: None = Depends(authenticate)): """ Get history for a given User. Reads the DB to find all the shares made by the user. Parameters: - - user_id: user id + - None Returns: - List of json of the transfer details. @@ -162,7 +146,7 @@ def get_history_return_all_shares_list( FUNCTION_NAME = "get_history_return_all_shares_list()" log.info("Entering {}".format(FUNCTION_NAME)) - response = upload_service.get_history_return_all_shares_list(user_id) + response = upload_service.get_history_return_all_shares_list(token_data) log.info("Exiting {}".format(FUNCTION_NAME)) return response diff --git a/middleware/app/api/services/download.py b/middleware/app/api/services/download.py index 967e37d..a59d2ff 100644 --- a/middleware/app/api/services/download.py +++ b/middleware/app/api/services/download.py @@ -24,7 +24,7 @@ class StatusEnum(PythonEnum): uploaded = "uploaded" -def get_file_url_return_name_link(upload_id: str, user_id: str | None = None): +def get_file_url_return_name_link(token_data, upload_id: str): FUNCTION_NAME = "get_file_url_return_name_link()" log.info("Entering {}".format(FUNCTION_NAME)) @@ -57,7 +57,7 @@ def get_file_url_return_name_link(upload_id: str, user_id: str | None = None): download_count = upload_metadata["download_count"] max_count = upload_metadata["max_download"] - if user_id == None or upload_metadata["creator_id"] != user_id: + if token_data == None or upload_metadata["creator_id"] != token_data["$id"]: if download_count >= max_count: log.warning( "BAD REQUEST for UploadID: {}\nERROR: {}".format( @@ -85,7 +85,7 @@ def get_file_url_return_name_link(upload_id: str, user_id: str | None = None): file_data[file_name]["size"] = helper.format_size(file_size) file_data[file_name]["download_url"] = file_url - if user_id == None or upload_metadata["creator_id"] != user_id: + if token_data == None or upload_metadata["creator_id"] != token_data["$id"]: keys = {"upload_id": upload_id} update_data = { "download_count": download_count + 1, diff --git a/middleware/app/api/services/upload.py b/middleware/app/api/services/upload.py index ff6b423..852e2cf 100644 --- a/middleware/app/api/services/upload.py +++ b/middleware/app/api/services/upload.py @@ -33,25 +33,16 @@ class StatusEnum(PythonEnum): class InitiateUpload(BaseModel): file_names: List[str] - creator_id: str - creator_email: str - creator_ip: str share_email_as_source: bool class FinaliseUpload(BaseModel): file_names: list receiver_email: str - sender_name: str class EditTitle(BaseModel): title: str - user_id: str - - -class DeleteUpload(BaseModel): - user_id: str # Storage @@ -73,6 +64,7 @@ class DeleteUpload(BaseModel): def initiate_upload( + token_data, body: InitiateUpload, request: Request, ): @@ -133,8 +125,8 @@ def initiate_upload( "status": StatusEnum.initiated.name, "title": "Upload with " + file_names[0], "scanned": False, - "creator_id": body.creator_id, - "creator_email": body.creator_email, + "creator_id": token_data["$id"], + "creator_email": token_data["email"], "creator_ip": client_ip, "receiver_email": "", "share_email_as_source": share_email_as_source, @@ -154,7 +146,7 @@ def initiate_upload( return result -def post_upload_return_link_qr(body: FinaliseUpload, upload_id: str): +def post_upload_return_link_qr(token_data, body: FinaliseUpload, upload_id: str): FUNCTION_NAME = "post_upload_return_link_qr()" log.info("Entering {}".format(FUNCTION_NAME)) @@ -244,7 +236,7 @@ def post_upload_return_link_qr(body: FinaliseUpload, upload_id: str): # Send the share link to email, if given if body.receiver_email: - name = body.sender_name + name = token_data["name"] params = { "from": "ByteShare ", "to": [body.receiver_email], @@ -291,12 +283,12 @@ def post_upload_return_link_qr(body: FinaliseUpload, upload_id: str): } -def delete_upload_return_done(upload_id: str, body: DeleteUpload): +def delete_upload_return_done(token_data, upload_id: str): FUNCTION_NAME = "delete_upload_return_done()" log.info("Entering {}".format(FUNCTION_NAME)) upload_metadata = dynamodb.read_item({"upload_id": upload_id}) - if upload_metadata["creator_id"] != body.user_id: + if upload_metadata["creator_id"] != token_data["$id"]: log.warning( "BAD REQUEST for UploadID: {}\nERROR: {}".format( upload_id, "User is not the owner of the upload." @@ -313,12 +305,12 @@ def delete_upload_return_done(upload_id: str, body: DeleteUpload): return {"status": "Done"} -def update_upload_title_return_done(body: EditTitle, upload_id: str): +def update_upload_title_return_done(token_data, body: EditTitle, upload_id: str): FUNCTION_NAME = "update_upload_title_return_done()" log.info("Entering {}".format(FUNCTION_NAME)) upload_metadata = dynamodb.read_item({"upload_id": upload_id}) - if upload_metadata["creator_id"] != body.user_id: + if upload_metadata["creator_id"] != token_data["$id"]: log.warning( "BAD REQUEST for UploadID: {}\nERROR: {}".format( upload_id, "User is not the owner of the upload." @@ -348,7 +340,7 @@ def update_upload_title_return_done(body: EditTitle, upload_id: str): return {"status": "Done"} -def get_history_return_all_shares_list(user_id: str): +def get_history_return_all_shares_list(token_data): FUNCTION_NAME = "get_history_return_all_shares_list()" log.info("Entering {}".format(FUNCTION_NAME)) @@ -359,7 +351,7 @@ def get_history_return_all_shares_list(user_id: str): # if(user==None): # raise HTTPException(status_code=400, detail="User does not exist") - upload_metadatas = dynamodb.read_items("creator_id", user_id) + upload_metadatas = dynamodb.read_items("creator_id", token_data["$id"]) for upload_metadata in upload_metadatas: upload = { "upload_id": upload_metadata["upload_id"], diff --git a/middleware/app/api/auth.py b/middleware/app/utils/auth.py similarity index 51% rename from middleware/app/api/auth.py rename to middleware/app/utils/auth.py index 68caae0..897b16b 100644 --- a/middleware/app/api/auth.py +++ b/middleware/app/utils/auth.py @@ -25,15 +25,14 @@ async def authenticate(authorization: Optional[str] = Header(None)): headers={"WWW-Authenticate": "Bearer"}, ) - token_type, token = authorization.split() - if token_type.lower() != "bearer": - raise HTTPException( - status_code=401, - detail="Invalid token type", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: + token_type, token = authorization.split() + if token_type.lower() != "bearer": + raise HTTPException( + status_code=401, + detail="Invalid token type", + headers={"WWW-Authenticate": "Bearer"}, + ) client = Client() ( client.set_endpoint(os.getenv("APPWRITE_URL")) @@ -43,8 +42,10 @@ async def authenticate(authorization: Optional[str] = Header(None)): account = Account(client) - account.get() log.info("Authenticated.") + log.info("Exiting {}".format(FUNCTION_NAME)) + return account.get() + except Exception as e: log.error("EXCEPTION authenticating: {}".format(str(e))) raise HTTPException( @@ -53,4 +54,31 @@ async def authenticate(authorization: Optional[str] = Header(None)): headers={"WWW-Authenticate": "Bearer"}, ) - log.info("Exiting {}".format(FUNCTION_NAME)) + +async def optional_authenticate(authorization: Optional[str] = Header(None)): + FUNCTION_NAME = "optional_authenticate()" + log.info("Entering {}".format(FUNCTION_NAME)) + + if authorization is None: + return None + + try: + token_type, token = authorization.split() + if token_type.lower() != "bearer": + return None + client = Client() + ( + client.set_endpoint(os.getenv("APPWRITE_URL")) + .set_project(os.getenv("APPWRITE_PROJECT_ID")) + .set_jwt(token) + ) + + account = Account(client) + + log.info("Authenticated.") + log.info("Exiting {}".format(FUNCTION_NAME)) + return account.get() + + except Exception as e: + log.error("EXCEPTION authenticating: {}".format(str(e))) + return None diff --git a/ui/src/app/(pages)/(protected)/history/page.tsx b/ui/src/app/(pages)/(protected)/history/page.tsx index 5f010e9..8b1e12f 100644 --- a/ui/src/app/(pages)/(protected)/history/page.tsx +++ b/ui/src/app/(pages)/(protected)/history/page.tsx @@ -88,10 +88,9 @@ function HistoryPage() { const apiBaseURL = process.env.NEXT_PUBLIC_API_BASE_URL const apiKey = process.env.NEXT_PUBLIC_API_KEY const jwtToken = await appwriteService.getJWTToken() - const userID = user['$id'] const historyResponse = await fetch( - apiBaseURL + '/upload/history' + '/' + userID, + apiBaseURL + '/upload/history', { method: 'GET', headers: { @@ -162,14 +161,16 @@ function HistoryPage() { const downloadInprogressToastID = toast.loading('Download in progress...', { duration: 9999999 }) const apiBaseURL = process.env.NEXT_PUBLIC_API_BASE_URL const apiKey = process.env.NEXT_PUBLIC_API_KEY + const jwtToken = await appwriteService.getJWTToken() const downloadResponse = await fetch( - apiBaseURL + '/download' + '/' + uploadId + '?user_id=' + user['$id'], + apiBaseURL + '/download' + '/' + uploadId, { method: 'GET', headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, + Authorization: 'Bearer ' + jwtToken.jwt, }, }, ) @@ -231,14 +232,11 @@ function HistoryPage() { const apiKey = process.env.NEXT_PUBLIC_API_KEY const jwtToken = await appwriteService.getJWTToken() - const deleteJSON = { - user_id: user['$id'], - } + const deleteResponse = await fetch( apiBaseURL + '/upload' + '/' + uploadId, { method: 'DELETE', - body: JSON.stringify(deleteJSON), headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, @@ -276,7 +274,6 @@ function HistoryPage() { const jwtToken = await appwriteService.getJWTToken() const editJSON = { - user_id: user['$id'], title: newTitle, } const editResponse = await fetch( diff --git a/ui/src/app/(pages)/page.tsx b/ui/src/app/(pages)/page.tsx index a39b2da..2322be0 100644 --- a/ui/src/app/(pages)/page.tsx +++ b/ui/src/app/(pages)/page.tsx @@ -340,9 +340,6 @@ export default function Home() { const initiateUploadJSON = { file_names: fileNames, - creator_id: user['$id'], - creator_email: userEmail, - creator_ip: '127.0.0.1', share_email_as_source: true, } @@ -374,7 +371,6 @@ export default function Home() { const fileJSON = { file_names: fileNames, receiver_email: receiverEmail, - sender_name: userName, } const postUploadResponse = await fetch( apiBaseURL + '/upload/finalise' + '/' + uploadID, diff --git a/ui/src/app/(pages)/share/[uploadId]/page.tsx b/ui/src/app/(pages)/share/[uploadId]/page.tsx index 96b2418..246e8b4 100644 --- a/ui/src/app/(pages)/share/[uploadId]/page.tsx +++ b/ui/src/app/(pages)/share/[uploadId]/page.tsx @@ -71,15 +71,22 @@ function SharePage({ params }: Params) { const apiKey = process.env.NEXT_PUBLIC_API_KEY const jwtToken = await appwriteService.getJWTToken() + const header = jwtToken + ? { + 'Content-Type': 'application/json', + 'x-api-key': apiKey, + Authorization: 'Bearer ' + jwtToken.jwt, + } + : { + 'Content-Type': 'application/json', + 'x-api-key': apiKey, + } + const downloadResponse = await fetch( apiBaseURL + '/download' + '/' + params.uploadId, { method: 'GET', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': apiKey, - Authorization: 'Bearer ' + jwtToken.jwt, - }, + headers: header, }, ) if (!downloadResponse.ok) {