Documentation
¶
Overview ¶
Package ts11client is a reusable client for TS11 credential metadata registries (registry.siros.org and compatible registries generated by registry-cli). It resolves SD-JWT VC Type Metadata documents by their vct claim value, and mdoc/MDDL metadata documents by their doctype value, across one or more registries queried concurrently - the first registry to answer wins, so a slow or unreachable registry never blocks resolution as long as at least one configured registry (or a configured local override) has the answer.
Index ¶
- Variables
- func FetchTS11Schemas(ctx context.Context, httpClient *http.Client, endpointURL string) ([]TS11Document, []SkippedDocument, error)
- func FetchTS11SchemasFromFirstPage(ctx context.Context, httpClient *http.Client, endpointURL string, ...) ([]TS11Document, []SkippedDocument, error)
- type Client
- type Config
- type LocalEntry
- type LocalSource
- type LogicalRegistry
- type MultiRegistryClient
- type RegistryConfig
- type Resolved
- type SkipReason
- type SkippedDocument
- type TS11Document
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("ts11client: not found")
ErrNotFound is returned (wrapped) when no configured local override or registry has an entry for the requested vct/doctype.
Functions ¶
func FetchTS11Schemas ¶
func FetchTS11Schemas(ctx context.Context, httpClient *http.Client, endpointURL string) ([]TS11Document, []SkippedDocument, error)
FetchTS11Schemas fetches every page of a TS11 /api/v1/schemas.json endpoint (following pagination to exhaustion) and every schema's declared format documents.
This is a stateless bulk operation, unlike ResolveVCT/ResolveDoctype: it has no cache and no local-override layer, since callers that need a poll-and-store model of their own (rather than per-key lazy resolution) already have their own storage/caching for exactly that - this just does the network fetch/parse/paginate mechanics for them.
A single schema or format document that fails to fetch or parse is skipped, not fatal - matching how a partial catalog is still useful - but is still reported via the returned skipped slice so callers can log or monitor individual failures. Only a failure fetching or parsing the first page fails the whole call.
func FetchTS11SchemasFromFirstPage ¶
func FetchTS11SchemasFromFirstPage(ctx context.Context, httpClient *http.Client, endpointURL string, firstPageBody []byte) ([]TS11Document, []SkippedDocument, error)
FetchTS11SchemasFromFirstPage is FetchTS11Schemas for callers that already fetched endpointURL's first-page body themselves - e.g. as part of their own response-format auto-detection, before knowing this was a TS11 schemas.json response. It reuses firstPageBody instead of fetching endpointURL a second time, and only fetches subsequent pages (if any).
Types ¶
type Client ¶
type Client interface {
// ResolveVCT resolves an SD-JWT VC Type Metadata document by its vct
// claim value. Returns an error wrapping ErrNotFound if nothing has it.
ResolveVCT(ctx context.Context, vct string) (*Resolved, error)
// ResolveDoctype resolves an mdoc MDDL metadata document by its
// doctype value. Returns an error wrapping ErrNotFound if nothing has it.
ResolveDoctype(ctx context.Context, doctype string) (*Resolved, error)
}
Client resolves credential metadata by vct (SD-JWT VC) or doctype (mdoc), from local overrides and/or one or more TS11 registries.
type Config ¶
type Config struct {
// Registries is an ordered list of logical (independent) registries.
// A later entry overrides an earlier one for the same key - the same
// convention a deployment-local registry uses to extend or override a
// shared upstream one - so resolution tries registries from the end
// of the list backwards, stopping at the first hit. Racing
// (happy-eyeballs, first-hit-wins) only ever happens within a single
// LogicalRegistry's Mirrors, never across distinct entries in this
// list - see LogicalRegistry's doc comment for why.
Registries []LogicalRegistry
// Local, if set, is checked first (synchronously, no network) and
// always wins over any registry - it exists so an existing
// vendored-local-file configuration keeps working unchanged when
// registries are introduced alongside it.
Local *LocalSource
// RefreshInterval controls how long a registry's discovery index (and
// derived doctype index) is trusted before being re-fetched. Zero
// means fetch once and cache forever (matches "always serve from
// cache" as the default - there is no time-based invalidation unless
// this is set).
RefreshInterval time.Duration
// HTTPClient is used for all registry requests. Defaults to
// http.DefaultClient if nil.
HTTPClient *http.Client
}
Config configures a MultiRegistryClient.
type LocalEntry ¶
type LocalEntry struct {
VCT string // set for an SD-JWT VC Type Metadata document
Doctype string // set for an mdoc MDDL metadata document
Data []byte
}
LocalEntry is one statically-configured metadata document - the caller's existing "vendored local file" behavior, expressed as data rather than a file path so callers can load it however they already do (embed, disk, config). Exactly one of VCT/Doctype should be set, matching which format Data holds.
type LocalSource ¶
type LocalSource struct {
// contains filtered or unexported fields
}
LocalSource is a fixed set of metadata documents that never expire and are never re-fetched - it exists so a deployment's existing local-file configuration keeps working unchanged when a MultiRegistryClient is introduced alongside it: a LocalSource entry behaves as if permanently present in the cache, and is always checked (and always wins) before any registry is consulted.
func NewLocalSource ¶
func NewLocalSource(entries ...LocalEntry) (*LocalSource, error)
NewLocalSource builds a LocalSource from a fixed list of entries.
func (*LocalSource) ResolveDoctype ¶
ResolveDoctype returns the locally-configured document for doctype, if any.
func (*LocalSource) ResolveVCT ¶
ResolveVCT returns the locally-configured document for vct, if any.
type LogicalRegistry ¶
type LogicalRegistry struct {
// Mirrors is the set of endpoints serving this logical registry's
// content. At least one is required.
Mirrors []RegistryConfig
}
LogicalRegistry is one independent TS11 registry, optionally served by more than one mirror endpoint holding equivalent content. Mirrors are queried concurrently and race - happy-eyeballs, first hit wins - since they're expected to hold the same data. Distinct LogicalRegistry entries are NOT raced against each other: they may hold different, non- overlapping credentials (e.g. one org's own registry plus a federation partner's), so racing them would be meaningless when only one of them actually has a given key. See Config.Registries for how they combine.
type MultiRegistryClient ¶
type MultiRegistryClient struct {
// contains filtered or unexported fields
}
MultiRegistryClient implements Client over a LocalSource (checked first, always wins) plus zero or more logical TS11 registries.
func New ¶
func New(cfg Config) (*MultiRegistryClient, error)
New builds a MultiRegistryClient from cfg. At least one of cfg.Local or cfg.Registries must be set.
func (*MultiRegistryClient) ResolveDoctype ¶
func (c *MultiRegistryClient) ResolveDoctype(ctx context.Context, doctype string) (*Resolved, error)
ResolveDoctype implements Client.
func (*MultiRegistryClient) ResolveVCT ¶
ResolveVCT implements Client.
type RegistryConfig ¶
type RegistryConfig struct {
// BaseURL is the registry's origin, e.g. "https://registry.siros.org"
// (no trailing slash required either way).
BaseURL string
// Timeout bounds each HTTP request to this registry. Defaults to
// defaultTimeout if zero.
Timeout time.Duration
}
RegistryConfig identifies one registry to query.
type Resolved ¶
type Resolved struct {
Entry schemameta.Entry
Format schemameta.Format
Data []byte
Source string // "local", or the base URL of the registry that answered
}
Resolved is the result of a successful resolution: the raw bytes of the resolved document, plus which format it is and where it came from. Callers decode Data into their own VCTM/MDDL type - this package does not impose one, matching how the rest of this document's format is already owned by each consumer.
type SkipReason ¶
type SkipReason int
SkipReason categorizes why FetchTS11Schemas skipped an item, so callers can log/monitor each distinctly instead of treating every skip as an identical generic failure.
const ( // SkipReasonNoSchemaURIs means a schema declared no schemaURIs at // all, so no document fetch was even attempted. SkipReasonNoSchemaURIs SkipReason = iota // SkipReasonFetchFailed means a specific format document's fetch // (or read) failed. SkipReasonFetchFailed )
type SkippedDocument ¶
type SkippedDocument struct {
Reason SkipReason
SchemaID string
FormatIdentifier string
URI string
Err error
}
SkippedDocument records one schema/format document that couldn't be fetched or was otherwise skipped, so callers can still log or monitor individual failures even though FetchTS11Schemas itself treats them as non-fatal.
type TS11Document ¶
type TS11Document struct {
Schema schemameta.SchemaMeta
FormatIdentifier string
URI string
Data []byte
}
TS11Document is one resolved (schema, format) document from a paginated TS11 /api/v1/schemas.json endpoint - a schema commonly declares more than one format (e.g. both "dc+sd-jwt" and "mso_mdoc") for the same logical credential, so one SchemaMeta can produce several TS11Documents.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package schemameta holds the wire types for a TS11 registry's published discovery index and per-credential documents, matching the JSON shapes generated by registry-cli (https://github.com/sirosfoundation/registry-cli) and served statically by registry.siros.org and compatible registries.
|
Package schemameta holds the wire types for a TS11 registry's published discovery index and per-credential documents, matching the JSON shapes generated by registry-cli (https://github.com/sirosfoundation/registry-cli) and served statically by registry.siros.org and compatible registries. |