feat(qoder): port Kiro-style provider integration with COSY signing

Replaces the Qoder placeholder with a real free-tier provider:

- Device-flow OAuth: PKCE + nonce generated locally, user authorizes at
  qoder.com/device/selectAccounts, poll openapi.qoder.sh until token
- COSY signing (RSA-1024 + AES-128-CBC + MD5) for chat / model-list
- WAF-bypass body encoding (custom-alphabet base64 + thirds rearrange)
- Live model_config catalog from /algo/api/v2/model/list, cached 1h
- 11 models registered (auto/ultimate/performance/efficient/lite +
  6 frontier *model ids)
- Usage fetcher for openapi.qoder.sh/api/v2/quota/usage
- Dashboard live-models resolver, provider test, OAuth modal hookup
- 24 unit tests covering encoder, PKCE, COSY headers, sigPath stripping
This commit is contained in:
Simon Shi
2026-05-29 17:36:27 +07:00
committed by decolua
parent 468c61b2ac
commit a6fd84691b
20 changed files with 1506 additions and 132 deletions
+12 -2
View File
@@ -151,7 +151,7 @@ export async function GET(request, { params }) {
: undefined;
// Providers that don't use PKCE for device code
const noPkceDeviceProviders = ["github", "kiro", "kimi-coding", "kilocode", "codebuddy"];
const noPkceDeviceProviders = ["github", "kiro", "kimi-coding", "kilocode", "codebuddy", "qoder"];
let deviceData;
if (noPkceDeviceProviders.includes(provider)) {
deviceData = await requestDeviceCode(provider, undefined, deviceOptions);
@@ -162,7 +162,9 @@ export async function GET(request, { params }) {
return NextResponse.json({
...deviceData,
codeVerifier: authData.codeVerifier,
// Prefer the verifier the provider's requestDeviceCode generated for
// itself (qoder rolls its own PKCE pair); fall back to the generic one.
codeVerifier: deviceData.codeVerifier || authData.codeVerifier,
});
}
@@ -276,6 +278,14 @@ export async function POST(request, { params }) {
} else if (provider === "kiro") {
// Kiro needs extraData (clientId, clientSecret) from device code response
result = await pollForToken(provider, deviceCode, null, extraData);
} else if (provider === "qoder") {
// Qoder needs both the PKCE verifier (codeVerifier) and the machineId
// captured at device-code time (extraData._qoderMachineId) so
// mapTokens can persist it for COSY signing.
if (!codeVerifier) {
return NextResponse.json({ error: "Missing code verifier" }, { status: 400 });
}
result = await pollForToken(provider, deviceCode, codeVerifier, extraData);
} else {
// Qwen and other PKCE providers
if (!codeVerifier) {