Major frontend & API rehaul

This commit is contained in:
Mint 2022-11-30 02:36:35 +03:00
parent 614aef2762
commit 6dd4da5cfb
2 changed files with 148 additions and 64 deletions

93
api.py
View file

@ -6,6 +6,7 @@ from fastapi.templating import Jinja2Templates
from requests import get from requests import get
from json import loads from json import loads
from re import sub from re import sub
from datetime import datetime
with open("config.json") as f: with open("config.json") as f:
config = loads(f.read()) config = loads(f.read())
@ -30,9 +31,33 @@ def info():
"blocks_recorded": blocks "blocks_recorded": blocks
} }
@app.get(base_url+"/top")
def top(blocked: int = None, blockers: int = None):
conn = sqlite3.connect("blocks.db")
c = conn.cursor()
if blocked == None and blockers == None:
raise HTTPException(status_code=400, detail="No filter specified")
elif blocked != None:
if blocked > 500:
raise HTTPException(status_code=400, detail="Too many results")
c.execute("select blocked, count(blocked) from blocks where block_level = 'reject' group by blocked order by count(blocked) desc limit ?", (blocked,))
elif blockers != None:
if blockers > 500:
raise HTTPException(status_code=400, detail="Too many results")
c.execute("select blocker, count(blocker) from blocks where block_level = 'reject' group by blocker order by count(blocker) desc limit ?", (blockers,))
scores = c.fetchall()
c.close()
scoreboard = []
print(scores)
for domain, highscore in scores:
scoreboard.append({"domain": domain, "highscore": highscore})
return scoreboard
@app.get(base_url+"/api") @app.get(base_url+"/api")
def blocked(domain: str = None, reason: str = None): def blocked(domain: str = None, reason: str = None, reverse: str = None):
if domain == None and reason == None: if domain == None and reason == None and reverse == None:
raise HTTPException(status_code=400, detail="No filter specified") raise HTTPException(status_code=400, detail="No filter specified")
if reason != None: if reason != None:
reason = sub("(%|_)", "", reason) reason = sub("(%|_)", "", reason)
@ -43,45 +68,46 @@ def blocked(domain: str = None, reason: str = None):
if domain != None: if domain != None:
wildchar = "*." + ".".join(domain.split(".")[-domain.count("."):]) wildchar = "*." + ".".join(domain.split(".")[-domain.count("."):])
punycode = domain.encode('idna').decode('utf-8') punycode = domain.encode('idna').decode('utf-8')
c.execute("select blocker, blocked, block_level, reason from blocks where blocked = ? or blocked = ? or blocked = ? or blocked = ? or blocked = ? or blocked = ?", c.execute("select blocker, blocked, block_level, reason, first_added, last_seen from blocks where blocked = ? or blocked = ? or blocked = ? or blocked = ? or blocked = ? or blocked = ? order by first_added asc",
(domain, "*." + domain, wildchar, get_hash(domain), punycode, "*." + punycode)) (domain, "*." + domain, wildchar, get_hash(domain), punycode, "*." + punycode))
elif reverse != None:
c.execute("select blocker, blocked, block_level, reason, first_added, last_seen from blocks where blocker = ? order by first_added asc", (reverse,))
else: else:
c.execute("select blocker, blocked, reason, block_level from blocks where reason like ? and reason != ''", ("%"+reason+"%",)) c.execute("select blocker, blocked, block_level, reason, first_added, last_seen from blocks where reason like ? and reason != '' order by first_added asc", ("%"+reason+"%",))
blocks = c.fetchall() blocks = c.fetchall()
conn.close() c.close()
result = {} result = {}
reasons = {} for blocker, blocked, block_level, reason, first_added, last_seen in blocks:
wildcards = [] entry = {"blocker": blocker, "blocked": blocked, "reason": reason, "first_added": first_added, "last_seen": last_seen}
if domain != None:
for domain, blocked, block_level, reason in blocks:
if block_level in result:
result[block_level].append(domain)
else:
result[block_level] = [domain]
if blocked == "*." + ".".join(blocked.split(".")[-blocked.count("."):]):
wildcards.append(domain)
if reason != "":
if block_level in reasons:
reasons[block_level][domain] = reason
else:
reasons[block_level] = {domain: reason}
return {"blocks": result, "reasons": reasons, "wildcards": wildcards}
for blocker, blocked, reason, block_level in blocks:
if block_level in result: if block_level in result:
result[block_level].append({"blocker": blocker, "blocked": blocked, "reason": reason}) result[block_level].append(entry)
else: else:
result[block_level] = [{"blocker": blocker, "blocked": blocked, "reason": reason}] result[block_level] = [entry]
return {"blocks": result}
return result
@app.get(base_url+"/scoreboard")
def index(request: Request, blockers: int = None, blocked: int = None):
if blockers == None and blocked == None:
raise HTTPException(status_code=400, detail="No filter specified")
elif blockers != None:
scores = get(f"http://127.0.0.1:{port}{base_url}/top?blockers={blockers}")
elif blocked != None:
scores = get(f"http://127.0.0.1:{port}{base_url}/top?blocked={blocked}")
if scores != None:
if not scores.ok:
raise HTTPException(status_code=blocks.status_code, detail=blocks.text)
scores = scores.json()
return templates.TemplateResponse("index.html", {"request": request, "scoreboard": True, "blockers": blockers, "blocked": blocked, "scores": scores})
@app.get(base_url+"/") @app.get(base_url+"/")
def index(request: Request, domain: str = None, reason: str = None): def index(request: Request, domain: str = None, reason: str = None, reverse: str = None):
if domain == "" or reason == "": if domain == "" or reason == "" or reverse == "":
return responses.RedirectResponse("/") return responses.RedirectResponse("/")
info = None info = None
blocks = None blocks = None
if domain == None and reason == None: if domain == None and reason == None and reverse == None:
info = get(f"http://127.0.0.1:{port}{base_url}/info") info = get(f"http://127.0.0.1:{port}{base_url}/info")
if not info.ok: if not info.ok:
raise HTTPException(status_code=info.status_code, detail=info.text) raise HTTPException(status_code=info.status_code, detail=info.text)
@ -90,11 +116,18 @@ def index(request: Request, domain: str = None, reason: str = None):
blocks = get(f"http://127.0.0.1:{port}{base_url}/api?domain={domain}") blocks = get(f"http://127.0.0.1:{port}{base_url}/api?domain={domain}")
elif reason != None: elif reason != None:
blocks = get(f"http://127.0.0.1:{port}{base_url}/api?reason={reason}") blocks = get(f"http://127.0.0.1:{port}{base_url}/api?reason={reason}")
elif reverse != None:
blocks = get(f"http://127.0.0.1:{port}{base_url}/api?reverse={reverse}")
if blocks != None: if blocks != None:
if not blocks.ok: if not blocks.ok:
raise HTTPException(status_code=blocks.status_code, detail=blocks.text) raise HTTPException(status_code=blocks.status_code, detail=blocks.text)
blocks = blocks.json() blocks = blocks.json()
return templates.TemplateResponse("index.html", {"request": request, "domain": domain, "blocks": blocks, "reason": reason, "info": info}) for block_level in blocks:
for block in blocks[block_level]:
block["first_added"] = datetime.utcfromtimestamp(block["first_added"]).strftime('%Y-%m-%d %H:%M')
block["last_seen"] = datetime.utcfromtimestamp(block["last_seen"]).strftime('%Y-%m-%d %H:%M')
return templates.TemplateResponse("index.html", {"request": request, "domain": domain, "blocks": blocks, "reason": reason, "reverse": reverse, "info": info})
if __name__ == "__main__": if __name__ == "__main__":
uvicorn.run("api:app", host="127.0.0.1", port=port, log_level="info") uvicorn.run("api:app", host="127.0.0.1", port=port, log_level="info")

