POLICY_README.md raw

ORLY Policy System

The ORLY relay includes a comprehensive policy system that allows fine-grained control over event storage and retrieval based on various criteria including event kinds, pubkeys, content, and custom script logic.

Configuration

Enable the policy system by setting the environment variable:

export ORLY_POLICY_ENABLED=true

Policy Configuration File

The policy configuration is loaded from $HOME/.config/ORLY/policy.json. See docs/example-policy.json for a complete example with global rules and age validation.

Structure

{
  "default_policy": "allow",
  "kind": {
    "whitelist": [1, 3, 5, 7, 9735],
    "blacklist": []
  },
  "global": {
    "description": "Global rules applied to all events",
    "write_allow": [],
    "write_deny": [],
    "read_allow": [],
    "read_deny": [],
    "size_limit": 100000,
    "content_limit": 50000,
    "max_age_of_event": 86400,
    "max_age_event_in_future": 300
  },
  "rules": {
    "1": {
      "description": "Text notes - allow all authenticated users",
      "write_allow": [],
      "write_deny": [],
      "read_allow": [],
      "read_deny": [],
      "size_limit": 32000,
      "content_limit": 10000,
      "max_age_of_event": 3600,
      "max_age_event_in_future": 60
    }
  }
}

Default Policy

The default_policy field determines the default behavior when no specific rules deny an event:

This applies to:

Policy Evaluation Order

The policy system evaluates events in the following order:

  1. Global Rules - Applied to all events first
  2. Kinds Filtering - Whitelist/blacklist by event kind
  3. Kind-specific Rules - Rules for specific event kinds
  4. Script Rules - Custom script logic (if enabled)
  5. Default Policy - Applied when no rules make a decision

Global Rules

The global section defines rules that apply to all events regardless of their kind. These rules are evaluated first and take precedence over kind-specific rules.

Global rules support all the same fields as kind-specific rules, allowing you to:

Kinds Filtering

Rule Fields

Age Validation

The policy system includes built-in timestamp validation to prevent common attacks:

MaxAgeOfEvent

- Prevent replay of old events - Ensure events are recent and relevant - Reduce storage of stale data

MaxAgeEventInFuture

- Prevent clock manipulation attacks - Ensure reasonable timestamp accuracy - Block events with impossible future timestamps

Age Validation Examples

{
  "global": {
    "max_age_of_event": 86400,        // Reject events older than 24 hours
    "max_age_event_in_future": 300   // Reject events more than 5 minutes in future
  },
  "rules": {
    "1": {
      "max_age_of_event": 3600,      // Text notes: reject older than 1 hour
      "max_age_event_in_future": 60  // Text notes: reject more than 1 minute in future
    },
    "4": {
      "max_age_of_event": 604800     // Direct messages: reject older than 7 days
    }
  }
}

Policy Scripts

For advanced policy logic, you can use custom scripts. The script should be placed at $HOME/.config/ORLY/policy.sh and made executable.

Script Interface

The script receives JSON events via stdin and outputs JSON responses via stdout. Each event includes:

Response Format

{"id": "event_id", "action": "accept|reject|shadowReject", "msg": "optional message"}

Example Script

See docs/example-policy.sh for a complete example showing:

Integration Points

EVENT Processing

When policy is enabled, every EVENT envelope is checked using CheckPolicy("write", event, loggedInPubkey, ipAddress) before being stored. The policy evaluation follows this order:

  1. Global Rules - Applied first to all events
  2. Kinds Filtering - Whitelist/blacklist check
  3. Kind-specific Rules - Rules for the event's kind
  4. Script Rules - Custom script logic (if enabled)

REQ Processing

When policy is enabled, every event returned in REQ responses is filtered using CheckPolicy("read", event, loggedInPubkey, ipAddress) before being sent to the client. The same evaluation order applies for read access.

Script Resilience

The policy system is designed to be resilient to script failures:

Automatic Recovery

Fallback Behavior

When a policy script fails or is not running:

Error Handling

Monitoring

Policy decisions and script health are logged:

Policy Decisions

Script Health

Best Practices

Global Rules

Age Validation

- Text notes (kind 1): 1-24 hours max age, 1-5 minutes future tolerance - Direct messages (kind 4): 7-30 days max age, 1-5 minutes future tolerance - Replaceable events (kind 0, 3): Longer max age, shorter future tolerance

Policy Hierarchy

Security Considerations