Webfinger server
Go to file
Gustavo Maronato 4f05b73bec
All checks were successful
Go / checks (push) Successful in 1m0s
Update README.md
Signed-off-by: Gustavo Maronato <maronato@noreply@maronato.dev>
2024-01-29 19:59:17 -03:00
.github/workflows initial 2023-09-18 01:36:29 -03:00
.vscode initial 2023-09-18 01:36:29 -03:00
cmd refactor so external servers can use Finger as a handler 2023-09-20 15:13:10 -03:00
handler refactor so external servers can use Finger as a handler 2023-09-20 15:13:10 -03:00
internal refactor so external servers can use Finger as a handler 2023-09-20 15:13:10 -03:00
webfingers refactor so external servers can use Finger as a handler 2023-09-20 15:13:10 -03:00
.dockerignore initial 2023-09-18 01:36:29 -03:00
.gitignore initial 2023-09-18 01:36:29 -03:00
.golangci.yml initial 2023-09-18 01:36:29 -03:00
.tool-versions initial 2023-09-18 01:36:29 -03:00
Dockerfile Add missing paths to dockerfile 2024-01-25 02:38:03 -03:00
go.mod refactor and add tests 2023-09-20 01:26:38 -03:00
go.sum refactor and add tests 2023-09-20 01:26:38 -03:00
LICENSE add license 2023-09-18 01:39:57 -03:00
main.go refactor and add tests 2023-09-20 01:26:38 -03:00
Makefile readme and makefile updates 2023-09-20 11:52:46 -03:00
README.md Update README.md 2024-01-29 19:59:17 -03:00
urns.yml add copyright notice to urns file 2023-09-19 11:50:12 -03:00

Finger

Webfinger handler / standalone server written in Go.

Features

  • 🍰 Easy YAML configuration
  • 🪶 Single 8MB binary / 0% idle CPU / 4MB idle RAM
  • Sub millisecond responses at 10,000 request per second
  • 🐳 10MB Docker image

In your existing server

To use Finger in your existing server, download the package as a dependency:

go get git.maronato.dev/maronato/finger@latest

Then, use it as a regular http.Handler:

package main

import (
	"log"
	"net/http"

	"git.maronato.dev/maronato/finger/handler"
	"git.maronato.dev/maronato/finger/webfingers"
)

func main() {
  // Create the webfingers map that will be served by the handler
  fingers, err := webfingers.NewWebFingers(
    // Pass a map of your resources (Subject key followed by it's properties and links)
    // the syntax is the same as the fingers.yml file (see below)
    webfingers.Resources{
      "user@example.com": {
        "name": "Example User",
      },
    },
    // Optionally, pass a map of URN aliases (see urns.yml for more)
    // If nil is provided, no aliases will be used
    webfingers.URNAliases{
      "name": "http://schema.org/name",
    },
  )
  if err != nil {
    log.Fatal(err)
  }

  mux := http.NewServeMux()
  // Then use the handler as a regular http.Handler
  mux.Handle("/.well-known/webfinger", handler.WebfingerHandler(fingers))

  log.Fatal(http.ListenAndServe("localhost:8080", mux))
}

As a standalone server

If you don't have a server, Finger can also serve itself. You can install it via go install or use the Docker image.

Via go install:

go install git.maronato.dev/maronato/finger@latest

Via Docker:

docker run \
    --name finger \
    -p 8080:8080 \
    -v ${PWD}/fingers.yml:/app/fingers.yml \
    git.maronato.dev/maronato/finger

Usage

If you installed it using go install, run

finger serve

To start the server on port 8080. Your resources will be queryable via locahost:8080/.well-known/webfinger?resource=<your-resource>

If you're using Docker, the use the same command in the install section.

By default, no resources will be exposed. You can create resources via a fingers.yml file. It should contain a collection of resources as keys and their attributes as their objects.

Some default URN aliases are provided via the built-in mapping (urns.yml). You can replace that with your own or use URNs directly in the fingers.yml file.

Here's an example:

# fingers.yml

# Resources go in the root of the file. Email address will have the acct: 
# prefix added automatically.
alice@example.com:
  # "avatar" is an alias of "http://webfinger.net/rel/avatar"
  # (see urns.yml for more)
  avatar: "https://example.com/alice-pic"

  # If the value is a URI, it'll be exposed as a webfinger link
  openid: "https://sso.example.com/"

  # If the value of the attribute is not a URI, it will be exposed as a
  # webfinger property
  name: "Alice Doe"

  # You can also specify URN's directly instead of the aliases
  http://webfinger.net/rel/profile-page: "https://example.com/user/alice"

bob@example.com:
  name: Bob Foo
  openid: "https://sso.example.com/"

# Resources can also be URIs
https://example.com/user/charlie:
  name: Charlie Baz
  profile: https://example.com/user/charlie

Example queries

Query Alice
GET http://localhost:8080/.well-known/webfinger?resource=acct:alice@example.com
{
  "subject": "acct:alice@example.com",
  "links": [
    {
      "rel": "avatar",
      "href": "https://example.com/alice-pic"
    },
    {
      "rel": "openid",
      "href": "https://sso.example.com/"
    },
    {
      "rel": "http://webfinger.net/rel/profile-page",
      "href": "https://example.com/user/alice"
    }
  ],
  "properties": {
    "name": "Alice Doe"
  }
}
Query Bob
GET http://localhost:8080/.well-known/webfinger?resource=acct:bob@example.com
{
  "subject": "acct:bob@example.com",
  "links": [
    {
      "rel": "http://openid.net/specs/connect/1.0/issuer",
      "href": "https://sso.example.com/"
    }
  ],
  "properties": {
    "http://schema.org/name": "Bob Foo"
  }
}
Query Charlie
GET http://localhost:8080/.well-known/webfinger?resource=https://example.com/user/charlie
{
  "subject": "https://example.com/user/charlie",
  "links": [
    {
      "rel": "http://webfinger.net/rel/profile-page",
      "href": "https://example.com/user/charlie"
    }
  ],
  "properties": {
    "http://schema.org/name": "Charlie Baz"
  }
}

Commands

Finger exposes two commands: serve and healthcheck. serve is the default command and starts the server. healthcheck is used by the Docker healthcheck to check if the server is up.

Configs

Here are the config options available. You can change them via command line flags or environment variables:

CLI flag Env variable Default Description
-p, --port WF_PORT 8080 Port where the server listens to
-h, --host WF_HOST localhost (0.0.0.0 when in Docker) Host where the server listens to
-f, --finger-file WF_FINGER_FILE fingers.yml Path to the webfingers definition file
-u, --urn-file WF_URN_FILE urns.yml Path to the URNs alias file
-d, --debug WF_DEBUG false Enable debug logging

Docker config

If you're using the Docker image, you can mount your fingers.yml file to /app/fingers.yml and the urns.yml to /app/urns.yml.

To run the docker image with flags or a different command, specify the command followed by the flags:

# Start the server on port 3030 in debug mode with a different fingers file
docker run git.maronato.dev/maronato/finger serve --port 3030 --debug --finger-file /app/my-fingers.yml

# or run a healthcheck on a different finger container
docker run git.maronato.dev/maronato/finger healthcheck --host otherhost --port 3030

Development

You need to have Go installed to build the project.

Clone the repo and run make build to build the binary. You can then run ./finger serve to start the server.

A few other commands are:

  • make run to run the server
  • make test to run the tests
  • make lint to run the linter
  • make clean to clean the build files

License

This project is licensed under the MIT License - see the LICENSE file for details.