Help us shape the future of Go! Take the 2026 Go Developer Survey

impersonate

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 25, 2026 License: MIT Imports: 24 Imported by: 0

README

Arandu

Arandu Impersonate

An operator goes into a user's account from the admin, without signing out of their own, acts there as the user — sees what the user sees, changes what the user can change — and comes back with one click. Every visit has a deadline, and everything is recorded in arandu-activitylog under the operator's name, with the account it was done in.

It is laravel-impersonate for Arandu, and the "inspecionar" of the team's consoles: the platform's manager -- never a member an account invited -- takes a user's place. Who may impersonate is a Policy, who may be impersonated is the application's answer, nobody impersonates from inside an account, and nothing done inside goes unlogged.

Parity with laravel-impersonate

laravel-impersonate here
canImpersonate() the policy: the action impersonate.take (ImpersonateTake) granted through arandu-permission, or the role impersonate.impersonator in an application that fills roles itself
canBeImpersonated() Config.CanBeImpersonated; an impersonator's account is never impersonated
no impersonating yourself, nor from inside an impersonation the same refusals
routes impersonate and impersonate.leave, take_redirect_to, leave_redirect_to the same names; TakeRedirectTo, LeaveRedirectTo
ProtectFromImpersonation middleware Protect()
@impersonating in Blade view.Impersonation in the layout (hesape v0.58.0)
TakeImpersonation, LeaveImpersonation events entries in arandu-activitylog, with every act done inside
-- a deadline (Guard()), the history, acting or only viewing

How it works

  • POST /impersonate/take/{id} — the operator goes into the account. The session is rotated to the account's owner with the operator kept as the one acting (hesape auth.ImpersonateActing), so the very same browser is now inside the account and every Grant writes as the owner would. The visit is recorded as an impersonation with a deadline (one hour by default), and as the entry impersonation.taken in the impersonate log.
  • Inside the account, every entry the application records names the operator as its causer and carries the impersonation property — by, on_behalf_of, mode: acting — which arandu-activitylog v0.3.0 adds by itself.
  • POST /impersonate/leave (route name impersonate.leave) — the operator comes back: the session is rotated to their own subject, the impersonation is closed and impersonation.left is recorded.
  • Guard() — past the deadline, the next request inside the account takes the operator back, closes the impersonation and records impersonation.expired.
  • GET /impersonate/history — the impersonations, newest first, for an impersonator.

Protect what only the owner does

Mount Protect() on the routes an impersonator must not reach even acting as the user -- the password, the e-mail, the two factors, deleting the account, paying:

	security := r.Group("/painel/seguranca", middleware.RequireAuth(sessions), impersonateModule.Protect())

A browser is sent back where it came from; a JSON client is answered 403.

The bar

Every page built with view.New (hesape v0.58.0) knows it is drawn for an operator inside somebody's account and where the way back is. The application's layout draws the bar from view.Impersonation:

@if(impersonating(.))
	<div class="..." role="status">
		Você está na conta deste usuário como administrador.
		<form method="post" action="{{ leaveLink(.) }}">@csrf<button>Voltar ao administrador</button></form>
	</div>
@endif

with, in the layout's @go block:

func impersonating(d hview.Layout) bool {
	i, ok := d.(hview.Impersonation)
	return ok && i.IsImpersonating()
}

Install

go get github.com/hyz-is/arandu-activitylog@v0.6.0
go get github.com/hyz-is/arandu-impersonate

It needs Go 1.26.10, Framework v0.66.0 and hesape v0.85.0 or newer.

Wire it

In bootstrap/app.go, after the session store and the activity log exist:

	impersonateModule, err := impersonate.New(impersonate.Config{
		Targets:  impersonate.TargetsFunc(users.ImpersonationTarget), // the account as its owner signs in
		Activity: activityModule.Logger(),
		TakeRedirectTo:  "/painel",
		LeaveRedirectTo:   "/admin/usuarios",
	}, db, sessions)
	if err != nil {
		return App{}, err
	}

register impersonateModule in k.Register(...), mount the guard after RequireAuth on the routes reachable from inside an account:

	panel := r.Group("/painel", middleware.RequireAuth(sessions), impersonateModule.Guard())

and run aru migrate. Targets answers the subject the account's owner signs in as — identifier, tenant, roles, actions — because the package keeps no users. The session store needs the application's SubjectResolver (sessions.ResolveSubjects, which the skeleton installs): the session keeps who is inside whose account, and the resolver reads the roles and actions of both on every request.

Who may be impersonated

	CanBeImpersonated: func(ctx context.Context, target security.Subject) bool {
		return !target.HasRole("super-admin")
	},

Give people access

