Readme
_
_ __ _ __ ___ _ __ ___ ___ ___ _ __ _ _ _ __ | | _
| ' _ \| '__ / _ \| ' _ ` _ \ / _ \ / __ | '__ | | | | ' _ \| __ |
| | _ ) | | | ( _ ) | | | | | | ( _ ) | ( __ | | | | _ | | | _ ) | | _
| . __ / | _ | \___ / | _ | | _ | | _ | \___ / \___ | _ | \__ , | .__/ \__ |
| _ | | ___ / | _ |
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.
Table of Contents
Overview
promocrypt is a high-performance CLI for generating and managing promotional codes. Built on the promocrypt-core cryptographic library, it provides:
Cryptographic security : Codes are generated using secure algorithms with embedded check digits
Machine binding : . pcbin files can be locked to specific machines
Database integration : Direct insertion to PostgreSQL and SQLite
Flexible formatting : Prefixes, suffixes, and separators (e.g., PROMO - XXXX - XXXX - 2024 )
Audit trail : Track generation history, secret rotations, and configuration changes
Features
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
Installation
Quick Install (Recommended)
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 completions
Manual Download
Download 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/
Build from Source
# 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/
Quick Start
1. Create a .pcbin file
# 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"
2. Generate codes
# 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
3. Validate codes
# 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
Commands Reference
Global Options
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
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
info
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
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
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
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
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...
config
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:
Uses machine ID only for encryption (no password in encryption key)
Password required for authentication (verifies access to .pcbin)
Encrypted files can only be decrypted on the same machine
rotate
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"
history
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
generation-log
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
pg-import
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
pg-export
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
completions
Generate shell completions.
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
Create the table:
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( )
);
Generate codes using connection URI:
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
SQLite Setup
Create the database:
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
);"
Generate codes using connection URI:
promocrypt generate -- password pass - n 10000 \
--db " sqlite:///codes.db" \
--table promo_codes
Using Configuration File
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
Typed Column Values
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}'
External Commands
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
Example Scripts
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 ( ) ;
Prefix and Suffix
# 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
Separators
# Create with separators at positions 4 and 8
promocrypt create --name readable --password pass \
--separator "-" --separator-positions "4,8"
# Output: XXXX-XXXX-XX
Check Position
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
Storage Encryption
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)
History & Generation Log
View History
# 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 Generation Log
# 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:
promocrypt rotate -- old-password " old-password" -- password " new-password"
After rotation:
All future operations require the new password
The change is logged in history
Shell Completions
Bash
promocrypt completions bash > ~ /.local/share/bash-completion/completions/promocrypt
# Or system-wide:
sudo promocrypt completions bash > /etc/bash_completion.d/promocrypt
Zsh
promocrypt completions zsh > ~ /.zsh/completions/_promocrypt
# Add to .zshrc:
fpath=(~/.zsh/completions $fpath)
autoload -Uz compinit && compinit
Fish
promocrypt completions fish > ~ /.config/fish/completions/promocrypt.fish
PowerShell
promocrypt completions powershell >> $ PROFILE
Environment Variables
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
Exit Codes
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)
Examples
Campaign Launch
# 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
Multi-Machine Deployment
# 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/
Bulk Validation
# 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
# 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
Building from Source
Requirements
Rust 1.89.0+
OpenSSL development libraries (Linux)
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
Build
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
# 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
License
MIT License - see LICENSE for details.
Made with Rust