hts-ai commited on
Commit
d150a68
·
verified ·
1 Parent(s): b2e052b

🐳 11/07 - 16:02 - Navigateur Virtuel Isolé.  REN,FORCÉ     import randomimport requestsfrom bs4 import BeautifulSoupfrom typing import Dict, Anyclass VirtualBrowserEngine:    """     Moteur de Naviga

Browse files
Files changed (2) hide show
  1. mcp_server.py +46 -0
  2. navigateur.html +114 -0
mcp_server.py CHANGED
@@ -251,6 +251,52 @@ def call_claude_api(messages, model=None, max_tokens=4096, temperature=0.4):
251
  return None, f"Claude API request failed: {str(e)}"
252
 
253
  # ── Flask App ──
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  app = Flask(__name__)
255
  CORS(app)
256
 
 
251
  return None, f"Claude API request failed: {str(e)}"
252
 
253
  # ── Flask App ──
254
+ # ── Browser proxy with identity mutation ─────────────────────────────────
255
+ import random
256
+
257
+ USER_AGENTS = [
258
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
259
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
260
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
261
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1",
262
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0"
263
+ ]
264
+ ACCEPT_LANGUAGES = [
265
+ "en-US,en;q=0.9",
266
+ "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7",
267
+ "de-DE,de;q=0.9,en-US;q=0.8",
268
+ "es-ES,es;q=0.9,en-US;q=0.8"
269
+ ]
270
+ RESOLUTIONS = ["1920x1080", "1366x768", "1440x900", "375x812", "1024x768"]
271
+
272
+ @app.route("/browser", methods=["POST"])
273
+ def browser_proxy():
274
+ data = request.get_json(force=True)
275
+ url = data.get("url", "")
276
+ if not url:
277
+ return jsonify({"error": "No URL provided"}), 400
278
+
279
+ headers = {
280
+ "User-Agent": random.choice(USER_AGENTS),
281
+ "Accept-Language": random.choice(ACCEPT_LANGUAGES),
282
+ "Accept-Encoding": "gzip, deflate, br",
283
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
284
+ "DNT": "1",
285
+ "Upgrade-Insecure-Requests": "1",
286
+ "X-Virtual-Res": random.choice(RESOLUTIONS)
287
+ }
288
+
289
+ try:
290
+ resp = http_requests.get(url, headers=headers, timeout=25, allow_redirects=True)
291
+ return jsonify({
292
+ "status": resp.status_code,
293
+ "content": resp.text,
294
+ "identity_used": headers["User-Agent"],
295
+ "fingerprint_shield": "Active"
296
+ })
297
+ except Exception as e:
298
+ return jsonify({"status": "error", "message": str(e)}), 502
299
+
300
  app = Flask(__name__)
301
  CORS(app)
302
 
navigateur.html CHANGED
@@ -112,6 +112,17 @@
112
  <button onclick="loadPage()"
113
  class="px-4 py-2 rounded-lg bg-gradient-to-r from-neon-cyan to-neon-blue text-dark-950 font-semibold text-sm hover:opacity-90 active:scale-95 transition shrink-0">Charger</button>
114
  </div>
 
 
 
 
 
 
 
 
 
 
 
115
  <div class="flex gap-2">
116
  <button onclick="clearFrame()"
117
  class="flex-1 py-2 rounded-lg border border-glass-border text-dark-300 text-xs hover:bg-white/5 transition">Effacer</button>
@@ -126,6 +137,7 @@
126
  </div>
127
  <div class="space-y-2 text-xs">
128
  <div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-neon-green animate-pulse"></span><span class="text-dark-300">Proxy CORS: actif</span></div>
 
129
  <div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-neon-green animate-pulse"></span><span class="text-dark-300">Historique & cookies: non sauvegardés</span></div>
130
  <div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-neon-green animate-pulse"></span><span class="text-dark-300">Votre IP masquée du site cible</span></div>
131
  </div>
@@ -180,6 +192,73 @@
180
 
181
  <script>
182
  let currentUrl = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  function updateClock() {
184
  const now = new Date();
185
  document.getElementById("navClock").textContent = now.toLocaleTimeString('fr-FR');
@@ -196,6 +275,10 @@
196
  let url = input.value.trim();
197
  if (!url) return;
198
  if (!/^https?:\/\//i.test(url)) url = 'https://' + url;
 
 
 
 
199
  const proxyUrl = 'https://corsproxy.io/?' + encodeURIComponent(url);
200
  document.getElementById('browserFrame').src = proxyUrl;
201
  document.getElementById('placeholder').classList.add('hidden');
@@ -204,6 +287,37 @@
204
  showToast('Page chargée via proxy');
205
  }
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  function clearFrame() {
208
  document.getElementById('browserFrame').src = 'about:blank';
209
  document.getElementById('placeholder').classList.remove('hidden');
 
112
  <button onclick="loadPage()"
113
  class="px-4 py-2 rounded-lg bg-gradient-to-r from-neon-cyan to-neon-blue text-dark-950 font-semibold text-sm hover:opacity-90 active:scale-95 transition shrink-0">Charger</button>
114
  </div>
115
+ <div class="flex gap-2 mb-3">
116
+ <label class="flex items-center gap-2 cursor-pointer">
117
+ <input type="checkbox" id="mutationToggle" onchange="toggleMutation()" class="w-4 h-4 rounded accent-neon-cyan">
118
+ <span class="text-xs text-dark-300">Mutation d'identité (via MCP)</span>
119
+ </label>
120
+ </div>
121
+ <div id="mutationPanel" class="hidden space-y-2 mb-3 pt-3 border-t border-glass-border">
122
+ <div class="text-[10px] text-dark-400">Identité actuelle :</div>
123
+ <div class="text-[11px] font-mono text-neon-cyan truncate" id="currentIdentity">—</div>
124
+ <button onclick="mutateIdentity()" class="text-xs text-neon-purple hover:text-neon-purple/70 transition">🔄 Nouvelle identité</button>
125
+ </div>
126
  <div class="flex gap-2">
127
  <button onclick="clearFrame()"
128
  class="flex-1 py-2 rounded-lg border border-glass-border text-dark-300 text-xs hover:bg-white/5 transition">Effacer</button>
 
137
  </div>
138
  <div class="space-y-2 text-xs">
139
  <div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-neon-green animate-pulse"></span><span class="text-dark-300">Proxy CORS: actif</span></div>
140
+ <div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-neon-green animate-pulse"></span><span class="text-dark-300">Mutation d'identité: <span id="mutationStatus">désactivée</span></span></div>
141
  <div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-neon-green animate-pulse"></span><span class="text-dark-300">Historique & cookies: non sauvegardés</span></div>
142
  <div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-neon-green animate-pulse"></span><span class="text-dark-300">Votre IP masquée du site cible</span></div>
143
  </div>
 
192
 
193
  <script>
194
  let currentUrl = '';
195
+ let mutationEnabled = false;
196
+ let currentIdentity = null;
197
+
198
+ const USER_AGENTS = [
199
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
200
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
201
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
202
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Mobile/15E148 Safari/604.1",
203
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0"
204
+ ];
205
+ const ACCEPT_LANGUAGES = [
206
+ "en-US,en;q=0.9",
207
+ "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7",
208
+ "de-DE,de;q=0.9,en-US;q=0.8",
209
+ "es-ES,es;q=0.9,en-US;q=0.8"
210
+ ];
211
+ const RESOLUTIONS = ["1920x1080", "1366x768", "1440x900", "375x812", "1024x768"];
212
+
213
+ function generateIdentity() {
214
+ currentIdentity = {
215
+ ua: USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)],
216
+ lang: ACCEPT_LANGUAGES[Math.floor(Math.random() * ACCEPT_LANGUAGES.length)],
217
+ res: RESOLUTIONS[Math.floor(Math.random() * RESOLUTIONS.length)]
218
+ };
219
+ document.getElementById('currentIdentity').textContent = currentIdentity.ua.substring(0, 50) + "…";
220
+ }
221
+
222
+ function toggleMutation() {
223
+ mutationEnabled = document.getElementById('mutationToggle').checked;
224
+ const panel = document.getElementById('mutationPanel');
225
+ const status = document.getElementById('mutationStatus');
226
+ if (mutationEnabled) {
227
+ panel.classList.remove('hidden');
228
+ generateIdentity();
229
+ status.textContent = 'active';
230
+ status.className = 'text-neon-cyan';
231
+ // Check MCP availability
232
+ checkMCPAvailability();
233
+ } else {
234
+ panel.classList.add('hidden');
235
+ status.textContent = 'désactivée';
236
+ status.className = 'text-dark-300';
237
+ }
238
+ }
239
+
240
+ function mutateIdentity() {
241
+ if (!mutationEnabled) return;
242
+ generateIdentity();
243
+ showToast('Identité mutée');
244
+ }
245
+
246
+ async function checkMCPAvailability() {
247
+ // Try to fetch /health on MCP endpoint
248
+ const endpoint = getMCPEndpoint();
249
+ try {
250
+ const resp = await fetch(endpoint + '/health');
251
+ if (resp.ok) {
252
+ showToast('MCP détecté — mutation complète disponible');
253
+ }
254
+ } catch(e) { /* MCP inaccessible, mutation partielle (side-client seule) */ }
255
+ }
256
+
257
+ function getMCPEndpoint() {
258
+ // Use the same endpoint as agent.html (par défaut http://localhost:5000)
259
+ return 'http://localhost:5000'; // Peut être rendu configurable plus tard
260
+ }
261
+
262
  function updateClock() {
263
  const now = new Date();
264
  document.getElementById("navClock").textContent = now.toLocaleTimeString('fr-FR');
 
275
  let url = input.value.trim();
276
  if (!url) return;
277
  if (!/^https?:\/\//i.test(url)) url = 'https://' + url;
278
+ if (mutationEnabled) {
279
+ loadPageWithMutation(url);
280
+ return;
281
+ }
282
  const proxyUrl = 'https://corsproxy.io/?' + encodeURIComponent(url);
283
  document.getElementById('browserFrame').src = proxyUrl;
284
  document.getElementById('placeholder').classList.add('hidden');
 
287
  showToast('Page chargée via proxy');
288
  }
289
 
290
+ async function loadPageWithMutation(url) {
291
+ const frame = document.getElementById('browserFrame');
292
+ document.getElementById('placeholder').classList.add('hidden');
293
+ document.getElementById('currentUrlDisplay').textContent = url;
294
+ document.getElementById('proxyLabel').classList.remove('hidden');
295
+ // Tentative via MCP
296
+ try {
297
+ const resp = await fetch(getMCPEndpoint() + '/browser', {
298
+ method: 'POST',
299
+ headers: { 'Content-Type': 'application/json' },
300
+ body: JSON.stringify({ url })
301
+ });
302
+ if (resp.ok) {
303
+ const data = await resp.json();
304
+ if (data.status === 200 && data.content) {
305
+ // Injecter le HTML muté dans l'iframe via srcdoc
306
+ frame.srcdoc = data.content;
307
+ frame.src = 'about:blank'; // Nettoyer l'URL de l'iframe
308
+ document.getElementById('currentIdentity').textContent = data.identity_used.substring(0, 50) + "…";
309
+ showToast('Page chargée avec mutation d\'identité ✓');
310
+ return;
311
+ }
312
+ }
313
+ } catch(e) {}
314
+ // Fallback : proxy classique mais avertir
315
+ showToast('Mutation impossible sans serveur MCP, passage en mode proxy simple');
316
+ const proxyUrl = 'https://corsproxy.io/?' + encodeURIComponent(url);
317
+ frame.src = proxyUrl;
318
+ frame.srcdoc = ''; // Effacer srcdoc si présent
319
+ }
320
+
321
  function clearFrame() {
322
  document.getElementById('browserFrame').src = 'about:blank';
323
  document.getElementById('placeholder').classList.remove('hidden');