Going into accounts and reading the history belong to the platform's managers -- never to a role an account gives its invited members. The policy opens ImpersonateTake and ImpersonateHistory to a subject that either

  • holds the action itself, impersonate and impersonate.history: this is how an application whose permissions arandu-permission administers grants it, because arandu-permission fills the Subject's Actions and never its Roles. Splice impersonate.Actions() into permission.Config.Actions, put both in the platform managers' group, and pass Middleware: []func(http.Handler) http.Handler{permissionModule.Roles()} so the module's routes see the actions it resolves on each request; or
  • carries the role impersonate.impersonator, in an application that decides by role and fills Roles itself.

Each action opens only itself: impersonate alone does not read the history. An account that holds the role or the action impersonate.take is an operator's (impersonate.IsOperator) and is never impersonated.

Configuration

field required meaning
Targets yes loads the account an operator goes into.
Activity yes arandu-activitylog's logger.
Prefix no where the routes are mounted. Defaults to /impersonate.
TakeRedirectTo no where the operator lands inside the account. Defaults to /.
LeaveRedirectTo no where they land back in their own. Defaults to /.
TTL no how long a visit lasts. Defaults to one hour; at most 12 hours.
UserType no the kind the activity log names accounts by. Defaults to user.
CanBeImpersonated no whether an account may be gone into at all. Nil lets every account through except an operator's.
Middleware no runs on the module's routes after RequireAuth: arandu-permission's Roles(), where it administers the actions.
RequireReason no refuses going in without a reason. The take route reads the form field reason; a refusal is validation.Errors on that field, which the router answers as a form's refusal (the flash and back, or 422 for JSON). A reason given is kept on the impersonation and on the entry of going in, with or without this.

The data path

Impersonation embeds model.Model and declares its table beside it. aru model:build generates ImpersonationQuery.go with Impersonations(db), committed and never edited by hand; aru model:build --check fails when it is out of date. ImpersonateService follows validate -> security.Authorize -> Grant -> Model terminal in every exported method, which the unit suite audits, and every route sits behind RequireAuth.

Example

go run -tags example ./example

It opens SQLite in a temporary directory, migrates arandu-activitylog and this package, and drives one browser: the operator goes into a user's account, changes a setting there, comes back, and the activity log is printed with every entry under the operator's name. It leaves nothing behind. The build tag is there so that installing this package never compiles it.

Tests

GOWORK=off go test ./... -race

The feature suite runs the whole visit in one browser against SQLite: going in, acting as the owner, coming back, the deadline, and every refusal, with the activity log's entries checked; the rules were checked by mutation.

The widening of the visits' instants is a statement PostgreSQL runs and SQLite has no use for, so it is proven against a server when one is named:

ARANDU_TEST_POSTGRES_DSN=postgres://user:password@localhost:5432/impersonate_test?sslmode=disable \
  GOWORK=off go test ./... -race

Without it, that one test is skipped.

Licence

MIT. See LICENSE.md.

Documentation

Overview

Package impersonate is an Arandu module that lets an impersonator -- the platform's manager -- take a user's place without signing out of their own account, act there as the user, and leave again, as laravel-impersonate does. The visit is held to a deadline, routes the application marks sensitive are protected while it lasts, and everything is recorded in arandu-activitylog under the impersonator's name.

module.go   -> registration, routes, handlers, the guard and the migration
config.go   -> what the application passes in
model.go    -> the impersonation
policy.go   -> who may go into which account
service.go  -> going in, coming back, the deadline, the history

The bar that tells the operator whose account they are in is drawn by the application's layout from hesape's view.Impersonation, which every page built with view.New answers; its button posts to the route named impersonate.leave, which this module registers.

Index

Constants

View Source
const (
	// DefaultPrefix is where the routes are mounted when Config leaves Prefix
	// empty.
	DefaultPrefix = "/impersonate"
	// DefaultTTL is how long an impersonation lasts before it lapses.
	DefaultTTL = time.Hour
	// MaxTTL is the longest an impersonation may be configured to last.
	MaxTTL = 12 * time.Hour
	// MaxReasonLen is the longest reason, in characters, an impersonation
	// keeps.
	MaxReasonLen = 500
	// ReasonRequiredMessage is what a refused reason says on its field.
	ReasonRequiredMessage = "Informe o motivo da entrada na conta (até 500 caracteres)."
	// DefaultUserType is the kind the activity log names an account by.
	DefaultUserType = "user"
	// LogName is the activity log the package's own entries go in.
	LogName = "impersonate"
)
View Source
const (
	// EndLeft is the operator going back to their own account.
	EndLeft = "left"
	// EndExpired is the deadline passing.
	EndExpired = "expired"
)

The reasons an impersonation ends.

View Source
const (
	// ImpersonateTake is an operator going into somebody's account.
	ImpersonateTake security.Action = "impersonate.take"
	// ImpersonateLeave is the operator going back to their own account.
	ImpersonateLeave security.Action = "impersonate.leave"
	// ImpersonateHistory is reading who went into which account, and when.
	ImpersonateHistory security.Action = "impersonate.history"
)

