Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

authz source pure

Package authz provides flexible authorization control for privileged actions.

Overview

Package authz provides flexible authorization control for privileged actions.

Authorization Strategies

The package supports multiple authorization strategies:

  • Member-based: Single user or team of users
  • Contract-based: Async authorization (e.g., via DAO)
  • Auto-accept: Allow all actions
  • Drop: Deny all actions

Core Components

  • Authority interface: Base interface implemented by all authorities
  • Authorizer: Main wrapper object for authority management
  • MemberAuthority: Manages authorized addresses
  • ContractAuthority: Delegates to another contract
  • AutoAcceptAuthority: Accepts all actions
  • DroppedAuthority: Denies all actions

Quick Start

Example
 1// Initialize with contract deployer as authority
 2var member address(...)
 3var auth = authz.NewWithMembers(member)
 4
 5// Create functions that require authorization
 6func UpdateConfig(cur realm, newValue string) error {
 7	return auth.DoByPrevious(0, cur, "update_config", func() error {
 8		config = newValue
 9		return nil
10	})
11}

See example_test.gno for more usage examples.

Functions 7

func NewRestrictedContractAuthority

1func NewRestrictedContractAuthority(path string, handler PrivilegedActionHandler, proposer Authority) Authority
source

NewRestrictedContractAuthority creates a new contract authority with a proposer restriction.

SECURITY:

  • `handler` is the same Class-4 captured-callback risk as NewContractAuthority — runs synchronously inside Authorize with the consumer's authority. Register only trusted handler functions.
  • `proposer` is an open-interface input (Class-3 impl-substitution). A hostile proposer Authority can always-approve creation of any proposal, defeating the restriction. Pass canonical impls only.

func NewWithAuthority

1func NewWithAuthority(authority Authority) *Authorizer
source

NewWithAuthority creates a new Authorizer with a specific authority.

SECURITY: `authority` is an open-interface input — any value satisfying Authority is accepted. A malicious impl can always-approve (privilege escalation) or always-deny (DoS). Prefer canonical impls from this package (NewMemberAuthority, NewContractAuthority, NewAutoAcceptAuthority, NewDroppedAuthority) unless you specifically need a foreign impl.

func NewWithMembers

1func NewWithMembers(addrs ...address) *Authorizer
source

NewWithMembers creates a new Authorizer whose authority is a MemberAuthority containing the given addresses. Callers express authority intent at the call site:

Example
 1// "auth realm is the authority"
 2a := authz.NewWithMembers(cur.Address())
 3
 4// "previous realm is the authority" (from a crossing function)
 5a := authz.NewWithMembers(cur.Previous().Address())
 6
 7// "EOA caller is the authority" (from init(cur realm))
 8if !cur.Previous().IsUserCall() {
 9    panic("realm must be initialized by EOA")
10}
11a := authz.NewWithMembers(cur.Previous().Address())

This replaces the previous NewWithCurrent / NewWithPrevious / NewWithOrigin sugar — those baked runtime.{Current,Previous,Origin} reads into the constructor, which (a) prevented use from package- level var initializers, (b) made the EOA-origin check inside NewWithOrigin an indirect address comparison rather than the straightforward IsUserCall predicate, and (c) coupled the constructor to the runtime walks the rest of the migration is moving away from.

func NewContractAuthority

1func NewContractAuthority(path string, handler PrivilegedActionHandler) *ContractAuthority
source

NewContractAuthority creates a new contract-based authority.

SECURITY (Class-4 captured callback): `handler` is a caller-supplied closure that runs SYNCHRONOUSLY inside Authorize, with the consumer's authority. A hostile handler can swallow actions, log the caller, or execute arbitrary code under the consumer's frame. The package-internal wrappedAction guards "execute action only from contractAddr" but the handler can call wrappedAction however it likes (multiple times, never, out of order). Register only trusted handler functions; treat handler registration as the trust boundary.

Types 7

type Authority

