From 8b6e2875a7a7f2c98f756089a291599dedea0cef Mon Sep 17 00:00:00 2001 From: Andrew Williams Date: Mon, 1 May 2023 07:27:44 +0100 Subject: [PATCH] Generate Mastodon links --- README.md | 22 +++++++++++++++++++++- app.py | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d7e1afc..e2b928f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A simple, Flask-based webfinger handler. -Simple Webfinger was created to provide an OIDC href from a basic YAML configuration file. Ideally to use with Tailscale and Authentik. +Simple Webfinger was created to provide an OIDC href from a basic YAML configuration file. Ideally for use with Tailscale and Authentik. ## Configuration @@ -13,4 +13,24 @@ The `example-config.yaml` has the basic layout of the YAML file, which has the f | `domain` | `doofnet.uk` | The domain to respond to, it'll return 404s for anything else | | `oidc_href` | `https://id.doofnet.uk/...` | The href to return for OIDC rels | +### Accounts +Accounts can be defined under the `accounts` key, and a key for each user, for example: + +```yaml +accounts: + nikdoof: + mastodon: nikdoof@mastodon.incognitus.net + aliases: [] + properties: [] + links: [] +``` + +The app will only reply to accounts listed in the configuration, otherwise, it'll return a 404. + +| Key | Value Example | Description | +| ------------ | --------------------------------- | --------------------------------------------------------------- | +| `mastodon` | `nikdoof@mastodon.incognitus.net` | A Mastodon account to generate the related links/properties for | +| `aliases` | `[]` | A list of aliases to include in the response for the account | +| `links` | `[]` | A list of dicts to include in the response | +| `properties` | `[]` | A list of dicts to include in the response | diff --git a/app.py b/app.py index 3d069ea..6438f6c 100644 --- a/app.py +++ b/app.py @@ -1,3 +1,5 @@ +from urllib.parse import urlparse + from flask import Flask, request, abort import yaml @@ -7,19 +9,57 @@ with open('config.yaml', 'rb') as fobj: data = yaml.load(fobj, yaml.SafeLoader) +def get_account_links(user): + links = [] + account_data = data['accounts'][user] + + # Append custom links + if 'links' in account_data: + links.extend(account_data['links']) + + if 'mastodon' in account_data: + account, domain = account_data['mastodon'].split('@') + links.extend([ + {'rel': 'http://webfinger.net/rel/profile-page', 'type': 'text/html', 'href': 'https://{0}/@{1}'.format(domain, account)}, + {'rel': 'self', 'type': 'application/activity+json', 'href': 'https://{0}/users/{1}'.format(domain, account)}, + {'rel': 'http://ostatus.org/schema/1.0/subscribe', 'template': "https://{0}/authorize_interaction?uri={{uri}}".format(domain)} + ]) + + # Append the OIDC link + if 'oidc_href' in data: + links.append({ + 'rel': 'http://openid.net/specs/connect/1.0/issuer', + 'href': data['oidc_href'], + }) + + return links + + +def filter_links(links, rel): + new_links = [] + for link in links: + if link['rel'] == rel: + new_links.append(link) + return new_links + + @app.route("/.well-known/webfinger") def webfinger(): resource = request.args.get('resource') + account, domain = urlparse(resource).path.split('@') - if resource.split('@')[1] != data['domain']: + if domain != data['domain'] or account not in data['accounts']: abort(404) + links = get_account_links(account) + + rel = request.args.get('rel') + if rel: + links = filter_links(links, rel) + return { 'subject': resource, - 'links': [{ - 'rel': "http://openid.net/specs/connect/1.0/issuer", - 'href': data['oidc_href'], - }] + 'links': links }