clapp-pm 1.0.16__py3-none-any.whl → 1.0.18__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.
package_signing.py ADDED
@@ -0,0 +1,370 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ package_signing.py - Paket İmzalama ve Doğrulama Sistemi
4
+
5
+ Bu modül clapp paketlerinin güvenliğini sağlamak için:
6
+ - Paket imzalama
7
+ - İmza doğrulama
8
+ - Checksum hesaplama
9
+ - Güvenlik kontrolü
10
+ """
11
+
12
+ import os
13
+ import json
14
+ import hashlib
15
+ import hmac
16
+ import base64
17
+ import tempfile
18
+ import zipfile
19
+ from pathlib import Path
20
+ from typing import Dict, Tuple, Optional
21
+ from cryptography.hazmat.primitives import hashes, serialization
22
+ from cryptography.hazmat.primitives.asymmetric import rsa, padding
23
+ from cryptography.hazmat.backends import default_backend
24
+
25
+ class PackageSigner:
26
+ """Paket imzalama ve doğrulama sınıfı"""
27
+
28
+ def __init__(self, private_key_path: Optional[str] = None, public_key_path: Optional[str] = None):
29
+ """
30
+ PackageSigner başlatıcısı
31
+
32
+ Args:
33
+ private_key_path: Özel anahtar dosyası yolu
34
+ public_key_path: Genel anahtar dosyası yolu
35
+ """
36
+ self.private_key_path = private_key_path
37
+ self.public_key_path = public_key_path
38
+ self.private_key = None
39
+ self.public_key = None
40
+
41
+ if private_key_path and os.path.exists(private_key_path):
42
+ self.load_private_key(private_key_path)
43
+
44
+ if public_key_path and os.path.exists(public_key_path):
45
+ self.load_public_key(public_key_path)
46
+
47
+ def generate_key_pair(self, key_size: int = 2048) -> Tuple[str, str]:
48
+ """
49
+ Yeni RSA anahtar çifti oluşturur
50
+
51
+ Args:
52
+ key_size: Anahtar boyutu (varsayılan: 2048)
53
+
54
+ Returns:
55
+ (private_key_path, public_key_path)
56
+ """
57
+ # Özel anahtar oluştur
58
+ private_key = rsa.generate_private_key(
59
+ public_exponent=65537,
60
+ key_size=key_size,
61
+ backend=default_backend()
62
+ )
63
+
64
+ # Genel anahtar al
65
+ public_key = private_key.public_key()
66
+
67
+ # Anahtarları kaydet
68
+ private_key_path = self._save_private_key(private_key)
69
+ public_key_path = self._save_public_key(public_key)
70
+
71
+ return private_key_path, public_key_path
72
+
73
+ def _save_private_key(self, private_key) -> str:
74
+ """Özel anahtarı dosyaya kaydet"""
75
+ key_path = os.path.join(os.path.expanduser("~"), ".clapp", "private_key.pem")
76
+ os.makedirs(os.path.dirname(key_path), exist_ok=True)
77
+
78
+ with open(key_path, "wb") as f:
79
+ f.write(private_key.private_bytes(
80
+ encoding=serialization.Encoding.PEM,
81
+ format=serialization.PrivateFormat.PKCS8,
82
+ encryption_algorithm=serialization.NoEncryption()
83
+ ))
84
+
85
+ return key_path
86
+
87
+ def _save_public_key(self, public_key) -> str:
88
+ """Genel anahtarı dosyaya kaydet"""
89
+ key_path = os.path.join(os.path.expanduser("~"), ".clapp", "public_key.pem")
90
+ os.makedirs(os.path.dirname(key_path), exist_ok=True)
91
+
92
+ with open(key_path, "wb") as f:
93
+ f.write(public_key.public_bytes(
94
+ encoding=serialization.Encoding.PEM,
95
+ format=serialization.PublicFormat.SubjectPublicKeyInfo
96
+ ))
97
+
98
+ return key_path
99
+
100
+ def load_private_key(self, key_path: str):
101
+ """Özel anahtarı dosyadan yükle"""
102
+ with open(key_path, "rb") as f:
103
+ self.private_key = serialization.load_pem_private_key(
104
+ f.read(),
105
+ password=None,
106
+ backend=default_backend()
107
+ )
108
+
109
+ def load_public_key(self, key_path: str):
110
+ """Genel anahtarı dosyadan yükle"""
111
+ with open(key_path, "rb") as f:
112
+ self.public_key = serialization.load_pem_public_key(
113
+ f.read(),
114
+ backend=default_backend()
115
+ )
116
+
117
+ def calculate_checksum(self, file_path: str) -> str:
118
+ """
119
+ Dosyanın SHA-256 checksum'unu hesaplar
120
+
121
+ Args:
122
+ file_path: Dosya yolu
123
+
124
+ Returns:
125
+ SHA-256 hash (hex formatında)
126
+ """
127
+ sha256_hash = hashlib.sha256()
128
+
129
+ with open(file_path, "rb") as f:
130
+ for chunk in iter(lambda: f.read(4096), b""):
131
+ sha256_hash.update(chunk)
132
+
133
+ return sha256_hash.hexdigest()
134
+
135
+ def calculate_package_checksum(self, package_path: str) -> Dict[str, str]:
136
+ """
137
+ Paket içindeki tüm dosyaların checksum'unu hesaplar
138
+
139
+ Args:
140
+ package_path: Paket dosyası yolu (.zip)
141
+
142
+ Returns:
143
+ Dosya yolları ve checksum'ları
144
+ """
145
+ checksums = {}
146
+
147
+ with zipfile.ZipFile(package_path, 'r') as zip_file:
148
+ for file_info in zip_file.filelist:
149
+ if not file_info.is_dir():
150
+ file_data = zip_file.read(file_info.filename)
151
+ checksum = hashlib.sha256(file_data).hexdigest()
152
+ checksums[file_info.filename] = checksum
153
+
154
+ return checksums
155
+
156
+ def sign_package(self, package_path: str) -> Tuple[bool, str, Optional[str]]:
157
+ """
158
+ Paketi imzalar
159
+
160
+ Args:
161
+ package_path: Paket dosyası yolu
162
+
163
+ Returns:
164
+ (success, message, signature_path)
165
+ """
166
+ if not self.private_key:
167
+ return False, "Özel anahtar yüklenmedi", None
168
+
169
+ try:
170
+ # Paket checksum'unu hesapla
171
+ checksum = self.calculate_checksum(package_path)
172
+
173
+ # Manifest dosyasını oku
174
+ manifest_data = self._extract_manifest_data(package_path)
175
+ if not manifest_data:
176
+ return False, "Manifest dosyası bulunamadı", None
177
+
178
+ # İmzalanacak veriyi hazırla
179
+ data_to_sign = {
180
+ "checksum": checksum,
181
+ "manifest": manifest_data,
182
+ "package_name": os.path.basename(package_path)
183
+ }
184
+
185
+ data_string = json.dumps(data_to_sign, sort_keys=True)
186
+ data_bytes = data_string.encode('utf-8')
187
+
188
+ # İmzala
189
+ signature = self.private_key.sign(
190
+ data_bytes,
191
+ padding.PSS(
192
+ mgf=padding.MGF1(hashes.SHA256()),
193
+ salt_length=padding.PSS.MAX_LENGTH
194
+ ),
195
+ hashes.SHA256()
196
+ )
197
+
198
+ # İmzayı kaydet
199
+ signature_path = package_path.replace('.zip', '.sig')
200
+ with open(signature_path, 'wb') as f:
201
+ f.write(base64.b64encode(signature))
202
+
203
+ return True, "Paket başarıyla imzalandı", signature_path
204
+
205
+ except Exception as e:
206
+ return False, f"İmzalama hatası: {str(e)}", None
207
+
208
+ def verify_package(self, package_path: str, signature_path: str) -> Tuple[bool, str]:
209
+ """
210
+ Paket imzasını doğrular
211
+
212
+ Args:
213
+ package_path: Paket dosyası yolu
214
+ signature_path: İmza dosyası yolu
215
+
216
+ Returns:
217
+ (is_valid, message)
218
+ """
219
+ if not self.public_key:
220
+ return False, "Genel anahtar yüklenmedi"
221
+
222
+ try:
223
+ # İmzayı oku
224
+ with open(signature_path, 'rb') as f:
225
+ signature = base64.b64decode(f.read())
226
+
227
+ # Paket checksum'unu hesapla
228
+ checksum = self.calculate_checksum(package_path)
229
+
230
+ # Manifest dosyasını oku
231
+ manifest_data = self._extract_manifest_data(package_path)
232
+ if not manifest_data:
233
+ return False, "Manifest dosyası bulunamadı"
234
+
235
+ # Doğrulanacak veriyi hazırla
236
+ data_to_verify = {
237
+ "checksum": checksum,
238
+ "manifest": manifest_data,
239
+ "package_name": os.path.basename(package_path)
240
+ }
241
+
242
+ data_string = json.dumps(data_to_verify, sort_keys=True)
243
+ data_bytes = data_string.encode('utf-8')
244
+
245
+ # İmzayı doğrula
246
+ self.public_key.verify(
247
+ signature,
248
+ data_bytes,
249
+ padding.PSS(
250
+ mgf=padding.MGF1(hashes.SHA256()),
251
+ salt_length=padding.PSS.MAX_LENGTH
252
+ ),
253
+ hashes.SHA256()
254
+ )
255
+
256
+ return True, "Paket imzası doğrulandı"
257
+
258
+ except Exception as e:
259
+ return False, f"İmza doğrulama hatası: {str(e)}"
260
+
261
+ def _extract_manifest_data(self, package_path: str) -> Optional[Dict]:
262
+ """Paket içinden manifest verilerini çıkarır"""
263
+ try:
264
+ with zipfile.ZipFile(package_path, 'r') as zip_file:
265
+ # packages/ klasörü altındaki manifest.json'u ara
266
+ for file_info in zip_file.filelist:
267
+ if file_info.filename.endswith('manifest.json'):
268
+ manifest_data = zip_file.read(file_info.filename)
269
+ return json.loads(manifest_data.decode('utf-8'))
270
+
271
+ # Doğrudan manifest.json'u ara
272
+ if 'manifest.json' in zip_file.namelist():
273
+ manifest_data = zip_file.read('manifest.json')
274
+ return json.loads(manifest_data.decode('utf-8'))
275
+
276
+ return None
277
+ except Exception:
278
+ return None
279
+
280
+ def verify_package_integrity(self, package_path: str) -> Tuple[bool, str]:
281
+ """
282
+ Paket bütünlüğünü kontrol eder
283
+
284
+ Args:
285
+ package_path: Paket dosyası yolu
286
+
287
+ Returns:
288
+ (is_valid, message)
289
+ """
290
+ try:
291
+ # ZIP dosyası geçerliliğini kontrol et
292
+ with zipfile.ZipFile(package_path, 'r') as zip_file:
293
+ # Dosya listesini kontrol et
294
+ file_list = zip_file.namelist()
295
+
296
+ # Manifest dosyası var mı?
297
+ has_manifest = any(f.endswith('manifest.json') for f in file_list)
298
+ if not has_manifest:
299
+ return False, "Manifest dosyası bulunamadı"
300
+
301
+ # Dosyaları test et
302
+ zip_file.testzip()
303
+
304
+ return True, "Paket bütünlüğü doğrulandı"
305
+
306
+ except zipfile.BadZipFile:
307
+ return False, "Geçersiz ZIP dosyası"
308
+ except Exception as e:
309
+ return False, f"Bütünlük kontrolü hatası: {str(e)}"
310
+
311
+ # Yardımcı fonksiyonlar
312
+ def create_package_signer() -> PackageSigner:
313
+ """Varsayılan ayarlarla PackageSigner oluşturur"""
314
+ clapp_dir = os.path.join(os.path.expanduser("~"), ".clapp")
315
+ private_key_path = os.path.join(clapp_dir, "private_key.pem")
316
+ public_key_path = os.path.join(clapp_dir, "public_key.pem")
317
+
318
+ return PackageSigner(private_key_path, public_key_path)
319
+
320
+ def sign_package_file(package_path: str) -> Tuple[bool, str]:
321
+ """Paket dosyasını imzalar"""
322
+ signer = create_package_signer()
323
+
324
+ # Anahtar yoksa oluştur
325
+ if not signer.private_key:
326
+ print("🔑 Yeni anahtar çifti oluşturuluyor...")
327
+ private_key_path, public_key_path = signer.generate_key_pair()
328
+ signer.load_private_key(private_key_path)
329
+ print(f"✅ Anahtarlar oluşturuldu: {clapp_dir}")
330
+
331
+ return signer.sign_package(package_path)
332
+
333
+ def verify_package_file(package_path: str, signature_path: str) -> Tuple[bool, str]:
334
+ """Paket dosyasının imzasını doğrular"""
335
+ signer = create_package_signer()
336
+ return signer.verify_package(package_path, signature_path)
337
+
338
+ def check_package_security(package_path: str) -> Dict[str, any]:
339
+ """Paket güvenlik kontrolü yapar"""
340
+ signer = create_package_signer()
341
+
342
+ results = {
343
+ "integrity": False,
344
+ "signature": False,
345
+ "checksum": "",
346
+ "warnings": []
347
+ }
348
+
349
+ # Bütünlük kontrolü
350
+ integrity_valid, integrity_msg = signer.verify_package_integrity(package_path)
351
+ results["integrity"] = integrity_valid
352
+
353
+ if not integrity_valid:
354
+ results["warnings"].append(f"Bütünlük hatası: {integrity_msg}")
355
+
356
+ # Checksum hesapla
357
+ results["checksum"] = signer.calculate_checksum(package_path)
358
+
359
+ # İmza kontrolü (varsa)
360
+ signature_path = package_path.replace('.zip', '.sig')
361
+ if os.path.exists(signature_path):
362
+ signature_valid, signature_msg = signer.verify_package(package_path, signature_path)
363
+ results["signature"] = signature_valid
364
+
365
+ if not signature_valid:
366
+ results["warnings"].append(f"İmza hatası: {signature_msg}")
367
+ else:
368
+ results["warnings"].append("İmza dosyası bulunamadı")
369
+
370
+ return results