Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resourse DB+ Upload check validations+ #42

Merged
merged 6 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/regps/app/api/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def check_login(self, aid: str):

def login(self, said: str, vlei: str):
verifier_response = self.verifier_adapter.verify_vlei_request(said, vlei)
if verifier_response.status_code != 200:
if verifier_response.status_code != 202:
raise VerifierServiceException(
verifier_response.json(), verifier_response.status_code
)
Expand Down
33 changes: 33 additions & 0 deletions src/regps/app/api/utils/reports_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from collections import defaultdict


class ReportsDB:
def __init__(self):
self.aid_reports = defaultdict(list)
self.lei_reports = defaultdict(list)
self.aid_to_lei_mapping = dict()
self.lei_digests = defaultdict(set)

def register_aid(self, aid, lei):
self.aid_to_lei_mapping[aid] = lei

def add_report(self, aid, dig, report):
lei = self.aid_to_lei_mapping[aid] or "-"
self.aid_reports[aid].append(report)
self.lei_reports[lei].append(report)
self.lei_digests[lei].add(dig)

def drop_status(self, aid):
self.aid_reports[aid] = []
return True

def get_reports_for_aid(self, aid):
return self.aid_reports[aid]

def get_reports_for_lei(self, aid):
lei = self.aid_to_lei_mapping[aid] or "-"
return self.lei_reports[lei]

def authorized_to_check_status(self, aid, dig):
lei = self.aid_to_lei_mapping[aid] or "-"
return dig in self.lei_digests[lei]
89 changes: 80 additions & 9 deletions src/regps/app/fastapi_app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import os
from collections import defaultdict


