pbring 0.1.0

Secure macOS clipboard history daemon
# pbring

Secure macOS clipboard history daemon. Encrypted, headless, pipe-first.
Like [cliphist](https://github.com/sentriz/cliphist), but for macOS.

*pasteboard + ring -- stores copy history in an encrypted ring buffer, like Emacs kill-ring.*

## Features

- AES-256-GCM per-entry encryption with key stored in macOS Keychain
- Automatic filtering of passwords (1Password, Keychain, etc.) via NSPasteboard markers
- Loop prevention via `org.nspasteboard.source`
- TTL-based auto-expiry (default: 24h)
- Memory safety with `zeroize` -- plaintext is wiped on drop
- No UI -- pure CLI, composable with any picker via pipes

## Install

```bash
cargo install --path .
```

## Quick Start

```bash
# Start the daemon (foreground)
pbringd

# Or register with launchd for auto-start
cp resources/com.pbring.daemon.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.pbring.daemon.plist

# Pick from history and copy to clipboard
pbring list | fzf | pbring copy
```

## Commands

### `pbringd`

Daemon binary. Polls `NSPasteboard.general.changeCount` every 500ms, encrypts and stores clipboard content in SQLite.

- PID file: `~/.local/state/pbring/pbringd.pid`
- Handles `SIGTERM` / `SIGINT` for clean shutdown

### `pbring list`

```
<id>\t<timestamp>\t<type>\t<preview>
```

| Option | Description |
|--------|-------------|
| `--limit N` | Max entries to show (default: 100) |
| `--type text\|image\|file` | Filter by media type |

### `pbring get`

Reads one line from stdin (`<id>\t...`), retrieves and decrypts the entry, and writes raw bytes to stdout. Useful for piping to other tools.

```bash
pbring list | head -1 | pbring get
```

### `pbring copy`

Reads one line from stdin (`<id>\t...`), retrieves and decrypts the entry, and writes it to the system pasteboard with the correct UTI. Works with text, images, and files.

```bash
pbring list | fzf | pbring copy
```

### `pbring delete`

Reads one line from stdin and deletes the entry.

```bash
echo "42" | pbring delete
```

### `pbring clear`

Deletes all entries. DB file remains.

### `pbring wipe`

Deletes all entries, zero-fills the DB file, then removes it.

## Security

### Pasteboard Marker Filtering

The daemon inspects `NSPasteboard.general.types` and skips entries with these markers:

| Marker | Source |
|--------|--------|
| `org.nspasteboard.ConcealedType` | Passwords (1Password, LastPass, Keychain) |
| `org.nspasteboard.TransientType` | Temporary content (TextExpander) |
| `org.nspasteboard.AutoGeneratedType` | Auto-generated content (Keyboard Maestro) |
| `com.agilebits.onepassword` | 1Password specific |
| `PasswordPboardType` | Legacy password marker |

### Encryption

- Algorithm: AES-256-GCM with random 96-bit nonce per entry
- Key: 256-bit, generated on first run, stored in macOS Keychain (`com.pbring.encryption-key`)
- Keychain access via `security` CLI

### Memory Safety

- Decrypted data held in `Zeroizing<Vec<u8>>` -- wiped on drop
- Encryption key held in `Zeroizing<[u8; 32]>`

## Configuration

`~/.config/pbring/config.toml`

```toml
poll_interval_ms = 500        # Polling interval (ms)
max_entries = 1000             # Max stored entries
ttl_seconds = 86400            # Entry TTL (0 = no expiry)
max_entry_bytes = 10_485_760   # Max entry size (10MB)
record_types = ["text", "image", "file"]
extra_ignored_types = []       # Additional NSPasteboardType strings to ignore
ignored_apps = []              # Bundle IDs to ignore
preview_max_chars = 100        # Preview truncation length
```

All fields are optional; defaults are shown above.

## File Locations

| File | Path |
|------|------|
| Database | `~/.local/share/pbring/history.db` |
| Config | `~/.config/pbring/config.toml` |
| PID file | `~/.local/state/pbring/pbringd.pid` |
| launchd plist | `~/Library/LaunchAgents/com.pbring.daemon.plist` |

## Requirements

- macOS 14 (Sonoma) or later
- Rust 1.75+

## License

MIT