]> git.mxchange.org Git - fba.git/blob - api.py
Handle IDNs in API
[fba.git] / api.py
1 import uvicorn
2 from fastapi import FastAPI, Request, HTTPException, responses
3 import sqlite3
4 from hashlib import sha256
5 from fastapi.templating import Jinja2Templates
6 from requests import get
7 from json import loads
8
9 with open("config.json") as f:
10     config = loads(f.read())
11     base_url = config["base_url"]
12     port = config["port"]
13 app = FastAPI(docs_url=base_url+"/docs", redoc_url=base_url+"/redoc")
14 templates = Jinja2Templates(directory=".")
15
16 def get_hash(domain: str) -> str:
17     return sha256(domain.encode("utf-8")).hexdigest()
18
19 @app.get(base_url+"/info")
20 def info():
21     conn = sqlite3.connect("blocks.db")
22     c = conn.cursor()
23     c.execute("select (select count(domain) from instances), (select count(domain) from instances where software in ('pleroma', 'mastodon')), (select count(blocker) from blocks)")
24     known, indexed, blocks = c.fetchone()
25     c.close()
26     return {
27         "known_instances": known,
28         "indexed_instances": indexed,
29         "blocks_recorded": blocks,
30         "source_code": "https://git.kiwifarms.net/mint/fedi-block-api",
31     }
32
33 @app.get(base_url+"/api")
34 def blocked(domain: str = None, reason: str = None):
35     if domain == None and reason == None:
36         raise HTTPException(status_code=400, detail="No filter specified")
37     conn = sqlite3.connect("blocks.db")
38     c = conn.cursor()
39     if domain != None:
40         wildchar = "*." + ".".join(domain.split(".")[-domain.count("."):])
41         c.execute("select blocker, block_level, reason from blocks where blocked = ? or blocked = ? or blocked = ? or blocked = ? or blocked = ? or blocked = ?",
42                   (domain, "*." + domain, wildchar, get_hash(domain), domain.encode('idna'), "*." + domain.encode('idna')))
43     else:
44         c.execute("select * from blocks where reason like ? and reason != ''", ("%"+reason+"%",))
45     blocks = c.fetchall()
46     conn.close()
47
48     result = {}
49     reasons = {}
50     if domain != None:
51         for domain, block_level, reason in blocks:
52             if block_level in result:
53                 result[block_level].append(domain)
54             else:
55                 result[block_level] = [domain]
56                 
57             if reason != "":
58                 if block_level in reasons:
59                     reasons[block_level][domain] = reason
60                 else:
61                     reasons[block_level] = {domain: reason}
62         return {"blocks": result, "reasons": reasons}
63
64     for blocker, blocked, reason, block_level in blocks:
65         if block_level in result:
66             result[block_level].append({"blocker": blocker, "blocked": blocked, "reason": reason})
67         else:
68             result[block_level] = [{"blocker": blocker, "blocked": blocked, "reason": reason}]
69     return {"blocks": result}
70
71 @app.get(base_url+"/")
72 def index(request: Request, domain: str = None, reason: str = None):
73     if domain == "" or reason == "":
74         return responses.RedirectResponse("/")
75     info = None
76     blocks = None
77     if domain == None and reason == None:
78         info = get(f"http://127.0.0.1:{port}{base_url}/info")
79         if not info.ok:
80             raise HTTPException(status_code=info.status_code, detail=info.text)
81         info = info.json()
82     elif domain != None:
83         blocks = get(f"http://127.0.0.1:{port}{base_url}/api?domain={domain}")
84     elif reason != None:
85         blocks = get(f"http://127.0.0.1:{port}{base_url}/api?reason={reason}")
86     if blocks != None:
87         if not blocks.ok:
88             raise HTTPException(status_code=blocks.status_code, detail=blocks.text)
89         blocks = blocks.json()
90     return templates.TemplateResponse("index.html", {"request": request, "domain": domain, "blocks": blocks, "reason": reason, "info": info})
91
92 if __name__ == "__main__":
93     uvicorn.run("api:app", host="127.0.0.1", port=port, log_level="info")