from regps.app.api.signed_headers_verifier import logger, VerifySignedHeaders
from fastapi import (
FastAPI,
Expand All @@ -23,6 +20,7 @@
VerifierServiceException,
)
from regps.app.api.controllers import APIController
from regps.app.api.utils.reports_db import ReportsDB
from regps.app.api.utils.swagger_examples import (
check_login_examples,
upload_examples,
Expand All @@ -37,8 +35,7 @@

api_controller = APIController()
verify_signed_headers = VerifySignedHeaders(api_controller)
reports = defaultdict(list)

reports_db = ReportsDB()

@app.get("/ping")
async def ping():
Expand All @@ -56,7 +53,10 @@ async def login(response: Response, data: LoginRequest):
try:
logger.info(f"Login: sending login cred {str(data)[:50]}...")
resp = api_controller.login(data.said, data.vlei)
return JSONResponse(status_code=200, content=resp)
lei = resp.get("lei")
aid = resp.get("aid")
reports_db.register_aid(aid, lei)
return JSONResponse(status_code=202, content=resp)
except VerifierServiceException as e:
logger.error(f"Login: Exception: {e}")
response.status_code = e.status_code
Expand Down Expand Up @@ -176,7 +176,7 @@ async def upload_route(
logger.info(
f"Upload: completed upload for {aid} {dig} with code {resp.status_code}"
)
reports[aid].append(resp.json())
reports_db.add_report(aid, dig, resp.json())
return JSONResponse(status_code=200, content=resp.json())
except HTTPException as e:
logger.error(f"Upload: Exception: {e}")
Expand Down Expand Up @@ -249,12 +249,18 @@ async def check_upload_route(
"""
try:
verify_signed_headers.process_request(request, aid)
if not reports_db.authorized_to_check_status(aid, dig):
raise HTTPException(status_code=401, detail=f"AID {aid} is not authorized to check status for digest {dig}")
resp = api_controller.check_upload(aid, dig)
return JSONResponse(status_code=200, content=resp)
except VerifierServiceException as e:
logger.error(f"CheckUpload: Exception: {e}")
response.status_code = e.status_code
return JSONResponse(content=e.detail, status_code=e.status_code)
except HTTPException as e:
logger.error(f"CheckUpload: Exception: {e}")
response.status_code = e.status_code
return JSONResponse(content=e.detail, status_code=e.status_code)
except Exception as e:
logger.error(f"CheckUpload: Exception: {e}")
raise HTTPException(status_code=500, detail=str(e))
Expand Down Expand Up @@ -312,7 +318,70 @@ async def status_route(
"""
try:
verify_signed_headers.process_request(request, aid)
resp = reports.get(aid, [])
resp = reports_db.get_reports_for_aid(aid)
return JSONResponse(status_code=202, content=resp)
except HTTPException as e:
logger.error(f"Status: Exception: {e}")
response.status_code = e.status_code
return JSONResponse(content=e.detail, status_code=e.status_code)
except Exception as e:
logger.error(f"Status: Exception: {e}")
raise HTTPException(status_code=500, detail=str(e))


@app.get("/report/status/lei/{aid}")
async def status_for_lei_route(
request: Request,
response: Response,
aid: str = Path(
...,
description="AID",
openapi_examples={
"default": {
"summary": "Default AID. Must have logged into the verifier with a role credential specifying the LEI.",
"value": check_upload_examples["request"]["aid"],
}
},
),
signature: str = Header(
openapi_examples={
"default": {
"summary": "Default signature for signed headers.",
"value": upload_examples["request"]["headers"]["signature"],
}
}
),
signature_input: str = Header(
openapi_examples={
"default": {
"summary": "Default signature_input for signed headers.",
"value": upload_examples["request"]["headers"]["signature_input"],
}
}
),
signify_resource: str = Header(
openapi_examples={
"default": {
"summary": "Default signify_resource for signed headers.",
"value": upload_examples["request"]["headers"]["signify_resource"],
}
}
),
signify_timestamp: str = Header(
openapi_examples={
"default": {
"summary": "Default signify_timestamp for signed headers.",
"value": upload_examples["request"]["headers"]["signify_timestamp"],
}
}
),
):
"""
Check upload status by aid.
"""
try:
verify_signed_headers.process_request(request, aid)
resp = reports_db.get_reports_for_lei(aid)
return JSONResponse(status_code=202, content=resp)
except VerifierServiceException as e:
logger.error(f"Status: Exception: {e}")
Expand All @@ -326,6 +395,7 @@ async def status_route(
# TODO: Remove this endpoint when we will have DB. IT's only for tests
@app.post("/status/{aid}/drop")
def clear_status_route(
request: Request,
aid: str = Path(
...,
description="AID",
Expand All @@ -340,7 +410,8 @@ def clear_status_route(
"""
Drop upload status for specified AID. For the test purposes
"""
reports[aid] = []
verify_signed_headers.process_request(request, aid)
reports_db.drop_status(aid)
resp = {"status": "success", "aid": aid}
return JSONResponse(status_code=202, content=resp)

Expand Down
65 changes: 65 additions & 0 deletions tests/unit/test_reports_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from regps.app.api.utils.reports_db import ReportsDB


def test_check_report_status_authorization():
aid = "jnhh8f7h79nufb97hbw3fieBHJBgg7uhn"
lei = "j9h7ufehhcWBUTDVWYH98h9bfyaebgGBFfsa3wFf"
report_1 = "report 1"
dig_1 = "sha256_moiuhLFBf9afnHJDfaffg4ehgh"
report_2 = "report 2"
dig_2 = "sha256_fer4grniuojnfaNHBBcaaUh89h"
reports_db = ReportsDB()
reports_db.register_aid(aid, lei)
reports_db.add_report(aid, dig_1, report_1)
reports_db.add_report(aid, dig_2, report_2)
assert reports_db.authorized_to_check_status(aid, dig_1)
assert reports_db.authorized_to_check_status(aid, dig_2)
assert len(reports_db.get_reports_for_aid(aid)) == 2
assert len(reports_db.get_reports_for_lei(aid)) == 2


def test_check_report_status_authorization_2_aids_from_the_same_lei():
aid_1 = "jnhh8f7h79nufb97hbw3fieBHJBgg7uhn"
aid_2 = "UNBOUb8dadh98hnansudHD0jndbuh8hnd"
lei = "j9h7ufehhcWBUTDVWYH98h9bfyaebgGBFfsa3wFf"
report_1 = "report 1"
dig_1 = "sha256_moiuhLFBf9afnHJDfaffg4ehgh"
report_2 = "report 2"
dig_2 = "sha256_fer4grniuojnfaNHBBcaaUh89h"
reports_db = ReportsDB()
reports_db.register_aid(aid_1, lei)
reports_db.register_aid(aid_2, lei)
reports_db.add_report(aid_1, dig_1, report_1)
reports_db.add_report(aid_2, dig_2, report_2)
assert reports_db.authorized_to_check_status(aid_1, dig_1)
assert reports_db.authorized_to_check_status(aid_1, dig_2)
assert reports_db.authorized_to_check_status(aid_2, dig_1)
assert reports_db.authorized_to_check_status(aid_2, dig_2)
assert len(reports_db.get_reports_for_aid(aid_1)) == 1
assert len(reports_db.get_reports_for_aid(aid_2)) == 1
assert len(reports_db.get_reports_for_lei(aid_1)) == 2
assert len(reports_db.get_reports_for_lei(aid_2)) == 2


def test_check_report_status_authorization_2_aids_from_different_lei():
aid_1 = "jnhh8f7h79nufb97hbw3fieBHJBgg7uhn"
aid_2 = "UNBOUb8dadh98hnansudHD0jndbuh8hnd"
lei_1 = "j9h7ufehhcWBUTDVWYH98h9bfyaebgGBFfsa3wFf"
lei_2 = "mOI8hbsah80hihSHFIHh8h3r8hf8h08hfaiffha0"
report_1 = "report 1"
dig_1 = "sha256_moiuhLFBf9afnHJDfaffg4ehgh"
report_2 = "report 2"
dig_2 = "sha256_fer4grniuojnfaNHBBcaaUh89h"
reports_db = ReportsDB()
reports_db.register_aid(aid_1, lei_1)
reports_db.register_aid(aid_2, lei_2)
reports_db.add_report(aid_1, dig_1, report_1)
reports_db.add_report(aid_2, dig_2, report_2)
assert reports_db.authorized_to_check_status(aid_1, dig_1)
assert not reports_db.authorized_to_check_status(aid_1, dig_2)
assert not reports_db.authorized_to_check_status(aid_2, dig_1)
assert reports_db.authorized_to_check_status(aid_2, dig_2)
assert len(reports_db.get_reports_for_aid(aid_1)) == 1
assert len(reports_db.get_reports_for_aid(aid_2)) == 1
assert len(reports_db.get_reports_for_lei(aid_1)) == 1
assert len(reports_db.get_reports_for_lei(aid_2)) == 1
Loading