Documentation
¶
Overview ¶
Package consolecall is the plumbing for the console's provider operations once they live in the provider's module (docs/decisions/0071, v1.76 D-v176-1 b): the console authenticates a person, snapshots who they are, and asks the module to do the work as that snapshot.
A call is a proto-JSON envelope, `{caller:{actor,roles,workspaces}, msg}`, over modcall. The module trusts the snapshot because only the caller class `console` may reach a console method: Handle registers with `Allow("console")` and nothing else, and Violations says which methods of a server do not. The transport names the class, never the envelope, so a payload cannot claim to be the console.
A refusal the person should read is a Problem in the reply, not a transport error: transport errors carry a code and no detail, since the caller is another trust domain.
Index ¶
- Constants
- Variables
- func Handle[Req, Resp proto.Message](s *modcall.Server, method string, ...)
- func HandleJSON[Req, Resp any](s *modcall.Server, method string, ...)
- func List() modcall.Option
- func Proxy[Req, Resp proto.Message](ctx context.Context, c modcall.Caller, module, method string, caller Caller, ...) (Resp, error)
- func ProxyJSON[Req, Resp any](ctx context.Context, c modcall.Caller, module, method string, caller Caller, ...) (Resp, error)
- func Violations(s *modcall.Server) []string
- func WithFacts(ctx context.Context, f *DirectoryFacts) context.Context
- type Caller
- type Callers
- type Directory
- type DirectoryFacts
- type Envelope
- type GroupFact
- type Problem
- type Reply
- type SourceDirectory
- type SourceGroup
- type UserFact
Constants ¶
const ( ModuleGitHub = "github" ModuleSlack = "slack" ModuleGoogle = "google" )
The modules a console operation can reach.
const ( SourcePerson = "person" SourceWorkload = "workload" SourceRecovery = "recovery" )
The values of Caller.Source.
const ( MaxDirectories = 256 MaxSourceGroups = 4000 MaxAddressFacts = 2000 )
The bounds of the facts of one call.
const Class = "console"
Class is the caller class of the console, the only one a console method answers.
const ListMaxBytes = 2 << 20
ListMaxBytes is the bound of a method that lists: above modcall.DefaultMaxBytes, well under modcall.HardMaxBytes.
const MethodPrefix = "console."
MethodPrefix starts the name of every console method, so a lint can tell them from the module's other methods.
Variables ¶
var ErrFacts = errors.New("the directory facts are not valid")
ErrFacts is a facts field that is not well formed.
Functions ¶
func Handle ¶
func Handle[Req, Resp proto.Message]( s *modcall.Server, method string, fn func(ctx context.Context, caller Caller, req Req) (Resp, error), opts ...modcall.Option, )
Handle registers a console method on a module's server. It answers the caller class Class and no other, whatever opts say about who may call: an modcall.Allow among them is overridden. A *Problem the function returns is told to the console as the reply's Problem; any other error is the transport's, with no detail.
func HandleJSON ¶
func HandleJSON[Req, Resp any]( s *modcall.Server, method string, fn func(ctx context.Context, caller Caller, req Req) (Resp, error), opts ...modcall.Option, )
HandleJSON registers a console method over Go values. It answers Class and no other, as Handle does.
func List ¶
List is the option of a method that lists: its bound is ListMaxBytes.
func Proxy ¶
func Proxy[Req, Resp proto.Message](ctx context.Context, c modcall.Caller, module, method string, caller Caller, req Req) (Resp, error)
Proxy calls one console method of a module as caller and returns its reply. A Problem the module told comes back as a *Problem error; any other failure is the transport's modcall.Error.
func ProxyJSON ¶
func ProxyJSON[Req, Resp any](ctx context.Context, c modcall.Caller, module, method string, caller Caller, req Req) (Resp, error)
ProxyJSON calls a console method registered by HandleJSON.
func Violations ¶
Violations lists the methods of s that break the console rule: a method named like a console method that answers anyone but Class, and a method that answers Class together with another class. A console method must answer the console alone because it trusts the caller snapshot; another class could send any snapshot it liked.
Types ¶
type Caller ¶
type Caller struct {
// Actor is who to write down: the address, else the subject.
Actor string `json:"actor"`
// Roles are the installation-wide roles held (the role and the roles it
// implies are not expanded: [access.Role.Implies] does that).
Roles []string `json:"roles,omitempty"`
// Workspaces are the roles held over one directory workspace each.
Workspaces map[string]string `json:"workspaces,omitempty"`
// Source says how the actor was established, so the trail names a workload
// or a recovery as what it is: "person" for an address, "workload", or
// "recovery"; empty for anyone else.
Source string `json:"source,omitempty"`
// Origin is the console's own address, where the provider sends the browser
// back (the redirect of an install). The console asserts it like the rest
// of the snapshot; a method that needs none ignores it.
Origin string `json:"origin,omitempty"`
}
Caller is the snapshot of who the console authorized, taken once per request. The module acts on it and re-checks nothing against the person's session.
type Callers ¶
Callers is how the console reaches each provider module: one modcall.Caller each, sending as the class Class.
type Directory ¶
type Directory struct {
ID string `json:"id"`
Primary string `json:"primary,omitempty"`
Served []string `json:"served,omitempty"`
// Authoritative is the served domains the directory answers for with
// confidence, sorted: what an owner is labelled with.
Authoritative []string `json:"authoritative,omitempty"`
}
Directory is one connected directory as an owner is chosen and shown.
type DirectoryFacts ¶
type DirectoryFacts struct {
// Directories are every connected directory: for choosing and showing an
// owner.
Directories []Directory `json:"directories,omitempty"`
// Sources are the directories' groups as a picker lists them, with
// SourcesError saying why they could not be read.
Sources []SourceDirectory `json:"sources,omitempty"`
SourcesError string `json:"sources_error,omitempty"`
// Groups and Users are, by lowercase address, what the call's own addresses
// are: whether a source is a group of a connected directory, and whether a
// listed person is an active user of one.
Groups map[string]GroupFact `json:"groups,omitempty"`
Users map[string]UserFact `json:"users,omitempty"`
}
DirectoryFacts are what a module may know of the connected directories for one call. A module reads no directory of its own (it holds no grant on the Google module's snapshot): the console, which already reads that snapshot, resolves what the method needs and sends it in the envelope. The module takes it as the console's word, like the caller snapshot, and refuses a field that is not well formed (DirectoryFacts.Validate).
Only what the methods ask is here, and each part is bounded.
func FactsFrom ¶
func FactsFrom(ctx context.Context) *DirectoryFacts
FactsFrom is the facts a call carries, nil when it carries none.
func (*DirectoryFacts) IDs ¶
func (f *DirectoryFacts) IDs() []string
IDs are the connected directories' ids, sorted.
func (*DirectoryFacts) Validate ¶
func (f *DirectoryFacts) Validate() error
Validate refuses a field that is oversized, names a directory twice or none, or says an address belongs to a directory the field does not list. A forged field can still lie within these rules, as the caller snapshot can: only the console class can send it.
type Envelope ¶
type Envelope struct {
Caller Caller `json:"caller"`
Msg json.RawMessage `json:"msg,omitempty"`
// Directory is what the console resolved of the connected directories for
// this call ([DirectoryFacts]); nil when the method needs none.
Directory *DirectoryFacts `json:"directory,omitempty"`
}
Envelope is a request on the wire: the caller and one proto message as proto-JSON.
type GroupFact ¶
type GroupFact struct {
Found bool `json:"found,omitempty"`
Workspace string `json:"workspace,omitempty"`
Err string `json:"err,omitempty"`
}
GroupFact is whether an address is a group of a connected directory, and of which. Err is the hub's own words when the address is not one.
type Problem ¶
type Problem struct {
// Code is the Connect code the console answers with, by its name
// ("failed_precondition"); empty is a failed precondition.
Code string `json:"code,omitempty"`
// Status is the HTTP status of the page the console renders for a provider
// callback that cannot finish. Zero is 409.
Status int `json:"status,omitempty"`
// Summary is one line.
Summary string `json:"summary"`
// Detail is what went wrong, safe to show the signed-in person.
Detail string `json:"detail,omitempty"`
// Hints are what to try.
Hints []string `json:"hints,omitempty"`
}
Problem is a refusal or a failure a person should read, told as data.
type Reply ¶
type Reply struct {
Msg json.RawMessage `json:"msg,omitempty"`
Problem *Problem `json:"problem,omitempty"`
}
Reply is the answer on the wire: a proto message, or a Problem.
type SourceDirectory ¶
type SourceDirectory struct {
Workspace string `json:"workspace"`
Domains []string `json:"domains,omitempty"`
Groups []SourceGroup `json:"groups,omitempty"`
}
SourceDirectory is a connected directory and its groups, as a picker lists them.
type SourceGroup ¶
SourceGroup is one group of a directory.
type UserFact ¶
type UserFact struct {
InDomain bool `json:"in_domain,omitempty"`
Authoritative bool `json:"authoritative,omitempty"`
Found bool `json:"found,omitempty"`
Suspended bool `json:"suspended,omitempty"`
Workspace string `json:"workspace,omitempty"`
Err string `json:"err,omitempty"`
}
UserFact is whether an address is an account a connected directory holds. InDomain is whether the address is in a domain a connected directory serves (Workspace says which), and Authoritative whether the directory can vouch for the rest just now.