policy

package
v0.46.0 Latest Latest
Warning

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

Go to latest
Published: Jan 3, 2026 License: Unlicense Imports: 22 Imported by: 0

README

ORLY Policy System

The policy system provides fine-grained control over event storage and retrieval in the ORLY Nostr relay. It allows relay operators to define rules based on event kinds, pubkeys, content size, timestamps, tags, and custom scripts.

Table of Contents

Overview

The policy system evaluates every event against configured rules before allowing storage (write) or retrieval (read). Rules are evaluated as AND operations—all configured criteria must be satisfied for an event to be allowed.

Key capabilities:

  • Kind filtering: Whitelist or blacklist specific event kinds
  • Pubkey access control: Allow/deny lists for reading and writing
  • Size limits: Restrict total event size and content length
  • Timestamp validation: Reject events that are too old or too far in the future
  • Expiry enforcement: Require events to have expiration tags within limits
  • Tag validation: Enforce regex patterns on tag values
  • Protected events: Require NIP-70 protected event markers
  • Follows-based access: Whitelist pubkeys followed by admins
  • Custom scripts: External scripts for complex validation logic

Quick Start

1. Enable the Policy System
export ORLY_POLICY_ENABLED=true
2. Create a Policy Configuration

Create ~/.config/ORLY/policy.json:

{
  "default_policy": "allow",
  "global": {
    "max_age_of_event": 86400,
    "size_limit": 100000
  },
  "rules": {
    "1": {
      "description": "Text notes",
      "size_limit": 32000,
      "max_expiry_duration": "P7D"
    }
  }
}
3. Restart the Relay
sudo systemctl restart orly

Configuration Structure

{
  "default_policy": "allow|deny",
  "kind": {
    "whitelist": [1, 3, 4],
    "blacklist": []
  },
  "global": { /* Rule fields applied to all events */ },
  "rules": {
    "1": { /* Rule fields for kind 1 */ },
    "30023": { /* Rule fields for kind 30023 */ }
  },
  "policy_admins": ["hex_pubkey_1", "hex_pubkey_2"],
  "policy_follow_whitelist_enabled": false
}

Policy Fields Reference

Top-Level Fields
Field Type Default Description
default_policy string "allow" Fallback behavior when no rules match: "allow" or "deny"
kind object {} Kind whitelist/blacklist configuration
global object {} Rule applied to ALL events regardless of kind
rules object {} Map of kind number (as string) to rule configuration
policy_admins array [] Hex-encoded pubkeys that can update policy via kind 12345 events
policy_follow_whitelist_enabled boolean false Enable follows-based whitelisting for write_allow_follows
Kind Filtering
"kind": {
  "whitelist": [1, 3, 4, 7, 9735],
  "blacklist": [4]
}
Field Type Description
whitelist array Only these kinds are allowed. If present, all others are denied.
blacklist array These kinds are denied. Only evaluated if whitelist is empty.

Precedence: Whitelist takes precedence over blacklist. If whitelist has entries, blacklist is ignored.

Rule Fields

Rules can be applied globally (in global) or per-kind (in rules). All configured criteria are evaluated as AND operations.

Description
{
  "description": "Human-readable description of this rule"
}
Access Control Lists
Field Type Description
write_allow array Hex pubkeys allowed to write. If present, all others denied.
write_deny array Hex pubkeys denied from writing. Only evaluated if write_allow is empty.
read_allow array Hex pubkeys allowed to read. If present, all others denied.
read_deny array Hex pubkeys denied from reading. Only evaluated if read_allow is empty.
{
  "write_allow": ["npub1...", "npub2..."],
  "write_deny": ["npub3..."],
  "read_allow": [],
  "read_deny": ["npub4..."]
}
Size Limits
Field Type Unit Description
size_limit integer bytes Maximum total serialized event size
content_limit integer bytes Maximum content field size
{
  "size_limit": 100000,
  "content_limit": 50000
}
Timestamp Validation
Field Type Unit Description
max_age_of_event integer seconds Maximum age of event's created_at (prevents replay attacks)
max_age_event_in_future integer seconds Maximum time event can be in the future
{
  "max_age_of_event": 86400,
  "max_age_event_in_future": 300
}
Expiry Enforcement
Field Type Description
max_expiry integer Deprecated. Maximum expiry time in raw seconds.
max_expiry_duration string Maximum expiry time in ISO-8601 duration format. Takes precedence over max_expiry.

When set, events must have an expiration tag, and the expiry time must be within the specified duration from the event's created_at time.

{
  "max_expiry_duration": "P7D"
}
Required Tags
Field Type Description
must_have_tags array Tag key letters that must be present on the event
{
  "must_have_tags": ["d", "t"]
}
Privileged Events
Field Type Description
privileged boolean Only parties involved (author or p-tag recipients) can read/write
{
  "privileged": true
}
Protected Events (NIP-70)
Field Type Description
protected_required boolean Requires events to have a - tag (NIP-70 protected marker)

Protected events signal that they should only be published to relays that enforce access control.

{
  "protected_required": true
}
Identifier Regex
Field Type Description
identifier_regex string Regex pattern that d tag values must match

When set, events must have at least one d tag, and all d tags must match the pattern.

{
  "identifier_regex": "^[a-z0-9-]{1,64}$"
}
Tag Validation
Field Type Description
tag_validation object Map of tag name to regex pattern

Validates that tag values match the specified regex patterns. Only validates tags that are present—does not require tags to exist.

