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
+10 -2
View File
@@ -152,7 +152,7 @@ export default function OAuthModal({ isOpen, provider, providerInfo, onSuccess,
setError(null);
// Device code flow providers
const deviceCodeProviders = ["github", "qwen", "kiro", "kimi-coding", "kilocode", "codebuddy"];
const deviceCodeProviders = ["github", "qwen", "kiro", "kimi-coding", "kilocode", "codebuddy", "qoder"];
if (deviceCodeProviders.includes(provider)) {
setIsDeviceCode(true);
setStep("waiting");
@@ -175,7 +175,9 @@ export default function OAuthModal({ isOpen, provider, providerInfo, onSuccess,
const verifyUrl = data.verification_uri_complete || data.verification_uri;
if (verifyUrl) window.open(verifyUrl, "_blank", "noopener,noreferrer");
// Pass extraData for Kiro (contains _clientId, _clientSecret)
// Pass extraData for Kiro (contains _clientId, _clientSecret) and
// Qoder (contains _qoderMachineId / _qoderNonce — needed so mapTokens
// can persist the machine id alongside the token).
const extraData = provider === "kiro"
? {
_clientId: data._clientId,
@@ -184,6 +186,12 @@ export default function OAuthModal({ isOpen, provider, providerInfo, onSuccess,
_authMethod: data._authMethod,
_startUrl: data._startUrl,
}
: provider === "qoder"
? {
_qoderNonce: data._qoderNonce,
_qoderMachineId: data._qoderMachineId,
_qoderVerifier: data.codeVerifier,
}
: null;
startPolling(data.device_code, data.codeVerifier, data.interval || 5, extraData);
return;