Initial QSfera import
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user