v0.0.1
This commit is contained in:
commit
f86e0ce7dd
|
@ -0,0 +1 @@
|
|||
Nostr_NIPs/
|
|
@ -0,0 +1,153 @@
|
|||
# Superball Daemon Rules
|
||||
|
||||
## What I Am
|
||||
I am Superball - an anonymizing node that provides location privacy for Nostr users by forwarding their encrypted events with timing delays and size obfuscation.
|
||||
|
||||
## What I Look For
|
||||
|
||||
### 1. Routing Events (Kind 30000)
|
||||
- Monitor all relays I'm connected to
|
||||
- Look for events with `kind: 30000`
|
||||
- Check if `tags` contains `["p", "<my_pubkey>"]`
|
||||
- These are events meant for me to process
|
||||
|
||||
### 2. Event Structure I Expect
|
||||
```json
|
||||
{
|
||||
"kind": 30000,
|
||||
"pubkey": "<some_ephemeral_key>", // Not important to me
|
||||
"content": "<nip44_encrypted_payload>", // This is what I need
|
||||
"tags": [["p", "<my_pubkey>"]],
|
||||
"created_at": <timestamp>,
|
||||
"id": "<event_id>",
|
||||
"sig": "<signature>"
|
||||
}
|
||||
```
|
||||
|
||||
## What I Do When I Receive An Event
|
||||
|
||||
### 1. Validate
|
||||
- Verify the event signature is valid
|
||||
- Confirm the `p` tag contains my pubkey
|
||||
- Ensure it's kind 30000
|
||||
|
||||
### 2. Decrypt
|
||||
- Use my private key with NIP-44 to decrypt the content
|
||||
- Extract the payload which contains:
|
||||
```json
|
||||
{
|
||||
"event": { /* The event to forward */ },
|
||||
"routing": {
|
||||
"relays": ["wss://relay1.com", "wss://relay2.com"],
|
||||
"delay": 30,
|
||||
"pad": "+150", // or "-50"
|
||||
"p": "next_superball_pubkey", // Optional - missing means final posting
|
||||
"audit": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", // Required audit tag
|
||||
"payment": "eCash_token" // Optional
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Process Routing Instructions
|
||||
|
||||
#### Delay
|
||||
- Wait the specified number of seconds before forwarding
|
||||
- Add random jitter (±10%) to prevent timing analysis
|
||||
- Queue the event for delayed processing
|
||||
|
||||
#### Padding
|
||||
- **Remove padding (`"pad": "-N"`)**: Delete N bytes worth of padding tags from the event
|
||||
- **Add padding (`"pad": "+N"`)**: Create new routing wrapper with N bytes of padding tags
|
||||
|
||||
#### Relays
|
||||
- Post to ALL relays in the `relays` array
|
||||
- Validate all relay URLs are properly formatted
|
||||
- Provides redundancy and availability
|
||||
|
||||
#### Next Hop Logic
|
||||
- **`p` field present**: Create routing event for specified next Superball (can apply padding)
|
||||
- **`p` field missing**: Extract inner event and post directly to relays (end chain, no padding changes)
|
||||
|
||||
#### Padding Logic
|
||||
- **`p` field present + `pad` field**: Apply padding changes when creating routing wrapper
|
||||
- **`p` field missing**: Ignore any `pad` field - cannot modify signed event
|
||||
- **Final hop rule**: Never modify signed events, post exactly as received
|
||||
|
||||
#### Audit Tag Processing
|
||||
- **`audit` field**: Always present - include as `["p", "<audit_tag>"]` in routing event
|
||||
- **Camouflage**: Audit tag looks identical to real next-hop pubkeys
|
||||
- **Security**: Enables user detection of dropped/delayed/modified events
|
||||
|
||||
#### Payment Processing
|
||||
- **`payment` field present**: Process eCash token for service payment
|
||||
- **`payment` field missing**: Process for free (if daemon allows)
|
||||
|
||||
### 4. Forward Event
|
||||
|
||||
#### Always Rewrap (Important for Privacy)
|
||||
**ALWAYS** create a new routing event to hide whether padding was added or removed:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 30000, // Always use routing event
|
||||
"pubkey": "<my_ephemeral_key>", // Generate fresh ephemeral key
|
||||
"content": "<encrypted_inner_event>", // Re-encrypt with my key
|
||||
"tags": [
|
||||
["p", "<next_hop_or_final_destination>"],
|
||||
["p", "<audit_tag_from_routing>"], // Always include audit tag as p tag
|
||||
["padding", "<random_data_1>"], // Adjusted padding
|
||||
["padding", "<random_data_2>"] // May be more or less than before
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Next Hop Handling
|
||||
- **If `p` field in routing**: Create routing event with that pubkey in p tag
|
||||
- **If no `p` field in routing**: Extract inner event and post directly to all relays
|
||||
- **Multi-relay posting**: Post to every relay in the `relays` array
|
||||
- **End of chain**: When no `p` field, I am the final hop
|
||||
|
||||
## My Rules
|
||||
|
||||
### Security Rules
|
||||
1. **Never log sensitive data** - Don't store decrypted content or routing info
|
||||
2. **Generate new keys** - Use fresh ephemeral keys for each forward
|
||||
3. **Validate everything** - Check signatures, event structure, relay URLs
|
||||
4. **Rate limiting** - Don't process more than X events per minute from same source
|
||||
|
||||
### Privacy Rules
|
||||
1. **No correlation** - Don't link input events to output events in logs
|
||||
2. **Clear memory** - Immediately clear decrypted data after processing
|
||||
3. **Random timing** - Add jitter to specified delays
|
||||
4. **Mix traffic** - Send decoy traffic when idle (optional)
|
||||
|
||||
### Processing Rules
|
||||
1. **First come, first served** - Process events in order received
|
||||
2. **Fail silently** - Drop invalid events without response
|
||||
3. **Retry logic** - Attempt to post 3 times before giving up
|
||||
4. **Resource limits** - Drop oldest queued events if memory/queue full
|
||||
|
||||
### Network Rules
|
||||
1. **Multiple relays** - Connect to diverse set of relays
|
||||
2. **Separate connections** - Use different connections for input/output
|
||||
3. **AUTH support** - Prefer relays that support AUTH for privacy
|
||||
4. **Rotate connections** - Periodically reconnect to prevent fingerprinting
|
||||
|
||||
## What I Never Do
|
||||
|
||||
1. **Never modify final signatures** - Only remove padding tags, never add to signed events
|
||||
2. **Never store routing paths** - Process and forget
|
||||
3. **Never respond to clients** - Silent operation only
|
||||
4. **Never correlate users** - Each event is independent
|
||||
5. **Never log destinations** - Only log operational metrics
|
||||
|
||||
## Example Processing Flow
|
||||
|
||||
1. **Receive**: Kind 30000 event with my pubkey in p tag
|
||||
2. **Decrypt**: Extract inner event + routing instructions
|
||||
3. **Queue**: Schedule for delayed processing (e.g., 30 seconds + jitter)
|
||||
4. **Process**: Apply padding changes and prepare for forwarding
|
||||
5. **Forward**: Post to target relay(s)
|
||||
6. **Clean**: Clear all decrypted data from memory
|
||||
|
||||
I am a privacy-preserving relay that helps users post content while hiding their location. I ask no questions, store no logs, and remember nothing about the events that pass through me.
|
|
@ -0,0 +1,157 @@
|
|||
# Superball Example: Anonymous Posting
|
||||
|
||||
## Scenario
|
||||
Alice wants to post a message under her real identity while hiding her location from surveillance.
|
||||
|
||||
### Participants
|
||||
- **Alice**: Original sender (pubkey: `alice123...`)
|
||||
- **Superball A**: First hop (pubkey: `sball_a789...`)
|
||||
- **Superball B**: Second hop (pubkey: `sball_b012...`)
|
||||
- **Relay1**: `wss://relay1.com` (where Alice posts)
|
||||
- **Relay2**: `wss://relay2.com` (intermediate relay)
|
||||
- **Relay3**: `wss://relay3.com` (where final message appears)
|
||||
|
||||
## Step-by-Step Flow
|
||||
|
||||
### 1. Alice Creates Her Final Message That Will Be Posted
|
||||
```json
|
||||
{
|
||||
"kind": 1,
|
||||
"pubkey": "alice123...",
|
||||
"content": "The government is lying about inflation statistics",
|
||||
"tags": [],
|
||||
"created_at": 1703000000,
|
||||
"id": "alice_event_id",
|
||||
"sig": "alice_signature"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Alice Encrypts Instructions for Superball B (Final Hop)
|
||||
Payload for Superball B (final hop - no `p` field):
|
||||
```json
|
||||
{
|
||||
"event": { /* Alice's signed event above */ },
|
||||
"routing": {
|
||||
"relays": ["wss://relay3.com", "wss://relay4.com"],
|
||||
"delay": 15,
|
||||
"audit": "9f8e7d6c5b4a39281726354019283746502918374650283746501928374650"
|
||||
// No "p" field - this means final posting
|
||||
// No "pad" field - can't modify signed event
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Creates routing event:
|
||||
```json
|
||||
{
|
||||
"kind": 30000,
|
||||
"pubkey": "ephemeral_key_2",
|
||||
"content": "<encrypted_payload_for_superball_b>",
|
||||
"tags": [["p", "sball_b012..."]],
|
||||
"created_at": 1703000100,
|
||||
"id": "routing_for_b",
|
||||
"sig": "ephemeral_signature_2"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Alice Encrypts Instructions for Superball A (First Hop)
|
||||
Payload for Superball A (continuing chain):
|
||||
```json
|
||||
{
|
||||
"event": { /* routing event for Superball B above */ },
|
||||
"routing": {
|
||||
"relays": ["wss://relay2.com"],
|
||||
"delay": 45,
|
||||
"pad": "+200",
|
||||
"p": "sball_b012...", // Next Superball in chain
|
||||
"audit": "1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890",
|
||||
"payment": "eCash_A1B2C3..." // Optional payment
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alice posts this to Relay1:
|
||||
```json
|
||||
{
|
||||
"kind": 30000,
|
||||
"pubkey": "ephemeral_key_1",
|
||||
"content": "<encrypted_payload_for_superball_a>",
|
||||
"tags": [["p", "sball_a789..."]],
|
||||
"created_at": 1703000200,
|
||||
"id": "routing_for_a",
|
||||
"sig": "ephemeral_signature_1"
|
||||
}
|
||||
```
|
||||
|
||||
## Execution Timeline
|
||||
|
||||
**T+0**: Alice posts routing event to Relay1
|
||||
```
|
||||
Relay1: kind 30000 event (p tag = sball_a789...)
|
||||
```
|
||||
|
||||
**T+5**: Superball A processes
|
||||
- Decrypts payload
|
||||
- Sees: relay2.com, delay 45s, pad +200
|
||||
- Needs to ADD padding, so creates new wrapper
|
||||
- Queues for 45-second delay
|
||||
|
||||
**T+50**: Superball A always rewraps (consistent behavior)
|
||||
```
|
||||
Relay2: NEW routing event (always looks the same)
|
||||
{
|
||||
"kind": 30000,
|
||||
"pubkey": "superball_a_ephemeral_key", // Fresh key
|
||||
"content": "<newly_encrypted_payload>", // Re-encrypted
|
||||
"tags": [
|
||||
["p", "sball_b012..."], // Real next hop
|
||||
["p", "1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890"], // Audit tag
|
||||
["padding", "random_data_1..."], // Adjusted padding
|
||||
["padding", "random_data_2..."], // (+200 bytes added)
|
||||
["padding", "random_data_3..."]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Alice monitors relay2.com and sees her audit tag `1a2b3c4d5e6f...` appear at T+50 with correct +200 byte padding, confirming Superball A is honest.
|
||||
|
||||
**T+55**: Superball B processes
|
||||
- Decrypts payload
|
||||
- Sees: Alice's event + instructions (relays=[relay3.com, relay4.com], delay 15s)
|
||||
- NO `p` field - this means final posting, extract and post Alice's event exactly as-is
|
||||
- Cannot modify padding on signed event
|
||||
- Queues for 15-second delay
|
||||
|
||||
**T+70**: Superball B posts Alice's final event (end of chain)
|
||||
```
|
||||
Relay3 AND Relay4: Alice's original signed event appears exactly as she created it
|
||||
{
|
||||
"kind": 1,
|
||||
"pubkey": "alice123...",
|
||||
"content": "The government is lying about inflation statistics",
|
||||
"tags": [], // Original tags preserved
|
||||
"created_at": 1703000000,
|
||||
"id": "alice_event_id",
|
||||
"sig": "alice_signature" // Original signature preserved
|
||||
}
|
||||
```
|
||||
|
||||
Alice's message now appears on both relay3.com and relay4.com for redundancy.
|
||||
|
||||
## Privacy and Security Achieved
|
||||
|
||||
- **Alice's location**: Completely hidden from surveillance
|
||||
- **Message origin**: Appears to come from Superball B's location
|
||||
- **Traffic analysis**: 65-second delay + size changes prevent correlation
|
||||
- **Identity preserved**: Alice's real pubkey and signature maintained
|
||||
- **Plausible deniability**: No proof Alice initiated the posting
|
||||
- **Malicious node detection**: Audit tags allow Alice to verify proper forwarding
|
||||
- **Accountability**: Bad Superballs can be identified and avoided
|
||||
|
||||
### Audit Trail for Alice
|
||||
- **T+50**: Audit tag `1a2b3c4d5e6f...` appears on relay2.com (✓ Superball A honest)
|
||||
- **T+70**: Final message appears on relay3.com and relay4.com (✓ Superball B honest)
|
||||
- **Size verification**: Event sizes match expected padding operations
|
||||
- **Timing verification**: Delays match requested timeouts
|
||||
|
||||
Alice successfully posts controversial content under her identity while protecting her physical location AND maintaining the ability to detect and avoid malicious routing nodes.
|
|
@ -0,0 +1 @@
|
|||
Norman Stingley - inventor of the super-ball
|
|
@ -0,0 +1,198 @@
|
|||
# Superball Protocol
|
||||
|
||||
## Overview
|
||||
|
||||
Superball provides location privacy for Nostr by using encrypted routing through daemon nodes. Users can post content under their real identity while completely hiding their network location.
|
||||
|
||||
## Protocol Structure
|
||||
|
||||
### Step 1: Create Signed Event
|
||||
User creates and signs their normal Nostr event:
|
||||
```json
|
||||
{
|
||||
"kind": 1,
|
||||
"pubkey": "user_pubkey",
|
||||
"content": "Message content",
|
||||
"tags": [],
|
||||
"created_at": 1703000000,
|
||||
"id": "event_id",
|
||||
"sig": "user_signature"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Create Routing Instructions
|
||||
User creates routing instructions:
|
||||
```json
|
||||
{
|
||||
"relays": [
|
||||
"wss://target-relay1.com",
|
||||
"wss://target-relay2.com",
|
||||
"wss://target-relay3.com"
|
||||
],
|
||||
"delay": 30,
|
||||
"pad": "+150",
|
||||
"p": "superball_b_pubkey", // Next superball (optional - if missing, final posting)
|
||||
"audit": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", // Audit pubkey (always required)
|
||||
"payment": "eCash_token_here" // Optional payment for processing
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Encrypt and Send
|
||||
User creates a routing event with NIP-44 encryption:
|
||||
```json
|
||||
{
|
||||
"kind": 30000, // Superball routing event
|
||||
"pubkey": "ephemeral_key",
|
||||
"content": "<nip44_encrypted_payload>",
|
||||
"tags": [
|
||||
["p", "superball_pubkey"]
|
||||
],
|
||||
"created_at": 1703000100,
|
||||
"id": "routing_event_id",
|
||||
"sig": "ephemeral_signature"
|
||||
}
|
||||
```
|
||||
|
||||
The encrypted payload contains:
|
||||
```json
|
||||
{
|
||||
"event": {
|
||||
"kind": 1,
|
||||
"pubkey": "user_pubkey",
|
||||
"content": "Message content",
|
||||
"tags": [],
|
||||
"created_at": 1703000000,
|
||||
"id": "event_id",
|
||||
"sig": "user_signature"
|
||||
},
|
||||
"routing": {
|
||||
"relays": ["wss://target-relay1.com", "wss://target-relay2.com"],
|
||||
"delay": 30,
|
||||
"pad": "+150",
|
||||
"p": "next_superball_pubkey", // Optional - if missing, final posting
|
||||
"audit": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456", // Required audit pubkey
|
||||
"payment": "eCash_token" // Optional payment
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Superball Processing
|
||||
|
||||
1. **Receive**: Monitor for kind 30000 events with p tag = own pubkey
|
||||
2. **Decrypt**: Use NIP-44 to decrypt the content
|
||||
3. **Parse**: Extract the event and routing instructions
|
||||
4. **Apply Padding**: Modify padding according to instructions
|
||||
5. **Delay**: Wait specified time
|
||||
6. **Always Rewrap**: Create new routing event to hide padding operations
|
||||
7. **Forward**: Post the new routing event to specified relay
|
||||
|
||||
## Always Rewrap Rule
|
||||
|
||||
### Privacy Protection
|
||||
Superballs **ALWAYS** create a new routing wrapper to prevent analysis of padding operations:
|
||||
- **Consistent behavior**: Every forward looks the same (new routing event)
|
||||
- **Hide operations**: No way to tell if padding was added, removed, or unchanged
|
||||
- **Fresh encryption**: New ephemeral key and encryption for each hop
|
||||
- **Metadata mixing**: Padding levels change unpredictably at each hop
|
||||
|
||||
### Routing Event Structure
|
||||
Every forward creates a new kind 30000 event:
|
||||
```json
|
||||
{
|
||||
"kind": 30000,
|
||||
"pubkey": "<fresh_ephemeral_key>",
|
||||
"content": "<newly_encrypted_payload>",
|
||||
"tags": [
|
||||
["p", "<next_superball_or_final_user>"],
|
||||
["p", "<audit_pubkey_from_routing>"],
|
||||
["padding", "<adjusted_random_data>"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Audit Mechanism for Security
|
||||
|
||||
### Purpose
|
||||
The audit mechanism allows users to detect malicious Superballs that drop events, ignore timing delays, or modify padding incorrectly.
|
||||
|
||||
### Audit Tag Structure
|
||||
- **Format**: 64-character hex string (looks like a Nostr pubkey)
|
||||
- **Generation**: User creates random audit tag for each hop
|
||||
- **Labeling**: Always labeled as `["p", "<audit_pubkey>"]` in routing events
|
||||
- **Camouflage**: Indistinguishable from real next-hop pubkeys to observers
|
||||
|
||||
### How It Works
|
||||
1. **User includes audit tag** in routing instructions for each hop
|
||||
2. **Superball posts audit tag** as additional `p` tag when forwarding
|
||||
3. **User monitors relays** for audit tag appearances
|
||||
4. **Timing and size analysis** reveals compliance with instructions
|
||||
|
||||
### Example Audit Detection
|
||||
```json
|
||||
// Alice creates routing with audit tag
|
||||
{
|
||||
"relays": ["wss://relay2.com"],
|
||||
"delay": 45,
|
||||
"pad": "+200",
|
||||
"p": "sball_b_real_pubkey",
|
||||
"audit": "a1b2c3...fake_pubkey_for_audit"
|
||||
}
|
||||
|
||||
// Superball A should post this after 45s with +200 bytes:
|
||||
{
|
||||
"kind": 30000,
|
||||
"tags": [
|
||||
["p", "sball_b_real_pubkey"], // Real next hop
|
||||
["p", "a1b2c3...fake_pubkey"], // Audit tag (looks identical)
|
||||
["padding", "..."] // +200 bytes of padding
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Alice monitors relay2.com and verifies the audit tag appears with correct timing and size.
|
||||
|
||||
### Security Properties
|
||||
- **Misbehavior Detection**: Dropped, delayed, or incorrectly padded events
|
||||
- **Reputation Building**: Users can rate Superball reliability over time
|
||||
- **Privacy Preserved**: Audit tags look like normal routing to observers
|
||||
- **Always Active**: Every routing event includes audit verification
|
||||
|
||||
## Routing Instructions Fields
|
||||
|
||||
### Required Fields
|
||||
- **`relays`**: Array of relay URLs to post to (allows multi-relay posting)
|
||||
- **`delay`**: Minimum delay in seconds before forwarding
|
||||
|
||||
### Required Fields
|
||||
- **`audit`**: 64-character hex audit tag (format: Nostr pubkey)
|
||||
- User-generated random identifier for this hop
|
||||
- Always posted as `["p", "<audit_tag>"]` in routing event
|
||||
- Enables detection of malicious Superballs
|
||||
|
||||
### Optional Fields
|
||||
- **`pad`**: Padding instruction (`"+N"` to add, `"-N"` to remove N bytes)
|
||||
- Only valid when `p` field is present (continuing chain)
|
||||
- Ignored when `p` field missing (final hop - can't modify signed event)
|
||||
- **`p`**: Pubkey of next Superball in chain
|
||||
- If present: Create routing event for next Superball (can apply padding)
|
||||
- If missing: Post final event directly to relays (end of chain, no padding changes)
|
||||
- **`payment`**: eCash token for processing payment
|
||||
- Allows monetized Superball services
|
||||
- Optional - many daemons may operate for free
|
||||
|
||||
## Processing Logic
|
||||
|
||||
### Multi-Relay Posting
|
||||
Superballs post to ALL specified relays in the `relays` array for redundancy and availability.
|
||||
|
||||
### Chain Termination
|
||||
- **`p` field present**: Continue routing chain to specified Superball
|
||||
- **`p` field missing**: Extract and post final event directly, end chain
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Location Privacy**: User's network location completely hidden
|
||||
- **Identity Preservation**: Posts appear with user's real pubkey
|
||||
- **Simple Implementation**: Single NIP-44 encryption layer per hop
|
||||
- **Purpose-Built**: Designed specifically for anonymous posting
|
||||
- **Traffic Analysis Resistance**: Timing delays and padding protect against correlation
|
|
@ -0,0 +1,29 @@
|
|||
# Superball
|
||||

|
||||
|
||||
Superball provides Tor-like location privacy for Nostr users. It's a daemon that bounces encrypted events between relays, allowing users to post content under their real identity while completely hiding their network location.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **User creates content** - Normal signed Nostr event with their real pubkey
|
||||
2. **Encrypt with routing** - Bundle event + routing instructions, encrypt to Superball daemon
|
||||
3. **Anonymous forwarding** - Event bounces through multiple daemons with delays and padding
|
||||
4. **Final posting** - Original event appears on target relay with user's identity but from daemon's location
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Location Privacy**: Hide your network location while preserving your identity
|
||||
- **Traffic Analysis Resistance**: Random delays and size padding prevent correlation
|
||||
- **Simple Protocol**: Uses NIP-44 encryption with new kind 30000 for routing
|
||||
- **Flexible Routing**: Support for multi-hop paths through multiple daemons
|
||||
- **Signature Preservation**: Original event signatures maintained for authenticity
|
||||
- **Audit Security**: Detect and avoid malicious Superballs through cryptographic verification
|
||||
|
||||
## Documentation
|
||||
|
||||
- [`PROTOCOL.md`](PROTOCOL.md) - Technical protocol specification
|
||||
- [`EXAMPLE.md`](EXAMPLE.md) - Complete walkthrough example
|
||||
- [`DAEMON.md`](DAEMON.md) - Rules and behavior for Superball daemon operators
|
||||
|
||||
Perfect for journalists, activists, or anyone who needs to protect their physical location while maintaining accountability for their public statements.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
Loading…
Reference in New Issue