interface
1type Authority interface {
2	// Authorize executes a privileged action if the caller is authorized
3	// Additional args can be provided for context (e.g., for proposal creation)
4	Authorize(caller address, title string, action PrivilegedAction, args ...any) error
5
6	// String returns a human-readable description of the authority
7	String() string
8}
source

Authority represents an entity that can authorize privileged actions. It is implemented by MemberAuthority, ContractAuthority, AutoAcceptAuthority, and DroppedAuthority.

Authority is the canonical safe shape for cross-package authority interfaces: methods are address-typed (no realm/cur crosses the interface boundary), and consumers correctly derive `caller` from `cur.Previous().Address()` under `rlm.IsCurrent()` before invoking Authorize. No cur-leak (class 1) is possible through this interface.

However, two RESIDUAL RISKS apply:

  • Class-3 impl-substitution: NewWithAuthority and Authorizer.Transfer accept any Authority impl. A malicious Authority can always-approve (silent privilege escalation) or always-deny (denial-of-service). Consumers should pass canonical impls from this package (MemberAuthority, ContractAuthority, AutoAcceptAuthority, DroppedAuthority) unless they have explicit reason to register a foreign impl. We do not expose an IsCanonicalAuthority allowlist because the package is intentionally extensible — third-party impls are the design intent.

  • Class-4 closed-over-authority: NewContractAuthority and NewRestrictedContractAuthority capture a caller-supplied PrivilegedActionHandler closure. The handler runs synchronously inside Authorize with the consumer's authority. A hostile handler can swallow actions, log the caller, or execute arbitrary code under the consumer's frame. Register only trusted handler functions. See r/gnops/valopers/init.gno for the realistic registration shape.

We do NOT seal Authority via an unexported marker method — that pattern is bypassable via embedding in Gno; see p/test/seal/filetests/z_seal_*_filetest.gno for the four bypass tests.

type Authorizer

struct
1type Authorizer struct {
2	auth Authority
3}
source

Authorizer is the main wrapper object that handles authority management. It is configured with a replaceable Authority implementation.

Methods on Authorizer

func Authority

method on Authorizer
1func (a *Authorizer) Authority() Authority
source

Authority returns the auth authority implementation

func DoByCurrent

method on Authorizer
1func (a *Authorizer) DoByCurrent(_ int, rlm realm, title string, action PrivilegedAction, args ...any) error
source

DoByCurrent executes a privileged action authorized as `rlm`. `rlm` must be the caller's own live cur (asserted via rlm.IsCurrent()); the authorized principal is `rlm.Address()`. To authorize as the realm that called your function, use `DoByPrevious`.

Example
1auth.DoByCurrent(0, cur, "update_config", func() error { ... })    // current realm authorizes
2auth.DoByPrevious(0, cur, "update_config", func() error { ... })   // calling realm authorizes

The `_ int` first parameter is a deliberate sentinel that pushes `rlm realm` past the first-arg position so DoByCurrent stays a non-crossing method — otherwise it would be a crossing method and rlm.Previous() inside would resolve one realm deeper than the caller intended.

SECURITY: the IsCurrent guard closes Class-2 designation forgery (see docs/resources/gno-security.md). A realm value's .Address() is set when the value is minted at a crossing frame; the value can in principle be stored and replayed. Without IsCurrent, a hostile realm could capture a high-privilege realm's cur.Previous() (e.g., when that realm called into it) and later pass the stored value here to authorize actions as that realm. IsCurrent rejects stale captures by requiring the value to match the topmost live crossing frame's cur.

func DoByPrevious

method on Authorizer
1func (a *Authorizer) DoByPrevious(_ int, rlm realm, title string, action PrivilegedAction, args ...any) error
source

DoByPrevious executes a privileged action authorized as the realm that called the function invoking DoByPrevious. `rlm` must be the caller's own live cur; the principal is derived as `rlm.Previous().Address()`. Mirrors the Transfer/AddMember pattern: always take live cur, derive the caller-of-caller internally rather than accepting a stored/forwarded realm value.

