From 2d29554d616acd6060bbf0ecf7078c78c309c0c4 Mon Sep 17 00:00:00 2001 From: ZuoZuo <68836346+Mrz-sakura@users.noreply.github.com> Date: Mon, 27 Apr 2026 00:11:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbd=E9=82=80=E8=AF=B7=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- h5/bd-static/shared.js | 121 +++++++++++++++++++++++++++++++++++------ h5/invite-bd/invite.js | 32 +++++++++-- 2 files changed, 132 insertions(+), 21 deletions(-) diff --git a/h5/bd-static/shared.js b/h5/bd-static/shared.js index 1ec5da8..2e1c3fc 100644 --- a/h5/bd-static/shared.js +++ b/h5/bd-static/shared.js @@ -202,26 +202,111 @@ function splitHeaderPairs(value) { return result; } -function parseAppHeaders(raw) { - const data = JSON.parse(raw); - const appIntel = splitHeaderPairs(data["Req-App-Intel"]); - const sysOrigin = splitHeaderPairs(data["Req-Sys-Origin"]); +function mapHeaderValue(target, key, value) { + if (value === null || value === undefined || value === "" || target[key]) return; + target[key] = String(value); +} + +function normalizeHeaderCandidate(value, depth = 0) { + if (depth > 4 || value === null || value === undefined) return {}; + if (typeof value === "string") { + const trimmed = value.trim(); + if (!trimmed) return {}; + if (trimmed[0] === "{" || trimmed[0] === "[") { + try { + return normalizeHeaderCandidate(JSON.parse(trimmed), depth + 1); + } catch { + return {}; + } + } + return /^bearer\s+/i.test(trimmed) ? { authorization: trimmed } : {}; + } + if (Array.isArray(value)) { + return value.reduce((result, item) => ({ ...result, ...normalizeHeaderCandidate(item, depth + 1) }), {}); + } + if (typeof value !== "object") return {}; + + const appIntel = splitHeaderPairs(value["Req-App-Intel"] || value["req-app-intel"]); + const sysOrigin = splitHeaderPairs(value["Req-Sys-Origin"] || value["req-sys-origin"]); + const normalized = {}; + + mapHeaderValue(normalized, "authorization", value.Authorization || value.authorization || value.token || value.accessToken); + mapHeaderValue(normalized, "reqLang", value["Req-Lang"] || value["req-lang"] || value.reqLang || value.lang || value.language); + mapHeaderValue(normalized, "appVersion", appIntel.version || value["App-Version"] || value.appVersion); + mapHeaderValue(normalized, "buildVersion", appIntel.build || value["Build-Version"] || value.buildVersion); + mapHeaderValue(normalized, "channel", appIntel.channel || value["App-Channel"] || value.appChannel || value.channel); + mapHeaderValue(normalized, "reqImei", value["Req-Imei"] || value["req-imei"] || value.reqImei || appIntel["Req-Imei"] || appIntel.reqImei); + mapHeaderValue(normalized, "origin", sysOrigin.origin || value["Sys-Origin"] || value.sysOrigin || value.origin); + mapHeaderValue(normalized, "child", sysOrigin.originChild || sysOrigin.child || value["Sys-Origin-Child"] || value.sysOriginChild || value.child); + + ["headerInfo", "headers", "auth", "data", "state"].forEach((key) => { + Object.assign(normalized, normalizeHeaderCandidate(value[key], depth + 1)); + }); + + Object.keys(value).forEach((key) => { + if (["headerInfo", "headers", "auth", "data", "state"].includes(key)) return; + if (value[key] && typeof value[key] === "object") { + Object.assign(normalized, normalizeHeaderCandidate(value[key], depth + 1)); + } + }); + + return normalized; +} + +function collectHeaderCandidate(collected, value) { + const normalized = normalizeHeaderCandidate(value); + if (Object.keys(normalized).length) collected.push(normalized); +} + +function collectHeadersFromStorage(collected, storage) { + if (!storage) return; + ["authorization", "Authorization", "token", "accessToken", "headerInfo", "headersFromApp", "appHeaders", "user", "userInfo"].forEach((key) => { + try { + collectHeaderCandidate(collected, storage.getItem(key)); + } catch {} + }); + try { + for (let index = 0; index < storage.length; index += 1) { + collectHeaderCandidate(collected, storage.getItem(storage.key(index))); + } + } catch {} +} + +function queryHeaderCandidate() { + const params = new URLSearchParams(window.location.search); return { - authorization: data.Authorization || data.authorization, - reqLang: data["Req-Lang"] || data.reqLang || data.lang, - appVersion: appIntel.version || data["App-Version"] || data.appVersion, - buildVersion: appIntel.build || data["Build-Version"] || data.buildVersion, - channel: appIntel.channel || data["App-Channel"] || data.appChannel || data.channel, - reqImei: data["Req-Imei"] || data.reqImei || appIntel["Req-Imei"], - origin: sysOrigin.origin || data["Sys-Origin"] || data.sysOrigin, - child: sysOrigin.originChild || sysOrigin.child || data["Sys-Origin-Child"] || data.sysOriginChild + authorization: params.get("authorization") || params.get("Authorization") || params.get("token"), + reqLang: params.get("lang"), + appVersion: params.get("appVersion"), + buildVersion: params.get("buildVersion"), + channel: params.get("appChannel") || params.get("channel"), + reqImei: params.get("reqImei"), + origin: params.get("sysOrigin"), + child: params.get("sysOriginChild") }; } +function discoverAppHeaders() { + const collected = [{ reqLang: lang }, queryHeaderCandidate()]; + collectHeaderCandidate(collected, window.__APP_HEADERS__); + collectHeaderCandidate(collected, window.__HEADER_INFO__); + collectHeaderCandidate(collected, window.headerInfo); + collectHeadersFromStorage(collected, window.localStorage); + collectHeadersFromStorage(collected, window.sessionStorage); + return collected.reduce((result, item) => ({ ...result, ...item }), {}); +} + +function applyDiscoveredHeaders() { + const discovered = discoverAppHeaders(); + if (headers.authorization) delete discovered.authorization; + if (Object.keys(discovered).length) setHeadersFromApp(discovered); + return discovered; +} + export function setHeadersFromApp(rawOrObject) { - const data = typeof rawOrObject === "string" ? parseAppHeaders(rawOrObject) : rawOrObject || {}; + const data = normalizeHeaderCandidate(rawOrObject || {}); const next = {}; - if (Object.prototype.hasOwnProperty.call(data, "authorization")) next.authorization = data.authorization || ""; + if (data.authorization) next.authorization = data.authorization; if (data.reqLang) next["req-lang"] = data.reqLang; if (data.appVersion || data.buildVersion || data.channel) { next["req-app-intel"] = [ @@ -258,7 +343,6 @@ function requestAccessOrigin() { if (!isAppEnvironment()) { setHeadersFromApp({ - authorization: "", reqLang: lang, appVersion: "1.0.0", buildVersion: "1", @@ -305,10 +389,12 @@ function requestAccessOrigin() { export async function connectToApp() { if (!appConnectionPromise) { + applyDiscoveredHeaders(); appConnectionPromise = requestAccessOrigin() .then((raw) => { if (raw) setHeadersFromApp(raw); - return { success: true, environment: isAppEnvironment() ? "app" : "browser" }; + else applyDiscoveredHeaders(); + return { success: true, environment: isAppEnvironment() ? "app" : "browser", authenticated: Boolean(headers.authorization) }; }) .finally(() => { appConnectionPromise = null; @@ -319,7 +405,8 @@ export async function connectToApp() { } export async function request(method, path, body) { - const options = { method, headers }; + applyDiscoveredHeaders(); + const options = { method, headers: { ...headers } }; if (body !== undefined) options.body = JSON.stringify(body); const response = await fetch(`${API_BASE_URL}${path}`, options); const data = await response.json().catch(() => ({})); diff --git a/h5/invite-bd/invite.js b/h5/invite-bd/invite.js index 3e0b50c..8bca4fe 100644 --- a/h5/invite-bd/invite.js +++ b/h5/invite-bd/invite.js @@ -1,4 +1,4 @@ -import { applyLang, avatarError, bindHeader, connectToApp, get, post, t, toast } from "../bd-static/shared.js"; +import { applyLang, avatarError, bindHeader, connectToApp, get, post, t, toast } from "../bd-static/shared.js?v=auth-bridge-2"; const config = { title: "invite_become_BD", @@ -10,6 +10,8 @@ const config = { let invited = []; let searchResult = []; let selected = null; +let locked = false; +let appConnected = false; bindHeader(config.title); applyLang(); @@ -19,6 +21,11 @@ input.placeholder = t("enter_user_id"); input.addEventListener("input", () => { selected = null; clearButton.hidden = !input.value; + if (!input.value.trim()) { + searchResult = []; + loadInvited(); + return; + } render(); }); input.addEventListener("keyup", (event) => { @@ -30,11 +37,22 @@ clearButton.addEventListener("click", () => { searchResult = []; selected = null; clearButton.hidden = true; - render(); + loadInvited(); }); -connectToApp().then(loadInvited); +init(); + +async function init() { + try { + await connectToApp(); + appConnected = true; + await loadInvited(); + } catch (error) { + toast(error.response?.errorMsg || error.message); + } +} async function loadInvited() { + if (!appConnected) return; try { const response = await get(config.list); invited = response.body || []; @@ -45,6 +63,7 @@ async function loadInvited() { } async function search() { + if (locked || !appConnected) return; const account = input.value.trim(); selected = null; searchResult = []; @@ -52,11 +71,15 @@ async function search() { await loadInvited(); return; } + locked = true; + render(); try { const response = await get(`/user/user-profile/open-search?account=${encodeURIComponent(account)}`); if (response.status && response.body) searchResult = [{ userProfile: response.body }]; } catch (error) { toast(error.response?.errorMsg || error.message); + } finally { + locked = false; } render(); } @@ -102,7 +125,7 @@ function render() { } async function invite() { - if (!selected) return; + if (!selected || !appConnected) return; try { await post(config.invite, { inviteUserId: selected.id }); toast(t("invitation_submitted")); @@ -116,6 +139,7 @@ async function invite() { } async function cancelInvite(id) { + if (!appConnected) return; try { await post(config.cancel(id)); toast(t("application_cancelled"));