The actions of the package. Constants rather than strings at the call site: a typo in an action name would silently authorize nothing, or worse, everything.

View Source
const ImpersonatorRole = "impersonate.impersonator"

ImpersonatorRole is the role that may go into other people's accounts and read the history, for an application that decides by role and fills the Subject's Roles itself.

An application whose permissions are administered by arandu-permission grants the actions instead: arandu-permission fills the Subject's Actions and never its Roles, so ImpersonateTake and ImpersonateHistory are what its platform managers' group holds. The policy accepts either, and an account that holds the role or ImpersonateTake is an operator's, never impersonated.

Variables

View Source
var (
	// ErrNotImpersonable is an operator going into another operator's
	// account.
	ErrNotImpersonable = fmt.Errorf("impersonate: this account cannot be impersonated: %w", security.ErrForbidden)
	// ErrNotImpersonating is a leave asked by somebody who is in no account but
	// their own.
	ErrNotImpersonating = fmt.Errorf("impersonate: nobody is inside another account here: %w", security.ErrForbidden)
)

The refusals of an impersonation the policy cannot see, because they are about the account and not the impersonation. Each wraps ErrForbidden.

View Source
var ErrNotFound = fmt.Errorf("impersonate: record not found: %w", model.ErrModelNotFound)

ErrNotFound is a record the caller may not see or that does not exist. It wraps model.ErrModelNotFound, which the router answers with 404.

Functions

func Actions added in v0.2.0

func Actions() []security.Action

Actions are the actions an application grants through arandu-permission, spliced into its permission.Config.Actions. ImpersonateLeave is not one of them: nobody is granted leaving, the operator who went in always may.

func IsOperator added in v0.2.0

func IsOperator(s security.Subject) bool

IsOperator reports whether the subject may go into other people's accounts: it carries ImpersonatorRole, or holds the action ImpersonateTake. Such an account is never impersonated itself.

Types

type Config

type Config struct {
	// Prefix is the path the routes are mounted under. Empty means
	// DefaultPrefix.
	Prefix string

	// Targets loads the account an operator goes into. Required.
	Targets Targets

	// Activity is arandu-activitylog's logger. Required: going in, coming
	// back and the deadline passing are entries, and everything done inside
	// the account is recorded under the operator's name by the log itself.
	Activity *activitylog.Logger

	// TakeRedirectTo is where the impersonator lands inside the account, and
	// LeaveRedirectTo where they land back in their own -- laravel-impersonate's
	// take_redirect_to and leave_redirect_to. Empty means "/".
	TakeRedirectTo  string
	LeaveRedirectTo string

	// TTL is how long an impersonation lasts. Zero means DefaultTTL; above
	// MaxTTL is refused.
	TTL time.Duration

	// UserType is the kind the activity log names accounts by, the one the
	// application's own entries use. Empty means DefaultUserType.
	UserType string

	// Middleware runs on the module's routes after RequireAuth, in order. An
	// application whose permissions arandu-permission administers mounts its
	// Roles() here: RequireAuth puts the subject as the session stored it --
	// without the actions arandu-permission resolves on each request -- and
	// without the actions the policy refuses a platform manager who holds
	// impersonate.take. Nil runs nothing more.
	Middleware []func(http.Handler) http.Handler

	// RequireReason refuses going into an account without a reason: the take
	// route reads it from the form field "reason", Take refuses an empty one
	// as validation.Errors on that field, and the reason is kept on the impersonation and on
	// its activity entry. False takes a reason when one is given and goes in
	// without one otherwise.
	RequireReason bool

	// CanBeImpersonated is the application's answer to whether an account may
	// be impersonated at all -- laravel-impersonate's canBeImpersonated: a
	// super admin's account, an account under legal hold. Nil lets every
	// account through, except an operator's -- one IsOperator answers true for
	// -- which is never impersonated whatever this answers.
	CanBeImpersonated func(ctx context.Context, target security.Subject) bool
}

Config is everything the module needs from the application.

func (Config) Validate

func (c Config) Validate() error

Validate reports the first setting that cannot work.

type Flag

type Flag bool

Flag is a yes-or-no stored as 0 or 1, which every engine reads the same.

func (*Flag) Scan

func (f *Flag) Scan(value any) error

Scan reads a flag from whatever the engine answers.

func (Flag) Value

func (f Flag) Value() (driver.Value, error)

Value writes the flag as 0 or 1.

type HistoryQuery

type HistoryQuery struct {
	ActorID  string
	TargetID string
	Status   Status
	Page     int
	PerPage  int
}

HistoryQuery narrows the history. Page counts from one.

type ImpersonatePolicy

type ImpersonatePolicy struct{}

