fix(app): proxy off must make the extension undetectable

Disabling "Proxy intégré" still left the userscript injected, so it ran
exposePageApi() which sets __MOVIX_EXTENSION_INSTALLED / hasMovixUserscript
/ dataset.movixExtension and fires movix-extension-loaded. The site (e.g.
movix.golf/extension) kept reporting "extension détectée et active" and
routed its requests through the proxy bridge — which then failed.

Fix: when proxyEnabled is false, don't inject the userscript at all. The
site no longer detects the extension and falls back to its own network
path. Bridge runtime + cast shim stay injected (debug console capture +
Chromecast).

Removes the now-dead direct-XHR fallback and the __MOVIX_PROXY_ENABLED
flag from the bridge runtime. Updates the settings hint to match.

https://claude.ai/code/session_01X52sah6aUu3ou26uJWHgzr
This commit is contained in:
Claude 2026-06-11 17:02:36 +00:00
parent fcb9a12c25
commit 5f35a0fc67
No known key found for this signature in database
3 changed files with 13 additions and 76 deletions

View file

@ -88,73 +88,8 @@ export function buildBridgeRuntime(): string {
return bytes.buffer;
}
// --- Helper: extrait le corps d'une requête GM en string ---
function gmBodyToString(data) {
if (data == null) return null;
if (typeof data === 'string') return data;
if (data instanceof URLSearchParams) return data.toString();
return String(data);
}
// --- GM_xmlhttpRequest DIRECT (proxy désactivé) ---
// Exécute la requête dans le contexte du WebView via XMLHttpRequest.
// Pas de bypass CORS, pas d'injection de headers : utilise le réseau et les
// cookies de la page directement.
function GM_xmlhttpRequest_direct(details) {
var xhr = new XMLHttpRequest();
var method = (details.method || 'GET').toUpperCase();
try {
xhr.open(method, details.url, true);
} catch (e) {
if (details.onerror) details.onerror({ error: String(e), status: 0, statusText: 'open failed' });
return { abort: function() {} };
}
if (details.responseType === 'arraybuffer') {
try { xhr.responseType = 'arraybuffer'; } catch (e) {}
}
if (details.timeout) xhr.timeout = details.timeout;
var headers = details.headers || {};
for (var hk in headers) {
try { xhr.setRequestHeader(hk, headers[hk]); } catch (e) {}
}
xhr.onload = function() {
if (!details.onload) return;
var isBuffer = details.responseType === 'arraybuffer';
details.onload({
status: xhr.status,
statusText: xhr.statusText,
responseHeaders: xhr.getAllResponseHeaders ? xhr.getAllResponseHeaders() : '',
response: xhr.response,
responseText: isBuffer ? '' : (xhr.responseText || ''),
finalUrl: xhr.responseURL || details.url
});
};
xhr.onerror = function() {
if (details.onerror) details.onerror({ error: 'Network error', status: xhr.status || 0, statusText: xhr.statusText || 'error' });
};
xhr.ontimeout = function() {
if (details.onerror) details.onerror({ error: 'Timeout', status: 0, statusText: 'timeout' });
};
try {
xhr.send(gmBodyToString(details.data));
} catch (e) {
if (details.onerror) details.onerror({ error: String(e), status: 0, statusText: 'send failed' });
}
return { abort: function() { try { xhr.abort(); } catch (e) {} } };
}
// --- GM_xmlhttpRequest ---
function GM_xmlhttpRequest(details) {
// Proxy intégré désactivé -> requête directe dans le WebView.
if (window.__MOVIX_PROXY_ENABLED === false) {
return GM_xmlhttpRequest_direct(details);
}
var headers = details.headers || {};
var bodyStr = null;

View file

@ -4,9 +4,13 @@ import { USERSCRIPT_SOURCE } from './userscript-source';
export interface InjectOptions {
/**
* Quand false, GM_xmlhttpRequest court-circuite le bridge natif et exécute
* les requêtes directement dans le WebView (cookies de la page, soumis au
* CORS). Utile quand le proxy natif casse certaines sources.
* Quand false, le userscript Movix n'est PAS injecté : le site ne détecte
* alors plus l'extension (drapeaux __MOVIX_EXTENSION_INSTALLED, etc.) et
* n'essaie pas de router ses requêtes via le proxy natif. Il retombe sur
* son propre chemin réseau utile pour les sources que le proxy casse.
*
* Le bridge runtime et le cast shim restent injectés (capture console de
* debug + Chromecast).
*/
proxyEnabled?: boolean;
}
@ -16,19 +20,17 @@ export function buildInjectedJavaScript(options: InjectOptions = {}): string {
const bridge = buildBridgeRuntime();
const castShim = buildCastShim();
// Flag lu par le bridge runtime (avant sa définition de GM_xmlhttpRequest).
const proxyFlag = `window.__MOVIX_PROXY_ENABLED = ${proxyEnabled ? 'true' : 'false'};`;
const userscript = proxyEnabled
? `// --- Userscript Movix ---\n${USERSCRIPT_SOURCE}`
: '// --- Userscript Movix non injecté (proxy intégré désactivé) ---';
// Cast shim FIRST — must be on window before any page JS runs.
return `
${proxyFlag}
${castShim}
${bridge}
// --- Userscript Movix ---
${USERSCRIPT_SOURCE}
${userscript}
true;
`;

View file

@ -219,8 +219,8 @@ export default function SettingsScreen() {
<Text style={styles.hint}>
{uiPrefs.proxyEnabled
? "Les requêtes du userscript passent par le proxy natif (contourne le CORS et injecte les headers). Si certaines sources ne se lancent pas, essaie de le désactiver."
: "Proxy désactivé : les requêtes s'exécutent directement dans le WebView (cookies de la page, soumises au CORS). La page est rechargée à chaque changement."}
? "L'extension Movix est injectée : le site la détecte et route ses requêtes via le proxy natif (contourne le CORS, injecte les headers). Si certaines sources ne se lancent pas, désactive-le."
: "Extension désactivée : le site ne la détecte plus et utilise son propre chemin de requêtes. La page est rechargée à chaque changement."}
</Text>
</View>