auth-service.ts•5.97 kB
import { OAuthManager } from './oauth-manager.js';
import { CredentialManager } from './credential-manager.js';
import { AuthMiddleware } from './auth-middleware.js';
import { AuthManager } from '../types/auth.js';
import { ErrorHandler, handleAsyncError } from '../utils/error-handler.js';
import { ConfigurationError, MissingConfigError } from '../types/errors.js';
/**
* Comprehensive authentication service that combines OAuth management,
* credential management, and security middleware
*/
export class AuthService implements AuthManager {
private oauthManager: OAuthManager | null = null;
private credentialManager: CredentialManager;
private authMiddleware: AuthMiddleware | null = null;
private initialized = false;
private errorHandler: ErrorHandler;
constructor(
credentialsPath?: string,
errorHandler?: ErrorHandler
) {
this.credentialManager = new CredentialManager(credentialsPath);
this.errorHandler = errorHandler || new ErrorHandler();
}
/**
* Initialize the authentication service
*/
async initialize(): Promise<void> {
const result = await handleAsyncError(async () => {
// Load credentials
const credentials = await this.credentialManager.loadCredentials();
// Initialize OAuth manager
this.oauthManager = new OAuthManager(credentials);
// Initialize middleware
this.authMiddleware = new AuthMiddleware(this);
this.initialized = true;
console.log('Authentication service initialized successfully');
}, { operation: 'initialize_auth_service' }, this.errorHandler);
if (!result.success) {
// Check if credentials file doesn't exist and offer to create sample
if (!(await this.credentialManager.credentialsExist())) {
console.log('Creating sample credentials file...');
await this.credentialManager.createSampleCredentialsFile();
throw new MissingConfigError('Credentials file created. Please update it with your Google OAuth credentials and restart.');
}
// Re-throw the handled error
throw result.error;
}
}
/**
* Authenticate with Google Drive API
*/
async authenticate(): Promise<boolean> {
this.ensureInitialized();
const result = await handleAsyncError(async () => {
return this.oauthManager!.authenticate();
}, { operation: 'authenticate' }, this.errorHandler);
if (!result.success) {
throw result.error;
}
return result.data;
}
/**
* Refresh the access token
*/
async refreshToken(): Promise<boolean> {
this.ensureInitialized();
return this.oauthManager!.refreshToken();
}
/**
* Get current access token
*/
getAccessToken(): string {
this.ensureInitialized();
return this.oauthManager!.getAccessToken();
}
/**
* Check if currently authenticated
*/
isAuthenticated(): boolean {
if (!this.initialized || !this.oauthManager) {
return false;
}
return this.oauthManager.isAuthenticated();
}
/**
* Get OAuth manager instance
*/
getOAuthManager(): OAuthManager {
this.ensureInitialized();
return this.oauthManager!;
}
/**
* Get authentication middleware
*/
getAuthMiddleware(): AuthMiddleware {
this.ensureInitialized();
return this.authMiddleware!;
}
/**
* Get credential manager
*/
getCredentialManager(): CredentialManager {
return this.credentialManager;
}
/**
* Perform initial OAuth setup (for first-time setup)
*/
async performInitialSetup(): Promise<string> {
this.ensureInitialized();
const authUrl = this.oauthManager!.getAuthUrl();
console.log('Please visit the following URL to authorize the application:');
console.log(authUrl);
console.log('After authorization, you will receive a code. Use exchangeCodeForTokens() with that code.');
return authUrl;
}
/**
* Exchange authorization code for tokens (part of initial setup)
*/
async exchangeCodeForTokens(code: string): Promise<boolean> {
this.ensureInitialized();
const success = await this.oauthManager!.exchangeCodeForTokens(code);
if (success) {
console.log('Authorization successful! Tokens have been saved.');
} else {
console.error('Authorization failed. Please try again.');
}
return success;
}
/**
* Clear all stored tokens (logout)
*/
async logout(): Promise<void> {
if (this.oauthManager) {
await this.oauthManager.clearTokens();
console.log('Logged out successfully. Tokens cleared.');
}
}
/**
* Validate current authentication and provide detailed status
*/
async validateAuthentication(): Promise<AuthValidationResult> {
if (!this.initialized) {
return {
isValid: false,
error: 'Authentication service not initialized',
needsReauth: true,
needsSetup: true
};
}
if (!this.authMiddleware) {
return {
isValid: false,
error: 'Authentication middleware not available',
needsReauth: true,
needsSetup: false
};
}
const result = await this.authMiddleware.validateAuth();
return {
...result,
needsSetup: false
};
}
/**
* Execute an API call with automatic authentication handling
*/
async executeWithAuth<T>(
apiCall: () => Promise<T>,
context?: string
): Promise<T> {
this.ensureInitialized();
return this.authMiddleware!.executeWithAuth(apiCall, context);
}
/**
* Ensure the service is initialized
*/
private ensureInitialized(): void {
if (!this.initialized) {
throw new ConfigurationError('Authentication service not initialized. Call initialize() first.');
}
}
}
/**
* Extended authentication validation result
*/
export interface AuthValidationResult {
isValid: boolean;
error: string | null;
needsReauth: boolean;
needsSetup: boolean;
}