- Fight Card page: dramatic poster background with cross-hatch, spotlights, vignettes, corner brackets, scan lines; 3D VS orb with punch animation; selectable undercard with main event always pinned at top - PosterSprite: high-quality 480px poster frame with 6-pass renderer (aura, glow, bevel, specular, particles); PixelGlove component - 12-char bot name limit across all forms and server validation - Mock bots: all 100 now have diverse archetypes (25 types), 25% human fighters; seedMockBots updates existing bots on restart - Leaderboard: inline SpritePreview next to each bot name - Nostr auth: persistent login, nsec copy button - Wallet: NWC + Lightning Address, ranked fight flow - Server: payments, ranked queue, customization endpoint Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
32 lines
1.4 KiB
TypeScript
32 lines
1.4 KiB
TypeScript
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto'
|
|
|
|
const ENCRYPTION_KEY_HEX = process.env.BOTFIGHTS_WALLET_ENCRYPTION_KEY
|
|
let encryptionKey: Buffer
|
|
|
|
if (ENCRYPTION_KEY_HEX) {
|
|
encryptionKey = Buffer.from(ENCRYPTION_KEY_HEX, 'hex')
|
|
} else if (process.env.NODE_ENV === 'production') {
|
|
throw new Error('CRITICAL: BOTFIGHTS_WALLET_ENCRYPTION_KEY not set. Cannot start in production.')
|
|
} else {
|
|
encryptionKey = randomBytes(32)
|
|
console.warn('[crypto] WARNING: No BOTFIGHTS_WALLET_ENCRYPTION_KEY set. Generated random key — wallet data will be lost on restart.')
|
|
}
|
|
|
|
export function encrypt(plaintext: string): string {
|
|
const iv = randomBytes(16)
|
|
const cipher = createCipheriv('aes-256-gcm', encryptionKey, iv)
|
|
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()])
|
|
const authTag = cipher.getAuthTag()
|
|
return iv.toString('hex') + ':' + authTag.toString('hex') + ':' + encrypted.toString('hex')
|
|
}
|
|
|
|
export function decrypt(ciphertext: string): string {
|
|
const [ivHex, authTagHex, encryptedHex] = ciphertext.split(':')
|
|
const iv = Buffer.from(ivHex, 'hex')
|
|
const authTag = Buffer.from(authTagHex, 'hex')
|
|
const encrypted = Buffer.from(encryptedHex, 'hex')
|
|
const decipher = createDecipheriv('aes-256-gcm', encryptionKey, iv)
|
|
decipher.setAuthTag(authTag)
|
|
return decipher.update(encrypted) + decipher.final('utf8')
|
|
}
|