ImpersonatePolicy is the only authority over who goes into whose account.

It denies unless a rule below allows. An operator goes into accounts of their own tenant and reads its history; whoever an impersonation names as its operator ends it. Whether the account itself may be gone into -- another operator's, the operator's own -- is the service's refusal, because the policy sees the impersonation and not the account.

func (ImpersonatePolicy) Can

Can decides whether the subject may perform the action on the record.

func (ImpersonatePolicy) Writes added in v0.4.0

Writes reports whether a Grant issued for the action may change anything.

Going in and coming back write the impersonation; everything else reads, so the Grant issued to read the history cannot insert, update or delete a row whatever the code holding it does next, and an action added without a decision here fails the first time it tries to write.

type ImpersonateService

type ImpersonateService struct {
	// contains filtered or unexported fields
}

ImpersonateService is the package's use cases. It owns the database handle; every exported method asks the policy before it reads or writes.

func NewImpersonateService

func NewImpersonateService(db *data.DB) *ImpersonateService

NewImpersonateService returns the use cases over a database handle. New wires the rest.

func (*ImpersonateService) Find

Find answers one impersonation, for an operator.

func (*ImpersonateService) History

History is a page of impersonations, newest first, and how many there are.

func (*ImpersonateService) Lapsed

func (s *ImpersonateService) Lapsed(ctx context.Context, current security.Subject) (bool, error)

Lapsed reports whether the impersonation the current subject is in has passed its deadline, or no longer exists as open. A subject that is in no impersonation has nothing lapsed.

func (*ImpersonateService) Leave

Leave takes the operator inside an account back to their own: the answer is the operator's own subject, for the session, and the impersonation it closed. reason is EndLeft or EndExpired.

func (*ImpersonateService) OpenNow

func (s *ImpersonateService) OpenNow(ctx context.Context, actor security.Subject) ([]*Impersonation, error)

OpenNow lists the impersonations under way: who is inside which account right now, and until when.

func (*ImpersonateService) Take

func (s *ImpersonateService) Take(ctx context.Context, actor security.Subject, targetID, reason string) (security.Subject, *Impersonation, error)

Start takes an operator into somebody's account: the answer is the subject the session carries from then on -- the account's owner, with the operator kept as the one acting, able to change it -- and the impersonation that records the visit.

The operator may not go into their own account, into another operator's, or anywhere from inside an account already.

reason is why the operator goes in, kept on the impersonation and on its activity entry. Where Config.RequireReason is set an empty one is refused, and one longer than MaxReasonLen always is, as validation.Errors on the field "reason", which the router answers as a form's refusal.

type Impersonation

type Impersonation struct {
	model.Model

	ID       string `db:"id"`
	TenantID string `db:"tenant_id"`

	// ActorID is the operator; TargetID the account they went into.
	ActorID  string `db:"actor_id"`
	TargetID string `db:"target_id"`

	// Acting says the operator could change the account, and not only look.
	Acting Flag `db:"acting"`

	// Status is open while the operator is inside, closed once they left or
	// the deadline passed. ClosedAt and EndReason mean something only once it
	// is closed.
	Status    Status    `db:"status"`
	StartedAt time.Time `db:"started_at"`
	ExpiresAt time.Time `db:"expires_at"`
	ClosedAt  time.Time `db:"closed_at"`
	EndReason string    `db:"end_reason"`

	// Reason is why the operator went in, as they wrote it; empty when the
	// application does not ask for one.
	Reason string `db:"reason"`

	CreatedAt time.Time `db:"created_at"`
	UpdatedAt time.Time `db:"updated_at"`
}

Impersonation is one time an operator went into somebody's account: who, whose account, whether they could change it, when it began, when it lapses, and how it ended.

It is the package's own record of the visit, kept so the session can be held to a deadline and so the list of who went where can be read without reading the whole activity log. What the operator did inside the account is in the activity log, under their name, and not here.

func (Impersonation) Expired

func (i Impersonation) Expired(now time.Time) bool

Expired reports whether the deadline has passed at now.

func (*Impersonation) Fresh

func (row *Impersonation) Fresh(ctx context.Context, g auth.Grant, with ...string) (*Impersonation, error)

Fresh reads the row again, as a new Impersonation; it shadows the untyped one the embedded model promotes.

func (*Impersonation) Replicate

func (row *Impersonation) Replicate(except ...string) (*Impersonation, error)

Replicate returns an unsaved copy of the row without its key; it shadows the untyped one the embedded model promotes.

type ImpersonationCollection

type ImpersonationCollection []*Impersonation

ImpersonationCollection is rows of Impersonation, as a query returns them.

func ImpersonationCollectionOf

func ImpersonationCollectionOf(rows model.Rows) ImpersonationCollection

ImpersonationCollectionOf converts rows of the table of Impersonation. A nil input is a nil collection.