func String

method on Authorizer
1func (a *Authorizer) String() string
source

String returns a string representation of the auth authority

func Transfer

method on Authorizer
1func (a *Authorizer) Transfer(_ int, rlm realm, newAuthority Authority) error
source

Transfer changes the auth authority after validation. rlm must be the caller's own captured cur (asserted via rlm.IsCurrent()); the principal is rlm.Previous().Address(). Closes the address-parameter forgery: an external realm cannot supply Owner() as `caller` to bypass the underlying Authority's check.

SECURITY (runtime substitution): once the current authority approves a Transfer, the new authority is installed and effective on the next call. If an attacker ever becomes the authority — even briefly — they can install a permanent DroppedAuthority (DoS) or an AutoAcceptAuthority (privilege escalation). Consumers concerned about this should wrap Transfer with a one-shot guard or a quorum/cooldown check.

`newAuthority` is also an open-interface input — see NewWithAuthority's Class-3 caveat. Pass canonical impls.

type AutoAcceptAuthority

struct
1type AutoAcceptAuthority struct{}
source

AutoAcceptAuthority implements an authority that accepts all actions AutoAcceptAuthority is a simple authority that automatically accepts all actions. It can be used as a proposer authority to allow anyone to create proposals.

Methods on AutoAcceptAuthority

func Authorize

method on AutoAcceptAuthority
1func (a *AutoAcceptAuthority) Authorize(caller address, title string, action PrivilegedAction, args ...any) error
source

func String

method on AutoAcceptAuthority
1func (a *AutoAcceptAuthority) String() string
source

type ContractAuthority

struct
1type ContractAuthority struct {
2	contractPath    string
3	contractAddr    address
4	contractHandler PrivilegedActionHandler
5	proposer        Authority // controls who can create proposals
6}
source

ContractAuthority implements async contract-based authority

Methods on ContractAuthority

func Authorize

method on ContractAuthority
1func (a *ContractAuthority) Authorize(caller address, title string, action PrivilegedAction, args ...any) error
source

func String

method on ContractAuthority
1func (a *ContractAuthority) String() string
source

type MemberAuthority

struct
1type MemberAuthority struct {
2	members addrset.Set
3}
source

MemberAuthority is the default implementation using addrset for member management.

Methods on MemberAuthority

func AddMember

method on MemberAuthority
1func (a *MemberAuthority) AddMember(_ int, rlm realm, addr address) error
source

AddMember adds a new member to the authority. rlm must be the caller's own captured cur; the principal is rlm.Previous().Address() and must already be a member. The IsCurrent guard closes the forgery where an external realm passes Owner() as caller to bypass members.Has(caller).

func AddMembers

method on MemberAuthority
1func (a *MemberAuthority) AddMembers(_ int, rlm realm, addrs ...address) error
source

AddMembers adds a list of members to the authority. Same rlm contract as AddMember.

func Authorize

method on MemberAuthority
1func (a *MemberAuthority) Authorize(caller address, title string, action PrivilegedAction, args ...any) error
source

func Has

method on MemberAuthority
1func (a *MemberAuthority) Has(addr address) bool
source

Has checks if the given address is a member of the authority

func RemoveMember

method on MemberAuthority
1func (a *MemberAuthority) RemoveMember(_ int, rlm realm, addr address) error
source

RemoveMember removes a member from the authority. Same rlm contract as AddMember.

func String

method on MemberAuthority
1func (a *MemberAuthority) String() string
source

func Tree

method on MemberAuthority
1func (a *MemberAuthority) Tree() *rotree.ReadOnlyTree
source

Tree returns a read-only view of the members tree

type PrivilegedAction

func
1type PrivilegedAction func() error
source

PrivilegedAction defines a function that performs a privileged action.

type PrivilegedActionHandler

func
1type PrivilegedActionHandler func(title string, action PrivilegedAction) error
source

PrivilegedActionHandler is called by contract-based authorities to handle privileged actions.

Imports 8

Source Files 4