{
  "tag_validation": {
    "d": "^[a-z0-9-]{1,64}$",
    "t": "^[a-z0-9]+$"
  }
}
Follows-Based Whitelisting
Field Type Description
write_allow_follows boolean DEPRECATED. Grant read+write access to policy admin follows
follows_whitelist_admins array DEPRECATED. Per-rule admin pubkeys whose follows are whitelisted
read_follows_whitelist array Pubkeys whose follows can READ events. Restricts read access when set.
write_follows_whitelist array Pubkeys whose follows can WRITE events. Restricts write access when set.

See Follows-Based Whitelisting for details.

Permissive Mode Overrides
Field Type Description
read_allow_permissive boolean Override kind whitelist for READ access (reads allowed for all kinds)
write_allow_permissive boolean Override kind whitelist for WRITE access (writes use global rule only)

These fields, when set on the global rule, allow independent control over read and write access relative to the kind whitelist/blacklist:

{
  "kind": {
    "whitelist": [1, 3, 5, 7]
  },
  "global": {
    "read_allow_permissive": true,
    "size_limit": 100000
  }
}

In this example:

  • READ: Allowed for ALL kinds (permissive override ignores whitelist)
  • WRITE: Only kinds 1, 3, 5, 7 can be written (whitelist applies)

Important constraints:

  • These flags only work on the global rule (ignored on kind-specific rules)
  • You cannot enable BOTH read_allow_permissive AND write_allow_permissive when a kind whitelist/blacklist is configured (this would make the whitelist meaningless)
  • Blacklists always take precedence—permissive flags do NOT override explicit blacklist entries

See Permissive Mode Examples for detailed use cases.

Rate Limiting
Field Type Unit Description
rate_limit integer bytes/second Maximum data rate per authenticated connection
{
  "rate_limit": 10000
}
Custom Scripts
Field Type Description
script string Path to external validation script

See Policy Scripts for details.

ISO-8601 Duration Format

The max_expiry_duration field uses strict ISO-8601 duration format, parsed by the sosodev/duration library.

Format
P[n]Y[n]M[n]W[n]DT[n]H[n]M[n]S
Component Meaning Example
P Required prefix (Period) P1D
Y Years (~365.25 days) P1Y
M Months (~30.44 days) - date part P1M
W Weeks (7 days) P2W
D Days P7D
T Required separator before time PT1H
H Hours (requires T) PT2H
M Minutes (requires T) - time part PT30M
S Seconds (requires T) PT90S
Examples
Duration Meaning Seconds
P1D 1 day 86,400
P7D 7 days 604,800
P30D 30 days 2,592,000
PT1H 1 hour 3,600
PT30M 30 minutes 1,800
PT90S 90 seconds 90
P1DT12H 1 day 12 hours 129,600
P1DT2H30M 1 day 2 hours 30 minutes 95,400
P1W 1 week 604,800
P1M 1 month 2,628,000
P1Y 1 year 31,536,000
PT1.5H 1.5 hours 5,400
P0.5D 12 hours 43,200
Important Notes
  1. P prefix is required: 1D is invalid, use P1D
  2. T separator is required before time: P1H is invalid, use PT1H
  3. Date components before T: PT1D is invalid (D is a date component)
  4. Case insensitive: p1d and P1D are equivalent
  5. Fractional values supported: PT1.5H, P0.5D
Invalid Examples
Invalid Why Correct
1D Missing P prefix P1D
P1H H needs T separator PT1H
PT1D D is date component P1D
P30S S needs T separator PT30S
P-5D Negative not allowed P5D
PD Missing number P1D

Access Control

Default-Permissive Access Model

The policy system uses a default-permissive model for both read and write access:

  • Read: Allowed by default unless a read restriction is configured
  • Write: Allowed by default unless a write restriction is configured

Restrictions become active when any of the following fields are set:

Access Restrictions
Read read_allow, read_follows_whitelist, or privileged
Write write_allow, write_follows_whitelist

Important: privileged ONLY applies to READ operations.

Write Access Evaluation (Default-Permissive)
1. Universal constraints (size, tags, age) - must pass
2. If pubkey in write_deny → DENY
3. If write_allow_follows enabled and pubkey in admin follows → ALLOW
4. If write_follows_whitelist set and pubkey in follows → ALLOW
5. If write_allow set and pubkey in list → ALLOW
6. If ANY write restriction is set → DENY (not in any whitelist)
7. Otherwise → ALLOW (default-permissive)
Read Access Evaluation (Default-Permissive)
1. If pubkey in read_deny → DENY
2. If read_allow_follows enabled and pubkey in admin follows → ALLOW
3. If read_follows_whitelist set and pubkey in follows → ALLOW
4. If read_allow set and pubkey in list → ALLOW
5. If privileged set and pubkey is party to event → ALLOW
6. If ANY read restriction is set → DENY (not in any whitelist)
7. Otherwise → ALLOW (default-permissive)
Privileged Events (Read-Only)

When privileged: true, only the author and p-tag recipients can access the event:

{
  "rules": {
    "4": {
      "description": "Encrypted DMs",
      "privileged": true
    }
  }
}

Follows-Based Whitelisting

The policy system supports whitelisting pubkeys based on follow lists (kind 3 events). There are two approaches:

Use read_follows_whitelist and write_follows_whitelist for fine-grained control:

{
  "global": {
    "read_follows_whitelist": ["curator_pubkey_hex"],
    "write_follows_whitelist": ["moderator_pubkey_hex"]
  },
  "rules": {
    "30023": {
      "description": "Articles - curated reading, moderated writing",
      "read_follows_whitelist": ["article_curator_hex"],
      "write_follows_whitelist": ["article_moderator_hex"]
    }
  }
}

How it works:

  • The pubkeys listed AND their follows (from kind 3 events) can access the events
  • read_follows_whitelist: Restricts WHO can read (when set)
  • write_follows_whitelist: Restricts WHO can write (when set)
  • If not set, the default-permissive behavior applies

Important: The relay will fail to start if the named pubkeys don't have kind 3 follow list events in the database. This ensures the follow lists are available for access control.

2. Legacy: Global Policy Admin Follows (DEPRECATED)

Enable whitelisting for all pubkeys followed by policy admins:

{
  "policy_admins": ["admin_pubkey_hex"],
  "policy_follow_whitelist_enabled": true,
  "rules": {
    "1": {
      "write_allow_follows": true
    }
  }
}

When write_allow_follows is true, pubkeys in the policy admins' kind 3 follow lists get both read AND write access.

3. Legacy: Per-Rule Follows Whitelist (DEPRECATED)

Configure specific admins per rule:

{
  "rules": {
    "30023": {
      "description": "Long-form articles from curator's follows",
      "follows_whitelist_admins": ["curator_pubkey_hex"]
    }
  }
}

This allows different rules to use different admin follow lists.

Loading Follow Lists at Startup

The application must load follow lists at startup. The new API provides separate methods:

// Get all pubkeys that need follow lists loaded (combines read + write + legacy)
allPubkeys := policy.GetAllFollowsWhitelistPubkeys()

// Or get them separately
readPubkeys := policy.GetAllReadFollowsWhitelistPubkeys()
writePubkeys := policy.GetAllWriteFollowsWhitelistPubkeys()
legacyAdmins := policy.GetAllFollowsWhitelistAdmins()

// Load follows and update the policy
for _, pubkeyHex := range readPubkeys {
    follows := loadFollowsFromKind3(pubkeyHex)
    // Update read follows whitelist for specific kinds
    policy.UpdateRuleReadFollowsWhitelist(kind, follows)
    // Or for global rule
    policy.UpdateGlobalReadFollowsWhitelist(follows)
}

for _, pubkeyHex := range writePubkeys {
    follows := loadFollowsFromKind3(pubkeyHex)
    policy.UpdateRuleWriteFollowsWhitelist(kind, follows)
    // Or for global rule
    policy.UpdateGlobalWriteFollowsWhitelist(follows)
}

Tag Validation

Using tag_validation

Validate multiple tags with regex patterns:

{
  "rules": {
    "30023": {
      "tag_validation": {
        "d": "^[a-z0-9-]{1,64}$",
        "t": "^[a-z0-9]+$",
        "title": "^.{1,100}$"
      }
    }
  }
}
  • Only validates tags that are present on the event
  • Does not require tags to exist (use must_have_tags for that)
  • All values of a repeated tag must match the pattern
Using identifier_regex

Shorthand for d tag validation:

{
  "identifier_regex": "^[a-z0-9-]{1,64}$"
}

This is equivalent to:

{
  "tag_validation": {
    "d": "^[a-z0-9-]{1,64}$"
  }
}

Important: When identifier_regex is set, events must have at least one d tag.

Common Patterns
Pattern Description
^[a-z0-9-]{1,64}$ URL-friendly slug
^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ UUID
^[a-zA-Z0-9_]+$ Alphanumeric with underscores
^.{1,100}$ Any characters, max 100

Policy Scripts

External scripts provide custom validation logic.

Script Interface

Input: JSON event objects on stdin (one per line):

{
  "id": "event_id_hex",
  "pubkey": "author_pubkey_hex",
  "kind": 1,
  "content": "Hello, world!",
  "tags": [["p", "recipient_hex"]],
  "created_at": 1640995200,
  "sig": "signature_hex",
  "logged_in_pubkey": "authenticated_user_hex",
  "ip_address": "127.0.0.1",
  "access_type": "write"
}

Output: JSON response on stdout:

{"id": "event_id_hex", "action": "accept", "msg": ""}
Actions
Action OK Response Effect
accept true Store/retrieve event normally
reject false Reject with error message
shadowReject true Silently drop (appears successful to client)
Script Requirements
  1. Long-lived process: Read stdin in a loop, don't exit after one event
  2. JSON only on stdout: Use stderr for debug logging
  3. Flush after each response: Call sys.stdout.flush() (Python) or equivalent
  4. Handle errors gracefully: Always return valid JSON
Example Script (Python)
#!/usr/bin/env python3
import json
import sys

def process_event(event):
    if 'spam' in event.get('content', '').lower():
        return {'id': event['id'], 'action': 'reject', 'msg': 'Spam detected'}
    return {'id': event['id'], 'action': 'accept', 'msg': ''}

for line in sys.stdin:
    if line.strip():
        try:
            event = json.loads(line)
            response = process_event(event)
            print(json.dumps(response))
            sys.stdout.flush()
        except json.JSONDecodeError:
            print(json.dumps({'id': '', 'action': 'reject', 'msg': 'Invalid JSON'}))
            sys.stdout.flush()
Configuration
{
  "rules": {
    "1": {
      "script": "/etc/orly/scripts/spam-filter.py"
    }
  }
}

Dynamic Policy Updates

