From 8697438a9d713a3d0e361beafaa8d40487789355 Mon Sep 17 00:00:00 2001 From: kongjie Date: Sat, 6 Jun 2026 21:48:38 +0800 Subject: [PATCH] fix: use configured base URL for QR login flow QR code fetch and status polling previously always hit ilinkai.weixin.qq.com even when BotOptions.baseUrl pointed at a local proxy hub (e.g. iLink Hub). Message APIs already respected baseUrl; this aligns the login path for hub pairing and custom gateways. Affected: Rust, Go, Node.js, Python SDKs. Co-authored-by: Cursor --- golang/internal/auth/login.go | 9 +++------ nodejs/src/auth/authenticator.ts | 8 +++----- python/wechatbot/auth.py | 5 ++--- rust/src/bot.rs | 6 ++---- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/golang/internal/auth/login.go b/golang/internal/auth/login.go index 5118a80..1a9c9c7 100644 --- a/golang/internal/auth/login.go +++ b/golang/internal/auth/login.go @@ -77,10 +77,7 @@ type LoginOptions struct { OnExpired func() } -const ( - maxQRRefreshCount = 3 - fixedQRBaseURL = "https://ilinkai.weixin.qq.com" -) +const maxQRRefreshCount = 3 // Login performs QR code login, returning credentials. // If stored credentials exist and Force is false, returns them directly. @@ -105,7 +102,7 @@ func Login(ctx context.Context, client *protocol.Client, opts LoginOptions) (*Cr return nil, fmt.Errorf("QR code expired %d times — login aborted", maxQRRefreshCount) } - qr, err := client.GetQRCode(ctx, fixedQRBaseURL) + qr, err := client.GetQRCode(ctx, baseURL) if err != nil { return nil, fmt.Errorf("get QR code: %w", err) } @@ -117,7 +114,7 @@ func Login(ctx context.Context, client *protocol.Client, opts LoginOptions) (*Cr } lastStatus := "" - currentPollBaseURL := fixedQRBaseURL + currentPollBaseURL := baseURL for { status, err := client.PollQRStatus(ctx, currentPollBaseURL, qr.QRCode) if err != nil { diff --git a/nodejs/src/auth/authenticator.ts b/nodejs/src/auth/authenticator.ts index ad48ae8..d5e78de 100644 --- a/nodejs/src/auth/authenticator.ts +++ b/nodejs/src/auth/authenticator.ts @@ -10,8 +10,6 @@ import type { Credentials, QrLoginCallbacks } from './types.js' const QR_POLL_INTERVAL_MS = 2_000 /** Maximum number of times to refresh the QR code before giving up. */ const MAX_QR_REFRESH_COUNT = 3 -/** Fixed API base URL for QR code requests (matches npm package). */ -const FIXED_QR_BASE_URL = 'https://ilinkai.weixin.qq.com' /** * Handles the entire QR login flow with credential persistence. @@ -71,7 +69,7 @@ export class Authenticator { /** * Execute the QR code scanning login flow. - * - Uses fixed base URL for QR requests (consistent with npm package) + * - Uses configured base URL for QR requests (supports proxy hubs) * - Handles `scaned_but_redirect` for IDC redirect * - Limits QR refreshes to MAX_QR_REFRESH_COUNT */ @@ -85,7 +83,7 @@ export class Authenticator { } this.logger.info(`Requesting QR code... (${qrRefreshCount}/${MAX_QR_REFRESH_COUNT})`) - const qr = await this.api.getQrCode(FIXED_QR_BASE_URL) + const qr = await this.api.getQrCode(baseUrl) // Pass QR URL to developer's callback — display is their responsibility if (callbacks?.onQrUrl) { @@ -96,7 +94,7 @@ export class Authenticator { let lastStatus: string | undefined // Current polling URL; may be updated on IDC redirect - let currentPollBaseUrl = FIXED_QR_BASE_URL + let currentPollBaseUrl = baseUrl for (;;) { const status = await this.api.pollQrStatus(currentPollBaseUrl, qr.qrcode) diff --git a/python/wechatbot/auth.py b/python/wechatbot/auth.py index 102751f..c97a146 100644 --- a/python/wechatbot/auth.py +++ b/python/wechatbot/auth.py @@ -18,7 +18,6 @@ DEFAULT_CRED_PATH = DEFAULT_CRED_DIR / "credentials.json" QR_POLL_INTERVAL = 2.0 MAX_QR_REFRESH_COUNT = 3 -FIXED_QR_BASE_URL = "https://ilinkai.weixin.qq.com" async def load_credentials(path: Path | None = None) -> Credentials | None: @@ -81,7 +80,7 @@ async def login( f"QR code expired {MAX_QR_REFRESH_COUNT} times — login aborted" ) - qr = await api.get_qr_code(FIXED_QR_BASE_URL) + qr = await api.get_qr_code(base_url) qr_url = qr["qrcode_img_content"] if on_qr_url: @@ -90,7 +89,7 @@ async def login( print(f"[wechatbot] Scan this URL in WeChat: {qr_url}", file=sys.stderr) last_status = "" - current_poll_base_url = FIXED_QR_BASE_URL + current_poll_base_url = base_url while True: status = await api.poll_qr_status(current_poll_base_url, qr["qrcode"]) current = status["status"] diff --git a/rust/src/bot.rs b/rust/src/bot.rs index 28d949e..0729a70 100644 --- a/rust/src/bot.rs +++ b/rust/src/bot.rs @@ -76,8 +76,6 @@ impl WeChatBot { /// Maximum number of QR code refresh attempts before giving up. const MAX_QR_REFRESH: u32 = 3; - /// Fixed API base URL for QR code requests. - const FIXED_QR_BASE_URL: &'static str = "https://ilinkai.weixin.qq.com"; /// Login via QR code. Returns credentials on success. pub async fn login(&self, force: bool) -> Result { @@ -103,7 +101,7 @@ impl WeChatBot { ))); } - let qr = self.client.get_qr_code(Self::FIXED_QR_BASE_URL).await?; + let qr = self.client.get_qr_code(&base_url).await?; if let Some(ref cb) = self.on_qr_url { cb(&qr.qrcode_img_content); @@ -112,7 +110,7 @@ impl WeChatBot { } let mut last_status = String::new(); - let mut current_poll_base_url = Self::FIXED_QR_BASE_URL.to_string(); + let mut current_poll_base_url = base_url.clone(); loop { let status = self .client