# promocrypt
```
_
_ __ _ __ ___ _ __ ___ ___ ___ _ __ _ _ _ __ | |_
| '_ \| '__/ _ \| '_ ` _ \ / _ \ / __| '__| | | | '_ \| __|
## Quick Start
### 1. Create a .bin file
```bash
# Create a new .bin file with default settings
promocrypt create --name production --secret "my-secure-password"
# Create with custom formatting
promocrypt create --name promo2024 \
--secret "password" \
--prefix "PROMO-" \
--suffix "-2024" \
--separator "-" \
--separator-positions "4,8"
```
### 2. Generate codes
```bash
# Generate a single code
promocrypt generate --secret "my-secure-password"
# Generate 1000 codes to file
promocrypt generate --secret "password" -n 1000 -o codes.txt
# Generate with database insertion
promocrypt generate --secret "password" -n 10000 --db db.toml --table promos
```
### 3. Validate codes
```bash
# Validate a single code
promocrypt validate PROMO-A3KF-7NP2-2024
# Validate from file
promocrypt validate -f codes.txt --summary
# Validate with quiet mode (only show invalid)
promocrypt validate -f codes.txt --quiet
```
---
## Commands Reference
### Global Options
```
promocrypt [OPTIONS] <COMMAND>
Options:
--bin <PATH> Path to .bin file (default: ./promocrypt.bin)
--format <FORMAT> Output format: plain, json, csv (default: plain)
--quiet Suppress non-essential output
--env-file <PATH> Load environment from file
-h, --help Print help
-V, --version Print version
```
### create
Create a new .bin file.
```bash
promocrypt create [OPTIONS]
Options:
--name <NAME> Secret name (required)
--secret <SECRET> Secret password (prompted if not provided)
--alphabet <ALPHABET> Custom alphabet (default: 0234679ABCDEFGHJKMNPQRTUXY)
--length <N> Code length excluding check (default: 9)
--check-position <POS> Check digit position: 0=start, -1=end, N=position
--counter-mode <MODE> Counter mode: file, inbin, manual (default: file)
--counter-path <PATH> Path for counter file
--force Overwrite if exists
--prefix <PREFIX> Prefix for generated codes
--suffix <SUFFIX> Suffix for generated codes
--separator <CHAR> Separator character (e.g., '-')
--separator-positions <POS> Comma-separated positions (e.g., "4,8")
--storage-encryption Enable storage encryption for codes
Examples:
# Basic
promocrypt create --name prod --secret "password"
# With formatting
promocrypt create --name promo --secret "pass" \
--prefix "SALE-" --separator "-" --separator-positions "4,8"
# With storage encryption
promocrypt create --name secure --secret "pass" --storage-encryption
```
### info
Show .bin file information.
```bash
promocrypt info [OPTIONS]
Options:
--show-audit Show audit trail details
--show-history Show history (rotations, masterings, changes)
--show-generation-log Show generation log
--show-machine-id Show current machine ID
--json Output as JSON
Examples:
promocrypt info
promocrypt info --show-history --json
promocrypt info --show-machine-id
```
### generate
Generate promotional codes.
```bash
promocrypt generate [OPTIONS]
Options:
--secret <SECRET> Secret password
-n, --count <N> Number of codes (default: 1)
-c, --counter <N> Manual counter value
-o, --output <FILE> Output file (default: stdout)
--chunk-size <N> Chunk size for batches (default: 10000)
--dry-run Preview without generating
--rate-limit <N> Max codes per second (0 = unlimited)
# Format options (override .bin config)
--prefix <PREFIX> Add prefix to codes
--suffix <SUFFIX> Add suffix to codes
--separator <CHAR> Separator character
--separator-positions <POS> Separator positions
# Database options
--db <CONFIG> Database config file (TOML)
--table <TABLE> Target table name
--column <COLUMN> Code column name (default: code)
--retry-duplicates Auto-retry on duplicate key conflict
# Typed column values
--set <KEY=VALUE> Set string column
--set-int <KEY=VALUE> Set integer column
--set-float <KEY=VALUE> Set float column
--set-bool <KEY=VALUE> Set boolean column
--set-now <KEY> Set column to current timestamp
--set-json <KEY=VALUE> Set JSON/JSONB column
--set-null <KEY> Set column to NULL
--extra <JSON> Extra columns as JSON
# External command
--exec <COMMAND> Pipe codes to external command
--exec-format <FMT> Format: plain, jsonl (default: plain)
Examples:
# Generate to stdout
promocrypt generate --secret pass -n 10
# Generate to file
promocrypt generate --secret pass -n 1000 -o codes.txt
# Generate with database
promocrypt generate --secret pass -n 10000 --db db.toml --table promos \
--set-int campaign_id=123 --set status=active --set-now created_at
# Dry run
promocrypt generate --secret pass -n 10 --dry-run
```
### validate
Validate promotional codes.
```bash
promocrypt validate [OPTIONS] [CODE]
Arguments:
[CODE] Single code to validate
Options:
-f, --file <FILE> File with codes (one per line)
--from-db Validate all codes in database table
--db <CONFIG> Database config (for --from-db)
--table <TABLE> Table to read codes from
--column <COLUMN> Code column name (default: code)
--quiet Only output invalid codes
--summary Show summary at end
Examples:
promocrypt validate A3KF7NP2XM
promocrypt validate -f codes.txt --summary
promocrypt validate --from-db --db db.toml --table promos
```
### lookup
Look up code status in database.
```bash
promocrypt lookup [OPTIONS] <CODE>
Arguments:
<CODE> Code to look up
Options:
--db <CONFIG> Database config file (required)
--table <TABLE> Table name (required)
--column <COLUMN> Code column name (default: code)
Example:
promocrypt lookup PROMO-A3KF7NP2XM-2024 --db db.toml --table promos
```
### stats
Show statistics about .bin file and database.
```bash
promocrypt stats [OPTIONS]
Options:
--db <CONFIG> Include database statistics
--table <TABLE> Table to count codes in
Examples:
promocrypt stats
promocrypt stats --db db.toml --table promos
```
### export
Export codes from database.
```bash
promocrypt export [OPTIONS]
Options:
--db <CONFIG> Database config (required)
--table <TABLE> Table name (required)
--column <COLUMN> Code column name (default: code)
-o, --output <FILE> Output file (required)
--export-format <FMT> Format: csv, json, sql (default: csv)
--where <CONDITION> SQL WHERE clause
--limit <N> Maximum rows to export
Examples:
promocrypt export --db db.toml --table promos -o codes.csv
promocrypt export --db db.toml --table promos -o unused.json \
--export-format json --where "used_at IS NULL"
```
### master
Master .bin for a different machine.
```bash
promocrypt master [OPTIONS]
Options:
--secret <SECRET> Secret password
--output <PATH> Output path for mastered .bin
--target-machine <HEX> Target machine ID (hex)
--show-machine-id Show machine ID and exit
Examples:
# Get your machine ID
promocrypt master --show-machine-id
# Master for another machine
promocrypt master --secret pass --output server.bin \
--target-machine a1b2c3d4e5f6...
```
### config
View or modify .bin configuration.
```bash
promocrypt config [OPTIONS]
Options:
--secret <SECRET> Secret password (required for modifications)
--show Show current configuration
--set-prefix <PREFIX> Set prefix (empty string to remove)
--set-suffix <SUFFIX> Set suffix (empty string to remove)
--set-separator <CHAR> Set separator character
--set-separator-positions <POS> Set separator positions
--set-check-position <N> Set check position index
--set-storage-encryption <BOOL> Enable/disable storage encryption
Examples:
promocrypt config --show
promocrypt config --secret pass --set-prefix "NEW-"
promocrypt config --secret pass --set-storage-encryption true
```
### rotate-secret
Rotate secret password.
```bash
promocrypt rotate-secret [OPTIONS]
Options:
--old-secret <SECRET> Current secret
--new-secret <SECRET> New secret (prompted if not provided)
Example:
promocrypt rotate-secret --old-secret "old-pass" --new-secret "new-pass"
```
### history
View, export, or clear history.
```bash
promocrypt history [OPTIONS]
Options:
--export <FILE> Export history to JSON file
--clear Clear history (requires --secret)
--keep-last <N> Keep last N entries when clearing
--secret <SECRET> Required for --clear
Examples:
promocrypt history
promocrypt history --export history.json
promocrypt history --clear --keep-last 10 --secret pass
```
### generation-log
View, export, or clear generation log.
```bash
promocrypt generation-log [OPTIONS]
Options:
--export <FILE> Export log to JSON file
--clear Clear log (requires --secret)
--keep-last <N> Keep last N entries when clearing
--secret <SECRET> Required for --clear
--summary Show summary only
Examples:
promocrypt generation-log
promocrypt generation-log --summary
promocrypt generation-log --export gen-log.json
```
### pg-import
Import .bin file into PostgreSQL.
```bash
promocrypt pg-import [OPTIONS]
Options:
--db <CONFIG> PostgreSQL config file (required)
--secret <SECRET> Secret password (required)
--name <NAME> Name in PostgreSQL (default: use .bin name)
Example:
promocrypt pg-import --db pg.toml --secret pass
```
### pg-export
Export .bin from PostgreSQL to file.
```bash
promocrypt pg-export [OPTIONS]
Options:
--db <CONFIG> PostgreSQL config file (required)
--name <NAME> Secret name in PostgreSQL (required)
--secret <SECRET> Secret password (required)
-o, --output <PATH> Output .bin file path (required)
Example:
promocrypt pg-export --db pg.toml --name campaign --secret pass -o campaign.bin
```
### completions
Generate shell completions.
```bash
promocrypt completions <SHELL>
Arguments:
<SHELL> Shell: bash, zsh, fish, powershell, elvish
Example:
promocrypt completions bash > ~/.local/share/bash-completion/completions/promocrypt
```
---
## Database Integration
### PostgreSQL Setup
1. Create a database config file:
```toml
# db-postgres.toml
[database]
type = "postgresql"
host = "localhost"
port = 5432
database = "mydb"
user = "user"
password = "password"
# OR use connection string:
# connection_string = "postgres://user:pass@localhost/mydb"
[insert]
table = "promo_codes"
code_column = "code"
[insert.extra]
campaign_id = 123
status = "active"
```
2. Create the table:
```sql
CREATE TABLE promo_codes (
id SERIAL PRIMARY KEY,
code VARCHAR(50) UNIQUE NOT NULL,
campaign_id INTEGER,
status VARCHAR(20) DEFAULT 'active',
used_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW()
);
```
3. Generate codes:
```bash
promocrypt generate --secret pass -n 10000 --db db-postgres.toml
```
### SQLite Setup
1. Create a database config file:
```toml
# db-sqlite.toml
[database]
type = "sqlite"
path = "./codes.db"
[insert]
table = "promo_codes"
code_column = "code"
```
2. Create the database:
```bash
sqlite3 codes.db "CREATE TABLE promo_codes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT UNIQUE NOT NULL,
campaign_id INTEGER,
status TEXT DEFAULT 'active',
used_at TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);"
```
3. Generate codes:
```bash
promocrypt generate --secret pass -n 10000 --db db-sqlite.toml
```
---
## Typed Column Values
Set column values with proper types during generation:
| `--set` | String | `--set status=active` |
| `--set-int` | Integer | `--set-int campaign_id=123` |
| `--set-float` | Float | `--set-float discount=19.99` |
| `--set-bool` | Boolean | `--set-bool single_use=true` |
| `--set-now` | Timestamp | `--set-now created_at` |
| `--set-json` | JSON/JSONB | `--set-json meta='{"source":"cli"}'` |
| `--set-null` | NULL | `--set-null deleted_at` |
**Priority:** `--set-*` > `--extra` > config file
**Example:**
```bash
promocrypt generate --secret pass -n 1000 --db db.toml --table promos \
--set-int campaign_id=123 \
--set-int discount=20 \
--set status=active \
--set-bool single_use=true \
--set-now created_at \
--set-json metadata='{"source": "cli", "version": 1}'
```
---
## External Commands
Pipe codes to any external program for custom database insertion:
```bash
# Plain text (one code per line)
promocrypt generate --secret pass -n 10000 --exec "./my-inserter.sh"
# JSON lines with extra data
promocrypt generate --secret pass -n 10000 \
--exec "python insert.py" \
--exec-format jsonl \
--set-int campaign_id=123
```
### Example Scripts
**Bash + psql (PostgreSQL):**
```bash
#!/bin/bash
while read code; do
psql -c "INSERT INTO promos (code) VALUES ('$code')"
done
```
**Python + MongoDB:**
```python
#!/usr/bin/env python3
import sys
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017')
db = client.mydb
for line in sys.stdin:
code = line.strip()
db.promos.insert_one({"code": code})
```
**Node.js + MySQL:**
```javascript
#!/usr/bin/env node
const mysql = require('mysql2/promise');
const readline = require('readline');
async function main() {
const conn = await mysql.createConnection({
host: 'localhost', user: 'root', database: 'mydb'
});
const rl = readline.createInterface({ input: process.stdin });
for await (const code of rl) {
await conn.execute(
'INSERT INTO promos (code) VALUES (?)',
[code.trim()]
);
}
await conn.end();
}
main();
```
---
## Code Formatting
### Prefix and Suffix
```bash
# Set during creation (stored in .bin)
promocrypt create --name promo --secret pass \
--prefix "PROMO-" --suffix "-2024"
# Override during generation
promocrypt generate --secret pass -n 10 --prefix "SALE-" --suffix ""
# Output: PROMO-A3KF7NP2XM-2024
```
### Separators
```bash
# Create with separators at positions 4 and 8
promocrypt create --name readable --secret pass \
--separator "-" --separator-positions "4,8"
# Output: XXXX-XXXX-XX
```
---
## Check Position
The check digit position can be configured for security:
| `-1` | End (default) | `XXXXXXXXX[C]` |
| `0` | Start | `[C]XXXXXXXXX` |
| `4` | Position 4 | `XXXX[C]XXXXX` |
| `-3` | 3rd from end | `XXXXXXX[C]XX` |
**Security benefit:** Attackers don't know where the check digit is located.
```bash
promocrypt create --name secure --secret pass --check-position 4
```
---
## Storage Encryption
Enable storage encryption for codes stored in SQLite (desktop apps):
```bash
# Enable during creation
promocrypt create --name desktop --secret pass --storage-encryption
# Toggle on existing .bin
promocrypt config --secret pass --set-storage-encryption true
```
**Algorithm:** AES-256-SIV (deterministic, allows lookups)
---
## History & Generation Log
### View History
```bash
# View all history
promocrypt history
# Export to JSON
promocrypt history --export history.json
# Clear (keep last 10)
promocrypt history --clear --keep-last 10 --secret pass
```
### View Generation Log
```bash
# View log
promocrypt generation-log
# View summary
promocrypt generation-log --summary
# Export to JSON
promocrypt generation-log --export gen-log.json
```
---
## Secret Rotation
Safely rotate the secret password:
```bash
promocrypt rotate-secret --old-secret "old-password" --new-secret "new-password"
```
After rotation:
- All future operations require the new secret
- The change is logged in history
---
## Shell Completions
### Bash
```bash
promocrypt completions bash > ~/.local/share/bash-completion/completions/promocrypt
# Or system-wide:
sudo promocrypt completions bash > /etc/bash_completion.d/promocrypt
```
### Zsh
```bash
promocrypt completions zsh > ~/.zsh/completions/_promocrypt
# Add to .zshrc:
fpath=(~/.zsh/completions $fpath)
autoload -Uz compinit && compinit
```
### Fish
```bash
promocrypt completions fish > ~/.config/fish/completions/promocrypt.fish
```
### PowerShell
```powershell
promocrypt completions powershell >> $PROFILE
```
---
## Environment Variables
| `PROMOCRYPT_SECRET` | Default secret password |
| `PROMOCRYPT_BIN` | Default .bin file path |
| `DATABASE_URL` | Database connection string |
**Example:**
```bash
export PROMOCRYPT_SECRET="my-secret"
export PROMOCRYPT_BIN="./production.bin"
# No need to specify --secret or --bin
promocrypt generate -n 100
```
---
## Exit Codes
| 0 | Success |
| 1 | Validation failed (some codes invalid) |
| 2 | File/path error |
| 3 | Authentication error (wrong secret/machine) |
| 4 | Database error |
| 5 | Configuration error |
| 6 | External command error |
| 7 | Code not found (lookup) |
---
## Examples
### Campaign Launch
```bash
# Create a campaign-specific .bin
promocrypt create --name summer2024 --secret "secure-pass" \
--prefix "SUMMER24-" \
--separator "-" --separator-positions "4,8"
# Generate 100,000 codes to database
promocrypt generate --secret "secure-pass" -n 100000 \
--db db.toml --table summer_promos \
--set-int campaign_id=42 \
--set-int discount=25 \
--set-now created_at
```
### Multi-Machine Deployment
```bash
# On development machine
promocrypt master --show-machine-id
# Output: a1b2c3d4e5f6...
# Get production server's machine ID
ssh prod-server "promocrypt master --show-machine-id"
# Output: f6e5d4c3b2a1...
# Master the .bin for production
promocrypt master --secret "pass" \
--output prod.bin \
--target-machine f6e5d4c3b2a1...
# Copy to production
scp prod.bin prod-server:/app/
```
### Bulk Validation
```bash
# Validate codes from file
promocrypt validate -f codes.txt --summary
# Validate all codes in database
promocrypt validate --from-db --db db.toml --table promos --summary
```
### Export Unused Codes
```bash
# Export unused codes to CSV
promocrypt export --db db.toml --table promos \
-o unused_codes.csv \
--where "used_at IS NULL"
# Export as SQL for migration
promocrypt export --db db.toml --table promos \
-o migrate.sql \
--export-format sql
```
---
## Building from Source
### Requirements
- Rust 1.89.0+
- OpenSSL development libraries (Linux)
### Build
```bash
git clone https://github.com/professor93/promocrypt-cli.git
cd promocrypt-cli
# Debug build
cargo build
# Release build
cargo build --release
# Run tests
cargo test
```
### Cross-compilation
```bash
# For Linux from macOS
rustup target add x86_64-unknown-linux-gnu
cargo build --release --target x86_64-unknown-linux-gnu
```
---
## License
MIT License - see [LICENSE](LICENSE) for details.
---
**Made with Rust**