package hostactors import ( "context" "github.com/carlosframework/platform/internal/release" ) type ConsoleInvitation struct { V int `json:"v"` Bucket string `json:"bucket"` Console Console `json:"console"` } func (d Directory) InviteConsole(ctx context.Context, signer release.Signer, c Console) error { o, err := d.Read(ctx) if err != nil { return err } if err := d.validateInvitedConsole(o, c.InstanceID, c); err != nil { return err } wire, err := release.SignRootEnvelope(signer, ConsoleInvitation{V: 1, Bucket: d.Bucket, Console: c}) if err != nil { return err } return release.CreateExact(ctx, d.Store, "control/host-console-invitations/"+c.InstanceID+".json", wire) } func (d Directory) InvitedConsole(ctx context.Context, o Observed, id string) (Console, error) { if !segment(id) { return Console{}, ErrRoster } wire, _, err := d.Store.Get(ctx, "control/host-console-invitations/"+id+".json") if err != nil { return Console{}, err } var invitation ConsoleInvitation if release.VerifyRootEnvelope(d.PublicKey, wire, &invitation) != nil || invitation.V != 1 || invitation.Bucket != d.Bucket { return Console{}, ErrRoster } if err := d.validateInvitedConsole(o, id, invitation.Console); err != nil { return Console{}, err } return invitation.Console, nil } func (d Directory) validateInvitedConsole(o Observed, id string, c Console) error { if !segment(id) || c.InstanceID != id { return ErrRoster } if _, exists := o.Roster.Consoles[id]; exists { return ErrRoster } next := Clone(o.Roster) next.Consoles[id] = c return next.Validate(d.Bucket) }