feat(core): Add PyPI and RubyGems protocol support, Cargo token management, and storage helpers

This commit is contained in:
2025-11-21 14:23:18 +00:00
parent fb8d6897e3
commit 9ca1e670ef
12 changed files with 2414 additions and 6 deletions

View File

@@ -317,12 +317,153 @@ export class AuthManager {
this.tokenStore.delete(token);
}
// ========================================================================
// CARGO TOKEN MANAGEMENT
// ========================================================================
/**
* Create a Cargo token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns Cargo UUID token
*/
public async createCargoToken(userId: string, readonly: boolean = false): Promise<string> {
const scopes = readonly ? ['cargo:*:*:read'] : ['cargo:*:*:*'];
return this.createUuidToken(userId, 'cargo', scopes, readonly);
}
/**
* Validate a Cargo token
* @param token - Cargo UUID token
* @returns Auth token object or null
*/
public async validateCargoToken(token: string): Promise<IAuthToken | null> {
if (!this.isValidUuid(token)) {
return null;
}
const authToken = this.tokenStore.get(token);
if (!authToken || authToken.type !== 'cargo') {
return null;
}
// Check expiration if set
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
this.tokenStore.delete(token);
return null;
}
return authToken;
}
/**
* Revoke a Cargo token
* @param token - Cargo UUID token
*/
public async revokeCargoToken(token: string): Promise<void> {
this.tokenStore.delete(token);
}
// ========================================================================
// PYPI AUTHENTICATION
// ========================================================================
/**
* Create a PyPI token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns PyPI UUID token
*/
public async createPypiToken(userId: string, readonly: boolean = false): Promise<string> {
const scopes = readonly ? ['pypi:*:*:read'] : ['pypi:*:*:*'];
return this.createUuidToken(userId, 'pypi', scopes, readonly);
}
/**
* Validate a PyPI token
* @param token - PyPI UUID token
* @returns Auth token object or null
*/
public async validatePypiToken(token: string): Promise<IAuthToken | null> {
if (!this.isValidUuid(token)) {
return null;
}
const authToken = this.tokenStore.get(token);
if (!authToken || authToken.type !== 'pypi') {
return null;
}
// Check expiration if set
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
this.tokenStore.delete(token);
return null;
}
return authToken;
}
/**
* Revoke a PyPI token
* @param token - PyPI UUID token
*/
public async revokePypiToken(token: string): Promise<void> {
this.tokenStore.delete(token);
}
// ========================================================================
// RUBYGEMS AUTHENTICATION
// ========================================================================
/**
* Create a RubyGems token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns RubyGems UUID token
*/
public async createRubyGemsToken(userId: string, readonly: boolean = false): Promise<string> {
const scopes = readonly ? ['rubygems:*:*:read'] : ['rubygems:*:*:*'];
return this.createUuidToken(userId, 'rubygems', scopes, readonly);
}
/**
* Validate a RubyGems token
* @param token - RubyGems UUID token
* @returns Auth token object or null
*/
public async validateRubyGemsToken(token: string): Promise<IAuthToken | null> {
if (!this.isValidUuid(token)) {
return null;
}
const authToken = this.tokenStore.get(token);
if (!authToken || authToken.type !== 'rubygems') {
return null;
}
// Check expiration if set
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
this.tokenStore.delete(token);
return null;
}
return authToken;
}
/**
* Revoke a RubyGems token
* @param token - RubyGems UUID token
*/
public async revokeRubyGemsToken(token: string): Promise<void> {
this.tokenStore.delete(token);
}
// ========================================================================
// UNIFIED AUTHENTICATION
// ========================================================================
/**
* Validate any token (NPM, Maven, or OCI)
* Validate any token (NPM, Maven, OCI, PyPI, RubyGems, Composer, Cargo)
* @param tokenString - Token string (UUID or JWT)
* @param protocol - Expected protocol type
* @returns Auth token object or null
@@ -331,7 +472,7 @@ export class AuthManager {
tokenString: string,
protocol?: TRegistryProtocol
): Promise<IAuthToken | null> {
// Try UUID-based tokens (NPM, Maven, Composer)
// Try UUID-based tokens (NPM, Maven, Composer, Cargo, PyPI, RubyGems)
if (this.isValidUuid(tokenString)) {
// Try NPM token
const npmToken = await this.validateNpmToken(tokenString);
@@ -350,6 +491,24 @@ export class AuthManager {
if (composerToken && (!protocol || protocol === 'composer')) {
return composerToken;
}
// Try Cargo token
const cargoToken = await this.validateCargoToken(tokenString);
if (cargoToken && (!protocol || protocol === 'cargo')) {
return cargoToken;
}
// Try PyPI token
const pypiToken = await this.validatePypiToken(tokenString);
if (pypiToken && (!protocol || protocol === 'pypi')) {
return pypiToken;
}
// Try RubyGems token
const rubygemsToken = await this.validateRubyGemsToken(tokenString);
if (rubygemsToken && (!protocol || protocol === 'rubygems')) {
return rubygemsToken;
}
}
// Try OCI JWT