/** * AuditService - Centralized audit logging */ import type { TAuditAction, TAuditResourceType } from '../interfaces/audit.interfaces.ts'; import { AuditLog } from '../models/index.ts'; export interface IAuditContext { actorId?: string; actorType?: 'user' | 'api_token' | 'system' | 'anonymous'; actorTokenId?: string; actorIp?: string; actorUserAgent?: string; organizationId?: string; repositoryId?: string; } export class AuditService { private context: IAuditContext; constructor(context: IAuditContext = {}) { this.context = context; } /** * Create a new audit service with context */ public static withContext(context: IAuditContext): AuditService { return new AuditService(context); } /** * Log an audit event */ public async log( action: TAuditAction, resourceType: TAuditResourceType, options: { resourceId?: string; resourceName?: string; organizationId?: string; repositoryId?: string; metadata?: Record; success?: boolean; errorCode?: string; errorMessage?: string; durationMs?: number; } = {} ): Promise { return await AuditLog.log({ actorId: this.context.actorId, actorType: this.context.actorType, actorTokenId: this.context.actorTokenId, actorIp: this.context.actorIp, actorUserAgent: this.context.actorUserAgent, action, resourceType, resourceId: options.resourceId, resourceName: options.resourceName, organizationId: options.organizationId || this.context.organizationId, repositoryId: options.repositoryId || this.context.repositoryId, metadata: options.metadata, success: options.success, errorCode: options.errorCode, errorMessage: options.errorMessage, durationMs: options.durationMs, }); } /** * Log a successful action */ public async logSuccess( action: TAuditAction, resourceType: TAuditResourceType, resourceId?: string, resourceName?: string, metadata?: Record ): Promise { return await this.log(action, resourceType, { resourceId, resourceName, metadata, success: true, }); } /** * Log a failed action */ public async logFailure( action: TAuditAction, resourceType: TAuditResourceType, errorCode: string, errorMessage: string, resourceId?: string, metadata?: Record ): Promise { return await this.log(action, resourceType, { resourceId, metadata, success: false, errorCode, errorMessage, }); } // Convenience methods for common actions public async logUserLogin(userId: string, success: boolean, errorMessage?: string): Promise { if (success) { return await this.logSuccess('USER_LOGIN', 'user', userId); } return await this.logFailure('USER_LOGIN', 'user', 'LOGIN_FAILED', errorMessage || 'Login failed', userId); } public async logUserLogout(userId: string): Promise { return await this.logSuccess('USER_LOGOUT', 'user', userId); } public async logTokenCreated(tokenId: string, tokenName: string): Promise { return await this.logSuccess('TOKEN_CREATED', 'api_token', tokenId, tokenName); } public async logTokenRevoked(tokenId: string, tokenName: string): Promise { return await this.logSuccess('TOKEN_REVOKED', 'api_token', tokenId, tokenName); } public async logPackagePublished( packageId: string, packageName: string, version: string, organizationId: string, repositoryId: string ): Promise { return await this.log('PACKAGE_PUBLISHED', 'package', { resourceId: packageId, resourceName: packageName, organizationId, repositoryId, metadata: { version }, success: true, }); } public async logPackageDownloaded( packageId: string, packageName: string, version: string, organizationId: string, repositoryId: string ): Promise { return await this.log('PACKAGE_DOWNLOADED', 'package', { resourceId: packageId, resourceName: packageName, organizationId, repositoryId, metadata: { version }, success: true, }); } public async logOrganizationCreated(orgId: string, orgName: string): Promise { return await this.logSuccess('ORGANIZATION_CREATED', 'organization', orgId, orgName); } public async logRepositoryCreated( repoId: string, repoName: string, organizationId: string ): Promise { return await this.log('REPOSITORY_CREATED', 'repository', { resourceId: repoId, resourceName: repoName, organizationId, success: true, }); } public async logPermissionChanged( resourceType: TAuditResourceType, resourceId: string, targetUserId: string, oldRole: string | null, newRole: string | null ): Promise { return await this.log('PERMISSION_CHANGED', resourceType, { resourceId, metadata: { targetUserId, oldRole, newRole, }, success: true, }); } }