Documentation
¶
Index ¶
- func IsPartyInvolved(ev *event.E, userPubkey []byte) bool
- type Kinds
- type P
- func (p *P) CheckPolicy(access string, ev *event.E, loggedInPubkey []byte, ipAddress string) (allowed bool, err error)
- func (p *P) GetAllFollowsWhitelistAdmins() []string
- func (p *P) GetGlobalRule() *Rule
- func (p *P) GetPolicyAdminsBin() [][]byte
- func (p *P) GetRuleForKind(kind int) *Rule
- func (p *P) GetRulesKinds() []int
- func (p *P) IsEnabled() bool
- func (p *P) IsPolicyAdmin(pubkey []byte) bool
- func (p *P) IsPolicyFollow(pubkey []byte) bool
- func (p *P) IsPolicyFollowWhitelistEnabled() bool
- func (p *P) LoadFromFile(configPath string) error
- func (p *P) Pause() error
- func (p *P) Reload(policyJSON []byte, configPath string) error
- func (p *P) Resume() error
- func (p *P) SaveToFile(configPath string) error
- func (p *P) UnmarshalJSON(data []byte) error
- func (p *P) UpdateGlobalFollowsWhitelist(follows [][]byte)
- func (p *P) UpdatePolicyFollows(follows [][]byte)
- func (p *P) UpdateRuleFollowsWhitelist(kind int, follows [][]byte)
- func (p *P) ValidateJSON(policyJSON []byte) error
- type PolicyEvent
- type PolicyManager
- type PolicyResponse
- type Rule
- type ScriptRunner
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsPartyInvolved ¶ added in v0.29.9
IsPartyInvolved checks if the given pubkey is a party involved in the event. A party is involved if they are either: 1. The author of the event (ev.Pubkey == userPubkey) 2. Mentioned in a p-tag of the event
Both ev.Pubkey and userPubkey must be binary ([]byte), not hex-encoded. P-tags may be stored in either binary-optimized format (33 bytes) or hex format.
This is the single source of truth for "parties_involved" / "privileged" checks.
Types ¶
type Kinds ¶
type Kinds struct {
// Whitelist is a list of event kinds that are allowed to be written to the relay. If any are present, implicitly all others are denied.
Whitelist []int `json:"whitelist,omitempty"`
// Blacklist is a list of event kinds that are not allowed to be written to the relay. If any are present, implicitly all others are allowed. Only takes effect in the absence of a Whitelist.
Blacklist []int `json:"blacklist,omitempty"`
}
Kinds defines whitelist and blacklist policies for event kinds. Whitelist takes precedence over blacklist - if whitelist is present, only whitelisted kinds are allowed. If only blacklist is present, all kinds except blacklisted ones are allowed.
type P ¶
type P struct {
// Kind is policies for accepting or rejecting events by kind number.
Kind Kinds `json:"kind"`
// Global is a rule set that applies to all events.
Global Rule `json:"global"`
// DefaultPolicy determines the default behavior when no rules deny an event ("allow" or "deny", defaults to "allow")
DefaultPolicy string `json:"default_policy"`
// PolicyAdmins is a list of hex-encoded pubkeys that can update policy configuration via kind 12345 events.
// These are SEPARATE from ACL relay admins - policy admins manage policy only.
PolicyAdmins []string `json:"policy_admins,omitempty"`
// PolicyFollowWhitelistEnabled enables automatic whitelisting of pubkeys followed by policy admins.
// When true and a rule has WriteAllowFollows=true, policy admin follows get read+write access.
PolicyFollowWhitelistEnabled bool `json:"policy_follow_whitelist_enabled,omitempty"`
// contains filtered or unexported fields
}
P represents a complete policy configuration for a Nostr relay. It defines access control rules, kind filtering, and default behavior. Policies are evaluated in order: global rules, kind filtering, specific rules, then default policy.
func New ¶
New creates a new policy from JSON configuration. If policyJSON is empty, returns a policy with default settings. The default_policy field defaults to "allow" if not specified.
func NewWithManager ¶
NewWithManager creates a new policy with a policy manager for script execution. It initializes the policy manager, loads configuration from files, and starts background processes for script management and periodic health checks.
func (*P) CheckPolicy ¶
func (p *P) CheckPolicy( access string, ev *event.E, loggedInPubkey []byte, ipAddress string, ) (allowed bool, err error)
CheckPolicy checks if an event is allowed based on the policy configuration. The access parameter should be "write" for accepting events or "read" for filtering events. Returns true if the event is allowed, false if denied, and an error if validation fails. Policy evaluation order: global rules → kind filtering → specific rules → default policy.
func (*P) GetAllFollowsWhitelistAdmins ¶ added in v0.31.2
GetAllFollowsWhitelistAdmins returns all unique admin pubkeys from FollowsWhitelistAdmins across all rules (including global). Returns hex-encoded pubkeys. This is used at startup to validate that kind 3 events exist for these admins.
func (*P) GetGlobalRule ¶ added in v0.31.2
GetGlobalRule returns a pointer to the global rule for modification.
func (*P) GetPolicyAdminsBin ¶ added in v0.31.1
GetPolicyAdminsBin returns a copy of the binary policy admin pubkeys. Used for checking if an event author is a policy admin.
func (*P) GetRuleForKind ¶ added in v0.31.2
GetRuleForKind returns the Rule for a specific kind, or nil if no rule exists. This allows external code to access and modify rule-specific follows whitelists.
func (*P) GetRulesKinds ¶ added in v0.31.2
GetRules returns the rules map for iteration. Note: Returns a copy of the map keys to prevent modification.
func (*P) IsEnabled ¶ added in v0.30.1
IsEnabled returns whether the policy system is enabled and ready to process events. This is the public API for checking if policy filtering should be applied.
func (*P) IsPolicyAdmin ¶ added in v0.31.1
IsPolicyAdmin checks if the given pubkey is in the policy_admins list. The pubkey parameter should be binary ([]byte), not hex-encoded.
func (*P) IsPolicyFollow ¶ added in v0.31.1
IsPolicyFollow checks if the given pubkey is in the policy admin follows list. The pubkey parameter should be binary ([]byte), not hex-encoded.
func (*P) IsPolicyFollowWhitelistEnabled ¶ added in v0.31.1
IsPolicyFollowWhitelistEnabled returns whether the policy follow whitelist feature is enabled. When enabled, pubkeys followed by policy admins are automatically whitelisted for access when rules have WriteAllowFollows=true.
func (*P) LoadFromFile ¶
LoadFromFile loads policy configuration from a JSON file. Returns an error if the file doesn't exist, can't be read, or contains invalid JSON.
func (*P) Pause ¶ added in v0.31.1
Pause pauses the policy manager and stops all script runners.
func (*P) Reload ¶ added in v0.31.1
Reload loads policy from JSON bytes and applies it to the existing policy instance. This validates JSON FIRST, then pauses the policy manager, updates configuration, and resumes. Returns error if validation fails - no changes are made on validation failure.
func (*P) Resume ¶ added in v0.31.1
Resume resumes the policy manager and restarts script runners.
func (*P) SaveToFile ¶ added in v0.31.1
SaveToFile persists the current policy configuration to disk using atomic write. Uses temp file + rename pattern to ensure atomic writes.
func (*P) UnmarshalJSON ¶ added in v0.30.1
UnmarshalJSON implements custom JSON unmarshalling to handle unexported fields.
func (*P) UpdateGlobalFollowsWhitelist ¶ added in v0.31.2
UpdateGlobalFollowsWhitelist updates the follows whitelist for the global rule. The follows should be binary pubkeys ([]byte), not hex-encoded.
func (*P) UpdatePolicyFollows ¶ added in v0.31.1
UpdatePolicyFollows replaces the policy follows list with a new set of pubkeys. This is called when policy admins update their follow lists (kind 3 events). The pubkeys should be binary ([]byte), not hex-encoded.
func (*P) UpdateRuleFollowsWhitelist ¶ added in v0.31.2
UpdateRuleFollowsWhitelist updates the follows whitelist for a specific kind's rule. The follows should be binary pubkeys ([]byte), not hex-encoded.
type PolicyEvent ¶
type PolicyEvent struct {
*event.E
LoggedInPubkey string `json:"logged_in_pubkey,omitempty"`
IPAddress string `json:"ip_address,omitempty"`
AccessType string `json:"access_type,omitempty"` // "read" or "write"
}
PolicyEvent represents an event with additional context for policy scripts. It embeds the Nostr event and adds authentication and network context.
func (*PolicyEvent) MarshalJSON ¶
func (pe *PolicyEvent) MarshalJSON() ([]byte, error)
MarshalJSON implements custom JSON marshaling for PolicyEvent. It safely serializes the embedded event and additional context fields.
type PolicyManager ¶
type PolicyManager struct {
// contains filtered or unexported fields
}
PolicyManager handles multiple policy script runners. It manages the lifecycle of policy scripts, handles communication with them, and provides resilient operation with automatic restart capabilities. Each unique script path gets its own ScriptRunner instance.
func (*PolicyManager) GetScriptPath ¶ added in v0.20.3
func (pm *PolicyManager) GetScriptPath() string
GetScriptPath returns the default script path.
func (*PolicyManager) IsEnabled ¶
func (pm *PolicyManager) IsEnabled() bool
IsEnabled returns whether the policy manager is enabled.
func (*PolicyManager) IsRunning ¶
func (pm *PolicyManager) IsRunning() bool
IsRunning returns whether the default policy script is currently running. Deprecated: Use getOrCreateRunner(scriptPath).IsRunning() for specific scripts.
func (*PolicyManager) Shutdown ¶
func (pm *PolicyManager) Shutdown()
Shutdown gracefully shuts down the policy manager and all running scripts.
type PolicyResponse ¶
type PolicyResponse struct {
ID string `json:"id"`
Action string `json:"action"` // accept, reject, or shadowReject
Msg string `json:"msg"` // NIP-20 response message (only used for reject)
}
PolicyResponse represents a response from the policy script. The script should return JSON with these fields to indicate its decision.
type Rule ¶
type Rule struct {
// Description is a human-readable description of the rule.
Description string `json:"description"`
// Script is a path to a script that will be used to determine if the event should be allowed to be written to the relay. The script should be a standard bash script or whatever is native to the platform. The script will return its opinion to be one of the criteria that must be met for the event to be allowed to be written to the relay (AND).
Script string `json:"script,omitempty"`
// WriteAllow is a list of pubkeys that are allowed to write this event kind to the relay. If any are present, implicitly all others are denied.
WriteAllow []string `json:"write_allow,omitempty"`
// WriteDeny is a list of pubkeys that are not allowed to write this event kind to the relay. If any are present, implicitly all others are allowed. Only takes effect in the absence of a WriteAllow.
WriteDeny []string `json:"write_deny,omitempty"`
// ReadAllow is a list of pubkeys that are allowed to read this event kind from the relay. If any are present, implicitly all others are denied.
ReadAllow []string `json:"read_allow,omitempty"`
// ReadDeny is a list of pubkeys that are not allowed to read this event kind from the relay. If any are present, implicitly all others are allowed. Only takes effect in the absence of a ReadAllow.
ReadDeny []string `json:"read_deny,omitempty"`
// MaxExpiry is the maximum expiry time in seconds for events written to the relay. If 0, there is no maximum expiry. Events must have an expiry time if this is set, and it must be no more than this value in the future compared to the event's created_at time.
// Deprecated: Use MaxExpiryDuration instead for human-readable duration strings.
MaxExpiry *int64 `json:"max_expiry,omitempty"` //nolint:staticcheck // Intentional backward compatibility
// MaxExpiryDuration is the maximum expiry time in ISO-8601 duration format.
// Format: P[n]Y[n]M[n]W[n]DT[n]H[n]M[n]S (e.g., "P7D" for 7 days, "PT1H" for 1 hour, "P1DT12H" for 1 day 12 hours).
// Parsed into maxExpirySeconds at load time.
MaxExpiryDuration string `json:"max_expiry_duration,omitempty"`
// MustHaveTags is a list of tag key letters that must be present on the event for it to be allowed to be written to the relay.
MustHaveTags []string `json:"must_have_tags,omitempty"`
// SizeLimit is the maximum size in bytes for the event's total serialized size.
SizeLimit *int64 `json:"size_limit,omitempty"`
// ContentLimit is the maximum size in bytes for the event's content field.
ContentLimit *int64 `json:"content_limit,omitempty"`
// Privileged means that this event is either authored by the authenticated pubkey, or has a p tag that contains the authenticated pubkey. This type of event is only sent to users who are authenticated and are party to the event.
Privileged bool `json:"privileged,omitempty"`
// RateLimit is the amount of data can be written to the relay per second by the authenticated pubkey. If 0, there is no rate limit. This is applied via the use of an EWMA of the event publication history on the authenticated connection
RateLimit *int64 `json:"rate_limit,omitempty"`
// MaxAgeOfEvent is the offset in seconds that is the oldest timestamp allowed for an event's created_at time. If 0, there is no maximum age. Events must have a created_at time if this is set, and it must be no more than this value in the past compared to the current time.
MaxAgeOfEvent *int64 `json:"max_age_of_event,omitempty"`
// MaxAgeEventInFuture is the offset in seconds that is the newest timestamp allowed for an event's created_at time ahead of the current time.
MaxAgeEventInFuture *int64 `json:"max_age_event_in_future,omitempty"`
// WriteAllowFollows grants BOTH read and write access to policy admin follows when enabled.
// Requires PolicyFollowWhitelistEnabled=true at the policy level.
WriteAllowFollows bool `json:"write_allow_follows,omitempty"`
// FollowsWhitelistAdmins specifies admin pubkeys (hex-encoded) whose follows are whitelisted for this rule.
// Unlike WriteAllowFollows which uses the global PolicyAdmins, this allows per-rule admin configuration.
// If set, the relay will fail to start if these admins don't have follow list events (kind 3) in the database.
// This provides explicit control over which admin's follow list controls access for specific kinds.
FollowsWhitelistAdmins []string `json:"follows_whitelist_admins,omitempty"`
// TagValidation is a map of tag_name -> regex pattern for validating tag values.
// Each tag present in the event must match its corresponding regex pattern.
// Example: {"d": "^[a-z0-9-]{1,64}$", "t": "^[a-z0-9-]{1,32}$"}
TagValidation map[string]string `json:"tag_validation,omitempty"`
// ProtectedRequired when true requires events to have a "-" tag (NIP-70 protected events).
// Protected events signal that they should only be published to relays that enforce access control.
ProtectedRequired bool `json:"protected_required,omitempty"`
// IdentifierRegex is a regex pattern that "d" tag identifiers must conform to.
// This is a convenience field - equivalent to setting TagValidation["d"] = pattern.
// Example: "^[a-z0-9-]{1,64}$" requires lowercase alphanumeric with hyphens, max 64 chars.
IdentifierRegex string `json:"identifier_regex,omitempty"`
// contains filtered or unexported fields
}
Rule defines policy criteria for a specific event kind.
Rules are evaluated in the following order: 1. If Script is present and running, it determines the outcome 2. If Script fails or is not running, falls back to default_policy 3. Otherwise, all specified criteria are evaluated as AND operations
For pubkey allow/deny lists: whitelist takes precedence over blacklist. If whitelist has entries, only whitelisted pubkeys are allowed. If only blacklist has entries, all pubkeys except blacklisted ones are allowed.
func (*Rule) GetFollowsWhitelistAdminsBin ¶ added in v0.31.2
GetFollowsWhitelistAdminsBin returns the binary-encoded admin pubkeys for this rule.
func (*Rule) HasFollowsWhitelistAdmins ¶ added in v0.31.2
HasFollowsWhitelistAdmins returns true if this rule has FollowsWhitelistAdmins configured.
func (*Rule) IsInFollowsWhitelist ¶ added in v0.31.2
IsInFollowsWhitelist checks if the given pubkey is in this rule's follows whitelist. The pubkey parameter should be binary ([]byte), not hex-encoded.
type ScriptRunner ¶ added in v0.27.1
type ScriptRunner struct {
// contains filtered or unexported fields
}
ScriptRunner manages a single policy script process. Each unique script path gets its own independent runner with its own goroutine.
func (*ScriptRunner) IsRunning ¶ added in v0.27.1
func (sr *ScriptRunner) IsRunning() bool
IsRunning returns whether the script is currently running.
func (*ScriptRunner) ProcessEvent ¶ added in v0.27.1
func (sr *ScriptRunner) ProcessEvent(evt *PolicyEvent) ( *PolicyResponse, error, )
ProcessEvent sends an event to the script and waits for a response.
func (*ScriptRunner) Start ¶ added in v0.27.1
func (sr *ScriptRunner) Start() error
Start starts the script process.
func (*ScriptRunner) Stop ¶ added in v0.27.1
func (sr *ScriptRunner) Stop() error
Stop stops the script gracefully.
Source Files
¶
- policy.go