feat(security): encrypt userId and userHash at rest with AES-256-GCM#27
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds encryption-at-rest for Idle Champions credentials by introducing AES-256-GCM helpers, encrypting userId/userHash before SQLite writes, and decrypting them on reads.
Changes:
- Added crypto helpers for AES-256-GCM encryption/decryption using
ENCRYPTION_KEY. - Updated
UserManagerpersistence and tests to store encrypted credential values. - Documented and configured
ENCRYPTION_KEYfor local/test environments.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/bot/utils/crypto.ts |
Adds encryption/decryption utilities and key validation. |
src/bot/database/userManager.ts |
Encrypts credentials on save and decrypts credentials on read. |
src/bot/database/userManager.test.ts |
Updates credential persistence tests for encrypted storage. |
src/test/setup.ts |
Sets a fixed encryption key for Bun tests. |
.env.example |
Documents the required encryption key variable. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Store game credentials encrypted in SQLite so a database leak cannot be directly exploited. A stolen DB file yields only opaque ciphertext. Implementation - src/bot/utils/crypto.ts (new): AES-256-GCM helpers using Node.js crypto. Key loaded from ENCRYPTION_KEY env var (64-char hex / 32 bytes). Ciphertext format: enc1:<iv_hex>:<authTag_hex>:<ciphertext_hex>. Key is validated eagerly at module load time (fail-fast). - src/bot/database/userManager.ts: encrypt on write, decrypt on read. saveCredentials() rejects empty userId/userHash. migratePlaintextCredentials() transparently upgrades existing rows on startup; each field is migrated independently (handles mixed-state rows). - src/bot/bot.ts: calls migratePlaintextCredentials() after DB init. - src/test/setup.ts: sets ENCRYPTION_KEY to a clearly non-secret 'deadbeef'-repeated test fixture to avoid secret-scanner false positives. - src/bot/database/userManager.test.ts: 5 new migration tests; existing tests updated to assert encrypted-at-rest storage. Configuration - .env.example: documents ENCRYPTION_KEY with generation hint. - docker-compose.yml / docker-compose.example.yml: forwards ENCRYPTION_KEY into the container. Docs updated in README, docs/development.md, docs/full-documentation.md, docs/podman.md, docs/github-secrets.md: ENCRYPTION_KEY listed as a required variable with openssl rand -hex 32 generation hint and a warning that the key must be generated once and retained — changing it after credentials have been saved makes those rows unreadable. Signed-off-by: Michael Cramer <michael@bigmichi1.de>
b42a34e to
579203c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Store Idle Champions credentials encrypted in the database so a leaked DB file cannot be used to impersonate users.