Files
QSfera/Server/services/webfinger/pkg/service/v0/service.go
T
Курнат Андрей 2315f25754 Initial QSfera import
2026-06-07 10:20:04 +03:00

106 lines
3.0 KiB
Go

package service
import (
"context"
"net/url"
"github.com/qsfera/server/pkg/log"
"github.com/qsfera/server/services/webfinger/pkg/config"
"github.com/qsfera/server/services/webfinger/pkg/webfinger"
)
// Service defines the extension handlers.
type Service interface {
// Webfinger is the endpoint for retrieving various href relations.
//
// GET /.well-known/webfinger?
// resource=acct%3Acarol%40example.com&
// rel=http%3A%2F%2Fwebfinger.qsfera%rel%2Fserver-instance
// HTTP/1.1
// Host: example.com
//
// The server might respond like this:
//
// HTTP/1.1 200 OK
// Access-Control-Allow-Origin: *
// Content-Type: application/jrd+json
//
// {
// "subject" : "acct:carol@example.com",
// "links" :
// [
// {
// "rel" : "http://webfinger.qsfera/rel/server-instance",
// "href" : "https://instance.example.com",
// "titles": {
// "en": "Readable Instance Name"
// }
// },
// {
// "rel" : "http://webfinger.qsfera/rel/server-instance",
// "href" : "https://otherinstance.example.com",
// "titles": {
// "en": "Other Readable Instance Name"
// }
// }
// ]
// }
Webfinger(ctx context.Context, queryTarget *url.URL, rels []string, platform string) (webfinger.JSONResourceDescriptor, error)
}
type RelationProvider interface {
Add(ctx context.Context, platform string, jrd *webfinger.JSONResourceDescriptor)
}
// New returns a new instance of Service
func New(opts ...Option) (Service, error) {
options := newOptions(opts...)
// TODO use fallback implementations of InstanceIdLookup and InstanceLookup?
// The InstanceIdLookup may have to happen earlier?
return svc{
log: options.Logger,
config: options.Config,
relationProviders: options.RelationProviders,
}, nil
}
type svc struct {
config *config.Config
log log.Logger
relationProviders map[string]RelationProvider
}
// TODO implement different implementations:
// static one returning the href or a configurable domain
// regex one returning different instances based on the regex that matches
// claim one that reads a claim and then fetches the instance?
// that is actually two interfaces / steps:
// - one that determines the instances/schools id (read from claim, regex match)
// - one that looks up in instance by id (use template, read from json, read from ldap, read from graph)
// Webfinger implements the service interface
func (s svc) Webfinger(ctx context.Context, queryTarget *url.URL, rel []string, platform string) (webfinger.JSONResourceDescriptor, error) {
jrd := webfinger.JSONResourceDescriptor{
Subject: queryTarget.String(),
}
if len(rel) == 0 {
// add all configured relation providers
for _, relation := range s.relationProviders {
relation.Add(ctx, platform, &jrd)
}
} else {
// only add requested relations
for _, r := range rel {
if relation, ok := s.relationProviders[r]; ok {
relation.Add(ctx, platform, &jrd)
}
}
}
return jrd, nil
}