feat(registry): add declarative protocol routing and request-scoped storage hook context across registries

This commit is contained in:
2026-04-16 10:42:33 +00:00
parent 09335d41f3
commit 9643ef98b9
28 changed files with 2327 additions and 1919 deletions
+29 -37
View File
@@ -105,56 +105,48 @@ export class MavenRegistry extends BaseRegistry {
// Remove base path from URL
const path = context.path.replace(this.basePath, '');
// Extract token from Authorization header
const authHeader = context.headers['authorization'] || context.headers['Authorization'];
const authHeader = this.getAuthorizationHeader(context);
let token: IAuthToken | null = null;
if (authHeader) {
if (/^Basic\s+/i.test(authHeader)) {
const basicCredentials = this.parseBasicAuthHeader(authHeader);
if (basicCredentials) {
// Maven sends Basic Auth: base64(username:password) — extract the password as token
const base64 = authHeader.replace(/^Basic\s+/i, '');
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
const colonIndex = decoded.indexOf(':');
const password = colonIndex >= 0 ? decoded.substring(colonIndex + 1) : decoded;
token = await this.authManager.validateToken(password, 'maven');
token = await this.authManager.validateToken(basicCredentials.password, 'maven');
} else {
const tokenString = authHeader.replace(/^Bearer\s+/i, '');
token = await this.authManager.validateToken(tokenString, 'maven');
const tokenString = this.extractBearerToken(authHeader);
token = tokenString ? await this.authManager.validateToken(tokenString, 'maven') : null;
}
}
// Build actor from context and validated token
const actor: IRequestActor = {
...context.actor,
userId: token?.userId,
ip: context.headers['x-forwarded-for'] || context.headers['X-Forwarded-For'],
userAgent: context.headers['user-agent'] || context.headers['User-Agent'],
};
const actor: IRequestActor = this.buildRequestActor(context, token);
// Parse path to determine request type
const coordinate = pathToGAV(path);
return this.storage.withContext({ protocol: 'maven', actor }, async () => {
// Parse path to determine request type
const coordinate = pathToGAV(path);
if (!coordinate) {
// Not a valid artifact path, could be metadata or root
if (path.endsWith('/maven-metadata.xml')) {
return this.handleMetadataRequest(context.method, path, token, actor);
if (!coordinate) {
// Not a valid artifact path, could be metadata or root
if (path.endsWith('/maven-metadata.xml')) {
return this.handleMetadataRequest(context.method, path, token, actor);
}
return {
status: 404,
headers: { 'Content-Type': 'application/json' },
body: { error: 'NOT_FOUND', message: 'Invalid Maven path' },
};
}
return {
status: 404,
headers: { 'Content-Type': 'application/json' },
body: { error: 'NOT_FOUND', message: 'Invalid Maven path' },
};
}
// Check if it's a checksum file
if (coordinate.extension === 'md5' || coordinate.extension === 'sha1' ||
coordinate.extension === 'sha256' || coordinate.extension === 'sha512') {
return this.handleChecksumRequest(context.method, coordinate, token, path);
}
// Check if it's a checksum file
if (coordinate.extension === 'md5' || coordinate.extension === 'sha1' ||
coordinate.extension === 'sha256' || coordinate.extension === 'sha512') {
return this.handleChecksumRequest(context.method, coordinate, token, path);
}
// Handle artifact requests (JAR, POM, WAR, etc.)
return this.handleArtifactRequest(context.method, coordinate, token, context.body, actor);
// Handle artifact requests (JAR, POM, WAR, etc.)
return this.handleArtifactRequest(context.method, coordinate, token, context.body, actor);
});
}
protected async checkPermission(