Feat: Allows instances to pull a badge (#13)
parent
cf488eb583
commit
ceb1c3cf3d
14
README.md
14
README.md
|
@ -7,3 +7,17 @@ It's reliant on the [Lemmy Fediverse Observer](https://lemmy.fediverse.observer/
|
||||||
The currently running instance is on https://fediseer.com
|
The currently running instance is on https://fediseer.com
|
||||||
|
|
||||||
See devlog: https://dbzer0.com/blog/overseer-a-fediverse-chain-of-trust/
|
See devlog: https://dbzer0.com/blog/overseer-a-fediverse-chain-of-trust/
|
||||||
|
|
||||||
|
# Badges
|
||||||
|
|
||||||
|
You can retrieve and display a badge for your fediverse domain by requesting a .svg for it on a special endpoint
|
||||||
|
|
||||||
|
`/v1/badges/guarantees/{domain}.svg` will give you an badge of guarantee, mentioning the domains which guaranteed for your domain
|
||||||
|
|
||||||
|
Example:
|
||||||
|
[![](http://fediseer.com/api/v1/badges/guarantees/lemmy.dbzer0.com.svg)](https://fediseer.com/api/v1/whitelist/lemmy.dbzer0.com)
|
||||||
|
|
||||||
|
`/v1/badges/endorsements/{domain}.svg` will give you an badge of endorsements, providing a count of how many other the fediverse domains guaranteed for yours
|
||||||
|
|
||||||
|
Example:
|
||||||
|
[![](http://fediseer.com/api/v1/badges/endorsements/lemmy.dbzer0.com.svg)](https://fediseer.com/api/v1/endorsements/lemmy.dbzer0.com)
|
||||||
|
|
|
@ -3,6 +3,7 @@ import fediseer.apis.v1.whitelist as whitelist
|
||||||
import fediseer.apis.v1.endorsements as endorsements
|
import fediseer.apis.v1.endorsements as endorsements
|
||||||
import fediseer.apis.v1.guarantees as guarantees
|
import fediseer.apis.v1.guarantees as guarantees
|
||||||
import fediseer.apis.v1.activitypub as activitypub
|
import fediseer.apis.v1.activitypub as activitypub
|
||||||
|
import fediseer.apis.v1.badges as badges
|
||||||
import fediseer.apis.v1.find as find
|
import fediseer.apis.v1.find as find
|
||||||
from fediseer.apis.v1.base import api
|
from fediseer.apis.v1.base import api
|
||||||
|
|
||||||
|
@ -16,3 +17,5 @@ api.add_resource(endorsements.Endorsements, "/endorsements/<string:domain>")
|
||||||
api.add_resource(endorsements.Approvals, "/approvals/<string:domain>")
|
api.add_resource(endorsements.Approvals, "/approvals/<string:domain>")
|
||||||
api.add_resource(guarantees.Guarantors, "/guarantors/<string:domain>")
|
api.add_resource(guarantees.Guarantors, "/guarantors/<string:domain>")
|
||||||
api.add_resource(guarantees.Guarantees, "/guarantees/<string:domain>")
|
api.add_resource(guarantees.Guarantees, "/guarantees/<string:domain>")
|
||||||
|
api.add_resource(badges.GuaranteeBadge, "/badges/guarantees/<string:domain>.svg")
|
||||||
|
api.add_resource(badges.EndorsementBadge, "/badges/endorsements/<string:domain>.svg")
|
||||||
|
|
|
@ -45,14 +45,14 @@ class Inbox(Resource):
|
||||||
self.args = self.post_parser.parse_args()
|
self.args = self.post_parser.parse_args()
|
||||||
json_payload = request.get_json()
|
json_payload = request.get_json()
|
||||||
actor = json_payload["actor"]
|
actor = json_payload["actor"]
|
||||||
if json_payload.get("Type") == "Follow":
|
if json_payload.get("type") == "Follow":
|
||||||
logger.info(f"Fediseer is now followed from: {actor}")
|
logger.info(f"Fediseer is now followed from: {actor}")
|
||||||
elif json_payload.get("Type") == "Delete":
|
elif json_payload.get("type") == "Delete":
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
message = json_payload["object"]["content"]
|
message = json_payload["object"]["content"]
|
||||||
logger.info(f"Fediseer Inbox Received: From: {actor} | {message}")
|
logger.info(f"Fediseer Inbox Received: From: {actor} | {message}")
|
||||||
except:
|
except:
|
||||||
logger.info(f"Received unexpected invox payload: {json_payload}")
|
logger.info(f"Received unexpected inbox payload: {json_payload}")
|
||||||
return {"message": "delivered"}, 200
|
return {"message": "delivered"}, 200
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
from fediseer.apis.v1.base import *
|
||||||
|
from fediseer.badges import generate_endorsements_badge, generate_guarantee_badge
|
||||||
|
from sqlalchemy.orm import aliased
|
||||||
|
from fediseer.classes.instance import Guarantee, Endorsement
|
||||||
|
from flask import make_response
|
||||||
|
from sqlalchemy import func
|
||||||
|
|
||||||
|
class GuaranteeBadge(Resource):
|
||||||
|
|
||||||
|
def get(self, domain):
|
||||||
|
'''Retrieve Guarantee Badge SVG
|
||||||
|
'''
|
||||||
|
guaranteed_instance_alias = aliased(Instance)
|
||||||
|
query = db.session.query(
|
||||||
|
Instance.domain,
|
||||||
|
guaranteed_instance_alias.domain,
|
||||||
|
).join(
|
||||||
|
Guarantee, Instance.id == Guarantee.guaranteed_id
|
||||||
|
).join(
|
||||||
|
guaranteed_instance_alias, guaranteed_instance_alias.id == Guarantee.guarantor_id
|
||||||
|
).filter(
|
||||||
|
Instance.domain == domain
|
||||||
|
)
|
||||||
|
guarantor = query.first()
|
||||||
|
if guarantor is None:
|
||||||
|
svg = generate_guarantee_badge(domain, None)
|
||||||
|
else:
|
||||||
|
svg = generate_guarantee_badge(domain, guarantor[1])
|
||||||
|
response = make_response(svg)
|
||||||
|
response.headers['Content-Type'] = 'image/svg+xml'
|
||||||
|
return response
|
||||||
|
|
||||||
|
class EndorsementBadge(Resource):
|
||||||
|
|
||||||
|
def get(self, domain):
|
||||||
|
'''Retrieve Endorsement Badge SVG
|
||||||
|
'''
|
||||||
|
query = db.session.query(
|
||||||
|
Instance.domain,
|
||||||
|
func.count(Endorsement.id) # Count the number of endorsements
|
||||||
|
).join(
|
||||||
|
Endorsement, Instance.id == Endorsement.endorsed_id
|
||||||
|
).filter(
|
||||||
|
Instance.domain == domain
|
||||||
|
).group_by(
|
||||||
|
Instance.domain
|
||||||
|
)
|
||||||
|
endorsements = query.first()
|
||||||
|
if endorsements is None:
|
||||||
|
svg = generate_endorsements_badge(domain, 0)
|
||||||
|
else:
|
||||||
|
svg = generate_endorsements_badge(domain, endorsements[1])
|
||||||
|
response = make_response(svg)
|
||||||
|
response.headers['Content-Type'] = 'image/svg+xml'
|
||||||
|
return response
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Assets
|
||||||
|
|
||||||
|
* [crossed-chains](https://game-icons.net/1x1/lorc/crossed-chains.html)
|
||||||
|
* [thumb-up](https://game-icons.net/1x1/delapouite/thumb-up.html)
|
||||||
|
*
|
|
@ -0,0 +1 @@
|
||||||
|
<svg style="height: 512px; width: 512px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g class="" style="" transform="translate(0,0)"><path d="M19.023 19.676v27.2L75.48 104.32l24.842-24.843-58.804-59.8H19.023zm65.41 3.498c-4.468.09-8.392.9-11.83 2.244L189.15 141.963c2.893-7.395 3.085-17.245-.146-29.094-4.61-16.908-16.108-36.597-33.408-53.895-17.3-17.3-36.99-28.8-53.897-33.41-6.34-1.73-12.125-2.495-17.265-2.39zm-63.09 53.51c-2.894 7.394-3.088 17.243.143 29.09 4.61 16.908 16.11 36.598 33.41 53.898 17.3 17.3 36.988 28.797 53.895 33.408 11.85 3.232 21.7 3.04 29.095.147L21.342 76.684zm107.07 30.96l-24.716 24.717 119.545 119.546 24.717-24.717-119.546-119.545zm366 56.57c-7.766 2.724-15.67 6.186-23.36 10.626-20.332 11.738-35.756 27.138-44.106 41.637-5.734 9.956-7.942 18.928-7.213 26.365l74.68-42.953v-35.675zm-257.07 11.87c-4.466.09-8.39.9-11.827 2.246l73.62 73.62c10.648-5.168 21.366-8.972 31.78-11.358-5.744-9.727-13.255-19.55-22.41-28.705-17.3-17.3-36.99-28.8-53.897-33.41-6.34-1.73-12.126-2.497-17.266-2.393zm-62.677 53.096c-2.894 7.394-3.085 17.244.147 29.093 4.61 16.907 16.11 36.597 33.41 53.897 6.408 6.408 13.144 12.014 19.945 16.775 1.55-7.685 4.687-15.44 9.016-22.86 1.705-2.925 3.62-5.822 5.7-8.69l-68.218-68.215zm304.063.668L338.36 311.03l16.425 28.75 137.88-79.628v-6.12l-13.936-24.184zm-122.783 26.406c-16.79.075-37.91 5.84-58.258 17.588-20.348 11.747-35.902 27.155-44.362 41.658-5.79 9.93-8.063 18.86-7.39 26.26l136.445-78.776c-6.074-4.282-14.942-6.78-26.436-6.73zm138.467 23.637l-39.684 22.936c3.228 2.31 7.23 4.13 12.22 5.32 7.53 1.793 17.022 1.925 27.464.307V279.89zm-75.32 43.643l-136.448 78.78c6.073 4.283 14.943 6.78 26.438 6.728 16.79-.074 37.912-5.84 58.26-17.587 20.347-11.747 35.9-27.154 44.36-41.658 5.793-9.93 8.063-18.86 7.39-26.262zM296.53 334.19l-10.686 6.167-.037-.037-12.73 7.35.09.008-116.956 67.525 16.472 28.53 140.32-81.012-16.473-28.53zm138.993 7.558c-1.74 5.896-4.36 11.778-7.675 17.463-2.508 4.3-5.44 8.55-8.743 12.71l68.754 68.754c2.892-7.394 3.084-17.244-.147-29.092-4.61-16.906-16.108-36.595-33.408-53.894-6.042-6.042-12.377-11.36-18.782-15.94zM177.44 360.326c-16.79.075-37.91 5.84-58.258 17.588C98.834 389.66 83.28 405.07 74.82 419.572c-5.79 9.928-8.062 18.86-7.39 26.26l136.445-78.775c-6.073-4.283-14.942-6.782-26.436-6.73zM427.2 406.61l-24.67 24.29 62.49 62.996h27.644V472.07L427.2 406.61zm-66.124 8.982c-10.614 4.73-21.244 8.11-31.514 10.076 5.956 10.888 14.173 22.015 24.458 32.3 17.298 17.3 36.987 28.8 53.894 33.41 11.85 3.233 21.7 3.04 29.096.147l-75.934-75.933zM239.09 427.674l-114.528 66.123h65.815c18.962-11.586 33.505-26.31 41.502-40.193 5.648-9.81 7.863-18.622 7.21-25.93zm-114.854 7.144L21.73 493.896h65.452l53.392-30.86-16.338-28.218z" fill="#f8cc1c" fill-opacity="1"></path></g></svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<svg style="height: 512px; width: 512px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g class="" style="" transform="translate(0,0)"><path d="M302.344 28.514c-2.386 1.354-4.334 3.497-6.273 7.182-2.335 4.438-4.28 10.836-5.94 18.29-3.316 14.91-5.51 33.828-12.098 51.26l-.54 1.43-.982 1.17c-53.308 63.59-92.07 98.36-119.014 148.817l-2.46 4.605-5.22.15s-10.63.322-22.607 2.46c-11.978 2.137-43.225 3.316-46.132 7.017-13.33 16.97-23.48 45.76-25.072 70.46-1.592 24.697 3.872 48.986 16.676 65.568.858 1.11 29.53 4.57 38.22 5.302 8.693.73 16.52.162 16.52.162l6.08-.457 2.678 5.48c14.83 30.325 61.456 50.595 110.937 66.056 4.384.248 11.962-1.82 20.852-6.295-19.818-7.57-35.37-14.03-52.5-23.087l-4.423-2.338-.347-4.99c-.896-12.814 5.672-23.273 13.61-30.256 2.54-2.237 5.24-4.216 7.985-6.038-1.54-.685-3.074-1.38-4.62-2.053l-4.698-2.05-.635-5.086c-1.752-14.04 2.566-27.897 11.664-37.728 1.852-2 3.932-3.81 6.19-5.405l-.23-.1-.438-5.31c-1.313-15.828 8.72-29.44 20.295-39.02 2.13-1.764 4.347-3.44 6.623-4.985l-.91-2.148c-4.49-10.608-2.336-21.785 3.01-29.815 5.35-8.03 13.357-13.657 21.92-16.79l.232-.086.236-.073c16.656-5.078 32.616-1.007 47.756 3.03 15.14 4.036 29.842 8.22 45.14 6.923 9.286 15.502 8.095 12.523 10.49 17.176l-8.966.76c-19.417 1.647-36.48-3.515-51.3-7.467-14.71-3.92-26.832-6.456-37.616-3.264-5.132 1.933-10.21 5.715-12.908 9.77-2.15 3.226-3.06 6.18-2.338 9.75 21.768 9.268 38.374 19.347 57.04 24.798 19.682 5.746 42.49 7.06 79.325-3.035 5.858-2.842 11.615-7.678 15.014-12.946 3.503-5.427 4.637-10.646 2.87-16-6.415-19.43-15.202-36.684-33.028-48.515-40.155-16.703-65.958-16.832-101.275-13.336-.627-5.215-.437-10.644.022-18.09 2.066-15.153 8.845-33.844 16.745-55.096 9.792-26.342 21.692-55.157 30.416-78.892-2.042-19.79-7.618-30.87-15.044-37.3-7.295-6.315-17.56-9.054-30.932-9.564zm-14.53 290.698c-4.52 1.1-10.952 3.76-16.513 8.363-6.763 5.6-11.67 12.988-13.268 18.99 24.578 11.48 43.09 22.944 74.63 33.086l66.92-3.794c11.996-4.2 19.78-8.523 24.07-12.197 4.42-3.79 5.292-6.294 5.45-8.77.265-4.15-3.83-11.11-9.88-18.43-37.514 9.835-63.92 8.562-86.034 2.105-16.627-4.855-30.524-12.225-45.375-19.353zm-25.398 49.41c-6.38.195-11.287 2.923-15.2 7.15-4.27 4.616-6.853 11.327-7.09 18.49 23.313 10.374 45.08 21.135 74.69 30.407l56.54-1.095c21.862-.903 27.79-9.79 28.918-17.854.6-4.28-.493-8.504-2.71-11.72l-67.27 3.815-1.57-.496c-28.61-9.035-47.056-19.095-66.265-28.698h-.044zm-9.96 50.937c-6.14 3.332-12.053 6.753-16.258 10.452-4.005 3.523-6.404 6.67-7.237 10.69 17.396 8.825 33.933 15.363 57.386 24.162l46.51 1.596c8.015-3.427 12.8-6.69 15.08-9.11 2.44-2.59 2.637-3.797 2.603-5.873-.035-2.12-1.344-5.413-3-9.437l-35.403.685-1.385-.427c-22.878-7.07-41.16-14.99-58.295-22.74z" fill="#f8cc1c" fill-opacity="1"></path></g></svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1,49 @@
|
||||||
|
from pybadges import badge
|
||||||
|
from loguru import logger
|
||||||
|
import base64
|
||||||
|
|
||||||
|
with open('fediseer/assets/crossed-chains.svg', 'rb') as file:
|
||||||
|
svg_data = file.read()
|
||||||
|
base64_data = base64.b64encode(svg_data).decode('utf-8')
|
||||||
|
embed_guarantee = f"data:image/svg+xml;base64,{base64_data}"
|
||||||
|
with open('fediseer/assets/thumb-up.svg', 'rb') as file:
|
||||||
|
svg_data = file.read()
|
||||||
|
base64_data = base64.b64encode(svg_data).decode('utf-8')
|
||||||
|
embed_endorsement = f"data:image/svg+xml;base64,{base64_data}"
|
||||||
|
|
||||||
|
def generate_guarantee_badge(domain: str, guarantor: str):
|
||||||
|
left_color = "SeaGreen"
|
||||||
|
right_text=guarantor
|
||||||
|
if guarantor is None:
|
||||||
|
left_color = "red"
|
||||||
|
right_text="None"
|
||||||
|
guarantee_badge = badge(
|
||||||
|
left_text="Guarantee",
|
||||||
|
right_text=right_text,
|
||||||
|
left_color=left_color,
|
||||||
|
logo=embed_guarantee,
|
||||||
|
whole_title="Fediseer Guarantee",
|
||||||
|
left_title=domain,
|
||||||
|
right_title="Guarantor",
|
||||||
|
left_link="https://fediseer.com",
|
||||||
|
right_link=f"https://fediseer.com/api/v1/endorsements/{domain}",
|
||||||
|
)
|
||||||
|
return guarantee_badge
|
||||||
|
|
||||||
|
def generate_endorsements_badge(domain: str, count: int):
|
||||||
|
left_color = "DarkOliveGreen"
|
||||||
|
right_text=str(count)
|
||||||
|
if count == 0:
|
||||||
|
left_color = "red"
|
||||||
|
endorsements_badge = badge(
|
||||||
|
left_text="Endorsements",
|
||||||
|
right_text=right_text,
|
||||||
|
left_color=left_color,
|
||||||
|
logo=embed_endorsement,
|
||||||
|
whole_title="Fediseer Endorsements",
|
||||||
|
left_title=domain,
|
||||||
|
right_title="Endorsements Count",
|
||||||
|
left_link="https://fediseer.com",
|
||||||
|
right_link=f"https://fediseer.com/api/v1/whitelist/{domain}",
|
||||||
|
)
|
||||||
|
return endorsements_badge
|
|
@ -15,3 +15,5 @@ psycopg2-binary
|
||||||
regex
|
regex
|
||||||
pythorhead>=0.8.2
|
pythorhead>=0.8.2
|
||||||
bleach
|
bleach
|
||||||
|
boto3
|
||||||
|
pybadges
|
50
test.py
50
test.py
|
@ -1,41 +1,13 @@
|
||||||
import requests
|
from dotenv import load_dotenv
|
||||||
import json
|
import os
|
||||||
from datetime import datetime
|
import logging
|
||||||
import OpenSSL.crypto
|
|
||||||
import base64
|
|
||||||
import hashlib
|
|
||||||
import sys
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
with open('lemmy-hello-world.json', 'r') as file:
|
load_dotenv()
|
||||||
document = json.loads(file.read())
|
|
||||||
document["id"] = f"https://fediseer.com/{uuid.uuid4()}"
|
|
||||||
document["object"]["id"] = f"https://fediseer.com/{uuid.uuid4()}"
|
|
||||||
document["object"]["published"] = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
||||||
document = json.dumps(document, indent=4)
|
|
||||||
print(document)
|
|
||||||
digest = hashlib.sha256(document.encode('utf-8')).digest()
|
|
||||||
encoded_digest = base64.b64encode(digest).decode('utf-8')
|
|
||||||
digest_header = "SHA-256=" + encoded_digest
|
|
||||||
date = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
|
|
||||||
|
|
||||||
with open('private.pem', 'rb') as file:
|
from fediseer.argparser import args
|
||||||
private_key_data = file.read()
|
from fediseer.flask import OVERSEER
|
||||||
private_key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, private_key_data)
|
from loguru import logger
|
||||||
|
from fediseer.badges import generate_guarantee_badge
|
||||||
signed_string = f"(request-target): post /inbox\nhost: overctrl.dbzer0.com\ndate: {date}\ndigest: {digest_header}"
|
if __name__ == "__main__":
|
||||||
signature = OpenSSL.crypto.sign(private_key, signed_string.encode('utf-8'), 'sha256')
|
# Only setting this for the WSGI logs
|
||||||
encoded_signature = base64.b64encode(signature).decode('utf-8')
|
print(generate_guarantee_badge("lemmy.dbzer0.com", "fediseer.com"))
|
||||||
|
|
||||||
header = f'keyId="https://fediseer.com/api/v1/user/fediseer",headers="(request-target) host date digest",signature="{encoded_signature}"'
|
|
||||||
headers = {
|
|
||||||
'Host': 'overctrl.dbzer0.com',
|
|
||||||
'Date': date,
|
|
||||||
'Signature': header,
|
|
||||||
'Digest': digest_header,
|
|
||||||
'Content-Type': 'application/ld+json; profile="http://www.w3.org/ns/activitystreams"'
|
|
||||||
}
|
|
||||||
url = 'https://overctrl.dbzer0.com/inbox'
|
|
||||||
response = requests.post(url, data=document, headers=headers)
|
|
||||||
print('Response Status:', response.status_code)
|
|
||||||
print('Response Body:', response.text)
|
|
||||||
|
|
Loading…
Reference in New Issue