func (ImpersonationCollection) Contains

func (c ImpersonationCollection) Contains(key any) bool

func (ImpersonationCollection) Except

func (ImpersonationCollection) Find

func (ImpersonationCollection) FindOrFail

func (c ImpersonationCollection) FindOrFail(key any) (*Impersonation, error)

func (ImpersonationCollection) Fresh

func (ImpersonationCollection) Load

func (c ImpersonationCollection) Load(ctx context.Context, g auth.Grant, relations ...string) error

func (ImpersonationCollection) LoadCount

func (c ImpersonationCollection) LoadCount(ctx context.Context, g auth.Grant, relations ...string) error

func (ImpersonationCollection) LoadMissing

func (c ImpersonationCollection) LoadMissing(ctx context.Context, g auth.Grant, relations ...string) error

func (ImpersonationCollection) ModelKeys

func (c ImpersonationCollection) ModelKeys() []any

func (ImpersonationCollection) Only

func (ImpersonationCollection) Pluck

func (c ImpersonationCollection) Pluck(column string) []any

func (ImpersonationCollection) Rows

Rows converts the collection back to the core's rows.

func (ImpersonationCollection) ToArray

func (c ImpersonationCollection) ToArray() []map[string]any

func (ImpersonationCollection) Unique

type ImpersonationQuery

type ImpersonationQuery struct {
	// contains filtered or unexported fields
}

ImpersonationQuery is a query on the table of Impersonation.

The methods that build return the query, so they chain. The methods that run take a context and an auth.Grant, and return Impersonation rows or a value; there is no way to run one without a Grant.

func Impersonations

func Impersonations(db model.DB) *ImpersonationQuery

Impersonations starts a query on the table of Impersonation, through db.

Global scopes are on and, unless the table is Global, every statement is filtered by the tenant of the Grant its terminal takes.

func (*ImpersonationQuery) AddSelect

func (q *ImpersonationQuery) AddSelect(columns ...any) *ImpersonationQuery

func (*ImpersonationQuery) Avg

func (q *ImpersonationQuery) Avg(ctx context.Context, g auth.Grant, column any) (any, error)

func (*ImpersonationQuery) Base

func (q *ImpersonationQuery) Base() *model.Builder

Base returns the core builder the query forwards to. It is for code in this package -- a local scope in the custom block of model.go -- and for the factory, which builds rows through it.

func (*ImpersonationQuery) Chunk

func (q *ImpersonationQuery) Chunk(ctx context.Context, g auth.Grant, count int, callback func(ImpersonationCollection, int) (bool, error)) error

func (*ImpersonationQuery) Clone

Clone returns an independent copy of the query.

func (*ImpersonationQuery) Count

func (q *ImpersonationQuery) Count(ctx context.Context, g auth.Grant, columns ...any) (int64, error)

func (*ImpersonationQuery) Create

func (q *ImpersonationQuery) Create(ctx context.Context, g auth.Grant, attributes map[string]any) (*Impersonation, error)

func (*ImpersonationQuery) Cursor

func (*ImpersonationQuery) CursorPaginate

func (q *ImpersonationQuery) CursorPaginate(ctx context.Context, g auth.Grant, perPage int, cursor *pagination.Cursor, opts pagination.Options, columns ...any) (ImpersonationCollection, *pagination.CursorPage, error)

func (*ImpersonationQuery) Decrement

func (q *ImpersonationQuery) Decrement(ctx context.Context, g auth.Grant, column string, amount any, extra map[string]any) (int64, error)

func (*ImpersonationQuery) Delete

func (q *ImpersonationQuery) Delete(ctx context.Context, g auth.Grant) (int64, error)

func (*ImpersonationQuery) DoesntExist

func (q *ImpersonationQuery) DoesntExist(ctx context.Context, g auth.Grant) (bool, error)

func (*ImpersonationQuery) DoesntHave

func (q *ImpersonationQuery) DoesntHave(relation, boolean string, callback func(*query.Builder)) *ImpersonationQuery

func (*ImpersonationQuery) Each

func (q *ImpersonationQuery) Each(ctx context.Context, g auth.Grant, count int, callback func(*Impersonation, int) (bool, error)) error

func (*ImpersonationQuery) Exists

func (q *ImpersonationQuery) Exists(ctx context.Context, g auth.Grant) (bool, error)

func (*ImpersonationQuery) Find

func (q *ImpersonationQuery) Find(ctx context.Context, g auth.Grant, id any, columns ...any) (*Impersonation, error)

func (*ImpersonationQuery) FindMany

func (q *ImpersonationQuery) FindMany(ctx context.Context, g auth.Grant, ids []any, columns ...any) (ImpersonationCollection, error)

func (*ImpersonationQuery) FindOrFail

func (q *ImpersonationQuery) FindOrFail(ctx context.Context, g auth.Grant, id any, columns ...any) (*Impersonation, error)

