bitter-sql
v1.0.0
Published
A flexible SQLite database scaffolding tool with encryption support using better-sqlite3-multiple-ciphers
Maintainers
Readme
bitter-sql
SQLite 3 Database Scaffolding with Encryption
Overview
A lightweight, developer-friendly SQLite database scaffolding tool with built-in encryption support. bitter-sql simplifies creating and managing encrypted databases through an intuitive CLI or as a Node.js library.
Key highlights:
- 🔐 Multiple encryption ciphers (SQLCipher, ChaCha20, AES variants)
- ⚡ Fast operations powered by better-sqlite3-multiple-ciphers
- 🎯 Secure by default with interactive mode
- 📦 Use as CLI tool or library
- 🛡️ Passwords never exposed in shell history
Perfect for development databases, secure data storage, and encrypted backups.
Features
- Database Encryption: Support for multiple encryption ciphers (ChaCha20-Poly1305, SQLCipher, AES256CBC, AES128CBC, RC4)
- Secure by Default: Interactive mode enables encryption by default with recommended cipher
- Database Rekeying: Change passwords and ciphers on existing encrypted databases
- Dual Interface: Use as a library or CLI tool
- Beautiful CLI: Colorful, interactive command-line interface with progress indicators
- Secure by Default: Built with security best practices in mind
- Custom Schemas: Initialize databases with your own SQL schema files
- Well Tested: Comprehensive test suite with >80% coverage
- Detailed Logging: Optional verbose logging to file for debugging
- Environment Variables: Support for configuration via .env files
Installation
# Install globally for CLI usage
npm install -g bitter-sql
# Install as a project dependency
npm install bitter-sqlRequirements
- Node.js >= 20.0.0
Quick Start
CLI Usage
Interactive Mode (Recommended)
# Create an encrypted database interactively (encryption enabled by default)
bitter-sql create
# Rekey an existing encrypted database
bitter-sql rekeyInteractive mode features:
- Encryption enabled by default with SQLCipher v4 (industry standard)
- Guided prompts for all options
- Easy to use, secure by default
- Passwords never stored in shell history
Command Line Mode
SECURITY Note: For security, passwords must be provided via .env file or interactive mode. CLI password options have been removed to prevent passwords from appearing in shell history.
# Create an encrypted database using .env for password
# First, set password=mypassword in .env file
bitter-sql create -n mydb.db -c sqlcipher
# Create an unencrypted database (if you really need to)
bitter-sql create -n mydb.db
# Create with verbose logging
bitter-sql create -n mydb.db -c chacha20 -v
# Rekey an existing database (passwords from .env: current_password, new_password)
bitter-sql rekey -n mydb.db
# Or use interactive mode for maximum security (recommended)
bitter-sql create
bitter-sql rekey
# View compatibility information
bitter-sql --help
# Displays SQLite and better-sqlite3-multiple-ciphers versionsNote: The CLI automatically displays SQLite and better-sqlite3-multiple-ciphers version information in the help output and interactive mode banner, helping you verify compatibility.
Library Usage
import { createScaffoldDatabase, rekeyDatabase } from 'bitter-sql';
// Create an unencrypted database
async function createPlainDatabase() {
const result = await createScaffoldDatabase({
databaseName: 'mydb.db',
verbose: false,
});
if (result.success) {
console.log(`Database created at: ${result.databasePath}`);
} else {
console.error(`Error: ${result.error}`);
}
}
// Create an encrypted database
async function createEncryptedDatabase() {
const result = await createScaffoldDatabase({
databaseName: 'secure.db',
password: 'my-secret-password',
cipher: 'sqlcipher', // recommended: SQLCipher v4 (best compatibility)
verbose: true,
});
if (result.success) {
console.log(`Encrypted database created: ${result.encrypted}`);
}
}
// Create database with custom schema
async function createWithSchema() {
const result = await createScaffoldDatabase({
databaseName: 'custom.db',
schemaPath: './schema.sql',
verbose: false,
});
}
// Rekey an existing database
async function rekeyExistingDatabase() {
const result = await rekeyDatabase({
databaseName: 'secure.db',
currentPassword: 'old-password',
newPassword: 'new-password',
newCipher: 'aes256cbc', // Optional: change cipher
verbose: false,
});
if (result.success) {
console.log('Database rekeyed successfully!');
}
}Configuration
Environment Variables
🔒 Security Best Practice: Always use a .env file for passwords to keep them out of shell history and command-line arguments.
Create a .env file in your project root:
# Database Creation
db_name=my_database.db
password=my-secret-password
cipher=sqlcipher
verbose=false
schema_path=./path/to/schema.sql
# Database Rekeying
current_password=old-password
new_password=new-passwordImportant: Add .env to your .gitignore to prevent committing sensitive passwords to version control!
Supported Ciphers
sqlcipher- SQLCipher AES-256 CBC with SHA512 HMAC (⭐ recommended default - industry standard, best tool compatibility)chacha20- ChaCha20-Poly1305 HMAC (modern IETF standard, best performance, less tool support)aes256cbc- AES-256 CBC mode (legacy, no tamper detection)aes128cbc- AES-128 CBC mode (legacy, no tamper detection)rc4- RC4 stream cipher (⚠️ not recommended, legacy compatibility only)
Why SQLCipher?
- Industry standard encryption used by thousands of applications
- Compatible with DB Browser for SQLite, SQLiteStudio, and other tools
- AES-256 CBC with SHA512 HMAC (strong authenticated encryption)
- 256,000 PBKDF2 iterations (resists brute force attacks)
- Well-documented and widely tested
Alternative: ChaCha20-Poly1305 offers better performance and modern cryptography but has limited tool support.
📚 For comprehensive cipher documentation, including SQLCipher versioning (v1-v4), security comparisons, legacy database support, and migration guides, see CIPHERS.md.
API Reference
Scaffold Database
createScaffoldDatabase(config: DatabaseConfig): Promise<ScaffoldResult>Creates a new SQLite database with optional encryption.
Parameters:
config.databaseName(string, required) - Name of the database fileconfig.password(string, optional) - Encryption password (min 4 characters)config.cipher(string, optional) - Encryption cipher to useconfig.verbose(boolean, optional) - Enable verbose loggingconfig.schemaPath(string, optional) - Path to custom SQL schema file
Returns: Promise
success(boolean) - Whether operation succeededdatabasePath(string) - Full path to created databaseencrypted(boolean) - Whether database is encryptederror(string) - Error message if failed
Rekey Database
rekeyDatabase(config: RekeyConfig): Promise<ScaffoldResult>Changes the encryption password and/or cipher of an existing database.
Parameters:
config.databaseName(string, required) - Name of the database fileconfig.currentPassword(string, required) - Current encryption passwordconfig.newPassword(string, required) - New encryption passwordconfig.newCipher(string, optional) - New cipher to useconfig.verbose(boolean, optional) - Enable verbose logging
Returns: Promise
Verify Database
verifyDatabase(databasePath: string, password?: string): booleanVerifies that a database can be opened and accessed.
Parameters:
databasePath(string, required) - Path to database filepassword(string, optional) - Password for encrypted database
Returns: boolean - True if database is accessible
Development
Setup
# Clone the repository
git clone https://github.com/kellydc/bitter-sql.git
cd bitter-sql
# Install dependencies
npm install
# Copy environment example
cp .env.example .envBuild
# Build TypeScript source
npm run build
# Clean build artifacts
npm run cleanTesting
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run E2E tests
npm run test:e2e
# Run tests with coverage
npm test -- --coverageCode Quality
# Lint code
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
# Check formatting
npm run format:checkUsing Makefile
# Install dependencies
make install
# Build project
make build
# Run tests
make test
# Run all quality checks
make check
# Publish to npm
make publishProject Structure
bitter-sql/
├── src/
│ ├── lib/
│ │ ├── database.ts # Core database operations
│ │ ├── logger.ts # Logging configuration
│ │ ├── validator.ts # Input validation
│ │ ├── types.ts # TypeScript type definitions
│ │ └── index.ts # Library exports
│ ├── cli.ts # CLI implementation
│ └── index.ts # Main entry point
├── tests/
│ ├── lib/ # Unit tests
│ └── e2e/ # End-to-end tests
├── .github/
│ └── workflows/
│ └── ci.yml # CI/CD pipeline
├── dist/ # Compiled JavaScript
├── logs/ # Log files (verbose mode)
├── package.json
├── tsconfig.json
├── jest.config.js
├── playwright.config.ts
├── Makefile
├── README.md
└── LICENSEUse Cases
1. Development Database Setup
Quickly create test databases for development:
bitter-sql create -n dev.db -s ./migrations/init.sql2. Secure Data Storage
Create encrypted databases for sensitive data:
const result = await createScaffoldDatabase({
databaseName: 'user-data.db',
password: process.env.DB_PASSWORD,
cipher: 'sqlcipher',
});3. Password Rotation
Regularly rotate database passwords for security:
await rekeyDatabase({
databaseName: 'production.db',
currentPassword: oldPassword,
newPassword: newPassword,
});4. Database Migration
Migrate databases to stronger encryption:
bitter-sql rekey -n legacy.db \
--current-password oldpass \
--new-password newpass \
--new-cipher aes256cbcTroubleshooting
Database Won't Open
- Verify the password is correct
- Check that the cipher matches what was used to create the database
- Ensure the database file isn't corrupted
Permission Issues
- Check file permissions on the database file and directory
- Ensure you have write permissions to the target directory
Build Errors
- Ensure you're using Node.js >= 20.0.0
- Try removing
node_modulesand runningnpm installagain - Check that all dependencies are properly installed
Test Failures
- Ensure no databases are locked by other processes
- Clean up test databases:
rm -rf tests/test-databases tests/e2e-test-dbs - Rebuild the project:
npm run clean && npm run build
Security Considerations
- Password Strength: Use strong passwords (minimum 4 characters, but 12+ recommended)
- Cipher Selection: SQLCipher is recommended for production use
- Password Storage: Never commit passwords to version control
- Environment Variables: Use environment variables or secure vaults for passwords
- Logging: Passwords are never logged, even in verbose mode
- File Permissions: Set appropriate file permissions on database files
Contributing
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests and linting (
make check) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Guidelines
- Follow the existing code style
- Add tests for new features
- Update documentation as needed
- Ensure all tests pass
- Maintain test coverage above 80%
Documentation
- ⚡ Quick Reference - Common commands and workflows
- 📋 Contributing Guidelines - How to contribute to the project
- 🔒 Security Policy - Security guidelines and reporting
- 📝 Changelog - Version history and migration guides
Deployment
For detailed instructions on publishing to npm, version management, and automated releases, see the comprehensive Deployment Guide.
Quick Reference:
# Automated deployment (recommended)
# Create a GitHub release - publishing happens automatically
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0
# Manual deployment
make publishDependency Management
This project uses automated dependency management:
- Dependabot: Automatic dependency updates (weekly)
- Security Audits: Daily vulnerability scanning
- License Compliance: Automated license checking
See .github/workflows/dependency-check.yml for details.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Built with better-sqlite3-multiple-ciphers
- Inspired by the need for simple, secure SQLite database management tools
- Thanks to the open-source community for feedback and contributions!
Support
- 📫 Report issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
- 📖 Documentation: Wiki
Changelog
See CHANGELOG.md for version history and migration guides.
