Skip to content

Commit 9ae9a5a

Browse files
committed
添加ssxmod算法(由@hSutIs提供), 自动生成和轮换ssxmod
1 parent 83713e0 commit 9ae9a5a

15 files changed

Lines changed: 534 additions & 81 deletions

File tree

.env.example

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,4 @@ LOG_DIR=./logs
7070
MAX_LOG_FILE_SIZE=10
7171

7272
# 保留的日志文件数量
73-
MAX_LOG_FILES=5
74-
75-
# 抓包获取 cookie 里的 ssxmod_itna
76-
SSXMOD_ITNA=""
77-
78-
# 抓包获取 cookie 里的 ssxmod_itna2
79-
SSXMOD_ITNA2=""
73+
MAX_LOG_FILES=5

README.md

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22

33
# 🚀 Qwen-Proxy
44

5-
[![Version](https://img.shields.io/badge/version-2025.07.24.12.00-blue.svg)](https://github.com/Rfym21/Qwen2API)
5+
[![Version](https://img.shields.io/badge/version-2025.12.11-blue.svg)](https://github.com/Rfym21/Qwen2API)
66
[![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
77
[![Docker](https://img.shields.io/badge/Docker-supported-blue.svg)](https://hub.docker.com/r/rfym21/qwen2api)
8-
[![Binary](https://img.shields.io/badge/Binary-Available-orange.svg)](https://github.com/Rfym21/Qwen2API/releases)
98

109
[🔗 加入交流群](https://t.me/nodejs_project) | [📖 文档](#api-文档) | [🐳 Docker 部署](#docker-部署)
1110

@@ -26,11 +25,6 @@ Qwen-Proxy 是一个将 `https://chat.qwen.ai` 和 `Qwen Code / Qwen Cli`端接
2625
- 支持 CLI 端点,提供 256K 上下文和工具调用能力
2726
- 提供 Web 管理界面,方便配置和监控
2827

29-
### 2025.12.8 紧急更新通知
30-
> 因官方风控严重必须填写 `SSXMOD_ITNA / SSXMOD_ITNA2`, 后续考虑使用部署外置的程序动态获取。(/cli端点不受影响)
31-
> 本次更新后不再内置 `SSXMOD_ITNA / SSXMOD_ITNA2`, 必须手动获取后填入环境变量。(下方有获取的文字教程和视频教程)
32-
> image-edit暂时不可用,请等待更新。(如果您已修复 欢迎pr)
33-
3428
### 环境要求
3529

3630
- Node.js 18+ (源码部署时需要)
@@ -66,10 +60,6 @@ REDIS_URL= # Redis 连接地址 (可选,使用TLS时为redi
6660

6761
# 📸 缓存配置
6862
CACHE_MODE=default # 图片缓存模式 (default/file)
69-
70-
# 🔑 高级配置
71-
SSXMOD_ITNA= # Qwen认证Cookie (可选)
72-
SSXMOD_ITNA2= # Qwen认证Cookie (可选)
7363
```
7464

7565
#### 📋 配置说明
@@ -87,14 +77,17 @@ SSXMOD_ITNA2= # Qwen认证Cookie (可选)
8777
| `DATA_SAVE_MODE` | 数据持久化方式 | `none`/`file`/`redis` |
8878
| `REDIS_URL` | Redis 数据库连接地址,使用TLS加密时需使用 `rediss://` 协议 | `redis://localhost:6379``rediss://xxx.upstash.io` |
8979
| `CACHE_MODE` | 图片缓存存储方式 | `default`/`file` |
90-
| `SSXMOD_ITNA` | Qwen 认证 Cookie 值,用于发送请求 | `1-Gqfx0DR70Q...` |
91-
| `SSXMOD_ITNA2` | Qwen 认证 Cookie 值,用于发送请求 | `1-Gqfx0DR70Q...` |
9280
| `LOG_LEVEL` | 日志级别 | `DEBUG`/`INFO`/`WARN`/`ERROR` |
9381
| `ENABLE_FILE_LOG` | 是否启用文件日志 | `true``false` |
9482
| `LOG_DIR` | 日志文件目录 | `./logs` |
9583
| `MAX_LOG_FILE_SIZE` | 最大日志文件大小(MB) | `10` |
9684
| `MAX_LOG_FILES` | 保留的日志文件数量 | `5` |
9785

86+
> 💡 **提示**: 可以在 [Upstash](https://upstash.com/) 免费创建 Redis 实例,使用 TLS 协议时地址格式为 `rediss://...`
87+
<div>
88+
<img src="./docs/images/upstash.png" alt="Upstash Redis" width="600">
89+
</div>
90+
9891
#### 🔑 多API_KEY配置说明
9992

10093
`API_KEY` 环境变量支持配置多个API密钥,用于实现不同权限级别的访问控制:
@@ -147,37 +140,6 @@ caches/
147140
└── ...
148141
```
149142

150-
> 💡 **提示**: 可以在 [Upstash](https://upstash.com/) 免费创建 Redis 实例,使用 TLS 协议时地址格式为 `rediss://...`
151-
152-
#### 🔑 SSXMOD_ITNA/SSXMOD_ITNA2 配置说明
153-
154-
`SSXMOD_ITNA``SSXMOD_ITNA2` 是 Qwen API 的认证 Cookie 参数,用于发送请求。
155-
156-
**配置方法:**
157-
1. 使用浏览器访问 [https://chat.qwen.ai](https://chat.qwen.ai)
158-
2. 打开浏览器开发者工具(F12),切换到 "网络(Network)" 标签
159-
3. 刷新页面或发送一条消息
160-
4. 在网络请求中找到任意请求,检查请求头中的 `Cookie` 字段
161-
5. 复制 `ssxmod_itna``ssxmod_itna2` 的值到环境变量中
162-
163-
<video src="./docs/videos/ssxmod_itna.mp4" controls width="600"></video>
164-
165-
**配置示例:**
166-
```bash
167-
SSXMOD_ITNA=1-Gqfx0DR70QdiqY5i7G7GqDODkAb07qYWDzxC5iOD_xQ5K08D6GDBRRQpq9YP0=...
168-
SSXMOD_ITNA2=1-Gqfx0DR70QdiqY5i7G7GqDODkAb07qYWDzxC5iOD_xQ5K08D6GDBRRQpq9YP0=...
169-
```
170-
171-
**作用说明:**
172-
- 这些 Cookie 值用于在请求时进行身份验证
173-
- 如果不配置,将使用默认值
174-
175-
> ⚠️ **注意**: 这些 Cookie 值包含敏感信息,请妥善保管,不要分享给他人。
176-
177-
<div>
178-
<img src="./docs/images/upstash.png" alt="Upstash Redis" width="600">
179-
</div>
180-
181143
---
182144

183145
## 🚀 部署方式

docs/videos/ssxmod_itna.mp4

-1.25 MB
Binary file not shown.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "qwen2api",
3-
"version": "2025.12.08.18.30",
3+
"version": "2025.12.11.17.00",
44
"main": "src/server.js",
55
"scripts": {
66
"start": "node src/start.js",

scripts/fingerprint_injector.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
(function() {
2+
// 拦截 String.prototype.charAt
3+
const originalCharAt = String.prototype.charAt;
4+
let capturedData = null;
5+
6+
String.prototype.charAt = function(index) {
7+
if (this.length > 200 && this.includes('^') && !capturedData) {
8+
const fields = this.split('^');
9+
if (fields.length === 37) {
10+
capturedData = this.toString();
11+
console.log('\n=== 检测到浏览器指纹 ===');
12+
console.log(capturedData);
13+
14+
// 恢复原方法
15+
String.prototype.charAt = originalCharAt;
16+
}
17+
}
18+
return originalCharAt.call(this, index);
19+
};
20+
})();

src/config/index.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ const config = {
3737
enableFileLog: process.env.ENABLE_FILE_LOG === 'true',
3838
logDir: process.env.LOG_DIR || "./logs",
3939
maxLogFileSize: parseInt(process.env.MAX_LOG_FILE_SIZE) || 10,
40-
maxLogFiles: parseInt(process.env.MAX_LOG_FILES) || 5,
41-
ssxmodItna: process.env.SSXMOD_ITNA || "",
42-
ssxmodItna2: process.env.SSXMOD_ITNA || ""
40+
maxLogFiles: parseInt(process.env.MAX_LOG_FILES) || 5
4341
}
4442

4543
module.exports = config

src/controllers/chat.image.video.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const { setResponseHeaders } = require('./chat.js')
44
const accountManager = require('../utils/account.js')
55
const { sleep } = require('../utils/tools.js')
66
const { generateChatID } = require('../utils/request.js')
7-
const config = require('../config/index.js')
7+
const { getSsxmodItna, getSsxmodItna2 } = require('../utils/ssxmod-manager')
88

99
/**
1010
* 主要的聊天完成处理函数
@@ -164,7 +164,7 @@ const handleImageVideoCompletion = async (req, res) => {
164164
"Sec-Fetch-Dest": "empty",
165165
"Referer": "https://chat.qwen.ai/c/guest",
166166
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
167-
"Cookie": `ssxmod_itna=${config.ssxmodItna};ssxmod_itna2=${config.ssxmodItna2}`,
167+
"Cookie": `ssxmod_itna=${getSsxmodItna()};ssxmod_itna2=${getSsxmodItna2()}`,
168168
},
169169
responseType: newChatType == 't2i' ? 'stream' : 'json',
170170
timeout: 1000 * 60 * 5
@@ -312,7 +312,7 @@ const getVideoTaskStatus = async (videoTaskID, token) => {
312312
"Authorization": `Bearer ${token}`,
313313
'Content-Type': 'application/json',
314314
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
315-
...(config.ssxmodItna && { 'Cookie': `ssxmod_itna=${config.ssxmodItna};ssxmod_itna2=${config.ssxmodItna2}` })
315+
...(getSsxmodItna() && { 'Cookie': `ssxmod_itna=${getSsxmodItna()};ssxmod_itna2=${getSsxmodItna2()}` })
316316
}
317317
})
318318

src/controllers/models.js

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,23 @@ const handleGetModels = async (req, res) => {
4040
models.push(newModelData)
4141
}
4242

43-
// if (isImage) {
44-
// const newModelData = JSON.parse(JSON.stringify(model))
45-
// newModelData.id = `${model.id}-image`
46-
// models.push(newModelData)
47-
// }
43+
if (isImage) {
44+
const newModelData = JSON.parse(JSON.stringify(model))
45+
newModelData.id = `${model.id}-image`
46+
models.push(newModelData)
47+
}
4848

49-
// if (isVideo) {
50-
// const newModelData = JSON.parse(JSON.stringify(model))
51-
// newModelData.id = `${model.id}-video`
52-
// models.push(newModelData)
53-
// }
49+
if (isVideo) {
50+
const newModelData = JSON.parse(JSON.stringify(model))
51+
newModelData.id = `${model.id}-video`
52+
models.push(newModelData)
53+
}
5454

55-
// if (isImageEdit) {
56-
// const newModelData = JSON.parse(JSON.stringify(model))
57-
// newModelData.id = `${model.id}-image-edit`
58-
// models.push(newModelData)
59-
// }
55+
if (isImageEdit) {
56+
const newModelData = JSON.parse(JSON.stringify(model))
57+
newModelData.id = `${model.id}-image-edit`
58+
models.push(newModelData)
59+
}
6060

6161
// if (isDeepResearch) {
6262
// const newModelData = JSON.parse(JSON.stringify(model))

src/models/models-map.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const axios = require('axios')
22
const accountManager = require('../utils/account.js')
3-
const config = require('../config/index.js')
3+
const { getSsxmodItna, getSsxmodItna2 } = require('../utils/ssxmod-manager')
44

55
let cachedModels = null
66
let fetchPromise = null
@@ -21,7 +21,7 @@ const getLatestModels = async (force = false) => {
2121
'Authorization': `Bearer ${accountManager.getAccountToken()}`,
2222
'Content-Type': 'application/json',
2323
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
24-
...(config.ssxmodItna && { 'Cookie': `ssxmod_itna=${config.ssxmodItna};ssxmod_itna2=${config.ssxmodItna2}` })
24+
...(getSsxmodItna() && { 'Cookie': `ssxmod_itna=${getSsxmodItna()};ssxmod_itna2=${getSsxmodItna2()}` })
2525
}
2626
}).then(response => {
2727
// console.log(response)

src/routes/chat.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ const selectChatCompletion = (req, res, next) => {
99
const ChatCompletionMap = {
1010
't2t': handleChatCompletion,
1111
'search': handleChatCompletion,
12-
// 't2i': handleImageVideoCompletion,
13-
// 't2v': handleImageVideoCompletion,
14-
// 'image_edit': handleImageVideoCompletion,
12+
't2i': handleImageVideoCompletion,
13+
't2v': handleImageVideoCompletion,
14+
'image_edit': handleImageVideoCompletion,
1515
// 'deep_research': handleDeepResearchCompletion
1616
}
1717

0 commit comments

Comments
 (0)