Policy admins can update configuration at runtime by publishing kind 12345 events.

Setup
{
  "policy_admins": ["admin_pubkey_hex"],
  "default_policy": "allow"
}
Publishing Updates

Send a kind 12345 event with the new policy as JSON content:

{
  "kind": 12345,
  "content": "{\"default_policy\": \"deny\", \"kind\": {\"whitelist\": [1,3,7]}}",
  "tags": [],
  "created_at": 1234567890
}
Security
  • Only pubkeys in policy_admins can update policy
  • Invalid JSON or configuration is rejected (existing policy preserved)
  • All updates are logged for audit purposes

Evaluation Order

Events are evaluated in this order:

  1. Global Rules - Applied to all events first
  2. Kind Filtering - Whitelist/blacklist check
  3. Kind-Specific Rules - Rules for the event's kind
  4. Script Evaluation - If configured and running
  5. Default Policy - Fallback if no rules deny

The first rule that denies access stops evaluation. If all rules pass, the event is allowed.

Rule Criteria (AND Logic)

Within a rule, all configured criteria must be satisfied:

access_allowed = (
    pubkey_check_passed AND
    size_check_passed AND
    timestamp_check_passed AND
    expiry_check_passed AND
    tag_check_passed AND
    protected_check_passed AND
    script_check_passed
)

Examples

Open Relay with Size Limits
{
  "default_policy": "allow",
  "global": {
    "size_limit": 100000,
    "max_age_of_event": 86400,
    "max_age_event_in_future": 300
  }
}
Private Relay
{
  "default_policy": "deny",
  "global": {
    "write_allow": ["trusted_pubkey_1", "trusted_pubkey_2"],
    "read_allow": ["trusted_pubkey_1", "trusted_pubkey_2"]
  }
}
Ephemeral Events with Expiry
{
  "default_policy": "allow",
  "rules": {
    "20": {
      "description": "Ephemeral events must expire within 24 hours",
      "max_expiry_duration": "P1D"
    }
  }
}
Long-Form Content with Strict Validation
{
  "default_policy": "deny",
  "rules": {
    "30023": {
      "description": "Long-form articles with strict requirements",
      "max_expiry_duration": "P30D",
      "protected_required": true,
      "identifier_regex": "^[a-z0-9-]{1,64}$",
      "follows_whitelist_admins": ["curator_pubkey_hex"],
      "tag_validation": {
        "t": "^[a-z0-9-]{1,32}$"
      },
      "size_limit": 100000,
      "content_limit": 50000
    }
  }
}
Encrypted DMs with Privacy
{
  "default_policy": "allow",
  "rules": {
    "4": {
      "description": "Encrypted DMs - private and protected",
      "protected_required": true,
      "privileged": true
    }
  }
}
Community-Curated Content
{
  "default_policy": "deny",
  "policy_admins": ["community_admin_hex"],
  "policy_follow_whitelist_enabled": true,
  "rules": {
    "1": {
      "description": "Only community members can post",
      "write_allow_follows": true,
      "size_limit": 32000
    }
  }
}
Kind Whitelist with Global Limits
{
  "default_policy": "deny",
  "kind": {
    "whitelist": [0, 1, 3, 4, 7, 9735, 30023]
  },
  "global": {
    "size_limit": 100000,
    "max_age_of_event": 604800,
    "max_age_event_in_future": 60
  }
}
Permissive Mode Examples
Read-Permissive Relay (Write-Restricted)

Allow anyone to read all events, but restrict writes to specific kinds:

{
  "default_policy": "allow",
  "kind": {
    "whitelist": [1, 3, 7, 9735]
  },
  "global": {
    "read_allow_permissive": true,
    "size_limit": 100000
  }
}

Behavior:

  • READ: Any kind can be read (permissive override)
  • WRITE: Only kinds 1, 3, 7, 9735 can be written

This is useful for relays that want to serve as aggregators (read any event type) but only accept specific event types from clients.

Write-Permissive with Read Restrictions

Allow writes of any kind (with global constraints), but restrict reads:

{
  "default_policy": "allow",
  "kind": {
    "whitelist": [0, 1, 3]
  },
  "global": {
    "write_allow_permissive": true,
    "size_limit": 50000,
    "max_age_of_event": 86400
  }
}

Behavior:

  • READ: Only kinds 0, 1, 3 can be read (whitelist applies)
  • WRITE: Any kind can be written (with size and age limits from global rule)

This is useful for relays that want to accept any event type but only serve a curated subset.

Archive Relay (Read Any, Accept Specific)

Perfect for archive/backup relays:

{
  "default_policy": "allow",
  "kind": {
    "whitelist": [0, 1, 3, 4, 7, 30023]
  },
  "global": {
    "read_allow_permissive": true,
    "size_limit": 500000
  },
  "rules": {
    "30023": {
      "description": "Long-form articles with validation",
      "identifier_regex": "^[a-z0-9-]{1,64}$",
      "max_expiry_duration": "P365D"
    }
  }
}

Behavior:

  • READ: All kinds can be read (historical data)
  • WRITE: Only whitelisted kinds accepted, with specific rules for articles

Testing

Run Policy Tests
CGO_ENABLED=0 go test -v ./pkg/policy/...
Test Scripts Manually
echo '{"id":"test","kind":1,"content":"test"}' | ./policy-script.py

Expected output:

{"id":"test","action":"accept","msg":""}

Troubleshooting

