~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
186 lines · 2.8 KB Raw History
package pds

import (
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	commonv1 "github.com/johnandersen777/socialweb-computer-kcp/api/common/v1alpha1"
)

const (
	CapabilityAccount = "pds.account"

	CapabilitySession = "pds.session"

	CapabilitySync = "repo.read"

	CapabilityServiceAuth = "pds.serviceauth"
)

var (
	ErrNotFound = errors.New("pds: not found")

	ErrUnsupported = errors.New("pds: the backend does not support this call")
)

type Info struct {
	DID string

	AvailableUserDomains []string

	Version string

	URL string
}

type AccountRequest struct {
	Handle string

	Email string

	Credentials commonv1.SecretRef
}

type Account struct {
	DID string

	Handle string

	Email string

	Active bool

	SigningKey string
}

type SessionRequest struct {
	Identifier string

	Credentials commonv1.SecretRef
}

type Session struct {
	DID string

	Handle string

	Active bool
}

type Commit struct {
	CID string

	Rev string
}

type Op struct {
	Action string

	Path string

	CID string

	Prev string
}

type Event struct {
	Seq int64

	Repo string

	Commit string

	Rev string

	Since string

	Time time.Time

	Ops []Op

	TooBig bool
}

type Accounts interface {
	Describe(ctx context.Context) (Info, error)

	CreateAccount(ctx context.Context, req AccountRequest) (Account, error)

	Account(ctx context.Context, did string) (Account, error)
}

type Sessions interface {
	SignIn(ctx context.Context, req SessionRequest) (Session, error)

	Session(ctx context.Context, did string) (Session, error)

	SignOut(ctx context.Context, did string) error
}

type ServiceAuth interface {
	ServiceAuth(ctx context.Context, did, audience, lxm string, expires time.Time) (string, error)
}

type ScopeGrants interface {
	GrantedScopes(did string) ([]string, bool)
}

type Sync interface {
	LatestCommit(ctx context.Context, did string) (Commit, error)

	GetRepo(ctx context.Context, did, since string) (io.ReadCloser, error)

	SubscribeRepos(ctx context.Context, cursor *int64, fn func(Event) error) error
}

type Verdict int

const (
	VerdictDone Verdict = iota

	VerdictRetryNonce

	VerdictRetryAuth
)

type Authenticator interface {
	DID() string

	Apply(req *http.Request) error

	Invalidate()

	Challenge(resp *http.Response) Verdict
}

type Transport interface {
	Address() string

	Client() *http.Client

	TLS() *tls.Config
}

func AccountDID(scope []string) (string, error) {
	var did string
	for _, entry := range scope {
		entry = strings.TrimSpace(entry)
		if entry == "" {
			continue
		}
		if did != "" && entry != did {
			return "", fmt.Errorf("pds: a repo handle serves one account; the scope names %v", scope)
		}
		did = entry
	}
	if !strings.HasPrefix(did, "did:") {
		return "", fmt.Errorf("pds: a repo handle needs the account DID as its pds.account scope, got %v", scope)
	}
	return did, nil
}