func (*ImpersonationQuery) FindOrNew

func (q *ImpersonationQuery) FindOrNew(ctx context.Context, g auth.Grant, id any, columns ...any) (*Impersonation, error)

func (*ImpersonationQuery) First

func (q *ImpersonationQuery) First(ctx context.Context, g auth.Grant, columns ...any) (*Impersonation, error)

First returns the first row, or nil and no error when there is none.

func (*ImpersonationQuery) FirstOrCreate

func (q *ImpersonationQuery) FirstOrCreate(ctx context.Context, g auth.Grant, attributes, values map[string]any) (*Impersonation, error)

func (*ImpersonationQuery) FirstOrFail

func (q *ImpersonationQuery) FirstOrFail(ctx context.Context, g auth.Grant, columns ...any) (*Impersonation, error)

func (*ImpersonationQuery) FirstOrNew

func (q *ImpersonationQuery) FirstOrNew(ctx context.Context, g auth.Grant, attributes, values map[string]any) (*Impersonation, error)

func (*ImpersonationQuery) FirstWhere

func (q *ImpersonationQuery) FirstWhere(ctx context.Context, g auth.Grant, column any, args ...any) (*Impersonation, error)

func (*ImpersonationQuery) ForPage

func (q *ImpersonationQuery) ForPage(page, perPage int) *ImpersonationQuery

func (*ImpersonationQuery) ForceCreate

func (q *ImpersonationQuery) ForceCreate(ctx context.Context, g auth.Grant, attributes map[string]any) (*Impersonation, error)

func (*ImpersonationQuery) Get

Get runs the query and returns the rows.

func (*ImpersonationQuery) GroupBy

func (q *ImpersonationQuery) GroupBy(groups ...any) *ImpersonationQuery

func (*ImpersonationQuery) Has

func (q *ImpersonationQuery) Has(relation, operator string, count int, boolean string, callback func(*query.Builder)) *ImpersonationQuery

func (*ImpersonationQuery) Increment

func (q *ImpersonationQuery) Increment(ctx context.Context, g auth.Grant, column string, amount any, extra map[string]any) (int64, error)

func (*ImpersonationQuery) Insert

func (q *ImpersonationQuery) Insert(ctx context.Context, g auth.Grant, values ...map[string]any) (bool, error)

func (*ImpersonationQuery) InsertOrIgnore

func (q *ImpersonationQuery) InsertOrIgnore(ctx context.Context, g auth.Grant, values ...map[string]any) (bool, error)

func (*ImpersonationQuery) Join

func (q *ImpersonationQuery) Join(table any, first any, args ...any) *ImpersonationQuery

func (*ImpersonationQuery) Latest

func (q *ImpersonationQuery) Latest(column ...string) *ImpersonationQuery

func (*ImpersonationQuery) Limit

func (q *ImpersonationQuery) Limit(value int) *ImpersonationQuery

func (*ImpersonationQuery) Max

func (q *ImpersonationQuery) Max(ctx context.Context, g auth.Grant, column any) (any, error)

func (*ImpersonationQuery) Min

func (q *ImpersonationQuery) Min(ctx context.Context, g auth.Grant, column any) (any, error)

func (*ImpersonationQuery) New

func (q *ImpersonationQuery) New() (*Impersonation, error)

New returns an empty Impersonation on the query's connection, not yet saved, filled with what WithAttributes recorded on the query.

func (*ImpersonationQuery) Offset

func (q *ImpersonationQuery) Offset(value int) *ImpersonationQuery

func (*ImpersonationQuery) Oldest

func (q *ImpersonationQuery) Oldest(column ...string) *ImpersonationQuery

func (*ImpersonationQuery) OrDoesntHave

func (q *ImpersonationQuery) OrDoesntHave(relation string) *ImpersonationQuery

func (*ImpersonationQuery) OrHas

func (q *ImpersonationQuery) OrHas(relation, operator string, count int) *ImpersonationQuery

func (*ImpersonationQuery) OrWhere

func (q *ImpersonationQuery) OrWhere(column any, args ...any) *ImpersonationQuery

OrWhere adds an or-where clause; a func(*ImpersonationQuery) in place of the column adds a group.

func (*ImpersonationQuery) OrWhereDoesntHave

func (q *ImpersonationQuery) OrWhereDoesntHave(relation string, callback func(*query.Builder)) *ImpersonationQuery

func (*ImpersonationQuery) OrWhereHas

func (q *ImpersonationQuery) OrWhereHas(relation string, callback func(*query.Builder)) *ImpersonationQuery

func (*ImpersonationQuery) OrWhereNot

func (q *ImpersonationQuery) OrWhereNot(column any, args ...any) *ImpersonationQuery

OrWhereNot adds an or-joined negated where clause, or a negated group.

