| Crates.io | promocrypt-cli |
| lib.rs | promocrypt-cli |
| version | 1.1.2 |
| created_at | 2026-01-10 08:12:50.004983+00 |
| updated_at | 2026-01-12 09:59:59.466705+00 |
| description | Command-line tool for promotional code generation |
| homepage | |
| repository | https://github.com/professor93/promocrypt-cli |
| max_upload_size | |
| id | 2033803 |
| size | 864,000 |
_
_ __ _ __ ___ _ __ ___ ___ ___ _ __ _ _ _ __ | |_
| '_ \| '__/ _ \| '_ ` _ \ / _ \ / __| '__| | | | '_ \| __|
| |_) | | | (_) | | | | | | (_) | (__| | | |_| | |_) | |_
| .__/|_| \___/|_| |_| |_|\___/ \___|_| \__, | .__/ \__|
|_| |___/|_|
Command-line tool for cryptographically secure promotional code generation and management.
Generate millions of unique, validated promotional codes with machine-binding security, database integration, and flexible output formats.
promocrypt is a high-performance CLI for generating and managing promotional codes. Built on the promocrypt-core cryptographic library, it provides:
.pcbin files can be locked to specific machinesPROMO-XXXX-XXXX-2024)| Feature | Description |
|---|---|
| Code Generation | Generate single codes or millions in batches |
| Code Validation | Validate codes from CLI, files, or databases |
| Database Insert | PostgreSQL and SQLite with batch insertion |
| Storage Encryption | Encrypt codes at rest (AES-256-SIV) |
| External Commands | Pipe to any script (Python, Node.js, etc.) |
| Output Formats | Plain text, JSON, CSV |
| Shell Completions | Bash, Zsh, Fish, PowerShell |
| Check Position | Configurable check digit placement |
| Code Formatting | Prefix, suffix, separators |
| Secret Rotation | Safely change passwords |
| History Tracking | Audit rotations, masterings, changes |
| Generation Log | Track when/how many codes generated |
| PG Sync | Import/export .pcbin to PostgreSQL |
| Dry-run Mode | Preview without generating |
| Rate Limiting | Control generation speed |
Install with automatic shell completions:
curl -fsSL https://raw.githubusercontent.com/professor93/promocrypt-cli/master/scripts/install.sh | sh
Options:
--version VERSION - Install specific version--install-dir DIR - Custom installation directory--init-system - Initialize system-wide configuration--no-completions - Skip shell completionsDownload the latest release for your platform:
# Linux (x86_64)
curl -LO https://github.com/professor93/promocrypt-cli/releases/latest/download/promocrypt-linux-x86_64.tar.gz
tar -xzf promocrypt-linux-x86_64.tar.gz
sudo mv promocrypt /usr/local/bin/
# macOS (Apple Silicon)
curl -LO https://github.com/professor93/promocrypt-cli/releases/latest/download/promocrypt-macos-arm64.tar.gz
tar -xzf promocrypt-macos-arm64.tar.gz
sudo mv promocrypt /usr/local/bin/
# Clone the repository
git clone https://github.com/professor93/promocrypt-cli.git
cd promocrypt-cli
# Build release binary
cargo build --release
# Install to PATH
sudo cp target/release/promocrypt /usr/local/bin/
# Create a new .pcbin file with default settings
promocrypt create --name production --password "my-secure-password"
# Create with custom formatting
promocrypt create --name promo2024 \
--password "password" \
--prefix "PROMO-" \
--suffix "-2024" \
--separator "-" \
--separator-positions "4,8"
# Generate a single code
promocrypt generate --password "my-secure-password"
# Generate 1000 codes to file
promocrypt generate --password "password" -n 1000 -o codes.txt
# Generate with database insertion
promocrypt generate --password "password" -n 10000 \
--db "postgres://user:pass@localhost/mydb" --table promos
# 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 --invalid-only
promocrypt [OPTIONS] <COMMAND>
Options:
--bin <PATH> Path to .pcbin file (default: ./promocrypt.pcbin)
--name <NAME> Project name (from config)
--config <PATH> Path to project config file
-s, --select Interactively select project
-J, --json JSON input/output mode (disables interactive prompts)
-C, --color <WHEN> Color output: auto, always, never
-E, --env-file <PATH> Load environment from file
-h, --help Print help
-V, --version Print version
Interactive Mode: When -J (JSON mode) is not enabled, interactive mode is
automatically active. Missing required parameters will be prompted interactively.
This provides a guided experience while keeping all CLI arguments available for
power users and script templates.
Create a new .pcbin file.
promocrypt create <NAME> [OPTIONS]
Arguments:
<NAME> Project name (required)
Options:
-p, --password <PASSWORD> Project password (prompted if not provided)
--alphabet <ALPHABET> Custom alphabet, auto-shuffled (default chars: 0234679ABCDEFGHJKMNPQRTUXY)
--length <N> Code length excluding check (default: 9)
-k, --check-position <POS> Check digit position: 0=start, -1=end, N=position
--counter-mode <MODE> Counter mode: file, inbin, external (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 prod --password "password"
# With formatting
promocrypt create promo --password "pass" \
--prefix "SALE-" --separator "-" --separator-positions "4,8"
# With storage encryption
promocrypt create secure --password "pass" --storage-encryption
Show .pcbin file information and statistics.
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
--stats Show statistics (.bin and database)
--db <URI> Database connection URI (for --stats)
--table <TABLE> Table name (for --stats)
Examples:
promocrypt info
promocrypt info --show-history
promocrypt info --show-machine-id
promocrypt info --stats --db "postgres://user:pass@localhost/mydb" --table promos
Generate promotional codes.
promocrypt generate [OPTIONS]
Options:
--password <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 .pcbin 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 <URI> Database connection URI
--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 --password pass -n 10
# Generate to file
promocrypt generate --password pass -n 1000 -o codes.txt
# Generate with database
promocrypt generate --password pass -n 10000 \
--db "postgres://user:pass@localhost/mydb" --table promos \
--set-int campaign_id=123 --set status=active --set-now created_at
# Dry run
promocrypt generate --password pass -n 10 --dry-run
Validate promotional codes. Also supports looking up code data in database.
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 <URI> Database connection URI
--table <TABLE> Table to read codes from
--column <COLUMN> Code column name (default: code)
-q, --invalid-only Only output invalid codes
--summary Show summary at end
-R, --show-row Show database row data for valid codes
Examples:
promocrypt validate A3KF7NP2XM
promocrypt validate -f codes.txt --summary
promocrypt validate --from-db --db "postgres://user:pass@localhost/mydb" --table promos
# Validate and lookup database row
promocrypt validate PROMO-A3KF7NP2XM-2024 --db "postgres://..." --table promos --show-row
Export codes from database.
promocrypt export [OPTIONS]
Options:
-d, --db <URI> Database connection URI (or set DATABASE_URL env var)
-t, --table <TABLE> Table name
-c, --column <COLUMN> Code column name (default: code)
-o, --output <FILE> Output file (required)
-F, --export-format <FMT> Format: csv, json, sql (default: csv)
-w, --where <CONDITION> SQL WHERE clause
-l, --limit <N> Maximum rows to export
Examples:
promocrypt export -d "postgres://user:pass@localhost/mydb" -t promos -o codes.csv
promocrypt export -d "postgres://user:pass@localhost/mydb" -t promos -o unused.json \
-F json -w "used_at IS NULL"
Master .pcbin for a different machine.
promocrypt master [OPTIONS]
Options:
--password <SECRET> Secret password
--output <PATH> Output path for mastered .pcbin
--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 --password pass --output server.pcbin \
--target-machine a1b2c3d4e5f6...
View or modify .pcbin configuration. Also encrypt/decrypt the .promocrypt config file.
promocrypt config [OPTIONS]
Options:
-p, --password <PASSWORD> Password (required for modifications and encrypt/decrypt)
-S, --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
--encrypt Encrypt .promocrypt config file (machine-bound)
--decrypt Decrypt .promocrypt config file
Examples:
promocrypt config --show
promocrypt config -p pass --set-prefix "NEW-"
promocrypt config -p pass --set-storage-encryption true
# Encrypt/decrypt config file
promocrypt config --encrypt -p pass
promocrypt config --decrypt -p pass
Config file encryption:
Rotate secret password.
promocrypt rotate [OPTIONS]
Options:
-o, --old-password <SECRET> Current password
-p, --password <SECRET> New password (prompted if not provided)
Example:
promocrypt rotate --old-password "old-pass" --password "new-pass"
View, export, or clear history.
promocrypt history [OPTIONS]
Options:
--export <FILE> Export history to JSON file
--clear Clear history (requires --password)
--keep-last <N> Keep last N entries when clearing
--password <SECRET> Required for --clear
Examples:
promocrypt history
promocrypt history --export history.json
promocrypt history --clear --keep-last 10 --password pass
View, export, or clear generation log.
promocrypt generation-log [OPTIONS]
Options:
--export <FILE> Export log to JSON file
--clear Clear log (requires --password)
--keep-last <N> Keep last N entries when clearing
--password <SECRET> Required for --clear
--summary Show summary only
Examples:
promocrypt generation-log
promocrypt generation-log --summary
promocrypt generation-log --export gen-log.json
Import .pcbin file into PostgreSQL.
promocrypt pg-import [OPTIONS]
Options:
--db <URI> PostgreSQL connection URI (required)
--password <SECRET> Secret password (required)
--name <NAME> Name in PostgreSQL (default: use .pcbin name)
Example:
promocrypt pg-import --db "postgres://user:pass@localhost/mydb" --password pass
Export .pcbin from PostgreSQL to file.
promocrypt pg-export [OPTIONS]
Options:
--db <URI> PostgreSQL connection URI (required)
--name <NAME> Secret name in PostgreSQL (required)
--password <SECRET> Secret password (required)
-o, --output <PATH> Output .pcbin file path (required)
Example:
promocrypt pg-export --db "postgres://user:pass@localhost/mydb" --name campaign --password pass -o campaign.pcbin
Generate shell completions.
promocrypt completions <SHELL>
Arguments:
<SHELL> Shell: bash, zsh, fish, powershell, elvish
Example:
promocrypt completions bash > ~/.local/share/bash-completion/completions/promocrypt
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()
);
promocrypt generate --password pass -n 10000 \
--db "postgres://user:pass@localhost/mydb" \
--table promo_codes \
--set-int campaign_id=123 \
--set status=active
Or use environment variable:
export DATABASE_URL="postgres://user:pass@localhost/mydb"
promocrypt generate --password pass -n 10000 --table promo_codes
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
);"
promocrypt generate --password pass -n 10000 \
--db "sqlite:///codes.db" \
--table promo_codes
Database settings can be configured in .promocrypt.toml:
# .promocrypt.toml
project_name = "myproject"
[database]
uri = "postgres://user:pass@localhost/mydb"
table = "promo_codes"
Then generate without --db flag:
promocrypt generate --password pass -n 10000
Set column values with proper types during generation:
| Option | Type | Example |
|---|---|---|
--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:
promocrypt generate --password pass -n 1000 \
--db "postgres://user:pass@localhost/mydb" --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}'
Pipe codes to any external program for custom database insertion:
# Plain text (one code per line)
promocrypt generate --password pass -n 10000 --exec "./my-inserter.sh"
# JSON lines with extra data
promocrypt generate --password pass -n 10000 \
--exec "python insert.py" \
--exec-format jsonl \
--set-int campaign_id=123
Bash + psql (PostgreSQL):
#!/bin/bash
while read code; do
psql -c "INSERT INTO promos (code) VALUES ('$code')"
done
Python + MongoDB:
#!/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:
#!/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();
# Set during creation (stored in .pcbin)
promocrypt create --name promo --password pass \
--prefix "PROMO-" --suffix "-2024"
# Override during generation
promocrypt generate --password pass -n 10 --prefix "SALE-" --suffix ""
# Output: PROMO-A3KF7NP2XM-2024
# Create with separators at positions 4 and 8
promocrypt create --name readable --password pass \
--separator "-" --separator-positions "4,8"
# Output: XXXX-XXXX-XX
The check digit position can be configured for security:
| Value | Meaning | Example (10-char) |
|---|---|---|
-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.
promocrypt create --name secure --password pass --check-position 4
Enable storage encryption for codes stored in SQLite (desktop apps):
# Enable during creation
promocrypt create --name desktop --password pass --storage-encryption
# Toggle on existing .pcbin
promocrypt config --password pass --set-storage-encryption true
Algorithm: AES-256-SIV (deterministic, allows lookups)
# View all history
promocrypt history
# Export to JSON
promocrypt history --export history.json
# Clear (keep last 10)
promocrypt history --clear --keep-last 10 --password pass
# View log
promocrypt generation-log
# View summary
promocrypt generation-log --summary
# Export to JSON
promocrypt generation-log --export gen-log.json
Safely rotate the secret password:
promocrypt rotate --old-password "old-password" --password "new-password"
After rotation:
promocrypt completions bash > ~/.local/share/bash-completion/completions/promocrypt
# Or system-wide:
sudo promocrypt completions bash > /etc/bash_completion.d/promocrypt
promocrypt completions zsh > ~/.zsh/completions/_promocrypt
# Add to .zshrc:
fpath=(~/.zsh/completions $fpath)
autoload -Uz compinit && compinit
promocrypt completions fish > ~/.config/fish/completions/promocrypt.fish
promocrypt completions powershell >> $PROFILE
| Variable | Description |
|---|---|
PROMOCRYPT_PASSWORD |
Default secret password |
PROMOCRYPT_PROJECT |
Default .pcbin file path |
PROMOCRYPT_CONFIG |
Path to .promocrypt config file |
DATABASE_URL |
Database connection string |
NO_COLOR |
Disable colored output |
Example:
export PROMOCRYPT_PASSWORD="my-secret"
export PROMOCRYPT_PROJECT="./production.pcbin"
# No need to specify --password or --bin
promocrypt generate -n 100
| Code | Meaning |
|---|---|
| 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) |
# Create a campaign-specific .pcbin
promocrypt create --name summer2024 --password "secure-pass" \
--prefix "SUMMER24-" \
--separator "-" --separator-positions "4,8"
# Generate 100,000 codes to database
promocrypt generate --password "secure-pass" -n 100000 \
--db "postgres://user:pass@localhost/mydb" --table summer_promos \
--set-int campaign_id=42 \
--set-int discount=25 \
--set-now created_at
# 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 .pcbin for production
promocrypt master --password "pass" \
--output prod.pcbin \
--target-machine f6e5d4c3b2a1...
# Copy to production
scp prod.pcbin prod-server:/app/
# Validate codes from file
promocrypt validate -f codes.txt --summary
# Validate all codes in database
promocrypt validate --from-db --db "postgres://user:pass@localhost/mydb" --table promos --summary
# Export unused codes to CSV
promocrypt export --db "postgres://user:pass@localhost/mydb" --table promos \
-o unused_codes.csv \
--where "used_at IS NULL"
# Export as SQL for migration
promocrypt export --db "postgres://user:pass@localhost/mydb" --table promos \
-o migrate.sql \
--export-format sql
| OS | Architecture | Build Target |
|---|---|---|
| Linux | x86_64 | x86_64-unknown-linux-gnu |
| Linux | ARM64 | aarch64-unknown-linux-gnu |
| macOS | Apple Silicon | aarch64-apple-darwin |
| macOS | Intel | x86_64-apple-darwin |
| Windows | x86_64 | x86_64-pc-windows-msvc |
| Windows | ARM64 | aarch64-pc-windows-msvc |
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
# For Linux from macOS
rustup target add x86_64-unknown-linux-gnu
cargo build --release --target x86_64-unknown-linux-gnu
| Operation | Target |
|---|---|
| Generate 1 code | < 100ms |
| Generate 10K codes | < 2s |
| Generate 1M codes | < 3 min |
| Validate 1 code | < 50ms |
| Validate 10K codes | < 1s |
| DB insert 10K batch | < 5s |
MIT License - see LICENSE for details.
Made with Rust