tryaii-mcp-server
Version:
TryAII MCP Server - 15+ AI models with comparison, cost tracking, and collective intelligence
106 lines • 4.33 kB
JavaScript
import * as bcrypt from 'bcryptjs';
import { logger } from '../utils/logger.js';
import { databaseService } from './database.js';
import { UserApiKeySchema, UserSchema } from '../models/existing/ExistingModels.js';
export class AuthenticationService {
static instance;
UserApiKeyModel;
UserModel;
constructor() { }
static getInstance() {
if (!AuthenticationService.instance) {
AuthenticationService.instance = new AuthenticationService();
}
return AuthenticationService.instance;
}
async initialize() {
try {
const mainConnection = databaseService.getMainConnection();
this.UserApiKeyModel = mainConnection.model('UserApiKey', UserApiKeySchema);
this.UserModel = mainConnection.model('User', UserSchema);
logger.info('Authentication Service initialized successfully');
}
catch (error) {
logger.error('Failed to initialize Authentication Service', { error });
throw error;
}
}
async authenticateApiKey(apiKey) {
try {
const startTime = Date.now();
// Extract key prefix for faster lookup
const keyPrefix = apiKey.substring(0, 8);
// Find API key by prefix first (indexed field)
const apiKeyDoc = await this.UserApiKeyModel.findOne({
keyPrefix,
isActive: true
}).lean();
if (!apiKeyDoc) {
logger.warn('API key not found or inactive', { keyPrefix });
return null;
}
// Verify the full key hash
const isValidKey = await bcrypt.compare(apiKey, apiKeyDoc.keyHash);
if (!isValidKey) {
logger.warn('Invalid API key hash', { keyPrefix, userId: apiKeyDoc.userId });
return null;
}
// Get user details
const user = await this.UserModel.findById(apiKeyDoc.userId).lean();
if (!user || !user.isActive) {
logger.warn('User not found or inactive', { userId: apiKeyDoc.userId });
return null;
}
// Update last used timestamp (fire and forget)
this.UserApiKeyModel.updateOne({ _id: apiKeyDoc._id }, { lastUsed: new Date() }).exec().catch((error) => logger.warn('Failed to update API key last used', { error }));
const authTime = Date.now() - startTime;
logger.debug('API key authenticated successfully', {
userId: user._id,
keyPrefix,
authTime: `${authTime}ms`
});
return {
userId: user._id,
apiKeyId: apiKeyDoc.keyId,
keyPrefix: apiKeyDoc.keyPrefix,
permissions: apiKeyDoc.permissions,
user: {
email: user.email,
name: user.name,
balance: {
currentAmount: user.balance?.currentAmount || 0,
currency: user.balance?.currency || 'USD'
}
}
};
}
catch (error) {
logger.error('Authentication error', { error });
return null;
}
}
async hasPermission(user, requiredPermission) {
return user.permissions.includes(requiredPermission);
}
async validatePermissions(user, requiredPermissions) {
return requiredPermissions.every(permission => user.permissions.includes(permission));
}
// Utility method to get fresh user balance
async getUserBalance(userId) {
try {
const user = await this.UserModel.findById(userId).lean();
return user?.balance?.currentAmount || 0;
}
catch (error) {
logger.error('Failed to get user balance', { userId, error });
return 0;
}
}
// Utility method to check if user has sufficient balance
async hasSufficientBalance(userId, requiredAmount) {
const currentBalance = await this.getUserBalance(userId);
return currentBalance >= requiredAmount;
}
}
export const authenticationService = AuthenticationService.getInstance();
//# sourceMappingURL=AuthenticationService.js.map