func (*ImpersonationQuery) OrWhereRelation

func (q *ImpersonationQuery) OrWhereRelation(relation string, column any, args ...any) *ImpersonationQuery

func (*ImpersonationQuery) OrderBy

func (q *ImpersonationQuery) OrderBy(column any, direction ...string) *ImpersonationQuery

func (*ImpersonationQuery) OrderByDesc

func (q *ImpersonationQuery) OrderByDesc(column any) *ImpersonationQuery

func (*ImpersonationQuery) Paginate

func (q *ImpersonationQuery) Paginate(ctx context.Context, g auth.Grant, perPage, page int, opts pagination.Options, columns ...any) (ImpersonationCollection, *pagination.LengthAwarePage, error)

func (*ImpersonationQuery) Pluck

func (q *ImpersonationQuery) Pluck(ctx context.Context, g auth.Grant, column string) ([]any, error)

func (*ImpersonationQuery) Select

func (q *ImpersonationQuery) Select(columns ...any) *ImpersonationQuery

func (*ImpersonationQuery) SelectRaw

func (q *ImpersonationQuery) SelectRaw(expression string, bindings ...any) *ImpersonationQuery

func (*ImpersonationQuery) SimplePaginate

func (q *ImpersonationQuery) SimplePaginate(ctx context.Context, g auth.Grant, perPage, page int, opts pagination.Options, columns ...any) (ImpersonationCollection, *pagination.Page, error)

func (*ImpersonationQuery) Sole

func (q *ImpersonationQuery) Sole(ctx context.Context, g auth.Grant, columns ...any) (*Impersonation, error)

func (*ImpersonationQuery) SoleValue

func (q *ImpersonationQuery) SoleValue(ctx context.Context, g auth.Grant, column string) (any, error)

func (*ImpersonationQuery) Sum

func (q *ImpersonationQuery) Sum(ctx context.Context, g auth.Grant, column any) (any, error)

func (*ImpersonationQuery) Touch

func (q *ImpersonationQuery) Touch(ctx context.Context, g auth.Grant, column ...string) (int64, error)

func (*ImpersonationQuery) Update

func (q *ImpersonationQuery) Update(ctx context.Context, g auth.Grant, values map[string]any) (int64, error)

func (*ImpersonationQuery) UpdateOrCreate

func (q *ImpersonationQuery) UpdateOrCreate(ctx context.Context, g auth.Grant, attributes, values map[string]any) (*Impersonation, error)

func (*ImpersonationQuery) Upsert

func (q *ImpersonationQuery) Upsert(ctx context.Context, g auth.Grant, values []map[string]any, uniqueBy, update []string) (int64, error)

func (*ImpersonationQuery) Value

func (q *ImpersonationQuery) Value(ctx context.Context, g auth.Grant, column string) (any, error)

func (*ImpersonationQuery) ValueOrFail

func (q *ImpersonationQuery) ValueOrFail(ctx context.Context, g auth.Grant, column string) (any, error)

func (*ImpersonationQuery) Where

func (q *ImpersonationQuery) Where(column any, args ...any) *ImpersonationQuery

Where adds a where clause; a func(*ImpersonationQuery) in place of the column adds a group.

func (*ImpersonationQuery) WhereBelongsTo

func (q *ImpersonationQuery) WhereBelongsTo(relationshipName string, related ...model.Entity) *ImpersonationQuery

func (*ImpersonationQuery) WhereBetween

func (q *ImpersonationQuery) WhereBetween(column any, from, to any) *ImpersonationQuery

func (*ImpersonationQuery) WhereColumn

func (q *ImpersonationQuery) WhereColumn(first any, args ...any) *ImpersonationQuery

func (*ImpersonationQuery) WhereDoesntHave

func (q *ImpersonationQuery) WhereDoesntHave(relation string, callback func(*query.Builder)) *ImpersonationQuery

func (*ImpersonationQuery) WhereExists

func (q *ImpersonationQuery) WhereExists(callback func(*query.Builder)) *ImpersonationQuery

func (*ImpersonationQuery) WhereHas

func (q *ImpersonationQuery) WhereHas(relation string, callback func(*query.Builder)) *ImpersonationQuery

func (*ImpersonationQuery) WhereHasCount

func (q *ImpersonationQuery) WhereHasCount(relation string, callback func(*query.Builder), operator string, count int) *ImpersonationQuery

func (*ImpersonationQuery) WhereIn

func (q *ImpersonationQuery) WhereIn(column any, values []any) *ImpersonationQuery

func (*ImpersonationQuery) WhereKey

func (q *ImpersonationQuery) WhereKey(id any) *ImpersonationQuery

func (*ImpersonationQuery) WhereNot

func (q *ImpersonationQuery) WhereNot(column any, args ...any) *ImpersonationQuery

