Spaces:
Running
Running
File size: 6,416 Bytes
a558c77 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | """
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")
|