feat(core): Add PyPI and RubyGems registries, integrate into SmartRegistry, extend storage and auth

This commit is contained in:
2025-11-21 17:13:06 +00:00
parent ac51a94c8b
commit 0d73230d5a
17 changed files with 3514 additions and 33 deletions

View File

@@ -351,22 +351,38 @@ export class PypiRegistry extends BaseRegistry {
return this.errorResponse(403, 'Insufficient permissions');
}
// Calculate hashes
// Calculate and verify hashes
const hashes: Record<string, string> = {};
if (formData.sha256_digest) {
hashes.sha256 = formData.sha256_digest;
} else {
hashes.sha256 = await helpers.calculateHash(fileData, 'sha256');
// Always calculate SHA256
const actualSha256 = await helpers.calculateHash(fileData, 'sha256');
hashes.sha256 = actualSha256;
// Verify client-provided SHA256 if present
if (formData.sha256_digest && formData.sha256_digest !== actualSha256) {
return this.errorResponse(400, 'SHA256 hash mismatch');
}
// Calculate MD5 if requested
if (formData.md5_digest) {
// MD5 digest in PyPI is urlsafe base64, convert to hex
hashes.md5 = await helpers.calculateHash(fileData, 'md5');
const actualMd5 = await helpers.calculateHash(fileData, 'md5');
hashes.md5 = actualMd5;
// Verify if client provided MD5
if (formData.md5_digest !== actualMd5) {
return this.errorResponse(400, 'MD5 hash mismatch');
}
}
// Calculate Blake2b if requested
if (formData.blake2_256_digest) {
hashes.blake2b = formData.blake2_256_digest;
const actualBlake2b = await helpers.calculateHash(fileData, 'blake2b');
hashes.blake2b = actualBlake2b;
// Verify if client provided Blake2b
if (formData.blake2_256_digest !== actualBlake2b) {
return this.errorResponse(400, 'Blake2b hash mismatch');
}
}
// Store file