Simple WebFinger server that returns static resources. Written with Python and FastAPI.
Go to file
a ac571289d4 add pylint and lint the project 2022-12-25 18:32:57 -06:00
bin move to better packaging practices 2022-12-07 23:40:51 -06:00
webfinger add pylint and lint the project 2022-12-25 18:32:57 -06:00
.editorconfig move to better packaging practices 2022-12-07 23:40:51 -06:00
.gitignore move to better packaging practices 2022-12-07 23:40:51 -06:00
README.md Add more examples 2022-12-15 02:12:25 -06:00
pdm.lock add pylint and lint the project 2022-12-25 18:32:57 -06:00
pyproject.toml add pylint and lint the project 2022-12-25 18:32:57 -06:00
requirements.txt move to better packaging practices 2022-12-07 23:40:51 -06:00

README.md

webfinger

Simple WebFinger server that returns static resources. Written with Python and FastAPI.

Deployment

Add static resources as a quickstart

  • Create a resource/ folder. This will map to the ?resource= query parameter.
  • Put a .jrd file in there; anything before the .jrd will be served via that resource query parameter.
    • Currently, the "subject" will be ignored (as the resource will be used directly).
    • Otherwise, links and aliases and properties will be served normally.
  • Symlinks will be resolved as well. Try using a URI as a symlink and maybe put it in aliases too!

Example resource/acct:a@trwnh.com.jrd

{
	"subject": "acct:a@trwnh.com",
	"aliases": ["https://ap.trwnh.com/actors/7057bc10-db1c-4ebe-9e00-22cf04be4e5e", "https://trwnh.com/~a", "acct:trwnh@ap.trwnh.com"],
	"links": [
		{
			"rel": "self",
			"type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
			"href": "https://trwnh.com/actors/7057bc10-db1c-4ebe-9e00-22cf04be4e5e"
		},
		{
			"rel": "https://webfinger.net/rel/profile-page/",
			"type": "text/html",
			"href": "https://trwnh.com/~a"
		}
	]
}

If your resource URI has slashes in it and would therefore be an invalid UNIX path, it must be percent-encoded. For example, to have the WebFinger server respond to a lookup for ?resource=https://trwnh.com/~a, you can create a symlink with the path resource/https%3A%2F%2Ftrwnh.com%2F~a.jrd like so:

cd resource
ln -s "acct:a@trwnh.com" "https%3A%2F%2Ftrwnh.com%2F~a.jrd"

Running the server

Environment variables you may use:

  • RESOURCE_DIR: specify the directory from which resources will be served

...with PDM

pdm install
pdm run uvicorn webfinger:app --port 7033

You can also run pdm run start or pdm run python -m webfinger

...with virtualenv

virtualenv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn webfinger:app --port 7033

You can also run python -m webfinger

Post-run proxy or redirect

You probably want to proxy /.well-known/webfinger to localhost:7033 or otherwise host a webfinger service externally and redirect to that instead.

For simple deployments on a single domain, you probably want to set up a reverse proxy to the running Uvicorn process (by default, this will be hosted at localhost:7033). This will allow you to serve WebFinger via your own domain, without a trailing port. Since WebFinger specifies HTTPS requests, your reverse proxy must support HTTPS.

Example nginx proxy_pass to localhost:

location /.well-known/webfinger {
	proxy_pass localhost:7033;
}

It's recommended that you do any redirects to external services with an HTTP 307 Temporary Redirect. Why not HTTP 302? This is because HTTP 302 does not usually preserve the HTTP method -- some browsers (especially older ones) will treat 302 as 303, issuing a GET request to the new Location regardless of the original request's method.

Example nginx redirect to external service:

location /.well-known/webfinger {
	add_header Access-Control-Allow-Origin *;
	return 307 https://webfinger.example$request_uri;
}

Development

pdm run dev or uvicorn webfinger:app --reload

TODO

some api for managing JRD documents

basic create/update/delete?

MAYBE support authorization and private attributes?

As with all web resources, access to the WebFinger resource could
require authentication.  Further, failure to provide required
credentials might result in the server forbidding access or providing
a different response than had the client authenticated with the
server.

Likewise, a WebFinger resource MAY provide different responses to
different clients based on other factors, such as whether the client
is inside or outside a corporate network.  As a concrete example, a
query performed on the internal corporate network might return link
relations to employee pictures, whereas link relations for employee
pictures might not be provided to external entities.
  • idk if i'm gonna do this but maybe if you authenticate as the owner of the JRD then you can see things like phone numbers and email addresses?
Systems or services that expose personal data via WebFinger MUST
provide an interface by which users can select which data elements
are exposed through the WebFinger interface.  For example, social
networking sites might allow users to mark certain data as "public"
and then utilize that marking as a means of determining what
information to expose via WebFinger.  The information published via
WebFinger would thus comprise only the information marked as public
by the user.  Further, the user has the ability to remove information
from publication via WebFinger by removing this marking.

WebFinger MUST NOT be used to provide any personal data unless
publishing that data via WebFinger by the relevant service was
explicitly authorized by the person whose information is being
shared.  Publishing one's personal data within an access-controlled
or otherwise limited environment on the Internet does not equate to
providing implicit authorization of further publication of that data
via WebFinger.
  • if the above gets done, then there should be a dashboard to choose which information is public and which is not. this probably breaks static serving though, or at least private info should be stored in a database and merged into the final response

MAYBE rate limit and proxy webfinger requests

It is RECOMMENDED that implementers of WebFinger server software take
steps to mitigate abuse, including malicious over-use of the server
and harvesting of user information.  Although there is no mechanism
that can guarantee that publicly accessible WebFinger databases won't
be harvested, rate-limiting by IP address will prevent or at least
dramatically slow harvest by private individuals without access to
botnets or other distributed systems.  The reason these mitigation
strategies are not mandatory is that the correct choice of mitigation
strategy (if any) depends greatly on the context.  Implementers
should not construe this as meaning that they do not need to consider
whether to use a mitigation strategy, and if so, what strategy to
use.

WebFinger client developers should also be aware of potential abuse
by spammers or those phishing for information about users.  As an
example, suppose a mail client was configured to automatically
perform a WebFinger query on the sender of each received mail
message.  If a spammer sent an email using a unique identifier in the
'From' header, then when the WebFinger query was performed, the
spammer would be able to associate the request with a particular
user's email address.  This would provide information to the spammer,
including the user's IP address, the fact the user just checked
email, what kind of WebFinger client the user utilized, and so on.
For this reason, it is strongly advised that clients not perform
WebFinger queries unless authorized by the user to do so.
  • if/when i add a REST API, the api could have a method to do a lookup proxied through the server. this would allow applications to not leak user IPs so long as they actually use the REST API