View file

@ -10,11 +10,33 @@
} }
.block_level { .block_level {
background-color: #1c1c3c; background-color: #1c1c3c;
width: 750px; width: 80em;
padding: 5px; padding: 5px;
margin: auto; margin: auto;
margin-top: 10px; margin-top: 10px;
} }
.scoreboard {
background-color: #1c1c3c;
width: 40em;
padding: 5px;
margin: auto;
margin-top: 10px;
}
table {
width: 100%;
background-color: #2d2d4d;
border-spacing: 0px;
}
table tr:nth-of-type(2n) {
background-color: #1c1c3c;
}
table td {
padding: 4px;
}
.block_level table td:nth-of-type(1), .block_level table td:nth-of-type(2),
.block_level table td:nth-of-type(4), .block_level table td:nth-of-type(5) {
white-space: nowrap;
}
.block { .block {
background-color: #2d2d4d; background-color: #2d2d4d;
padding: 5px; padding: 5px;
@ -52,40 +74,60 @@
</style> </style>
</head> </head>
<body> <body>
{% if reason %} {% if scoreboard %}
<h1>Instances that use "{{reason}}" in their Reason</h1> {% if blockers %}
{% for block_level in blocks.blocks %} <h1>Top {{blockers}} defederating instances</h1>
<div class="block_level"> {% elif blocked %}
<h2>{{block_level}} ({{blocks.blocks[block_level]|length}})</h2> <h1>Top {{blocked}} defederated instances</h1>
{% for block in blocks.blocks[block_level] %} {% endif %}
<div class="block"> <div class="scoreboard">
<img src="https://proxy.duckduckgo.com/ip3/{{block.blocker}}.ico" width=16/> <table>
<b><a href="https://{{block.blocker}}" rel="nofollow noopener noreferrer">{{block.blocker}}</a></b> -> <th>Instance</th>
<img src="https://proxy.duckduckgo.com/ip3/{{block.blocked}}.ico" width=16/> <th>Defederations</th>
<b><a href="https://{{block.blocked}}" rel="nofollow noopener noreferrer">{{block.blocked}}</a></b><br/> {% for entry in scores %}
{{block.reason}} <tr>
</div> <td>
<img src="https://proxy.duckduckgo.com/ip3/{{entry['domain']}}.ico" width=16/>
<b><a href="https://{{entry['domain']}}" rel="nofollow noopener noreferrer">{{entry['domain']}}</a></b>
</td>
<td>{{entry['highscore']}}</td>
</tr>
{% endfor %} {% endfor %}
</div> </table>
{% endfor %} </div>
{% elif blocks %} {% elif reason or blocks or reverse %}
<h1>Instances that block {{domain}}</h1> {% if reason %}
{% for block_level in blocks.blocks %} <h1>Instances that use "{{reason}}" in their reason</h1>
{% elif reverse %}
<h1>Instances that are blocked by {{reverse}}</h1>
{% elif blocks %}
<h1>Instances that block {{domain}}</h1>
{% endif %}
{% for block_level in blocks %}
<div class="block_level" id="{{block_level}}"> <div class="block_level" id="{{block_level}}">
<h2>{{block_level}} ({{blocks.blocks[block_level]|length}})</h2> <h2>{{block_level}} ({{blocks[block_level]|length}})</h2>
{% for block in blocks.blocks[block_level] %} <table>
<div class="block"> <th>Blocker</th>
<img src="https://proxy.duckduckgo.com/ip3/{{block}}.ico" width=16/> <th>{% if block_level == 'accept' %}Accepted{% else %}Blocked{% endif %}</th>
<b><a href="https://{{block}}" rel="nofollow noopener noreferrer">{{block}}</a></b> <th>Reason</th>
{% if block in blocks.wildcards %} <th>First added</th>
(<span title="wildcard block">&lowast;</span>) <th>Last seen</th>
{% endif %} {% for block in blocks[block_level] %}
<br/> <tr>
{% if block_level in blocks.reasons %} <td>
{{blocks.reasons[block_level][block]}} <img src="https://proxy.duckduckgo.com/ip3/{{block['blocker']}}.ico" width=16/>
{% endif %} <b><a href="https://{{block['blocker']}}" rel="nofollow noopener noreferrer">{{block['blocker']}}</a></b>
</div> </td>
{% endfor %} <td>
<img src="https://proxy.duckduckgo.com/ip3/{{domain or block['blocked']}}.ico" width=16/>
<b><a href="https://{{domain or block['blocked']}}" rel="nofollow noopener noreferrer">{{block['blocked']}}</a></b>
</td>
<td>{{block['reason']}}</td>
<td>{{block['first_added']}}</td>
<td>{{block['last_seen']}}</td>
</tr>
{% endfor %}
</table>
</div> </div>
{% endfor %} {% endfor %}
{% else %} {% else %}
@ -99,11 +141,20 @@
<input type="text" name="reason" placeholder="free speech" /> <input type="text" name="reason" placeholder="free speech" />
<input type="submit" value="Submit" /> <input type="submit" value="Submit" />
</form> </form>
<h1>Reverse search</h1>
<form>
<input type="text" name="reverse" placeholder="example.com" />
<input type="submit" value="Submit" />
</form>
<p>
<a href="./scoreboard?blockers=50">top 50 defederating</a> / <a href="./scoreboard?blocked=50">defederated instances</a>
</p>
<div class="info"> <div class="info">
known instances: {{info.known_instances}}<br/> known instances: {{info.known_instances}}<br/>
indexed instances: {{info.indexed_instances}}<br/> indexed instances: {{info.indexed_instances}}<br/>
blocks recorded: {{info.blocks_recorded}}<br/> blocks recorded: {{info.blocks_recorded}}<br/>
source code: <a href="https://git.kiwifarms.net/mint/fedi-block-api">git.kiwifarms.net/mint/fedi-block-api</a> (<a href="https://gitgud.io/mintplg/fedi-block-api">mirror</a>) source code: <a href="https://git.kiwifarms.net/mint/fedi-block-api">git.kiwifarms.net/mint/fedi-block-api</a> (<a href="https://gitgud.io/mintplg/fedi-block-api">mirror</a>)<br/>
fuck jannies
</div> </div>
{% endif %} {% endif %}
</body> </body>