WhereNot adds a negated where clause, or a negated group.

func (*ImpersonationQuery) WhereNotExists

func (q *ImpersonationQuery) WhereNotExists(callback func(*query.Builder)) *ImpersonationQuery

func (*ImpersonationQuery) WhereNotIn

func (q *ImpersonationQuery) WhereNotIn(column any, values []any) *ImpersonationQuery

func (*ImpersonationQuery) WhereNotNull

func (q *ImpersonationQuery) WhereNotNull(columns ...any) *ImpersonationQuery

func (*ImpersonationQuery) WhereNull

func (q *ImpersonationQuery) WhereNull(columns ...any) *ImpersonationQuery

func (*ImpersonationQuery) WhereRelation

func (q *ImpersonationQuery) WhereRelation(relation string, column any, args ...any) *ImpersonationQuery

func (*ImpersonationQuery) With

func (q *ImpersonationQuery) With(relations ...string) *ImpersonationQuery

func (*ImpersonationQuery) WithAvg

func (q *ImpersonationQuery) WithAvg(relation, column string) *ImpersonationQuery

func (*ImpersonationQuery) WithCount

func (q *ImpersonationQuery) WithCount(relations ...string) *ImpersonationQuery

func (*ImpersonationQuery) WithExists

func (q *ImpersonationQuery) WithExists(relation string) *ImpersonationQuery

func (*ImpersonationQuery) WithMax

func (q *ImpersonationQuery) WithMax(relation, column string) *ImpersonationQuery

func (*ImpersonationQuery) WithMin

func (q *ImpersonationQuery) WithMin(relation, column string) *ImpersonationQuery

func (*ImpersonationQuery) WithSum

func (q *ImpersonationQuery) WithSum(relation, column string) *ImpersonationQuery

func (*ImpersonationQuery) Without

func (q *ImpersonationQuery) Without(relations ...string) *ImpersonationQuery

func (*ImpersonationQuery) WithoutGlobalScope

func (q *ImpersonationQuery) WithoutGlobalScope(identifier string) *ImpersonationQuery

func (*ImpersonationQuery) WithoutGlobalScopes

func (q *ImpersonationQuery) WithoutGlobalScopes(identifiers ...string) *ImpersonationQuery

type Module

type Module struct {
	// contains filtered or unexported fields
}

Module is what the application registers.

func New

func New(cfg Config, db *data.DB, sessions *security.SessionStore) (*Module, error)

New returns the module, or the reason it cannot be built.

func (*Module) Guard

func (m *Module) Guard() func(stdhttp.Handler) stdhttp.Handler

Guard ends an impersonation whose deadline passed: the next request of the operator inside the account is taken back to their own, and the end is recorded. The application mounts it after RequireAuth on the routes an operator can reach from inside an account -- its panel, usually:

panel := r.Group("/painel", middleware.RequireAuth(sessions), impersonateModule.Guard())

func (*Module) Migrations

func (m *Module) Migrations() []foundation.Migration

Migrations declares the schema this module owns.

func (*Module) Name

func (m *Module) Name() string

Name is the module identifier.

func (*Module) Protect

func (m *Module) Protect() func(stdhttp.Handler) stdhttp.Handler

Protect refuses a route to somebody impersonating -- laravel-impersonate's ProtectFromImpersonation. The application mounts it on what only the real owner may do even when the impersonator acts as them: changing the password or the e-mail, the two factors, deleting the account, paying. A browser is sent back where it came from, a client that asks for JSON is answered 403.

r.Group("/painel/seguranca", middleware.RequireAuth(sessions), impersonateModule.Protect())

func (*Module) Routes

func (m *Module) Routes(r *fhttp.Router)

Routes registers the module's routes, behind RequireAuth and then the application's Config.Middleware.

impersonate.leave is the name hesape's view.New links the way back by, so the bar every page draws posts here without the application spelling the path.

func (*Module) Service

func (m *Module) Service() *ImpersonateService

Service is the use cases, for an application that calls them from its own code. Every method asks the policy.

type Status

type Status string

Status is where an impersonation stands.

const (
	// Open is an operator inside the account now.
	Open Status = "open"
	// Closed is an impersonation that ended.
	Closed Status = "closed"
)

type Targets

type Targets interface {
	Target(ctx context.Context, tenant, userID string) (security.Subject, error)
}

Targets is the application's answer to "who is this account": the subject its owner signs in as -- identifier, tenant, roles, actions -- so the operator inside the account is exactly what the owner is. The package keeps no users of its own.

type TargetsFunc

type TargetsFunc func(ctx context.Context, tenant, userID string) (security.Subject, error)

TargetsFunc is a function that answers Targets.

func (TargetsFunc) Target

func (f TargetsFunc) Target(ctx context.Context, tenant, userID string) (security.Subject, error)

Target calls f.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL