IanShaw afcfbb458d fix(gemini): Google One 强制使用内置 OAuth client + 自动获取 project_id + UI 优化 (#212)
* fix(gemini): Google One 强制使用内置 OAuth client + 自动获取 project_id + UI 优化

## 后端改动

### 1. Google One 强制使用内置 Gemini CLI OAuth Client
**问题**:
- Google One 之前允许使用自定义 OAuth client,导致认证流程不稳定
- 与 Code Assist 的行为不一致

**解决方案**:
- 修改 `gemini_oauth_service.go`: Google One 现在与 Code Assist 一样强制使用内置 client (L122-135)
- 更新 `gemini_oauth_client.go`: ExchangeCode 和 RefreshToken 方法支持强制内置 client (L31-44, L77-86)
- 简化 `geminicli/oauth.go`: Google One scope 选择逻辑 (L187-190)
- 标记 `geminicli/constants.go`: DefaultGoogleOneScopes 为 DEPRECATED (L30-33)
- 更新测试用例以反映新行为

**OAuth 类型对比**:
| OAuth类型 | Client来源 | Scopes | Redirect URI |
|-----------|-----------|--------|-----------------|
| code_assist | 内置 Gemini CLI | DefaultCodeAssistScopes | https://codeassist.google.com/authcode |
| google_one | 内置 Gemini CLI (新) | DefaultCodeAssistScopes | https://codeassist.google.com/authcode |
| ai_studio | 必须自定义 | DefaultAIStudioScopes | http://localhost:1455/auth/callback |

### 2. Google One 自动获取 project_id
**问题**:
- Google One 个人账号测试模型时返回 403/404 错误
- 原因:cloudaicompanion API 需要 project_id,但个人账号无需手动创建 GCP 项目

**解决方案**:
- 修改 `gemini_oauth_service.go`: OAuth 流程中自动调用 fetchProjectID
- Google 通过 LoadCodeAssist API 自动分配 project_id
- 与 Gemini CLI 行为保持一致
- 后端根据 project_id 自动选择正确的 API 端点

**影响**:
- Google One 账号现在可以正常使用(需要重新授权)
- Code Assist 和 AI Studio 账号不受影响

### 3. 修复 Gemini 测试账号无内容输出问题
**问题**:
- 测试 Gemini 账号时只显示"测试成功",没有显示 AI 响应内容
- 原因:processGeminiStream 在检查到 finishReason 时立即返回,跳过了内容提取

**解决方案**:
- 修改 `account_test_service.go`: 调整逻辑顺序,先提取内容再检查是否完成
- 确保最后一个 chunk 的内容也能被正确显示

**影响**:
- 所有 Gemini 账号类型(API Key、OAuth)的测试现在都会显示完整响应内容
- 用户可以看到流式输出效果

## 前端改动

### 1. 修复图标宽度压缩问题
**问题**:
- 账户类型选择按钮中的图标在某些情况下会被压缩变形

**解决方案**:
- 修改 `CreateAccountModal.vue`: 为所有平台图标容器添加 `shrink-0` 类
- 确保 Anthropic、OpenAI、Gemini、Antigravity 图标保持固定 8×8 尺寸 (32px × 32px)

### 2. 优化重新授权界面
**问题**:
- 重新授权时显示三个可点击的授权类型选择按钮,可能导致用户误切换到不兼容的授权方式

**解决方案**:
- 修改 `ReAuthAccountModal.vue` (admin 和普通用户版本):
  - 将可点击的授权类型选择按钮改为只读信息展示框
  - 根据账号的 `credentials.oauth_type` 动态显示对应图标和文本
  - 删除 `geminiAIStudioOAuthEnabled` 状态和 `handleSelectGeminiOAuthType` 方法
  - 防止用户误操作

## 测试验证
-  所有后端单元测试通过
-  OAuth client 选择逻辑正确
-  Google One 和 Code Assist 行为一致
-  测试账号显示完整响应内容
-  UI 图标显示正常
-  重新授权界面只读展示正确

* fix(lint): 修复 golangci-lint 错误信息格式问题

- 将错误信息改为小写开头以符合 Go 代码规范
- 修复 ST1005: error strings should not be capitalized
2026-01-08 23:47:29 +08:00
2025-12-18 13:50:39 +08:00
2025-12-18 10:26:18 +08:00

Sub2API

Go Vue PostgreSQL Redis Docker

AI API Gateway Platform for Subscription Quota Distribution

English | 中文


Demo

Try Sub2API online: https://v2.pincc.ai/

Demo credentials (shared demo environment; not created automatically for self-hosted installs):

Email Password
admin@sub2api.com admin123

Overview

Sub2API is an AI API gateway platform designed to distribute and manage API quotas from AI product subscriptions (like Claude Code $200/month). Users can access upstream AI services through platform-generated API Keys, while the platform handles authentication, billing, load balancing, and request forwarding.

Features

  • Multi-Account Management - Support multiple upstream account types (OAuth, API Key)
  • API Key Distribution - Generate and manage API Keys for users
  • Precise Billing - Token-level usage tracking and cost calculation
  • Smart Scheduling - Intelligent account selection with sticky sessions
  • Concurrency Control - Per-user and per-account concurrency limits
  • Rate Limiting - Configurable request and token rate limits
  • Admin Dashboard - Web interface for monitoring and management

Tech Stack

Component Technology
Backend Go 1.25.5, Gin, Ent
Frontend Vue 3.4+, Vite 5+, TailwindCSS
Database PostgreSQL 15+
Cache/Queue Redis 7+

Documentation

  • Dependency Security: docs/dependency-security.md

Deployment

One-click installation script that downloads pre-built binaries from GitHub Releases.

Prerequisites

  • Linux server (amd64 or arm64)
  • PostgreSQL 15+ (installed and running)
  • Redis 7+ (installed and running)
  • Root privileges

Installation Steps

curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/install.sh | sudo bash

The script will:

  1. Detect your system architecture
  2. Download the latest release
  3. Install binary to /opt/sub2api
  4. Create systemd service
  5. Configure system user and permissions

Post-Installation

# 1. Start the service
sudo systemctl start sub2api

# 2. Enable auto-start on boot
sudo systemctl enable sub2api

# 3. Open Setup Wizard in browser
# http://YOUR_SERVER_IP:8080

The Setup Wizard will guide you through:

  • Database configuration
  • Redis configuration
  • Admin account creation

Upgrade

You can upgrade directly from the Admin Dashboard by clicking the Check for Updates button in the top-left corner.

The web interface will:

  • Check for new versions automatically
  • Download and apply updates with one click
  • Support rollback if needed

Useful Commands

# Check status
sudo systemctl status sub2api

# View logs
sudo journalctl -u sub2api -f

# Restart service
sudo systemctl restart sub2api

# Uninstall
curl -sSL https://raw.githubusercontent.com/Wei-Shaw/sub2api/main/deploy/install.sh | sudo bash -s -- uninstall -y

Method 2: Docker Compose

Deploy with Docker Compose, including PostgreSQL and Redis containers.

Prerequisites

  • Docker 20.10+
  • Docker Compose v2+

Installation Steps

# 1. Clone the repository
git clone https://github.com/Wei-Shaw/sub2api.git
cd sub2api

# 2. Enter the deploy directory
cd deploy

# 3. Copy environment configuration
cp .env.example .env

# 4. Edit configuration (set your passwords)
nano .env

Required configuration in .env:

# PostgreSQL password (REQUIRED - change this!)
POSTGRES_PASSWORD=your_secure_password_here

# Optional: Admin account
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=your_admin_password

# Optional: Custom port
SERVER_PORT=8080

# Optional: Security configuration
# Enable URL allowlist validation (false to skip allowlist checks, only basic format validation)
SECURITY_URL_ALLOWLIST_ENABLED=false

# Allow insecure HTTP URLs when allowlist is disabled (default: false, requires https)
# ⚠️ WARNING: Enabling this allows HTTP (plaintext) URLs which can expose API keys
#             Only recommended for:
#             - Development/testing environments
#             - Internal networks with trusted endpoints
#             - When using local test servers (http://localhost)
# PRODUCTION: Keep this false or use HTTPS URLs only
SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP=false

# Allow private IP addresses for upstream/pricing/CRS (for internal deployments)
SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS=false
# 5. Start all services
docker-compose up -d

# 6. Check status
docker-compose ps

# 7. View logs
docker-compose logs -f sub2api

Access

Open http://YOUR_SERVER_IP:8080 in your browser.

Upgrade

# Pull latest image and recreate container
docker-compose pull
docker-compose up -d

Useful Commands

# Stop all services
docker-compose down

# Restart
docker-compose restart

# View all logs
docker-compose logs -f

Method 3: Build from Source

Build and run from source code for development or customization.

Prerequisites

  • Go 1.21+
  • Node.js 18+
  • PostgreSQL 15+
  • Redis 7+

Build Steps

# 1. Clone the repository
git clone https://github.com/Wei-Shaw/sub2api.git
cd sub2api

# 2. Install pnpm (if not already installed)
npm install -g pnpm

# 3. Build frontend
cd frontend
pnpm install
pnpm run build
# Output will be in ../backend/internal/web/dist/

# 4. Build backend with embedded frontend
cd ../backend
go build -tags embed -o sub2api ./cmd/server

# 5. Create configuration file
cp ../deploy/config.example.yaml ./config.yaml

# 6. Edit configuration
nano config.yaml

Note: The -tags embed flag embeds the frontend into the binary. Without this flag, the binary will not serve the frontend UI.

Key configuration in config.yaml:

server:
  host: "0.0.0.0"
  port: 8080
  mode: "release"

database:
  host: "localhost"
  port: 5432
  user: "postgres"
  password: "your_password"
  dbname: "sub2api"

redis:
  host: "localhost"
  port: 6379
  password: ""

jwt:
  secret: "change-this-to-a-secure-random-string"
  expire_hour: 24

default:
  user_concurrency: 5
  user_balance: 0
  api_key_prefix: "sk-"
  rate_multiplier: 1.0

Additional security-related options are available in config.yaml:

  • cors.allowed_origins for CORS allowlist
  • security.url_allowlist for upstream/pricing/CRS host allowlists
  • security.url_allowlist.enabled to disable URL validation (use with caution)
  • security.url_allowlist.allow_insecure_http to allow HTTP URLs when validation is disabled
  • security.url_allowlist.allow_private_hosts to allow private/local IP addresses
  • security.response_headers.enabled to enable configurable response header filtering (disabled uses default allowlist)
  • security.csp to control Content-Security-Policy headers
  • billing.circuit_breaker to fail closed on billing errors
  • server.trusted_proxies to enable X-Forwarded-For parsing
  • turnstile.required to require Turnstile in release mode

⚠️ Security Warning: HTTP URL Configuration

When security.url_allowlist.enabled=false, the system performs minimal URL validation by default, rejecting HTTP URLs and only allowing HTTPS. To allow HTTP URLs (e.g., for development or internal testing), you must explicitly set:

security:
  url_allowlist:
    enabled: false                # Disable allowlist checks
    allow_insecure_http: true     # Allow HTTP URLs (⚠️ INSECURE)

Or via environment variable:

SECURITY_URL_ALLOWLIST_ENABLED=false
SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP=true

Risks of allowing HTTP:

  • API keys and data transmitted in plaintext (vulnerable to interception)
  • Susceptible to man-in-the-middle (MITM) attacks
  • NOT suitable for production environments

When to use HTTP:

  • Development/testing with local servers (http://localhost)
  • Internal networks with trusted endpoints
  • Testing account connectivity before obtaining HTTPS
  • Production environments (use HTTPS only)

Example error without this setting:

Invalid base URL: invalid url scheme: http

If you disable URL validation or response header filtering, harden your network layer:

  • Enforce an egress allowlist for upstream domains/IPs
  • Block private/loopback/link-local ranges
  • Enforce TLS-only outbound traffic
  • Strip sensitive upstream response headers at the proxy
# 6. Run the application
./sub2api

Development Mode

# Backend (with hot reload)
cd backend
go run ./cmd/server

# Frontend (with hot reload)
cd frontend
pnpm run dev

Code Generation

When editing backend/ent/schema, regenerate Ent + Wire:

cd backend
go generate ./ent
go generate ./cmd/server

Simple Mode

Simple Mode is designed for individual developers or internal teams who want quick access without full SaaS features.

  • Enable: Set environment variable RUN_MODE=simple
  • Difference: Hides SaaS-related features and skips billing process
  • Security note: In production, you must also set SIMPLE_MODE_CONFIRM=true to allow startup

Antigravity Support

Sub2API supports Antigravity accounts. After authorization, dedicated endpoints are available for Claude and Gemini models.

Dedicated Endpoints

Endpoint Model
/antigravity/v1/messages Claude models
/antigravity/v1beta/ Gemini models

Claude Code Configuration

export ANTHROPIC_BASE_URL="http://localhost:8080/antigravity"
export ANTHROPIC_AUTH_TOKEN="sk-xxx"

Hybrid Scheduling Mode

Antigravity accounts support optional hybrid scheduling. When enabled, the general endpoints /v1/messages and /v1beta/ will also route requests to Antigravity accounts.

⚠️ Warning: Anthropic Claude and Antigravity Claude cannot be mixed within the same conversation context. Use groups to isolate them properly.

Known Issues

In Claude Code, Plan Mode cannot exit automatically. (Normally when using the native Claude API, after planning is complete, Claude Code will pop up options for users to approve or reject the plan.)

Workaround: Press Shift + Tab to manually exit Plan Mode, then type your response to approve or reject the plan.


Project Structure

sub2api/
├── backend/                  # Go backend service
│   ├── cmd/server/           # Application entry
│   ├── internal/             # Internal modules
│   │   ├── config/           # Configuration
│   │   ├── model/            # Data models
│   │   ├── service/          # Business logic
│   │   ├── handler/          # HTTP handlers
│   │   └── gateway/          # API gateway core
│   └── resources/            # Static resources
│
├── frontend/                 # Vue 3 frontend
│   └── src/
│       ├── api/              # API calls
│       ├── stores/           # State management
│       ├── views/            # Page components
│       └── components/       # Reusable components
│
└── deploy/                   # Deployment files
    ├── docker-compose.yml    # Docker Compose configuration
    ├── .env.example          # Environment variables for Docker Compose
    ├── config.example.yaml   # Full config file for binary deployment
    └── install.sh            # One-click installation script

License

MIT License


If you find this project useful, please give it a star!

Description
No description provided
Readme MIT 44 MiB
Languages
Go 62%
Vue 27.2%
TypeScript 9.6%
Shell 0.6%
CSS 0.4%
Other 0.1%