Policy Not Loading
# Check file exists and is valid JSON
cat ~/.config/ORLY/policy.json | jq .
Script Not Working
# Check script is executable
ls -la /path/to/script.py

# Test script independently
echo '{"id":"test","kind":1}' | /path/to/script.py
Enable Debug Logging
export ORLY_LOG_LEVEL=debug
Common Issues
Issue Cause Solution
"invalid ISO-8601 duration" Wrong format Use P1D not 1d
"H requires T separator" Missing T Use PT1H not P1H
Script timeout Script not responding Ensure flush after each response
Broken pipe Script exited Script must run continuously

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ProtectedFields = []string{"owners", "policy_admins"}

ProtectedFields are fields that only owners can modify

Functions

func IsPartyInvolved added in v0.29.9

func IsPartyInvolved(ev *event.E, userPubkey []byte) bool

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.

func ValidateOwnerPolicy added in v0.31.4

func ValidateOwnerPolicy(policy *P) error

ValidateOwnerPolicy validates a policy update from an owner. Ensures owners list is non-empty.

func ValidatePolicyAdminContribution added in v0.31.4

func ValidatePolicyAdminContribution(
	ownerPolicy *P,
	contribution *PolicyAdminContribution,
	existingContributions map[string]*PolicyAdminContribution,
) error

ValidatePolicyAdminContribution validates a contribution from a policy admin. Ensures no protected fields are modified and extensions are valid.

Types

type ComposedPolicy added in v0.31.4

type ComposedPolicy struct {
	// OwnerPolicy is the base policy set by owners
	OwnerPolicy *P
	// Contributions is a map of event ID -> contribution for deduplication
	Contributions map[string]*PolicyAdminContribution
	// contains filtered or unexported fields
}

ComposedPolicy manages the base owner policy and policy admin contributions. It computes an effective merged policy at runtime.

func NewComposedPolicy added in v0.31.4

func NewComposedPolicy(ownerPolicy *P, configDir string) *ComposedPolicy

NewComposedPolicy creates a new composed policy from an owner policy.

func (*ComposedPolicy) AddContribution added in v0.31.4

func (cp *ComposedPolicy) AddContribution(contribution *PolicyAdminContribution) error

AddContribution adds a policy admin contribution. Returns error if validation fails.

func (*ComposedPolicy) GetEffectivePolicy added in v0.31.4

func (cp *ComposedPolicy) GetEffectivePolicy() *P

GetEffectivePolicy computes the merged effective policy. Composition rules: - Whitelists are unioned (OR) - Blacklists are unioned and override whitelists - Limits use the most permissive value - Conflicts between PAs: oldest created_at wins (except deny always wins)

func (*ComposedPolicy) LoadContributions added in v0.31.4

func (cp *ComposedPolicy) LoadContributions() error

LoadContributions loads all contributions from disk.

func (*ComposedPolicy) RemoveContribution added in v0.31.4

func (cp *ComposedPolicy) RemoveContribution(eventID string)

