106 lines
3.0 KiB
Go
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
|
|
}
|