fix app invite gateway headers
This commit is contained in:
parent
f42551294f
commit
c27a8acd8f
@ -7,6 +7,14 @@ const ONLINE_INVITE_API_BASE = "https://jvapi.haiyihy.com/";
|
|||||||
const ONLINE_INVITE_API_PREFIX = "/go";
|
const ONLINE_INVITE_API_PREFIX = "/go";
|
||||||
const DEFAULT_AVATAR = "./assets/avatar-sample.png";
|
const DEFAULT_AVATAR = "./assets/avatar-sample.png";
|
||||||
const DEFAULT_RESET_PERIOD_MS = 30 * 86400 * 1000;
|
const DEFAULT_RESET_PERIOD_MS = 30 * 86400 * 1000;
|
||||||
|
const DEFAULT_REQUEST_HEADERS = {
|
||||||
|
"Req-Sys-Origin": "origin=LIKEI;originChild=LIKEI",
|
||||||
|
"Req-Client": "Android",
|
||||||
|
"Req-App-Intel": "version=1.0.0;build=1;channel=Web;model=H5;sysVersion=Web",
|
||||||
|
"Req-Lang": "en",
|
||||||
|
"Req-Version": "V2",
|
||||||
|
"Req-Zone": "Asia/Shanghai",
|
||||||
|
};
|
||||||
const DEFAULT_TASK_NOTES = {
|
const DEFAULT_TASK_NOTES = {
|
||||||
transport: "(Only the highest-level bonuses may be awarded)",
|
transport: "(Only the highest-level bonuses may be awarded)",
|
||||||
quota: "(You'll receive a reward upon reaching each level)",
|
quota: "(You'll receive a reward upon reaching each level)",
|
||||||
@ -37,6 +45,7 @@ const state = {
|
|||||||
apiBase: resolveAPIBase(),
|
apiBase: resolveAPIBase(),
|
||||||
apiPrefix: resolveAPIPrefix(),
|
apiPrefix: resolveAPIPrefix(),
|
||||||
authorization: resolveAuthorization(),
|
authorization: resolveAuthorization(),
|
||||||
|
requestHeaders: resolveRequestHeaders(),
|
||||||
landingCode: resolveLandingCode(),
|
landingCode: resolveLandingCode(),
|
||||||
inviteLink: query.get("inviteLink") || DEFAULTS.inviteLink,
|
inviteLink: query.get("inviteLink") || DEFAULTS.inviteLink,
|
||||||
inviteCode: query.get("inviteCode") || DEFAULTS.inviteCode,
|
inviteCode: query.get("inviteCode") || DEFAULTS.inviteCode,
|
||||||
@ -122,6 +131,8 @@ function hasAuthorizationInput() {
|
|||||||
trimValue(query.get("authorization")) ||
|
trimValue(query.get("authorization")) ||
|
||||||
trimValue(query.get("Authorization")) ||
|
trimValue(query.get("Authorization")) ||
|
||||||
trimValue(query.get("token")) ||
|
trimValue(query.get("token")) ||
|
||||||
|
trimValue(query.get("token?")) ||
|
||||||
|
trimValue(query.get("accessToken")) ||
|
||||||
trimValue(query.get("auth")) ||
|
trimValue(query.get("auth")) ||
|
||||||
(typeof window.__APP_INVITE_AUTHORIZATION__ === "string" &&
|
(typeof window.__APP_INVITE_AUTHORIZATION__ === "string" &&
|
||||||
trimValue(window.__APP_INVITE_AUTHORIZATION__)) ||
|
trimValue(window.__APP_INVITE_AUTHORIZATION__)) ||
|
||||||
@ -214,6 +225,8 @@ function resolveAuthorization() {
|
|||||||
query.get("authorization"),
|
query.get("authorization"),
|
||||||
query.get("Authorization"),
|
query.get("Authorization"),
|
||||||
query.get("token"),
|
query.get("token"),
|
||||||
|
query.get("token?"),
|
||||||
|
query.get("accessToken"),
|
||||||
query.get("auth"),
|
query.get("auth"),
|
||||||
typeof window.__APP_INVITE_AUTHORIZATION__ === "string"
|
typeof window.__APP_INVITE_AUTHORIZATION__ === "string"
|
||||||
? window.__APP_INVITE_AUTHORIZATION__
|
? window.__APP_INVITE_AUTHORIZATION__
|
||||||
@ -234,6 +247,214 @@ function resolveAuthorization() {
|
|||||||
return `Bearer ${normalized}`;
|
return `Bearer ${normalized}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveRequestHeaders() {
|
||||||
|
const headers = { ...DEFAULT_REQUEST_HEADERS };
|
||||||
|
const sysOrigin = trimValue(query.get("sysOrigin") || query.get("origin"));
|
||||||
|
const sysOriginChild = trimValue(
|
||||||
|
query.get("sysOriginChild") || query.get("originChild") || sysOrigin,
|
||||||
|
);
|
||||||
|
const reqClient = trimValue(query.get("reqClient") || query.get("client"));
|
||||||
|
const reqLang = trimValue(query.get("reqLang") || query.get("lang"));
|
||||||
|
const reqZone = trimValue(query.get("reqZone") || query.get("zone"));
|
||||||
|
const reqVersion = trimValue(query.get("reqVersion") || query.get("version"));
|
||||||
|
const reqImei = trimValue(query.get("reqImei") || query.get("imei"));
|
||||||
|
const appVersion = trimValue(query.get("appVersion")) || "1.0.0";
|
||||||
|
const buildVersion = trimValue(query.get("buildVersion") || query.get("build")) || "1";
|
||||||
|
const appChannel = trimValue(query.get("appChannel") || query.get("channel")) || "Web";
|
||||||
|
|
||||||
|
if (sysOrigin) {
|
||||||
|
headers["Req-Sys-Origin"] = `origin=${sysOrigin};originChild=${sysOriginChild || sysOrigin}`;
|
||||||
|
}
|
||||||
|
if (reqClient) {
|
||||||
|
headers["Req-Client"] = reqClient;
|
||||||
|
}
|
||||||
|
if (reqLang) {
|
||||||
|
headers["Req-Lang"] = reqLang;
|
||||||
|
}
|
||||||
|
if (reqZone) {
|
||||||
|
headers["Req-Zone"] = reqZone;
|
||||||
|
}
|
||||||
|
if (reqVersion) {
|
||||||
|
headers["Req-Version"] = reqVersion;
|
||||||
|
}
|
||||||
|
if (reqImei) {
|
||||||
|
headers["Req-Imei"] = reqImei;
|
||||||
|
}
|
||||||
|
|
||||||
|
headers["Req-App-Intel"] = buildAppIntelHeader({
|
||||||
|
version: appVersion,
|
||||||
|
build: buildVersion,
|
||||||
|
channel: appChannel,
|
||||||
|
model: trimValue(query.get("model")) || "H5",
|
||||||
|
sysVersion: trimValue(query.get("sysVersion")) || "Web",
|
||||||
|
imei: reqImei,
|
||||||
|
});
|
||||||
|
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAppIntelHeader(parts) {
|
||||||
|
const items = [];
|
||||||
|
const version = trimValue(parts?.version) || "1.0.0";
|
||||||
|
const build = trimValue(parts?.build) || "1";
|
||||||
|
const channel = trimValue(parts?.channel) || "Web";
|
||||||
|
const model = trimValue(parts?.model);
|
||||||
|
const sysVersion = trimValue(parts?.sysVersion);
|
||||||
|
const imei = trimValue(parts?.imei);
|
||||||
|
|
||||||
|
items.push(`version=${version}`);
|
||||||
|
items.push(`build=${build}`);
|
||||||
|
items.push(`channel=${channel}`);
|
||||||
|
if (model) {
|
||||||
|
items.push(`model=${model}`);
|
||||||
|
}
|
||||||
|
if (sysVersion) {
|
||||||
|
items.push(`sysVersion=${sysVersion}`);
|
||||||
|
}
|
||||||
|
if (imei) {
|
||||||
|
items.push(`Req-Imei=${imei}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.join(";");
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitHeaderPairs(value) {
|
||||||
|
const result = {};
|
||||||
|
trimValue(value)
|
||||||
|
.split(";")
|
||||||
|
.forEach((item) => {
|
||||||
|
const index = item.indexOf("=");
|
||||||
|
if (index > -1) {
|
||||||
|
result[item.slice(0, index)] = item.slice(index + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAccessOrigin(raw) {
|
||||||
|
const data = typeof raw === "string" ? JSON.parse(raw) : raw;
|
||||||
|
if (!data || typeof data !== "object") {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const appIntel = splitHeaderPairs(data["Req-App-Intel"] || data["req-app-intel"]);
|
||||||
|
const sysOrigin = splitHeaderPairs(data["Req-Sys-Origin"] || data["req-sys-origin"]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
authorization: data.Authorization || data.authorization,
|
||||||
|
reqLang: data["Req-Lang"] || data["req-lang"],
|
||||||
|
reqClient: data["Req-Client"] || data["req-client"],
|
||||||
|
reqImei: data["Req-Imei"] || data["req-imei"] || appIntel["Req-Imei"],
|
||||||
|
appVersion: appIntel.version,
|
||||||
|
buildVersion: appIntel.build,
|
||||||
|
appChannel: appIntel.channel,
|
||||||
|
model: appIntel.model,
|
||||||
|
sysVersion: appIntel.sysVersion,
|
||||||
|
sysOrigin: sysOrigin.origin,
|
||||||
|
sysOriginChild: sysOrigin.originChild || sysOrigin.child,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHeadersFromApp(info) {
|
||||||
|
if (!info || typeof info !== "object") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const next = {};
|
||||||
|
const authorization = normalizeAuthorizationValue(info.authorization);
|
||||||
|
if (authorization) {
|
||||||
|
state.authorization = authorization;
|
||||||
|
}
|
||||||
|
if (info.reqLang) {
|
||||||
|
next["Req-Lang"] = info.reqLang;
|
||||||
|
}
|
||||||
|
if (info.reqClient) {
|
||||||
|
next["Req-Client"] = info.reqClient;
|
||||||
|
}
|
||||||
|
if (info.reqImei) {
|
||||||
|
next["Req-Imei"] = info.reqImei;
|
||||||
|
}
|
||||||
|
if (info.sysOrigin) {
|
||||||
|
next["Req-Sys-Origin"] =
|
||||||
|
`origin=${info.sysOrigin};originChild=${info.sysOriginChild || info.sysOrigin}`;
|
||||||
|
}
|
||||||
|
if (info.appVersion || info.buildVersion || info.appChannel || info.model || info.sysVersion) {
|
||||||
|
next["Req-App-Intel"] = buildAppIntelHeader({
|
||||||
|
version: info.appVersion,
|
||||||
|
build: info.buildVersion,
|
||||||
|
channel: info.appChannel,
|
||||||
|
model: info.model,
|
||||||
|
sysVersion: info.sysVersion,
|
||||||
|
imei: info.reqImei,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
state.requestHeaders = { ...state.requestHeaders, ...next };
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAuthorizationValue(value) {
|
||||||
|
const normalized = trimValue(value);
|
||||||
|
if (!normalized) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (/^bearer\s+/i.test(normalized)) {
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
return `Bearer ${normalized}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectToApp() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let finished = false;
|
||||||
|
const finish = (value) => {
|
||||||
|
if (finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
resolve(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.renderData = finish;
|
||||||
|
window.getIosAccessOriginParam = finish;
|
||||||
|
|
||||||
|
if (!(window.app || window.webkit || window.FlutterPageControl || window.FlutterApp)) {
|
||||||
|
finish(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let attempt = 0;
|
||||||
|
const poll = () => {
|
||||||
|
attempt += 1;
|
||||||
|
if (window.app && typeof window.app.getAccessOrigin === "function") {
|
||||||
|
try {
|
||||||
|
finish(window.app.getAccessOrigin());
|
||||||
|
} catch {
|
||||||
|
finish(null);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (attempt < 50) {
|
||||||
|
window.setTimeout(poll, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (window.FlutterApp && typeof window.FlutterApp.postMessage === "function") {
|
||||||
|
window.FlutterApp.postMessage("requestAccessOrigin");
|
||||||
|
}
|
||||||
|
window.setTimeout(() => finish(null), 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
poll();
|
||||||
|
}).then((value) => {
|
||||||
|
if (value) {
|
||||||
|
try {
|
||||||
|
setHeadersFromApp(parseAccessOrigin(value));
|
||||||
|
} catch {
|
||||||
|
// App bridge data is best-effort; query token and default gateway headers still work.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function escapeHtml(value) {
|
function escapeHtml(value) {
|
||||||
return String(value).replace(/[&<>"']/g, (match) => {
|
return String(value).replace(/[&<>"']/g, (match) => {
|
||||||
const entityMap = {
|
const entityMap = {
|
||||||
@ -544,11 +765,13 @@ function extractErrorMessage(payload) {
|
|||||||
async function requestJSON(path, options = {}) {
|
async function requestJSON(path, options = {}) {
|
||||||
const { method = "GET", headers = {}, body, searchParams } = options;
|
const { method = "GET", headers = {}, body, searchParams } = options;
|
||||||
const url = buildAPIURL(path, searchParams);
|
const url = buildAPIURL(path, searchParams);
|
||||||
|
const requestHeaders = shouldAttachGatewayHeaders(path) ? state.requestHeaders : {};
|
||||||
|
|
||||||
const response = await fetch(url.toString(), {
|
const response = await fetch(url.toString(), {
|
||||||
method,
|
method,
|
||||||
headers: {
|
headers: {
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
|
...requestHeaders,
|
||||||
...headers,
|
...headers,
|
||||||
},
|
},
|
||||||
body,
|
body,
|
||||||
@ -565,6 +788,11 @@ async function requestJSON(path, options = {}) {
|
|||||||
return payload?.body || payload?.data || payload || null;
|
return payload?.body || payload?.data || payload || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldAttachGatewayHeaders(path) {
|
||||||
|
const normalizedPath = joinURLPath(path);
|
||||||
|
return !normalizedPath.startsWith("/public/");
|
||||||
|
}
|
||||||
|
|
||||||
function joinURLPath(...parts) {
|
function joinURLPath(...parts) {
|
||||||
return `/${parts
|
return `/${parts
|
||||||
.map((part) => trimValue(part).replace(/^\/+|\/+$/g, ""))
|
.map((part) => trimValue(part).replace(/^\/+|\/+$/g, ""))
|
||||||
@ -945,6 +1173,7 @@ async function init() {
|
|||||||
bindEvents();
|
bindEvents();
|
||||||
setView(state.view);
|
setView(state.view);
|
||||||
setupCountdown();
|
setupCountdown();
|
||||||
|
await connectToApp();
|
||||||
await refreshPageData();
|
await refreshPageData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user