lunalib 1.1.0__py3-none-any.whl → 1.2.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
storage/database.py ADDED
@@ -0,0 +1,222 @@
1
+ import os
2
+ import sqlite3
3
+ import json
4
+ import time
5
+ from typing import Dict, List, Optional, Any
6
+
7
+ class WalletDatabase:
8
+ """Manages wallet data storage"""
9
+
10
+ def __init__(self, db_path=None):
11
+ self.db_path = db_path or os.path.join(os.path.expanduser("~"), ".luna_wallet", "wallets.db")
12
+ os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
13
+ self._init_database()
14
+
15
+ def _init_database(self):
16
+ """Initialize wallet database"""
17
+ conn = sqlite3.connect(self.db_path)
18
+ cursor = conn.cursor()
19
+
20
+ # Wallets table
21
+ cursor.execute('''
22
+ CREATE TABLE IF NOT EXISTS wallets (
23
+ address TEXT PRIMARY KEY,
24
+ label TEXT,
25
+ public_key TEXT,
26
+ encrypted_private_key TEXT,
27
+ balance REAL DEFAULT 0.0,
28
+ created REAL,
29
+ last_accessed REAL,
30
+ metadata TEXT
31
+ )
32
+ ''')
33
+
34
+ # Transactions table
35
+ cursor.execute('''
36
+ CREATE TABLE IF NOT EXISTS transactions (
37
+ tx_hash TEXT PRIMARY KEY,
38
+ wallet_address TEXT,
39
+ tx_type TEXT,
40
+ from_address TEXT,
41
+ to_address TEXT,
42
+ amount REAL,
43
+ fee REAL,
44
+ timestamp REAL,
45
+ block_height INTEGER,
46
+ status TEXT,
47
+ memo TEXT,
48
+ raw_data TEXT,
49
+ FOREIGN KEY (wallet_address) REFERENCES wallets (address)
50
+ )
51
+ ''')
52
+
53
+ # Pending transactions table
54
+ cursor.execute('''
55
+ CREATE TABLE IF NOT EXISTS pending_transactions (
56
+ tx_hash TEXT PRIMARY KEY,
57
+ wallet_address TEXT,
58
+ from_address TEXT,
59
+ to_address TEXT,
60
+ amount REAL,
61
+ fee REAL,
62
+ created_time REAL,
63
+ status TEXT DEFAULT 'pending',
64
+ retry_count INTEGER DEFAULT 0,
65
+ last_retry REAL,
66
+ raw_data TEXT
67
+ )
68
+ ''')
69
+
70
+ conn.commit()
71
+ conn.close()
72
+
73
+ def save_wallet(self, wallet_data: Dict) -> bool:
74
+ """Save wallet to database"""
75
+ try:
76
+ conn = sqlite3.connect(self.db_path)
77
+ cursor = conn.cursor()
78
+
79
+ cursor.execute('''
80
+ INSERT OR REPLACE INTO wallets
81
+ (address, label, public_key, encrypted_private_key, balance, created, last_accessed, metadata)
82
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
83
+ ''', (
84
+ wallet_data['address'],
85
+ wallet_data.get('label', ''),
86
+ wallet_data.get('public_key', ''),
87
+ wallet_data.get('encrypted_private_key', ''),
88
+ wallet_data.get('balance', 0.0),
89
+ wallet_data.get('created', time.time()),
90
+ time.time(),
91
+ json.dumps(wallet_data.get('metadata', {}))
92
+ ))
93
+
94
+ conn.commit()
95
+ conn.close()
96
+ return True
97
+
98
+ except Exception as e:
99
+ print(f"Save wallet error: {e}")
100
+ return False
101
+
102
+ def load_wallet(self, address: str) -> Optional[Dict]:
103
+ """Load wallet from database"""
104
+ try:
105
+ conn = sqlite3.connect(self.db_path)
106
+ cursor = conn.cursor()
107
+
108
+ cursor.execute('SELECT * FROM wallets WHERE address = ?', (address,))
109
+ result = cursor.fetchone()
110
+ conn.close()
111
+
112
+ if result:
113
+ return {
114
+ 'address': result[0],
115
+ 'label': result[1],
116
+ 'public_key': result[2],
117
+ 'encrypted_private_key': result[3],
118
+ 'balance': result[4],
119
+ 'created': result[5],
120
+ 'last_accessed': result[6],
121
+ 'metadata': json.loads(result[7]) if result[7] else {}
122
+ }
123
+
124
+ except Exception as e:
125
+ print(f"Load wallet error: {e}")
126
+
127
+ return None
128
+
129
+ def save_transaction(self, transaction: Dict, wallet_address: str) -> bool:
130
+ """Save transaction to database"""
131
+ try:
132
+ conn = sqlite3.connect(self.db_path)
133
+ cursor = conn.cursor()
134
+
135
+ cursor.execute('''
136
+ INSERT OR REPLACE INTO transactions
137
+ (tx_hash, wallet_address, tx_type, from_address, to_address, amount, fee,
138
+ timestamp, block_height, status, memo, raw_data)
139
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
140
+ ''', (
141
+ transaction.get('hash', ''),
142
+ wallet_address,
143
+ transaction.get('type', 'transfer'),
144
+ transaction.get('from', ''),
145
+ transaction.get('to', ''),
146
+ transaction.get('amount', 0),
147
+ transaction.get('fee', 0),
148
+ transaction.get('timestamp', time.time()),
149
+ transaction.get('block_height'),
150
+ transaction.get('status', 'confirmed'),
151
+ transaction.get('memo', ''),
152
+ json.dumps(transaction)
153
+ ))
154
+
155
+ conn.commit()
156
+ conn.close()
157
+ return True
158
+
159
+ except Exception as e:
160
+ print(f"Save transaction error: {e}")
161
+ return False
162
+
163
+ def get_wallet_transactions(self, wallet_address: str, limit: int = 100) -> List[Dict]:
164
+ """Get transactions for a wallet"""
165
+ try:
166
+ conn = sqlite3.connect(self.db_path)
167
+ cursor = conn.cursor()
168
+
169
+ cursor.execute('''
170
+ SELECT raw_data FROM transactions
171
+ WHERE wallet_address = ?
172
+ ORDER BY timestamp DESC
173
+ LIMIT ?
174
+ ''', (wallet_address, limit))
175
+
176
+ results = cursor.fetchall()
177
+ conn.close()
178
+
179
+ transactions = []
180
+ for result in results:
181
+ try:
182
+ tx = json.loads(result[0])
183
+ transactions.append(tx)
184
+ except:
185
+ continue
186
+
187
+ return transactions
188
+
189
+ except Exception as e:
190
+ print(f"Get transactions error: {e}")
191
+ return []
192
+
193
+ def save_pending_transaction(self, transaction: Dict, wallet_address: str) -> bool:
194
+ """Save pending transaction"""
195
+ try:
196
+ conn = sqlite3.connect(self.db_path)
197
+ cursor = conn.cursor()
198
+
199
+ cursor.execute('''
200
+ INSERT OR REPLACE INTO pending_transactions
201
+ (tx_hash, wallet_address, from_address, to_address, amount, fee,
202
+ created_time, status, raw_data)
203
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
204
+ ''', (
205
+ transaction.get('hash', ''),
206
+ wallet_address,
207
+ transaction.get('from', ''),
208
+ transaction.get('to', ''),
209
+ transaction.get('amount', 0),
210
+ transaction.get('fee', 0),
211
+ time.time(),
212
+ 'pending',
213
+ json.dumps(transaction)
214
+ ))
215
+
216
+ conn.commit()
217
+ conn.close()
218
+ return True
219
+
220
+ except Exception as e:
221
+ print(f"Save pending transaction error: {e}")
222
+ return False
storage/encryption.py ADDED
@@ -0,0 +1,105 @@
1
+ import os
2
+ import json
3
+ import base64
4
+ import hashlib
5
+ from cryptography.fernet import Fernet
6
+ from cryptography.hazmat.primitives import hashes
7
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
8
+ from typing import Dict, Optional
9
+ class EncryptionManager:
10
+ """Handles encryption and decryption of sensitive data"""
11
+
12
+ def __init__(self):
13
+ self.salt = b'luna_wallet_salt' # In production, use random salt per wallet
14
+
15
+ def encrypt_wallet(self, wallet_data: Dict, password: str) -> Dict:
16
+ """Encrypt wallet data"""
17
+ try:
18
+ # Derive key from password
19
+ key = self._derive_key(password)
20
+ fernet = Fernet(key)
21
+
22
+ # Encrypt private key separately
23
+ private_key = wallet_data.get('private_key', '')
24
+ if private_key:
25
+ encrypted_private = fernet.encrypt(private_key.encode()).decode()
26
+ wallet_data['encrypted_private_key'] = encrypted_private
27
+ del wallet_data['private_key']
28
+
29
+ # Encrypt entire wallet data
30
+ wallet_json = json.dumps(wallet_data)
31
+ encrypted_wallet = fernet.encrypt(wallet_json.encode()).decode()
32
+
33
+ return {
34
+ 'encrypted_data': encrypted_wallet,
35
+ 'version': '1.0',
36
+ 'salt': base64.b64encode(self.salt).decode()
37
+ }
38
+
39
+ except Exception as e:
40
+ print(f"Encryption error: {e}")
41
+ return {}
42
+
43
+ def decrypt_wallet(self, encrypted_data: Dict, password: str) -> Optional[Dict]:
44
+ """Decrypt wallet data"""
45
+ try:
46
+ encrypted_wallet = encrypted_data.get('encrypted_data', '')
47
+ if not encrypted_wallet:
48
+ return None
49
+
50
+ # Derive key from password
51
+ key = self._derive_key(password)
52
+ fernet = Fernet(key)
53
+
54
+ # Decrypt wallet
55
+ decrypted_data = fernet.decrypt(encrypted_wallet.encode())
56
+ wallet_data = json.loads(decrypted_data.decode())
57
+
58
+ # Decrypt private key if present
59
+ encrypted_private = wallet_data.get('encrypted_private_key')
60
+ if encrypted_private:
61
+ private_key = fernet.decrypt(encrypted_private.encode()).decode()
62
+ wallet_data['private_key'] = private_key
63
+ del wallet_data['encrypted_private_key']
64
+
65
+ return wallet_data
66
+
67
+ except Exception as e:
68
+ print(f"Decryption error: {e}")
69
+ return None
70
+
71
+ def _derive_key(self, password: str) -> bytes:
72
+ """Derive encryption key from password"""
73
+ kdf = PBKDF2HMAC(
74
+ algorithm=hashes.SHA256(),
75
+ length=32,
76
+ salt=self.salt,
77
+ iterations=100000,
78
+ )
79
+ key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
80
+ return key
81
+
82
+ def verify_password(self, encrypted_data: Dict, password: str) -> bool:
83
+ """Verify password without full decryption"""
84
+ try:
85
+ # Try to decrypt a small part to verify password
86
+ key = self._derive_key(password)
87
+ fernet = Fernet(key)
88
+
89
+ # This will throw an exception if password is wrong
90
+ fernet.decrypt(encrypted_data.get('encrypted_data', 'A')[:10].encode())
91
+ return True
92
+ except:
93
+ return False
94
+
95
+ def encrypt_data(self, data: str, password: str) -> str:
96
+ """Encrypt arbitrary data"""
97
+ key = self._derive_key(password)
98
+ fernet = Fernet(key)
99
+ return fernet.encrypt(data.encode()).decode()
100
+
101
+ def decrypt_data(self, encrypted_data: str, password: str) -> str:
102
+ """Decrypt arbitrary data"""
103
+ key = self._derive_key(password)
104
+ fernet = Fernet(key)
105
+ return fernet.decrypt(encrypted_data.encode()).decode()
File without changes
@@ -0,0 +1,172 @@
1
+ import time
2
+ import hashlib
3
+ from typing import Dict, Tuple
4
+
5
+ class TransactionSecurity:
6
+ """Enhanced transaction security system"""
7
+
8
+ def __init__(self):
9
+ self.min_transaction_amount = 0.000001
10
+ self.max_transaction_amount = 100000000
11
+ self.required_fee = 0.00001
12
+ self.rate_limits = {}
13
+ self.blacklisted_addresses = set()
14
+
15
+ def validate_transaction_security(self, transaction: Dict) -> Tuple[bool, str]:
16
+ """Comprehensive transaction security validation"""
17
+ tx_type = transaction.get("type", "").lower()
18
+
19
+ if tx_type == "gtx_genesis":
20
+ return self._validate_genesis_transaction(transaction)
21
+ elif tx_type == "reward":
22
+ return self._validate_reward_transaction(transaction)
23
+ elif tx_type == "transfer":
24
+ return self._validate_transfer_transaction(transaction)
25
+ else:
26
+ return False, f"Unknown transaction type: {tx_type}"
27
+
28
+ def _validate_genesis_transaction(self, transaction: Dict) -> Tuple[bool, str]:
29
+ """Validate GTX Genesis transaction"""
30
+ required_fields = ["bill_serial", "denomination", "mining_difficulty", "hash", "nonce"]
31
+ for field in required_fields:
32
+ if field not in transaction:
33
+ return False, f"Missing GTX field: {field}"
34
+
35
+ # Validate denomination
36
+ denomination = transaction.get("denomination")
37
+ valid_denominations = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000]
38
+ if denomination not in valid_denominations:
39
+ return False, f"Invalid denomination: {denomination}"
40
+
41
+ # Validate mining proof
42
+ if not self._validate_mining_proof(transaction):
43
+ return False, "Invalid mining proof"
44
+
45
+ return True, "Valid GTX Genesis transaction"
46
+
47
+ def _validate_reward_transaction(self, transaction: Dict) -> Tuple[bool, str]:
48
+ """Validate reward transaction"""
49
+ required_fields = ["from", "to", "amount", "block_height", "hash"]
50
+ for field in required_fields:
51
+ if field not in transaction:
52
+ return False, f"Missing reward field: {field}"
53
+
54
+ # Only network can create rewards
55
+ if transaction.get("from") != "network":
56
+ return False, "Unauthorized reward creation"
57
+
58
+ return True, "Valid reward transaction"
59
+
60
+ def _validate_transfer_transaction(self, transaction: Dict) -> Tuple[bool, str]:
61
+ """Validate transfer transaction"""
62
+ required_fields = ["from", "to", "amount", "signature", "public_key", "nonce"]
63
+ for field in required_fields:
64
+ if field not in transaction:
65
+ return False, f"Missing field: {field}"
66
+
67
+ # Amount validation
68
+ amount = transaction.get("amount", 0)
69
+ if amount < self.min_transaction_amount:
70
+ return False, f"Amount below minimum: {self.min_transaction_amount}"
71
+ if amount > self.max_transaction_amount:
72
+ return False, f"Amount above maximum: {self.max_transaction_amount}"
73
+
74
+ # Fee validation
75
+ fee = transaction.get("fee", 0)
76
+ if fee < self.required_fee:
77
+ return False, f"Insufficient fee: {fee} (required: {self.required_fee})"
78
+
79
+ # Signature validation
80
+ if not self._validate_signature(transaction):
81
+ return False, "Invalid signature"
82
+
83
+ # Anti-spam checks
84
+ from_address = transaction.get("from", "")
85
+ if not self._check_rate_limit(from_address):
86
+ return False, "Rate limit exceeded"
87
+
88
+ if self._is_blacklisted(from_address):
89
+ return False, "Address is blacklisted"
90
+
91
+ return True, "Valid transfer transaction"
92
+
93
+ def _validate_mining_proof(self, transaction: Dict) -> bool:
94
+ """Validate mining proof-of-work"""
95
+ try:
96
+ difficulty = transaction.get("mining_difficulty", 0)
97
+ bill_hash = transaction.get("hash", "")
98
+
99
+ # Verify difficulty requirement
100
+ target = "0" * difficulty
101
+ return bill_hash.startswith(target)
102
+ except:
103
+ return False
104
+
105
+ def _validate_signature(self, transaction: Dict) -> bool:
106
+ """Validate transaction signature"""
107
+ try:
108
+ signature = transaction.get("signature", "")
109
+ public_key = transaction.get("public_key", "")
110
+
111
+ # Basic format validation
112
+ if len(signature) != 64:
113
+ return False
114
+
115
+ # In production, use proper ECDSA verification
116
+ # For now, simplified check
117
+ return all(c in "0123456789abcdef" for c in signature.lower())
118
+ except:
119
+ return False
120
+
121
+ def _check_rate_limit(self, address: str) -> bool:
122
+ """Check transaction rate limiting"""
123
+ now = time.time()
124
+
125
+ if address not in self.rate_limits:
126
+ self.rate_limits[address] = []
127
+
128
+ # Remove old entries (older than 1 minute)
129
+ self.rate_limits[address] = [t for t in self.rate_limits[address] if now - t < 60]
130
+
131
+ # Check if over limit (10 transactions per minute)
132
+ if len(self.rate_limits[address]) >= 10:
133
+ return False
134
+
135
+ self.rate_limits[address].append(now)
136
+ return True
137
+
138
+ def _is_blacklisted(self, address: str) -> bool:
139
+ """Check if address is blacklisted"""
140
+ return address.lower() in self.blacklisted_addresses
141
+
142
+ def blacklist_address(self, address: str):
143
+ """Add address to blacklist"""
144
+ self.blacklisted_addresses.add(address.lower())
145
+
146
+ def calculate_security_score(self, transaction: Dict) -> int:
147
+ """Calculate security score for transaction"""
148
+ score = 0
149
+
150
+ # Signature strength
151
+ signature = transaction.get("signature", "")
152
+ if len(signature) == 64:
153
+ score += 40
154
+
155
+ # Public key presence
156
+ if transaction.get("public_key"):
157
+ score += 20
158
+
159
+ # Timestamp freshness
160
+ timestamp = transaction.get("timestamp", 0)
161
+ if time.time() - timestamp < 600: # 10 minutes
162
+ score += 20
163
+
164
+ # Nonce uniqueness
165
+ if transaction.get("nonce"):
166
+ score += 10
167
+
168
+ # Additional security features
169
+ if transaction.get("security_hash"):
170
+ score += 10
171
+
172
+ return min(score, 100)