File size: 2,546 Bytes
69b897d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6c6056a
 
 
69b897d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
const logger = require('../../utils/logger')
const { CLIENT_DEFINITIONS } = require('../clientDefinitions')

/**
 * Gemini CLI 验证器
 * 验证请求是否来自 Gemini CLI
 */
class GeminiCliValidator {
  /**
   * 获取客户端ID
   */
  static getId() {
    return CLIENT_DEFINITIONS.GEMINI_CLI.id
  }

  /**
   * 获取客户端名称
   */
  static getName() {
    return CLIENT_DEFINITIONS.GEMINI_CLI.name
  }

  /**
   * 获取客户端描述
   */
  static getDescription() {
    return CLIENT_DEFINITIONS.GEMINI_CLI.description
  }

  /**
   * 获取客户端图标
   */
  static getIcon() {
    return CLIENT_DEFINITIONS.GEMINI_CLI.icon || '💎'
  }

  /**
   * 验证请求是否来自 Gemini CLI
   * @param {Object} req - Express 请求对象
   * @returns {boolean} 验证结果
   */
  static validate(req) {
    try {
      const userAgent = req.headers['user-agent'] || ''
      const path = req.originalUrl || ''

      // 1. 必须是 /gemini 开头的路径
      if (!path.startsWith('/gemini')) {
        // 非 /gemini 路径不属于 Gemini
        return false
      }

      // 2. 对于 /gemini 路径,检查是否包含 generateContent
      if (path.includes('generateContent')) {
        // 包含 generateContent 的路径需要验证 User-Agent
        const geminiCliPattern = /^GeminiCLI\/v?[\d\.]+/i
        if (!geminiCliPattern.test(userAgent)) {
          logger.debug(
            `Gemini CLI validation failed - UA mismatch for generateContent: ${userAgent}`
          )
          return false
        }
      }

      // 所有必要检查通过
      logger.debug(`Gemini CLI validation passed for path: ${path}`)
      return true
    } catch (error) {
      logger.error('Error in GeminiCliValidator:', error)
      // 验证出错时默认拒绝
      return false
    }
  }

  /**
   * 比较版本号
   * @returns {number} -1: v1 < v2, 0: v1 = v2, 1: v1 > v2
   */
  static compareVersions(v1, v2) {
    const parts1 = v1.split('.').map(Number)
    const parts2 = v2.split('.').map(Number)

    for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
      const part1 = parts1[i] || 0
      const part2 = parts2[i] || 0

      if (part1 < part2) return -1
      if (part1 > part2) return 1
    }

    return 0
  }

  /**
   * 获取验证器信息
   */
  static getInfo() {
    return {
      id: this.getId(),
      name: this.getName(),
      description: this.getDescription(),
      icon: CLIENT_DEFINITIONS.GEMINI_CLI.icon
    }
  }
}

module.exports = GeminiCliValidator