Spaces:
Running
Running
| """ | |
| Script to verify wallet balance encryption in the database. | |
| This demonstrates that balances are stored encrypted and cannot be read without the key. | |
| """ | |
| import asyncio | |
| import asyncpg | |
| from decimal import Decimal | |
| from app.core.config import settings | |
| from app.wallet.services.service import WalletEncryption | |
| async def verify_encryption(): | |
| """Verify that wallet balances are encrypted in the database""" | |
| print("\n" + "="*70) | |
| print("Wallet Balance Encryption Verification") | |
| print("="*70 + "\n") | |
| # Connect to database | |
| conn = await asyncpg.connect( | |
| host=settings.POSTGRES_HOST, | |
| port=settings.POSTGRES_PORT, | |
| database=settings.POSTGRES_DB, | |
| user=settings.POSTGRES_USER, | |
| password=settings.POSTGRES_PASSWORD | |
| ) | |
| try: | |
| # Get a sample wallet | |
| row = await conn.fetchrow( | |
| "SELECT wallet_id, partner_id, encrypted_balance FROM trans.spa_wallets LIMIT 1" | |
| ) | |
| if not row: | |
| print("β No wallets found in database. Create a wallet first.") | |
| return | |
| wallet_id = row['wallet_id'] | |
| partner_id = row['partner_id'] | |
| encrypted_balance = row['encrypted_balance'] | |
| print(f"π Wallet Information:") | |
| print(f" Wallet ID: {wallet_id}") | |
| print(f" Partner ID: {partner_id}") | |
| print(f"\nπ Encrypted Balance (as stored in database):") | |
| print(f" Type: {type(encrypted_balance)}") | |
| print(f" Length: {len(encrypted_balance)} bytes") | |
| print(f" Raw bytes (first 50): {encrypted_balance[:50]}") | |
| print(f" Hex representation: {encrypted_balance.hex()[:100]}...") | |
| # Try to decrypt | |
| try: | |
| decrypted_balance = WalletEncryption.decrypt_balance(encrypted_balance) | |
| print(f"\nβ Decrypted Balance (using encryption key):") | |
| print(f" Balance: {decrypted_balance}") | |
| print(f" Type: {type(decrypted_balance)}") | |
| except Exception as e: | |
| print(f"\nβ Decryption failed: {e}") | |
| # Demonstrate encryption/decryption cycle | |
| print(f"\nπ Encryption/Decryption Cycle Test:") | |
| test_balance = Decimal("12345.67") | |
| print(f" Original: {test_balance}") | |
| encrypted = WalletEncryption.encrypt_balance(test_balance) | |
| print(f" Encrypted: {encrypted.hex()[:100]}...") | |
| decrypted = WalletEncryption.decrypt_balance(encrypted) | |
| print(f" Decrypted: {decrypted}") | |
| if test_balance == decrypted: | |
| print(f" β Encryption/Decryption cycle successful!") | |
| else: | |
| print(f" β Encryption/Decryption cycle failed!") | |
| # Show that different values produce different encrypted data | |
| print(f"\nπ Encryption Uniqueness Test:") | |
| balance1 = Decimal("1000.00") | |
| balance2 = Decimal("2000.00") | |
| encrypted1 = WalletEncryption.encrypt_balance(balance1) | |
| encrypted2 = WalletEncryption.encrypt_balance(balance2) | |
| print(f" Balance 1: {balance1}") | |
| print(f" Encrypted 1: {encrypted1.hex()[:50]}...") | |
| print(f" Balance 2: {balance2}") | |
| print(f" Encrypted 2: {encrypted2.hex()[:50]}...") | |
| print(f" Are they different? {encrypted1 != encrypted2} β ") | |
| # Security note | |
| print(f"\nπ‘οΈ Security Notes:") | |
| print(f" β’ Balance is stored as binary data (BYTEA) in PostgreSQL") | |
| print(f" β’ Encryption uses AES via Fernet (symmetric encryption)") | |
| print(f" β’ Key is derived from SECRET_KEY using SHA256") | |
| print(f" β’ Without the encryption key, the balance cannot be read") | |
| print(f" β’ Even database administrators cannot see actual balances") | |
| print(f" β’ Each encryption produces different ciphertext (includes IV)") | |
| # Show transaction amounts (not encrypted) | |
| print(f"\nπ Transaction History (amounts are NOT encrypted):") | |
| transactions = await conn.fetch( | |
| """ | |
| SELECT transaction_type, amount, balance_after, description, created_at | |
| FROM trans.spa_wallet_transactions | |
| WHERE partner_id = $1 | |
| ORDER BY created_at DESC | |
| LIMIT 5 | |
| """, | |
| partner_id | |
| ) | |
| if transactions: | |
| for txn in transactions: | |
| print(f" {txn['created_at']} | {txn['transaction_type']:6} | " | |
| f"βΉ{txn['amount']:>10} | Balance: βΉ{txn['balance_after']:>10} | " | |
| f"{txn['description']}") | |
| else: | |
| print(f" No transactions found") | |
| print(f"\nπ‘ Why transaction amounts are not encrypted:") | |
| print(f" β’ Needed for reporting and analytics") | |
| print(f" β’ Balance history is maintained in transactions") | |
| print(f" β’ Only current balance in wallet table is encrypted") | |
| print(f" β’ Transaction amounts are historical and less sensitive") | |
| finally: | |
| await conn.close() | |
| print("\n" + "="*70) | |
| print("Verification Complete") | |
| print("="*70 + "\n") | |
| if __name__ == "__main__": | |
| print(""" | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β Wallet Balance Encryption Verification Script β | |
| β β | |
| β This script demonstrates that wallet balances are stored β | |
| β encrypted in the database and cannot be read without the β | |
| β encryption key. β | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| """) | |
| try: | |
| asyncio.run(verify_encryption()) | |
| except Exception as e: | |
| print(f"\nβ Error: {e}") | |
| print("\nMake sure:") | |
| print(" 1. Database is running") | |
| print(" 2. .env file is configured") | |
| print(" 3. Wallet tables are created (run migration)") | |
| print(" 4. At least one wallet exists in the database") | |