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

91
api.py
View file

@ -6,6 +6,7 @@ from fastapi.templating import Jinja2Templates
from requests import get
from json import loads
from re import sub
from datetime import datetime
with open("config.json") as f:
config = loads(f.read())
@ -30,9 +31,33 @@ def info():
"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")
def blocked(domain: str = None, reason: str = None):
if domain == None and reason == None:
def blocked(domain: str = None, reason: str = None, reverse: str = None):
if domain == None and reason == None and reverse == None:
raise HTTPException(status_code=400, detail="No filter specified")
if reason != None:
reason = sub("(%|_)", "", reason)
@ -43,45 +68,46 @@ def blocked(domain: str = None, reason: str = None):
if domain != None:
wildchar = "*." + ".".join(domain.split(".")[-domain.count("."):])
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))
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:
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()
conn.close()
c.close()
result = {}
reasons = {}
wildcards = []
if domain != None:
for domain, blocked, block_level, reason in blocks:
for blocker, blocked, block_level, reason, first_added, last_seen in blocks:
entry = {"blocker": blocker, "blocked": blocked, "reason": reason, "first_added": first_added, "last_seen": last_seen}
if block_level in result:
result[block_level].append(domain)
result[block_level].append(entry)
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}
result[block_level] = [entry]
for blocker, blocked, reason, block_level in blocks:
if block_level in result:
result[block_level].append({"blocker": blocker, "blocked": blocked, "reason": reason})
else:
result[block_level] = [{"blocker": blocker, "blocked": blocked, "reason": reason}]
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+"/")
def index(request: Request, domain: str = None, reason: str = None):
if domain == "" or reason == "":
def index(request: Request, domain: str = None, reason: str = None, reverse: str = None):
if domain == "" or reason == "" or reverse == "":
return responses.RedirectResponse("/")
info = 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")
if not info.ok:
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}")
elif reason != None:
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 not blocks.ok:
raise HTTPException(status_code=blocks.status_code, detail=blocks.text)
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__":
uvicorn.run("api:app", host="127.0.0.1", port=port, log_level="info")

View file

@ -10,11 +10,33 @@
}
.block_level {
background-color: #1c1c3c;
width: 750px;
width: 80em;
padding: 5px;
margin: auto;
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 {
background-color: #2d2d4d;
padding: 5px;
@ -52,40 +74,60 @@
</style>
</head>
<body>
{% if scoreboard %}
{% if blockers %}
<h1>Top {{blockers}} defederating instances</h1>
{% elif blocked %}
<h1>Top {{blocked}} defederated instances</h1>
{% endif %}
<div class="scoreboard">
<table>
<th>Instance</th>
<th>Defederations</th>
{% for entry in scores %}
<tr>
<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 %}
</table>
</div>
{% elif reason or blocks or reverse %}
{% if reason %}
<h1>Instances that use "{{reason}}" in their Reason</h1>
{% for block_level in blocks.blocks %}
<div class="block_level">
<h2>{{block_level}} ({{blocks.blocks[block_level]|length}})</h2>
{% for block in blocks.blocks[block_level] %}
<div class="block">
<img src="https://proxy.duckduckgo.com/ip3/{{block.blocker}}.ico" width=16/>
<b><a href="https://{{block.blocker}}" rel="nofollow noopener noreferrer">{{block.blocker}}</a></b> ->
<img src="https://proxy.duckduckgo.com/ip3/{{block.blocked}}.ico" width=16/>
<b><a href="https://{{block.blocked}}" rel="nofollow noopener noreferrer">{{block.blocked}}</a></b><br/>
{{block.reason}}
</div>
{% endfor %}
</div>
{% endfor %}
<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>
{% for block_level in blocks.blocks %}
{% endif %}
{% for block_level in blocks %}
<div class="block_level" id="{{block_level}}">
<h2>{{block_level}} ({{blocks.blocks[block_level]|length}})</h2>
{% for block in blocks.blocks[block_level] %}
<div class="block">
<img src="https://proxy.duckduckgo.com/ip3/{{block}}.ico" width=16/>
<b><a href="https://{{block}}" rel="nofollow noopener noreferrer">{{block}}</a></b>
{% if block in blocks.wildcards %}
(<span title="wildcard block">&lowast;</span>)
{% endif %}
<br/>
{% if block_level in blocks.reasons %}
{{blocks.reasons[block_level][block]}}
{% endif %}
</div>
<h2>{{block_level}} ({{blocks[block_level]|length}})</h2>
<table>
<th>Blocker</th>
<th>{% if block_level == 'accept' %}Accepted{% else %}Blocked{% endif %}</th>
<th>Reason</th>
<th>First added</th>
<th>Last seen</th>
{% for block in blocks[block_level] %}
<tr>
<td>
<img src="https://proxy.duckduckgo.com/ip3/{{block['blocker']}}.ico" width=16/>
<b><a href="https://{{block['blocker']}}" rel="nofollow noopener noreferrer">{{block['blocker']}}</a></b>
</td>
<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>
{% endfor %}
{% else %}
@ -99,11 +141,20 @@
<input type="text" name="reason" placeholder="free speech" />
<input type="submit" value="Submit" />
</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">
known instances: {{info.known_instances}}<br/>
indexed instances: {{info.indexed_instances}}<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>
{% endif %}
</body>