RemoveContribution removes a policy admin contribution by event ID.

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"`

	// Owners is a list of hex-encoded pubkeys that have full control of the relay.
	// These are merged with owners from the ORLY_OWNERS environment variable.
	// Useful for cloud deployments where environment variables cannot be modified.
	Owners []string `json:"owners,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

func New(policyJSON []byte) (p *P, err error)

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. Returns an error if the policy JSON contains invalid values (e.g., invalid ISO-8601 duration format for max_expiry_duration, invalid regex patterns, etc.).

func NewWithManager

func NewWithManager(ctx context.Context, appName string, enabled bool, customPolicyPath string) *P

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.

The customPolicyPath parameter allows overriding the default policy file location. If empty, uses the default path: $HOME/.config/{appName}/policy.json If provided, it MUST be an absolute path (starting with /) or the function will panic.

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 (more specific rules take precedence): 1. Kinds whitelist/blacklist - if kind is blocked, deny immediately 2. Kind-specific rule - if exists for this kind, use it exclusively 3. Global rule - fallback if no kind-specific rule exists 4. Default policy - fallback if no rules apply

Thread-safety: Uses followsMx.RLock to protect reads of follows whitelists during policy checks. Write operations (Update*) acquire the write lock, which blocks concurrent reads.

func (*P) ConfigPath added in v0.35.3

func (p *P) ConfigPath() string

ConfigPath returns the path to the policy configuration file. Delegates to the internal PolicyManager.

func (*P) GetAllFollowsWhitelistAdmins added in v0.31.2

func (p *P) GetAllFollowsWhitelistAdmins() []string

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) GetAllFollowsWhitelistPubkeys added in v0.32.4

func (p *P) GetAllFollowsWhitelistPubkeys() []string

GetAllFollowsWhitelistPubkeys returns all unique pubkeys from both ReadFollowsWhitelist and WriteFollowsWhitelist across all rules (including global). Returns hex-encoded pubkeys. This is a convenience method for startup validation to check all required kind 3 events.

func (*P) GetAllReadFollowsWhitelistPubkeys added in v0.32.4

func (p *P) GetAllReadFollowsWhitelistPubkeys() []string

GetAllReadFollowsWhitelistPubkeys returns all unique pubkeys from ReadFollowsWhitelist across all rules (including global). Returns hex-encoded pubkeys. This is used at startup to validate that kind 3 events exist for these pubkeys.

func (*P) GetAllWriteFollowsWhitelistPubkeys added in v0.32.4

func (p *P) GetAllWriteFollowsWhitelistPubkeys() []string

GetAllWriteFollowsWhitelistPubkeys returns all unique pubkeys from WriteFollowsWhitelist across all rules (including global). Returns hex-encoded pubkeys. This is used at startup to validate that kind 3 events exist for these pubkeys.

func (*P) GetGlobalRule added in v0.31.2

func (p *P) GetGlobalRule() *Rule

GetGlobalRule returns a pointer to the global rule for modification.

func (*P) GetOwners added in v0.31.3

func (p *P) GetOwners() []string

GetOwners returns the hex-encoded owner pubkeys defined in the policy. These are merged with environment-defined owners by the application layer.

func (*P) GetOwnersBin added in v0.31.3

func (p *P) GetOwnersBin() [][]byte

GetOwnersBin returns a copy of the binary owner pubkeys defined in the policy. These are merged with environment-defined owners by the application layer. Useful for cloud deployments where environment variables cannot be modified.

func (*P) GetPolicyAdminsBin added in v0.31.1

func (p *P) GetPolicyAdminsBin() [][]byte

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

func (p *P) GetRuleForKind(kind int) *Rule

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

func (p *P) GetRulesKinds() []int

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

func (p *P) IsEnabled() bool

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) IsOwner added in v0.31.4

func (p *P) IsOwner(pubkey []byte) bool

IsOwner checks if the given pubkey is an owner. The pubkey parameter should be binary ([]byte), not hex-encoded.

func (*P) IsOwnerOrPolicyAdmin added in v0.31.4

func (p *P) IsOwnerOrPolicyAdmin(pubkey []byte) bool

IsOwnerOrPolicyAdmin checks if the given pubkey is an owner or policy admin. The pubkey parameter should be binary ([]byte), not hex-encoded.

func (*P) IsPolicyAdmin added in v0.31.1

func (p *P) IsPolicyAdmin(pubkey []byte) bool

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

func (p *P) IsPolicyFollow(pubkey []byte) bool

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

func (p *P) IsPolicyFollowWhitelistEnabled() bool

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

func (p *P) LoadFromFile(configPath string) error

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

func (p *P) Pause() error

Pause pauses the policy manager and stops all script runners.

func (*P) Reload added in v0.31.1

func (p *P) Reload(policyJSON []byte, configPath string) error

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) ReloadAsOwner added in v0.31.4

func (p *P) ReloadAsOwner(policyJSON []byte, configPath string) error

ReloadAsOwner reloads the policy from an owner's kind 12345 event. Owners can modify all fields but the owners list must be non-empty.

func (*P) ReloadAsPolicyAdmin added in v0.31.4

func (p *P) ReloadAsPolicyAdmin(policyJSON []byte, configPath string, adminPubkey []byte) error

ReloadAsPolicyAdmin reloads the policy from a policy admin's kind 12345 event. Policy admins cannot modify protected fields (owners, policy_admins) and cannot reduce owner-granted permissions.

func (*P) Resume added in v0.31.1

func (p *P) Resume() error

Resume resumes the policy manager and restarts script runners.

func (*P) SaveToFile added in v0.31.1

func (p *P) SaveToFile(configPath string) error

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

func (p *P) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom JSON unmarshalling to handle unexported fields.

func (*P) UpdateGlobalFollowsWhitelist added in v0.31.2

func (p *P) UpdateGlobalFollowsWhitelist(follows [][]byte)

UpdateGlobalFollowsWhitelist updates the follows whitelist for the global rule. The follows should be binary pubkeys ([]byte), not hex-encoded. Note: We directly modify p.Global's unexported field because Global is a value type (not *Rule), so calling p.Global.UpdateFollowsWhitelist() would operate on a copy and discard changes. Thread-safe: uses followsMx to protect concurrent access.

func (*P) UpdateGlobalReadFollowsWhitelist added in v0.32.4

func (p *P) UpdateGlobalReadFollowsWhitelist(follows [][]byte)

UpdateGlobalReadFollowsWhitelist updates the read follows whitelist for the global rule. The follows should be binary pubkeys ([]byte), not hex-encoded. Note: We directly modify p.Global's unexported field because Global is a value type (not *Rule), so calling p.Global.UpdateReadFollowsWhitelist() would operate on a copy and discard changes. Thread-safe: uses followsMx to protect concurrent access.

func (*P) UpdateGlobalWriteFollowsWhitelist added in v0.32.4

func (p *P) UpdateGlobalWriteFollowsWhitelist(follows [][]byte)

UpdateGlobalWriteFollowsWhitelist updates the write follows whitelist for the global rule. The follows should be binary pubkeys ([]byte), not hex-encoded. Note: We directly modify p.Global's unexported field because Global is a value type (not *Rule), so calling p.Global.UpdateWriteFollowsWhitelist() would operate on a copy and discard changes. Thread-safe: uses followsMx to protect concurrent access.

func (*P) UpdatePolicyFollows added in v0.31.1

func (p *P) UpdatePolicyFollows(follows [][]byte)

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

func (p *P) UpdateRuleFollowsWhitelist(kind int, follows [][]byte)

UpdateRuleFollowsWhitelist updates the follows whitelist for a specific kind's rule. The follows should be binary pubkeys ([]byte), not hex-encoded. Thread-safe: uses followsMx to protect concurrent access.

func (*P) UpdateRuleReadFollowsWhitelist added in v0.32.4

func (p *P) UpdateRuleReadFollowsWhitelist(kind int, follows [][]byte)

UpdateRuleReadFollowsWhitelist updates the read follows whitelist for a specific kind's rule. The follows should be binary pubkeys ([]byte), not hex-encoded. Thread-safe: uses followsMx to protect concurrent access.

func (*P) UpdateRuleWriteFollowsWhitelist added in v0.32.4

func (p *P) UpdateRuleWriteFollowsWhitelist(kind int, follows [][]byte)

UpdateRuleWriteFollowsWhitelist updates the write follows whitelist for a specific kind's rule. The follows should be binary pubkeys ([]byte), not hex-encoded. Thread-safe: uses followsMx to protect concurrent access.

func (*P) ValidateJSON added in v0.31.1

func (p *P) ValidateJSON(policyJSON []byte) error

ValidateJSON validates policy JSON without applying changes. This is called BEFORE any modifications to ensure JSON is valid. Returns error if validation fails - no changes are made to current policy.

func (*P) ValidateOwnerPolicyUpdate added in v0.31.4

func (p *P) ValidateOwnerPolicyUpdate(policyJSON []byte) error

ValidateOwnerPolicyUpdate validates a full policy update from an owner. Owners can modify all fields but the owners list must be non-empty.

func (*P) ValidatePolicyAdminUpdate added in v0.31.4

func (p *P) ValidatePolicyAdminUpdate(policyJSON []byte, adminPubkey []byte) error

ValidatePolicyAdminUpdate validates a policy update from a policy admin. Policy admins CANNOT modify: owners, policy_admins Policy admins CAN: extend rules, add blacklists, add new kind rules

type PolicyAdminContribution added in v0.31.4

type PolicyAdminContribution struct {
	// AdminPubkey is the hex-encoded pubkey of the policy admin who made this contribution
	AdminPubkey string `json:"admin_pubkey"`
	// CreatedAt is the Unix timestamp when this contribution was created
	CreatedAt int64 `json:"created_at"`
	// EventID is the Nostr event ID that created this contribution (for audit trail)
	EventID string `json:"event_id,omitempty"`

	// KindWhitelistAdd adds kinds to the whitelist (OR with owner's whitelist)
	KindWhitelistAdd []int `json:"kind_whitelist_add,omitempty"`
	// KindBlacklistAdd adds kinds to the blacklist (overrides whitelist)
	KindBlacklistAdd []int `json:"kind_blacklist_add,omitempty"`

	// RulesExtend extends existing rules defined by the owner
	RulesExtend map[int]RuleExtension `json:"rules_extend,omitempty"`
	// RulesAdd adds new rules for kinds not defined by the owner
	RulesAdd map[int]Rule `json:"rules_add,omitempty"`

	// GlobalExtend extends the global rule
	GlobalExtend *RuleExtension `json:"global_extend,omitempty"`
}

PolicyAdminContribution represents extensions/additions from a policy admin. Policy admins can extend the base owner policy but cannot modify protected fields (owners, policy_admins) or reduce owner-granted permissions.

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) ConfigPath added in v0.35.3

func (pm *PolicyManager) ConfigPath() string

ConfigPath returns the path to the policy configuration file. This is used by hot-reload handlers to know where to save updated policy.

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.
	// DEPRECATED: Use ReadFollowsWhitelist and WriteFollowsWhitelist instead.
	FollowsWhitelistAdmins []string `json:"follows_whitelist_admins,omitempty"`

	// ReadFollowsWhitelist specifies pubkeys (hex-encoded) whose follows are allowed to READ events.
	// The relay will fail to start if these pubkeys don't have follow list events (kind 3) in the database.
	// When present, only the follows of these pubkeys (plus the pubkeys themselves) can read.
	// This restricts read access - without it, read is permissive by default (except for privileged events).
	ReadFollowsWhitelist []string `json:"read_follows_whitelist,omitempty"`

	// WriteFollowsWhitelist specifies pubkeys (hex-encoded) whose follows are allowed to WRITE events.
	// The relay will fail to start if these pubkeys don't have follow list events (kind 3) in the database.
	// When present, only the follows of these pubkeys (plus the pubkeys themselves) can write.
	// Without this, write permission is allowed by default.
	WriteFollowsWhitelist []string `json:"write_follows_whitelist,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"`

	// ReadAllowPermissive when set on a GLOBAL rule, allows read access for ALL kinds,
	// even when a kind whitelist is configured. This allows the kind whitelist to
	// restrict WRITE operations while keeping reads permissive.
	// When true:
	// - READ: Allowed for all kinds (global rule still applies for other read restrictions)
	// - WRITE: Kind whitelist/blacklist applies as normal
	// Only meaningful on the Global rule - ignored on kind-specific rules.
	ReadAllowPermissive bool `json:"read_allow_permissive,omitempty"`

	// WriteAllowPermissive when set on a GLOBAL rule, allows write access for kinds
	// that don't have specific rules defined, bypassing the implicit kind whitelist.
	// When true:
	// - Kinds without specific rules apply global rule constraints only
	// - Kind whitelist still blocks reads for unlisted kinds (unless ReadAllowPermissive is also set)
	// Only meaningful on the Global rule - ignored on kind-specific rules.
	WriteAllowPermissive bool `json:"write_allow_permissive,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

