fix(android): cross-origin Bearer auth in Tauri shell

Inject a Tauri shell script during CI prep to disable service workers and attach Bearer tokens on cross-origin API requests. Enable Android third-party cookies in MainActivity and eval the same script from Rust on page load.
This commit is contained in:
2026-07-03 20:10:35 +08:00
parent 6ed4ca576d
commit 0c48dc8897
5 changed files with 173 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
(function () {
if (window.__web2appShellInstalled) return;
window.__web2appShellInstalled = true;
function isTauriShell() {
var protocol = location.protocol;
var host = location.hostname;
return (
protocol === "tauri:" ||
protocol === "file:" ||
host === "asset.localhost" ||
host === "tauri.localhost"
);
}
if (!isTauriShell()) return;
var TOKEN_KEYS = ["sprout2fa_session", "__web2app_bearer_token"];
function readToken() {
try {
for (var i = 0; i < TOKEN_KEYS.length; i++) {
var value = localStorage.getItem(TOKEN_KEYS[i]);
if (value) return value;
}
} catch (_) {
/* ignore */
}
return null;
}
function writeToken(token) {
if (!token) return;
try {
for (var i = 0; i < TOKEN_KEYS.length; i++) {
localStorage.setItem(TOKEN_KEYS[i], token);
}
} catch (_) {
/* ignore */
}
}
function clearToken() {
try {
for (var i = 0; i < TOKEN_KEYS.length; i++) {
localStorage.removeItem(TOKEN_KEYS[i]);
}
} catch (_) {
/* ignore */
}
}
if ("serviceWorker" in navigator) {
navigator.serviceWorker.getRegistrations().then(function (regs) {
for (var i = 0; i < regs.length; i++) regs[i].unregister();
});
navigator.serviceWorker.register = function () {
return Promise.resolve({
active: null,
installing: null,
waiting: null,
unregister: function () {
return Promise.resolve(true);
},
update: function () {
return Promise.resolve();
},
});
};
}
var originalFetch = window.fetch;
window.fetch = function (input, init) {
init = init || {};
var url =
typeof input === "string"
? input
: input instanceof URL
? input.href
: input && input.url
? input.url
: "";
var requestUrl;
try {
requestUrl = new URL(url, location.href);
} catch (_) {
return originalFetch.call(this, input, init);
}
var crossOrigin = requestUrl.origin !== location.origin;
if (crossOrigin) {
var headers = new Headers(init.headers || {});
if (!headers.has("Authorization")) {
var token = readToken();
if (token) headers.set("Authorization", "Bearer " + token);
}
init = Object.assign({}, init, { headers: headers });
}
return originalFetch.call(this, input, init).then(function (response) {
if (!response.ok) return response;
var path = requestUrl.pathname.replace(/\/$/, "");
if (/\/auth\/login$/i.test(path)) {
response
.clone()
.json()
.then(function (data) {
if (data && typeof data.token === "string" && data.token) {
writeToken(data.token);
}
})
.catch(function () {
/* ignore */
});
}
if (/\/auth\/logout$/i.test(path)) {
clearToken();
}
return response;
});
};
})();

View File

@@ -1,5 +1,7 @@
use tauri::Manager;
const TAURI_SHELL_SCRIPT: &str = include_str!("../../scripts/tauri-shell.js");
const IN_APP_NAV_SCRIPT: &str = r##"
(function () {
if (window.__web2appNavInstalled) return;
@@ -68,12 +70,14 @@ pub fn run() {
tauri::Builder::default()
.setup(|app| {
if let Some(window) = app.get_webview_window("main") {
let _ = window.eval(TAURI_SHELL_SCRIPT);
let _ = window.eval(IN_APP_NAV_SCRIPT);
}
Ok(())
})
.on_page_load(|webview, payload| {
if payload.event() == tauri::webview::PageLoadEvent::Finished {
let _ = webview.eval(TAURI_SHELL_SCRIPT);
let _ = webview.eval(IN_APP_NAV_SCRIPT);
}
})