import { TokenStorage } from './token-storage.js';
import { BrowserAuth } from './browser-auth.js';
import { VergeApiClient } from '../client/api.js';
/**
* 認証結果
*/
export interface AuthResult {
token: string;
email: string;
baseUrl: string;
}
/**
* 統合認証マネージャー
* 保存されたトークンの確認、ブラウザ認証、環境変数からの認証を統合管理
*/
export class AuthManager {
private tokenStorage: TokenStorage;
private baseUrl: string;
private browserAuth?: BrowserAuth;
private apiClient?: VergeApiClient;
constructor(
baseUrl: string,
tokenStorage?: TokenStorage,
browserAuth?: BrowserAuth,
apiClient?: VergeApiClient
) {
this.baseUrl = baseUrl;
this.tokenStorage = tokenStorage ?? new TokenStorage();
this.browserAuth = browserAuth;
this.apiClient = apiClient;
}
/**
* 認証を実行 (優先順位に従って自動的に最適な方法を選択)
*
* 優先順位:
* 1. 保存されたトークンを使用(API検証を行い、無効な場合は次の方法へ)
* 2. 環境変数 (VERGE_EMAIL, VERGE_PASSWORD) からログイン
* 3. ブラウザ認証
*/
async authenticate(): Promise<AuthResult> {
// 1. 保存されたトークンを確認
try {
const savedToken = await this.tokenStorage.loadToken();
if (savedToken && savedToken.baseUrl === this.baseUrl) {
// トークンの有効性をAPI検証
const isValid = await this.validateToken(savedToken.token);
if (isValid) {
console.error('✅ 保存されたトークンを使用します');
console.error('');
return {
token: savedToken.token,
email: savedToken.email,
baseUrl: savedToken.baseUrl,
};
} else {
// 無効なトークンは削除
console.error('⚠️ 保存されたトークンが無効です。再認証します...');
await this.tokenStorage.deleteToken();
}
}
} catch (error) {
// TokenStorageのエラーは無視して次の認証方法に進む
console.error('⚠️ 保存されたトークンの読み込みに失敗しました:', error instanceof Error ? error.message : 'Unknown error');
}
// 2. 環境変数からログイン
const email = process.env.VERGE_EMAIL;
const password = process.env.VERGE_PASSWORD;
if (email && password) {
console.error('🔑 環境変数から認証情報を取得しています...');
try {
const client = this.apiClient ?? new VergeApiClient({
baseUrl: this.baseUrl,
});
const loginResponse = await client.login(email, password);
// 有効期限を計算(デフォルト7日)
const defaultExpiresInSeconds = 7 * 24 * 60 * 60; // 7日
const expiresAt = Date.now() + defaultExpiresInSeconds * 1000;
// トークンを保存
await this.tokenStorage.saveToken({
token: loginResponse.token,
baseUrl: this.baseUrl,
email: email,
expiresAt,
});
console.error('✅ 認証成功!');
console.error('');
return {
token: loginResponse.token,
email: email,
baseUrl: this.baseUrl,
};
} catch (error) {
console.error('⚠️ 環境変数での認証に失敗しました:', error instanceof Error ? error.message : 'Unknown error');
console.error('');
// ブラウザ認証にフォールバック
}
}
// 3. ブラウザ認証
const browserAuth = this.browserAuth ?? new BrowserAuth(this.baseUrl);
const result = await browserAuth.authenticate();
return {
token: result.token,
email: result.email,
baseUrl: this.baseUrl,
};
}
/**
* 保存されたトークンを削除 (ログアウト)
*/
async logout(): Promise<void> {
await this.tokenStorage.deleteToken();
console.error('✅ ログアウトしました');
}
/**
* トークンの有効性を確認
*/
async validateToken(token: string): Promise<boolean> {
try {
const client = this.apiClient ?? new VergeApiClient({
baseUrl: this.baseUrl,
});
client.setToken(token);
await client.getCurrentUser();
return true;
} catch {
return false;
}
}
}
// エクスポート
export { TokenStorage } from './token-storage.js';
export { BrowserAuth } from './browser-auth.js';
export type { TokenInfo } from './token-storage.js';
export type { BrowserAuthResult } from './browser-auth.js';