func (r *Rule) GetFollowsWhitelistAdminsBin() [][]byte

GetFollowsWhitelistAdminsBin returns the binary-encoded admin pubkeys for this rule.

func (*Rule) GetReadFollowsWhitelistBin added in v0.32.4

func (r *Rule) GetReadFollowsWhitelistBin() [][]byte

GetReadFollowsWhitelistBin returns the binary-encoded pubkeys for ReadFollowsWhitelist.

func (*Rule) GetWriteFollowsWhitelistBin added in v0.32.4

func (r *Rule) GetWriteFollowsWhitelistBin() [][]byte

GetWriteFollowsWhitelistBin returns the binary-encoded pubkeys for WriteFollowsWhitelist.

func (*Rule) HasFollowsWhitelistAdmins added in v0.31.2

func (r *Rule) HasFollowsWhitelistAdmins() bool

HasFollowsWhitelistAdmins returns true if this rule has FollowsWhitelistAdmins configured. DEPRECATED: Use HasReadFollowsWhitelist and HasWriteFollowsWhitelist instead.

func (*Rule) HasReadFollowsWhitelist added in v0.32.4

func (r *Rule) HasReadFollowsWhitelist() bool

HasReadFollowsWhitelist returns true if this rule has ReadFollowsWhitelist configured.

