feat(core): Add Cargo and Composer registries with storage, auth and helpers

This commit is contained in:
2025-11-21 09:13:02 +00:00
parent 92d27d8b15
commit 8d48627301
19 changed files with 1869 additions and 56 deletions

View File

@@ -118,17 +118,7 @@ export class MavenRegistry extends BaseRegistry {
switch (method) {
case 'GET':
case 'HEAD':
// Read permission required
if (!await this.checkPermission(token, resource, 'read')) {
return {
status: 401,
headers: {
'WWW-Authenticate': `Bearer realm="${this.basePath}",service="maven-registry"`,
},
body: { error: 'UNAUTHORIZED', message: 'Authentication required' },
};
}
// Maven repositories typically allow anonymous reads
return method === 'GET'
? this.getArtifact(groupId, artifactId, version, filename)
: this.headArtifact(groupId, artifactId, version, filename);
@@ -181,24 +171,15 @@ export class MavenRegistry extends BaseRegistry {
private async handleChecksumRequest(
method: string,
coordinate: IMavenCoordinate,
token: IAuthToken | null
token: IAuthToken | null,
path: string
): Promise<IResponse> {
const { groupId, artifactId, version, extension } = coordinate;
const resource = `${groupId}:${artifactId}`;
// Checksums follow the same permissions as their artifacts
// Checksums follow the same permissions as their artifacts (public read)
if (method === 'GET' || method === 'HEAD') {
if (!await this.checkPermission(token, resource, 'read')) {
return {
status: 401,
headers: {
'WWW-Authenticate': `Bearer realm="${this.basePath}",service="maven-registry"`,
},
body: { error: 'UNAUTHORIZED', message: 'Authentication required' },
};
}
return this.getChecksum(groupId, artifactId, version, coordinate);
return this.getChecksum(groupId, artifactId, version, coordinate, path);
}
return {
@@ -402,9 +383,14 @@ export class MavenRegistry extends BaseRegistry {
groupId: string,
artifactId: string,
version: string,
coordinate: IMavenCoordinate
coordinate: IMavenCoordinate,
fullPath: string
): Promise<IResponse> {
const checksumFilename = buildFilename(coordinate);
// Extract the filename from the full path (last component)
// The fullPath might be something like /com/example/test/test-artifact/1.0.0/test-artifact-1.0.0.jar.md5
const pathParts = fullPath.split('/');
const checksumFilename = pathParts[pathParts.length - 1];
const data = await this.storage.getMavenArtifact(groupId, artifactId, version, checksumFilename);
if (!data) {
@@ -567,10 +553,8 @@ export class MavenRegistry extends BaseRegistry {
const xml = generateMetadataXml(metadata);
await this.storage.putMavenMetadata(groupId, artifactId, Buffer.from(xml, 'utf-8'));
// Also store checksums for metadata
const checksums = await calculateChecksums(Buffer.from(xml, 'utf-8'));
const metadataFilename = 'maven-metadata.xml';
await this.storeChecksums(groupId, artifactId, '', metadataFilename, checksums);
// Note: Checksums for maven-metadata.xml are optional and not critical
// They would need special handling since metadata uses a different storage path
}
// ========================================================================