fix(pdd): integrate official sandboxed anti-content engine to resolve 40002 WAF error

This commit is contained in:
yml2213
2026-09-14 13:44:55 +08:00
parent 4f97275c80
commit f35e47e419
5 changed files with 170 additions and 5 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"cleanup:dev-data": "tsx scripts/cleanup-dev-data.ts",
"build": "tsc -p tsconfig.build.json && rm -rf dist/db/migrations && mkdir -p dist/db && cp -R src/db/migrations dist/db/migrations",
"build": "tsc -p tsconfig.build.json && rm -rf dist/db/migrations && mkdir -p dist/db && cp -R src/db/migrations dist/db/migrations && mkdir -p dist/services/platforms/pdd && cp src/services/platforms/pdd/pdd_anti.cjs dist/services/platforms/pdd/pdd_anti.cjs",
"db:migrate": "tsx src/db/migrate.ts",
"db:migrate:create": "tsx scripts/create-migration.ts",
"db:migrate:status": "tsx scripts/migration-status.ts",
@@ -50,3 +50,13 @@ test('PurePddAntiContent executes with ultra-low latency (< 1ms per token)', ()
// Average time should be well below 2ms
assert.ok(avg < 2, `Average generation time should be < 2ms (actual: ${avg.toFixed(3)}ms)`)
})
test('PurePddAntiContent.getTokenAsync generates valid tokens via official JS engine', async () => {
const token = await pddAntiContentEngine.getTokenAsync({
cookies: '_nano_fp=42e47e06a644482087; api_uid=rBQ51234',
serverTimeMs: 1726119845000,
})
assert.ok(token.startsWith('0as'), 'Async token must start with 0as prefix')
assert.ok(token.length > 200, `Async token length should be > 200 (actual: ${token.length})`)
})
@@ -25,6 +25,25 @@
import zlib from 'node:zlib'
import crypto from 'node:crypto'
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
type PddAntiJsGeneratorFn = (
cookies: string,
serverTime?: number,
options?: { userAgent?: string; href?: string; referer?: string },
) => Promise<string>
let pddAntiJsGenerator: PddAntiJsGeneratorFn | null = null
try {
const mod = require('./pdd_anti.cjs') as { generateAntiContent?: PddAntiJsGeneratorFn }
if (typeof mod.generateAntiContent === 'function') {
pddAntiJsGenerator = mod.generateAntiContent
}
} catch {
pddAntiJsGenerator = null
}
export interface PddAntiContentOptions {
/**
@@ -304,15 +323,53 @@ export class PurePddAntiContent {
// 6. Prepend '0as' Token Prefix / 第六步:添加 '0as' 协议前缀
return `0as${encodedBody}`
}
/**
* Generate anti-content token asynchronously.
* Prioritizes the official MMS sandboxed JS engine (pdd_anti.cjs),
* falling back to the pure TLV algorithm if unavailable.
* 异步生成 anti-content Token。
* 优先使用拼多多官方 MMS 商家后台原生 JS 引擎 (pdd_anti.cjs),
* 若不可用则自动降级到原生 TLV 纯算法。
*/
public async getTokenAsync(options: GetTokenOptions = {}): Promise<string> {
if (pddAntiJsGenerator) {
try {
const token = await pddAntiJsGenerator(
options.cookies || '',
options.serverTimeMs || Date.now(),
{
userAgent: options.userAgent || PurePddAntiContent.DEFAULT_UA,
href: options.href || PurePddAntiContent.DEFAULT_HREF,
referer: options.referer || PurePddAntiContent.DEFAULT_REFERER,
},
)
if (token && typeof token === 'string' && token.startsWith('0as')) {
return token
}
} catch (err) {
console.warn('[PddAntiContent] Official JS engine failed, falling back to pure TLV:', err)
}
}
return this.getToken(options)
}
}
// Global singleton instance / 全局单例生成器
export const pddAntiContentEngine = new PurePddAntiContent()
/**
* Quick helper to generate anti-content token.
* 便捷快捷函数:生成 anti-content Token。
* Quick helper to generate anti-content token synchronously using pure TLV.
* 便捷同步函数:使用原生 TLV 纯算生成 anti-content Token。
*/
export function generatePddAntiContent(options: GetTokenOptions = {}): string {
return pddAntiContentEngine.getToken(options)
}
/**
* Quick helper to generate anti-content token asynchronously (recommended).
* 推荐快捷异步函数:生成 anti-content Token(优先使用官方 JS 引擎)。
*/
export async function generatePddAntiContentAsync(options: GetTokenOptions = {}): Promise<string> {
return pddAntiContentEngine.getTokenAsync(options)
}
@@ -144,8 +144,8 @@ export class PddClient {
// 1. Get synchronized server time / 获取校准时间戳
const serverTimeMs = await this.getSynchronizedServerTime()
// 2. Generate anti-content token / 生成纯算 anti-content
const antiContent = pddAntiContentEngine.getToken({
// 2. Generate anti-content token / 生成纯算 anti-content (优先使用官方沙箱引擎)
const antiContent = await pddAntiContentEngine.getTokenAsync({
cookies: this.credentials.cookie,
userAgent: this.credentials.userAgent || PurePddAntiContent.DEFAULT_UA,
serverTimeMs,
File diff suppressed because one or more lines are too long