Skip to content
This repository was archived by the owner on Sep 30, 2025. It is now read-only.

Commit eaf5418

Browse files
committed
Implement reporting functionality
1 parent 0bad463 commit eaf5418

5 files changed

Lines changed: 77 additions & 14 deletions

File tree

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
JWT_SECRET_KEY=
22
ANALYTICS_API_KEY=
3+
TURNSTILE_SECRET_KEY=
34
DB_CONNECTION_STRING=
45
MASTER_USER=
56
MASTER_PASSWORD=

config/database.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88

99
db = client.smc_db
1010

11-
collection_name = db["sites_collection"]
11+
sites_collection = db["sites_collection"]
12+
reports_collection = db["reports_collection"]

main.py

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import os
1+
import os, requests, json
22
from datetime import timedelta, datetime
33
from fastapi import FastAPI, Depends, HTTPException
44
from fastapi.middleware.cors import CORSMiddleware
55
from authx import AuthX, AuthXConfig
6-
from models.site import IllegalSite
7-
from config.database import collection_name
6+
from models.site import IllegalSite, ReportedIllegalSite
7+
from config.database import sites_collection, reports_collection
88
from schema.schemas import site_entities
99
from dotenv import load_dotenv
1010
from api_analytics.fastapi import Analytics
@@ -18,7 +18,7 @@
1818
allow_methods=["*"],
1919
allow_headers=["*"],
2020
)
21-
app.add_middleware(Analytics, api_key=os.getenv("ANALYTICS_API_KEY"))
21+
# app.add_middleware(Analytics, api_key=os.getenv("ANALYTICS_API_KEY"))
2222

2323
load_dotenv()
2424

@@ -53,34 +53,87 @@ def login(username: str, password: str):
5353

5454
@app.get("/sites")
5555
async def get_sites() -> list[IllegalSite]:
56-
sites = site_entities(collection_name.find())
56+
sites = site_entities(sites_collection.find())
5757
return sites
5858

5959

6060
@app.get("/sites/{domain}")
6161
async def get_site(domain) -> list[IllegalSite]:
62-
site = site_entities(collection_name.find({"domain": domain}))
62+
site = site_entities(sites_collection.find({"domain": domain}))
6363
return site
6464

6565

6666
@app.post("/sites", dependencies=[Depends(auth.access_token_required)])
6767
async def post_site(site: IllegalSite):
68-
collection_name.insert_one(dict(site))
68+
sites_collection.insert_one(dict(site))
6969

7070

7171
@app.put("/sites/{domain}", dependencies=[Depends(auth.access_token_required)])
7272
async def put_site(domain: str, site: IllegalSite):
73-
collection_name.find_one_and_update({"domain": domain}, {"$set": dict(site)})
73+
sites_collection.find_one_and_update({"domain": domain}, {"$set": dict(site)})
7474

7575

7676
@app.delete("/sites/{domain}", dependencies=[Depends(auth.access_token_required)])
7777
async def delete_site(domain: str):
78-
collection_name.find_one_and_delete({"domain": domain})
78+
sites_collection.find_one_and_delete({"domain": domain})
7979

8080

81+
@app.get("/reports")
82+
async def get_reports() -> list[IllegalSite]:
83+
sites = site_entities(reports_collection.find())
84+
return sites
85+
86+
87+
@app.get("/reports/{domain}")
88+
async def get_report(domain) -> list[IllegalSite]:
89+
site = site_entities(reports_collection.find({"domain": domain}))
90+
return site
91+
92+
93+
@app.delete("/reports/{domain}", dependencies=[Depends(auth.access_token_required)])
94+
async def delete_report(domain: str):
95+
reports_collection.find_one_and_delete({"domain": domain})
96+
97+
98+
@app.post("/reports")
99+
async def post_report(site: ReportedIllegalSite):
100+
r = requests.post("https://challenges.cloudflare.com/turnstile/v0/siteverify", data={
101+
"secret": os.getenv("TURNSTILE_SECRET_KEY"),
102+
"response": site.token
103+
})
104+
105+
if json.loads(r.text)["success"]:
106+
site_dict = dict(site)
107+
site_dict.pop('token', None)
108+
109+
if not reports_collection.find_one({"domain": site.domain}):
110+
111+
match site_dict["reason"]:
112+
case "illegal-redistribution":
113+
hr_reason = "Illegal redistribution"
114+
case "phishing":
115+
hr_reason = "Phishing website"
116+
case "malware":
117+
hr_reason = "Contains malware"
118+
case "puw":
119+
hr_reason = "Potentially unwanted website"
120+
case "false-pos":
121+
hr_reason = "False positive"
122+
case _:
123+
raise HTTPException(400, "Invalid reason")
124+
125+
site_dict["reason"] = hr_reason
126+
reports_collection.insert_one(site_dict)
127+
else:
128+
raise HTTPException(409, "Report already exists")
129+
else:
130+
raise HTTPException(400, "Invalid captcha")
131+
81132
@app.get("/stats")
82133
async def get_stats():
83-
sites = site_entities(collection_name.find())
134+
sites = site_entities(sites_collection.find())
135+
reports = site_entities(reports_collection.find())
84136
return {
85-
"sites": len(list(sites))
137+
"sites": len(list(sites)),
138+
"reports": len(list(reports))
86139
}

models/site.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,12 @@ class IllegalSite(BaseModel):
55
domain: str
66
notes: str
77
path: str
8-
reason: str
8+
reason: str
9+
10+
11+
class ReportedIllegalSite(BaseModel):
12+
domain: str
13+
notes: str
14+
path: str
15+
reason: str
16+
token: str

schema/schemas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ def site_entity(site) -> dict:
99

1010

1111
def site_entities(sites) -> list:
12-
return (site_entity(site) for site in sites)
12+
return (site_entity(site) for site in sites)

0 commit comments

Comments
 (0)