Feat: Allows instances to pull a badge (#13)

pull/17/head
Divided by Zer0 2023-06-27 16:11:51 +02:00 committed by GitHub
parent cf488eb583
commit ceb1c3cf3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 146 additions and 44 deletions

View File

@ -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
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)

View File

@ -3,6 +3,7 @@ import fediseer.apis.v1.whitelist as whitelist
import fediseer.apis.v1.endorsements as endorsements
import fediseer.apis.v1.guarantees as guarantees
import fediseer.apis.v1.activitypub as activitypub
import fediseer.apis.v1.badges as badges
import fediseer.apis.v1.find as find
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(guarantees.Guarantors, "/guarantors/<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")

View File

@ -45,14 +45,14 @@ class Inbox(Resource):
self.args = self.post_parser.parse_args()
json_payload = request.get_json()
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}")
elif json_payload.get("Type") == "Delete":
elif json_payload.get("type") == "Delete":
pass
else:
try:
message = json_payload["object"]["content"]
logger.info(f"Fediseer Inbox Received: From: {actor} | {message}")
except:
logger.info(f"Received unexpected invox payload: {json_payload}")
logger.info(f"Received unexpected inbox payload: {json_payload}")
return {"message": "delivered"}, 200

View File

@ -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

View File

@ -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)
*

View File

@ -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

View File

@ -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

49
fediseer/badges.py 100644
View File

@ -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

View File

@ -15,3 +15,5 @@ psycopg2-binary
regex
pythorhead>=0.8.2
bleach
boto3
pybadges

50
test.py
View File

@ -1,41 +1,13 @@
import requests
import json
from datetime import datetime
import OpenSSL.crypto
import base64
import hashlib
import sys
import uuid
from dotenv import load_dotenv
import os
import logging
with open('lemmy-hello-world.json', 'r') as file:
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')
load_dotenv()
with open('private.pem', 'rb') as file:
private_key_data = file.read()
private_key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, private_key_data)
signed_string = f"(request-target): post /inbox\nhost: overctrl.dbzer0.com\ndate: {date}\ndigest: {digest_header}"
signature = OpenSSL.crypto.sign(private_key, signed_string.encode('utf-8'), 'sha256')
encoded_signature = base64.b64encode(signature).decode('utf-8')
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)
from fediseer.argparser import args
from fediseer.flask import OVERSEER
from loguru import logger
from fediseer.badges import generate_guarantee_badge
if __name__ == "__main__":
# Only setting this for the WSGI logs
print(generate_guarantee_badge("lemmy.dbzer0.com", "fediseer.com"))