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.
- cache_manager.py +376 -0
- {clapp_pm-1.0.16.data → clapp_pm-1.0.18.data}/data/version.json +1 -1
- {clapp_pm-1.0.16.dist-info → clapp_pm-1.0.18.dist-info}/METADATA +1 -1
- {clapp_pm-1.0.16.dist-info → clapp_pm-1.0.18.dist-info}/RECORD +13 -9
- {clapp_pm-1.0.16.dist-info → clapp_pm-1.0.18.dist-info}/top_level.txt +4 -0
- main.py +183 -0
- package_signing.py +370 -0
- smart_search.py +451 -0
- version.py +1 -1
- version_manager.py +351 -0
- {clapp_pm-1.0.16.dist-info → clapp_pm-1.0.18.dist-info}/WHEEL +0 -0
- {clapp_pm-1.0.16.dist-info → clapp_pm-1.0.18.dist-info}/entry_points.txt +0 -0
- {clapp_pm-1.0.16.dist-info → clapp_pm-1.0.18.dist-info}/licenses/LICENSE +0 -0
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
|