func (*Rule) HasWriteFollowsWhitelist added in v0.32.4

func (r *Rule) HasWriteFollowsWhitelist() bool

HasWriteFollowsWhitelist returns true if this rule has WriteFollowsWhitelist configured.

func (*Rule) IsInFollowsWhitelist added in v0.31.2

func (r *Rule) IsInFollowsWhitelist(pubkey []byte) bool

IsInFollowsWhitelist checks if the given pubkey is in this rule's follows whitelist. The pubkey parameter should be binary ([]byte), not hex-encoded.

func (*Rule) IsInReadFollowsWhitelist added in v0.32.4

func (r *Rule) IsInReadFollowsWhitelist(pubkey []byte) bool

IsInReadFollowsWhitelist checks if the given pubkey is in this rule's read follows whitelist. The pubkey parameter should be binary ([]byte), not hex-encoded. Returns true if either: 1. The pubkey is one of the ReadFollowsWhitelist pubkeys themselves, OR 2. The pubkey is in the follows list of the ReadFollowsWhitelist pubkeys.

func (*Rule) IsInWriteFollowsWhitelist added in v0.32.4

func (r *Rule) IsInWriteFollowsWhitelist(pubkey []byte) bool

IsInWriteFollowsWhitelist checks if the given pubkey is in this rule's write follows whitelist. The pubkey parameter should be binary ([]byte), not hex-encoded. Returns true if either: 1. The pubkey is one of the WriteFollowsWhitelist pubkeys themselves, OR 2. The pubkey is in the follows list of the WriteFollowsWhitelist pubkeys.

func (*Rule) UpdateFollowsWhitelist added in v0.31.2

func (r *Rule) UpdateFollowsWhitelist(follows [][]byte)

UpdateFollowsWhitelist sets the follows list for this rule's FollowsWhitelistAdmins. The follows should be binary pubkeys ([]byte), not hex-encoded.

func (*Rule) UpdateReadFollowsWhitelist added in v0.32.4

func (r *Rule) UpdateReadFollowsWhitelist(follows [][]byte)

UpdateReadFollowsWhitelist sets the follows list for this rule's ReadFollowsWhitelist. The follows should be binary pubkeys ([]byte), not hex-encoded.

func (*Rule) UpdateWriteFollowsWhitelist added in v0.32.4

func (r *Rule) UpdateWriteFollowsWhitelist(follows [][]byte)

UpdateWriteFollowsWhitelist sets the follows list for this rule's WriteFollowsWhitelist. The follows should be binary pubkeys ([]byte), not hex-encoded.

type RuleExtension added in v0.31.4

type RuleExtension struct {
	// WriteAllowAdd adds pubkeys to the write allow list
	WriteAllowAdd []string `json:"write_allow_add,omitempty"`
	// WriteDenyAdd adds pubkeys to the write deny list (overrides allow)
	WriteDenyAdd []string `json:"write_deny_add,omitempty"`
	// ReadAllowAdd adds pubkeys to the read allow list
	ReadAllowAdd []string `json:"read_allow_add,omitempty"`
	// ReadDenyAdd adds pubkeys to the read deny list (overrides allow)
	ReadDenyAdd []string `json:"read_deny_add,omitempty"`

	// SizeLimitOverride can only make the limit MORE permissive (larger)
	SizeLimitOverride *int64 `json:"size_limit_override,omitempty"`
	// ContentLimitOverride can only make the limit MORE permissive (larger)
	ContentLimitOverride *int64 `json:"content_limit_override,omitempty"`
	// MaxAgeOfEventOverride can only make the limit MORE permissive (older allowed)
	MaxAgeOfEventOverride *int64 `json:"max_age_of_event_override,omitempty"`
	// MaxAgeEventInFutureOverride can only make the limit MORE permissive (further future allowed)
	MaxAgeEventInFutureOverride *int64 `json:"max_age_event_in_future_override,omitempty"`

	// WriteAllowFollows extends the follow whitelist feature
	WriteAllowFollows *bool `json:"write_allow_follows,omitempty"`
	// FollowsWhitelistAdminsAdd adds admin pubkeys whose follows are whitelisted
	FollowsWhitelistAdminsAdd []string `json:"follows_whitelist_admins_add,omitempty"`
}

RuleExtension defines how a policy admin can extend an existing owner rule. All fields are additive - they extend, not replace, the owner's configuration.

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

  • composition.go
  • policy.go

Jump to

Keyboard shortcuts

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