您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Modern age bypass for X.com using webpack chunk interception
// ==UserScript== // @name AgebypassX – Webpack Edition // @namespace https://github.com/Saganaki22/AgebypassX // @version 1.3.0 // @description Modern age bypass for X.com using webpack chunk interception // @author Saganaki22 // @license MIT // @match https://x.com/* // @match https://twitter.com/* // @run-at document-start // @grant none // @homepageURL https://github.com/Saganaki22/AgebypassX // @supportURL https://github.com/Saganaki22/AgebypassX/issues // @connect none // @noframes // ==/UserScript== (function () { 'use strict'; // 🔧 Configuration const CONFIG = { debug: false, // Set to true for console logs maxWaitTime: 30000, // Stop waiting after 30 seconds checkInterval: 500, // Check every 500ms hidePrivacyWarning: true, // Auto-hide X's misleading warning webpackChunkName: 'webpackChunk_twitter_responsive_web', }; // 📊 Runtime State const STATE = { interceptCount: 0, patchAttempts: 0, isPatched: false, lastPatchTime: null, webpackHooked: false, }; // 🎨 Inject UI Styles (status dot + tooltip) const style = document.createElement('style'); style.textContent = ` #agebypassx-indicator { position: fixed; top: 20px; right: 20px; width: 18px; height: 18px; border-radius: 50%; background: #ffa500; border: 2px solid white; box-shadow: 0 0 10px rgba(0,0,0,0.3); z-index: 9999999; cursor: pointer; transition: all 0.2s ease; pointer-events: auto; } #agebypassx-indicator[data-state="ok"] { background: #00ff66; box-shadow: 0 0 15px rgba(0, 255, 102, 0.6); } #agebypassx-indicator[data-state="err"] { background: #ff3333; box-shadow: 0 0 15px rgba(255, 51, 51, 0.6); } #agebypassx-indicator[data-state="pending"] { animation: agebypassx-pulse 1.5s infinite; } @keyframes agebypassx-pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.8; } 100% { transform: scale(1); opacity: 1; } } #agebypassx-tooltip { position: fixed; left: 0; top: 0; background: #111; color: #fff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 13px; border-radius: 8px; padding: 12px; max-width: 300px; box-shadow: 0 4px 20px rgba(0,0,0,0.5); z-index: 9999999; pointer-events: none; opacity: 0; transition: opacity 0.2s; border: 1px solid #333; line-height: 1.5; } #agebypassx-tooltip::before { content: ''; position: absolute; top: -6px; left: 16px; width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #111; } `; document.documentElement.appendChild(style); // 🟡 Status Indicator Dot const dot = document.createElement('div'); dot.id = 'agebypassx-indicator'; dot.dataset.state = 'pending'; dot.title = 'AgebypassX: Initializing...'; document.documentElement.appendChild(dot); // 💬 Tooltip const tooltip = document.createElement('div'); tooltip.id = 'agebypassx-tooltip'; document.documentElement.appendChild(tooltip); // 🛠 Utility Functions const log = (msg, data) => CONFIG.debug && console.log(`[AgebypassX] ${msg}`, data || ''); const warn = (msg, data) => console.warn(`[AgebypassX] ${msg}`, data || ''); function updateIndicator(state = 'ok', title = 'ACTIVE') { dot.dataset.state = state; dot.title = `AgebypassX: ${title}`; STATE.isPatched = (state === 'ok'); } function showTooltip(html) { tooltip.innerHTML = html; const rect = dot.getBoundingClientRect(); tooltip.style.left = `${rect.left - 140}px`; tooltip.style.top = `${rect.bottom + 10}px`; tooltip.style.opacity = 1; } function hideTooltip() { tooltip.style.opacity = 0; } dot.addEventListener('mouseenter', () => { const status = STATE.isPatched ? 'ACTIVE ✅' : 'FAILED ❌'; const webpackStatus = STATE.webpackHooked ? 'Hooked' : 'Not hooked'; const info = ` <strong>AgebypassX v1.3.0</strong><br> Status: ${status}<br> Webpack: ${webpackStatus}<br> Intercepts: ${STATE.interceptCount}<br> Patches: ${STATE.patchAttempts}<br> Last: ${STATE.lastPatchTime || 'Never'} `; showTooltip(info); }); dot.addEventListener('mouseleave', hideTooltip); dot.addEventListener('click', () => { alert( `AgebypassX v1.3.0\n` + `Status: ${STATE.isPatched ? 'ACTIVE' : 'FAILED'}\n` + `Webpack: ${STATE.webpackHooked ? 'Hooked' : 'Not hooked'}\n` + `Intercepts: ${STATE.interceptCount}\n` + `Patches: ${STATE.patchAttempts}\n` + `Last Patch: ${STATE.lastPatchTime || 'Never'}\n\n` + `Debug: ${CONFIG.debug ? 'Enabled' : 'Disabled'}\n` + `(Enable in CONFIG to see logs)` ); }); // 🔧 Core: Patch webpack modules containing sensitive media settings function patchWebpackModule(moduleId, moduleFunc) { if (!moduleFunc || typeof moduleFunc !== 'function') return false; try { const funcStr = moduleFunc.toString(); // Look for sensitive media settings in the module if (funcStr.includes('SensitiveMediaSettingsQuery') || funcStr.includes('view_adult_content') || funcStr.includes('can_user_allow_sensitive_content')) { log(`Found sensitive media module ${moduleId}, attempting to patch`); // This is where we would modify the module function // For now, we'll just track that we found it STATE.patchAttempts++; STATE.lastPatchTime = new Date().toLocaleTimeString(); STATE.isPatched = true; return true; } } catch (e) { warn('Failed to patch webpack module', e); } return false; } // 🔁 Hook: Webpack Chunk Loading function setupWebpackHook() { try { // Wait for webpack chunks to be available const checkWebpack = () => { if (window[CONFIG.webpackChunkName]) { const webpackChunks = window[CONFIG.webpackChunkName]; // Hook the push method to intercept new chunks const originalPush = webpackChunks.push.bind(webpackChunks); webpackChunks.push = function(chunk) { STATE.interceptCount++; log('Intercepted webpack chunk', chunk); // Check if this chunk contains sensitive media modules if (chunk && chunk[1]) { let patchedInChunk = false; Object.keys(chunk[1]).forEach(moduleId => { if (patchWebpackModule(moduleId, chunk[1][moduleId])) { patchedInChunk = true; } }); if (patchedInChunk) { updateIndicator('ok', 'ACTIVE - Patched'); } } return originalPush(chunk); }; // Also check existing chunks webpackChunks.forEach((chunk, index) => { if (chunk && chunk[1]) { Object.keys(chunk[1]).forEach(moduleId => { patchWebpackModule(moduleId, chunk[1][moduleId]); }); } }); STATE.webpackHooked = true; log('Webpack hook installed successfully'); return true; } return false; }; // Try immediately, then poll if (checkWebpack()) { return true; } const interval = setInterval(() => { if (checkWebpack()) { clearInterval(interval); } }, CONFIG.checkInterval); setTimeout(() => clearInterval(interval), CONFIG.maxWaitTime); return false; } catch (e) { warn('Failed to hook webpack chunks', e); return false; } } // 🔍 Fallback: Hook fetch/XHR for GraphQL queries function hookNetworkRequests() { // Hook fetch for GraphQL requests const originalFetch = window.fetch; window.fetch = function(url, options) { if (url && url.includes && (url.includes('graphql') || url.includes('SensitiveMediaSettingsQuery'))) { log('Intercepted GraphQL request', url); return originalFetch.apply(this, arguments).then(response => { // Clone the response to read it without consuming the original const clonedResponse = response.clone(); clonedResponse.json().then(data => { log('GraphQL response data', data); // Here we could potentially patch the response data }).catch(() => { // Ignore JSON parse errors }); return response; }); } return originalFetch.apply(this, arguments); }; log('Network request hooking enabled'); } // 🧹 Remove X's misleading privacy warning function hidePrivacyWarningBanner() { if (!CONFIG.hidePrivacyWarning) return; const observer = new MutationObserver(() => { document.body.querySelectorAll('div, span, p').forEach(el => { if ( el.innerText?.includes('privacy related extensions') || el.innerText?.includes('may cause issues on x.com') ) { if (el.style.display !== 'none') { el.style.display = 'none'; log('Hid misleading privacy warning banner'); } } }); }); observer.observe(document.body, { childList: true, subtree: true }); } // 🚀 Initialize log('AgebypassX v3.0: Script loaded, initializing...'); // Step 1: Try webpack hook if (!setupWebpackHook()) { updateIndicator('pending', 'Waiting for webpack...'); log('Webpack hook setup initiated, waiting for chunks'); } // Step 2: Start fallbacks hookNetworkRequests(); hidePrivacyWarningBanner(); // Final status check setTimeout(() => { if (!STATE.isPatched) { if (STATE.webpackHooked) { updateIndicator('err', 'HOOKED - No sensitive media found'); warn('Webpack hooked but no sensitive media modules found'); } else { updateIndicator('err', 'FAILED - No webpack chunks'); warn('Failed to hook webpack chunks. Age gate may appear.'); } } }, CONFIG.maxWaitTime + 1000); // 🌐 Expose debug API window.AgebypassX = { state: STATE, config: CONFIG, version: '1.3.0', forceWebpackCheck: setupWebpackHook, showStatus: () => alert(`AgebypassX v3.0: ${STATE.isPatched ? 'ACTIVE' : 'FAILED'}`), }; log('AgebypassX v3.0: Initialization complete'); })();