Skip to main content
Glama
ip-authentication.ts4.07 kB
/** * IP Authentication Service * Centralized service for IP-based user authentication and management */ import { logger } from "../utils/logger.js"; interface UserRecord { user_id: string; email?: string; name?: string; plan_type: string; created_at: string; updated_at: string; } export interface IPAuthenticationResult { userId: string; email: string; name: string; planType: string; } export interface UserTokenData { userId: string; email: string; name: string; } /** * Centralized IP Authentication Service * Handles all IP-based authentication logic with caching and optimization */ export class IPAuthenticationService { constructor(private d1: D1Database) {} /** * Check if IP is authorized for a user (with full user data including plan) * Used by rate-limit service for comprehensive authentication */ async authenticateIP( clientIP: string ): Promise<IPAuthenticationResult | null> { try { // Query database for authorized IP with user and subscription data const result = await this.d1 .prepare( `SELECT uai.user_id, u.email, u.name, COALESCE(us.plan_type, 'hobby') as plan_type FROM user_authorized_ips uai JOIN users u ON uai.user_id = u.id LEFT JOIN user_subscriptions us ON u.id = us.user_id WHERE uai.ip_address = ?` ) .bind(clientIP) .all(); if (!result.results || result.results.length === 0) { return null; } const user = result.results[0] as unknown as UserRecord; // Update last_used_at in background await this.updateIPLastUsedAsync(clientIP, user.user_id); return { userId: user.user_id, email: user.email || "ip-authenticated", name: user.name || "IP User", planType: user.plan_type, }; } catch (error) { logger.error( `IP authentication failed for ${clientIP}: ${error instanceof Error ? error.message : String(error)}` ); return null; } } /** * Check if IP is authorized for a user (basic user data only) * Used by auth-middleware for simple authentication */ async checkIPAuthentication(clientIP: string): Promise<UserTokenData | null> { try { // Query database for authorized IP with basic user data const result = await this.d1 .prepare( `SELECT uai.user_id, u.email, u.name FROM user_authorized_ips uai JOIN users u ON uai.user_id = u.id WHERE uai.ip_address = ?` ) .bind(clientIP) .all(); if (!result.results || result.results.length === 0) { return null; } const user = result.results[0] as unknown as UserRecord; // Update last_used_at in background await this.updateIPLastUsedAsync(clientIP, user.user_id); return { userId: user.user_id, email: user.email || "ip-authenticated", name: user.name || "IP User", }; } catch (error) { logger.error( `IP authentication check failed for ${clientIP}: ${error instanceof Error ? error.message : String(error)}` ); return null; } } /** * Update IP last_used_at timestamp (non-blocking) * Private method used internally by both authentication methods */ private async updateIPLastUsedAsync( ipAddress: string, userId: string ): Promise<void> { try { const result = await this.d1 .prepare( "UPDATE user_authorized_ips SET last_used_at = ? WHERE ip_address = ? AND user_id = ?" ) .bind(new Date().toISOString(), ipAddress, userId) .run(); if (!result.success) { throw new Error("D1 IP update execution failed"); } } catch (error) { logger.error( `❌ Failed to update IP last_used_at for ${ipAddress} (userId: ${userId.substring(0, 8)}...): ${error instanceof Error ? error.message : String(error)}` ); // 不重新抛出错误,避免影响主流程 } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/adimowis/appler'

If you have feedback or need assistance with the MCP directory API, please join our Discord server