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")