// ==UserScript== // @name 广建智能查寝 // @namespace http://tampermonkey.net/ // @version 12.3 // @description 解决了一些已知问题。 // @author Security Researcher // @license MIT // @match *://xsgz.gdcvi.edu.cn/* // @match *://cas.gdcvi.edu.cn/lyuapServer/login* // @match *://*.map.qq.com/* // @match *://*.mapapi.qq.com/* // @match *://*.lbs.qq.com/* // @match *://*.3gimg.qq.com/* // @run-at document-start // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function() { 'use strict'; const D_LAT = 23.738999; const D_LNG = 113.0890105; const Store = { get: (k, d) => { try { return typeof GM_getValue === 'function' ? GM_getValue(k, d) : (parseFloat(localStorage.getItem(k)) || d); } catch(e) { return d; } }, set: (k, v) => { try { if (typeof GM_setValue === 'function') GM_setValue(k, v); else localStorage.setItem(k, v); } catch(e) {} } }; let F_LAT = Store.get('gdcvi_fake_lat', D_LAT); let F_LNG = Store.get('gdcvi_fake_lng', D_LNG); if (window === window.top) { setInterval(() => { const frames = document.querySelectorAll('iframe'); frames.forEach(f => { try { if (f.contentWindow) f.contentWindow.postMessage({ type: 'SYNC_COORD', lat: F_LAT, lng: F_LNG }, '*'); } catch(err){} }); }, 1000); } const mainWorldScript = function(initLat, initLng) { if(window.__CYBER_HOOK_ACTIVE__) return; window.__CYBER_HOOK_ACTIVE__ = true; let lat = parseFloat(initLat); let lng = parseFloat(initLng); window.addEventListener('message', (e) => { if (!e.data) return; if (e.data.type === 'SYNC_COORD') { lat = parseFloat(e.data.lat); lng = parseFloat(e.data.lng); } else if (e.data.type === 'PRIME_AUTO_CLICK') { window.__AUTO_CLICKED__ = true; } }); const PI = 3.1415926535897932384626; const a = 6378245.0; const ee = 0.00669342162296594323; const transformLat = (x, y) => { let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0; ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0; return ret; }; const transformLng = (x, y) => { let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x)); ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0; ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0; ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0; return ret; }; const gcj02towgs84 = (lng, lat) => { let dlat = transformLat(lng - 105.0, lat - 35.0); let dlng = transformLng(lng - 105.0, lat - 35.0); let radlat = lat / 180.0 * PI; let magic = Math.sin(radlat); magic = 1 - ee * magic * magic; let sqrtmagic = Math.sqrt(magic); dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); return [lng * 2 - (lng + dlng), lat * 2 - (lat + dlat)]; }; const getFakeData = () => { const jitter = () => (Math.random() - 0.5) * 0.00004; return { lat: lat + jitter(), lng: lng + jitter(), accuracy: 10 + Math.random() * 5 }; }; const origToString = Function.prototype.toString; Object.defineProperty(Function.prototype, 'toString', { value: new Proxy(origToString, { apply(target, thisArg, args) { if (thisArg && thisArg.__cyber_name) return 'function ' + thisArg.__cyber_name + '() { [native code] }'; return Reflect.apply(target, thisArg, args); } }), configurable: true, writable: true }); try { const origIframeSrcDesc = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, 'src'); if (origIframeSrcDesc) { const newSet = new Proxy(origIframeSrcDesc.set, { apply(target, thisArg, args) { if (args[0] && typeof args[0] === 'string' && args[0].includes('geolocation')) args[0] = 'about:blank'; return Reflect.apply(target, thisArg, args); } }); newSet.__cyber_name = 'set src'; Object.defineProperty(HTMLIFrameElement.prototype, 'src', { set: newSet, get: origIframeSrcDesc.get, configurable: origIframeSrcDesc.configurable, enumerable: origIframeSrcDesc.enumerable }); } } catch(e) {} const hookW3C = (origMethod, name) => { if (typeof origMethod !== 'function') return origMethod; const proxy = new Proxy(origMethod, { apply(target, thisArg, args) { const suc = args[0]; if (typeof suc === 'function') { const fd = getFakeData(); const [wgsLng, wgsLat] = gcj02towgs84(fd.lng, fd.lat); setTimeout(() => suc({coords:{latitude: wgsLat, longitude: wgsLng, accuracy: fd.accuracy}, timestamp:Date.now()}), 50); } return name === 'watchPosition' ? Math.floor(Math.random() * 10000) : undefined; } }); proxy.__cyber_name = name; return proxy; }; if (window.Geolocation && Geolocation.prototype) { try { Object.defineProperty(Geolocation.prototype, 'getCurrentPosition', { value: hookW3C(Geolocation.prototype.getCurrentPosition, 'getCurrentPosition'), configurable: false, writable: false }); Object.defineProperty(Geolocation.prototype, 'watchPosition', { value: hookW3C(Geolocation.prototype.watchPosition, 'watchPosition'), configurable: false, writable: false }); } catch(e) {} } if (navigator.geolocation) { try { const geoProxy = new Proxy(navigator.geolocation, { get(target, prop) { if (prop === 'getCurrentPosition') return hookW3C(target[prop], 'getCurrentPosition'); if (prop === 'watchPosition') return hookW3C(target[prop], 'watchPosition'); return typeof target[prop] === 'function' ? target[prop].bind(target) : target[prop]; } }); Object.defineProperty(navigator, 'geolocation', { value: geoProxy, configurable: false, writable: false, enumerable: true }); } catch(e) {} } const proxyCache = new WeakSet(); const hookTencentGeo = (OrigGeo) => { if (proxyCache.has(OrigGeo)) return OrigGeo; const HookedGeo = new Proxy(OrigGeo, { construct(target, args) { const instance = Reflect.construct(target, args); if (proxyCache.has(instance)) return instance; const InstanceProxy = new Proxy(instance, { get(target2, prop) { if (prop === 'getLocation' || prop === 'getIpLocation') { const fakeMethod = function(suc) { if (suc) { const fd = getFakeData(); setTimeout(() => suc({ module: 'geolocation', type: 'h5', lat: fd.lat, lng: fd.lng, accuracy: fd.accuracy, nation: '中国', province: '广东省', city: '清远市', adcode: '441802', __cyber_fake__: true }), 50); } }; fakeMethod.__cyber_name = prop; return fakeMethod; } const val = Reflect.get(target2, prop); return typeof val === 'function' ? val.bind(target2) : val; } }); proxyCache.add(InstanceProxy); return InstanceProxy; } }); proxyCache.add(HookedGeo); return HookedGeo; }; let _qq = window.qq; Object.defineProperty(window, 'qq', { get() { if (_qq && !proxyCache.has(_qq)) { _qq = new Proxy(_qq, { get(target, prop) { if (prop === 'maps') { const maps = Reflect.get(target, prop); if (maps && !proxyCache.has(maps)) { const mapsProxy = new Proxy(maps, { get(target2, prop2) { return prop2 === 'Geolocation' ? hookTencentGeo(Reflect.get(target2, prop2)) : Reflect.get(target2, prop2); } }); proxyCache.add(mapsProxy); return mapsProxy; } } return Reflect.get(target, prop); } }); proxyCache.add(_qq); } return _qq; }, set(v) { _qq = v; }, configurable: true }); const origOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { this._method = method; this._url = url; return origOpen.apply(this, arguments); }; const origSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { this.addEventListener('load', function() { if (window.__AUTO_CLICKED__) { try { const res = JSON.parse(this.responseText); let msg = res.message || res.msg || res.error || ''; if (!msg && (this._method || '').toUpperCase() === 'GET') return; let isSuccess = false; if (msg.includes('成功')) { isSuccess = true; } else if (msg.match(/(失败|不在|未到|不允许|异常|无法|太远)/)) { isSuccess = false; } else { isSuccess = (res.code === 200 || res.code === 0 || res.success === true); } if (!msg) msg = isSuccess ? '已完成' : '状态非预期'; window.postMessage({ type: 'NOTIFY_TOAST', isSuccess, msg }, '*'); window.__AUTO_CLICKED__ = false; } catch(e) {} } }); return origSend.apply(this, arguments); }; }; const injectToMainWorld = () => { const script = document.createElement('script'); script.textContent = '(' + mainWorldScript.toString() + `)(${F_LAT}, ${F_LNG});`; const target = document.head || document.documentElement; if (target) { target.appendChild(script); script.remove(); } }; if (document.head || document.documentElement) injectToMainWorld(); else { const obs = new MutationObserver(() => { if (document.head || document.documentElement) { obs.disconnect(); injectToMainWorld(); } }); obs.observe(document, { childList: true, subtree: true }); } const isMapEnv = () => { try { const h = window.location.hostname || ''; return h.includes('qq.com') || h.includes('tencent') || h.includes('map'); } catch(e) { return false; } }; const shouldRenderUI = () => { if (isMapEnv()) return false; if (window.innerWidth < 50 || window.innerHeight < 50) return false; try { if (window.parent !== window && window.parent.document) return false; } catch(e) {} return true; }; let shadowRoot = null; window.addEventListener('message', (e) => { if (e.data && e.data.type === 'NOTIFY_TOAST') { showToast(e.data.msg, !e.data.isSuccess); } }); const showToast = (msg, isError = false) => { if (!shadowRoot) return; const color = isError ? 'rgba(255, 59, 48, 0.9)' : 'rgba(52, 199, 89, 0.9)'; const toast = document.createElement('div'); toast.style.cssText = `position:absolute;top:60px;left:50%;transform:translateX(-50%);background:rgba(255,255,255,0.95);border:1px solid ${color};color:${color};padding:14px 24px;border-radius:30px;font-size:15px;font-weight:900;box-shadow:0 8px 24px rgba(0,0,0,0.15);display:flex;align-items:center;gap:10px;white-space:nowrap;z-index:9999;transition:all 0.4s cubic-bezier(0.32, 0.72, 0, 1);opacity:0;backdrop-filter:blur(10px);`; toast.innerHTML = (isError?'请求失败':'请求成功') + ``; shadowRoot.appendChild(toast); setTimeout(() => { toast.style.opacity = '1'; }, 10); setTimeout(() => { toast.style.opacity = '0'; toast.style.top = '-50px'; }, 3000); setTimeout(() => { if(toast.parentNode) toast.remove(); }, 3500); }; const createUI = () => { if (!shouldRenderUI()) return; if (document.getElementById('gdcvi-stay-host')) return; const root = document.documentElement || document.body; if (!root) return; const hostElement = document.createElement('div'); hostElement.id = 'gdcvi-stay-host'; hostElement.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:2147483647;'; root.appendChild(hostElement); shadowRoot = hostElement.attachShadow({ mode: 'closed' }); const style = document.createElement('style'); style.textContent = ` * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; font-family: -apple-system, BlinkMacSystemFont, sans-serif; } #fab { position: absolute; top: 100px; right: 20px; width: 52px; height: 52px; background: rgba(255, 255, 255, 0.85); border-radius: 50%; box-shadow: 0 4px 16px rgba(0,0,0,0.12), inset 0 1px 0 rgba(255,255,255,1); pointer-events: auto; display: flex; justify-content: center; align-items: center; cursor: pointer; user-select: none; backdrop-filter: blur(12px) saturate(180%); transition: transform 0.2s cubic-bezier(0.25, 0.8, 0.25, 1); } #fab:active { transform: scale(0.88); } #overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.4); opacity: 0; pointer-events: none; transition: opacity 0.35s cubic-bezier(0.25, 0.8, 0.25, 1); backdrop-filter: blur(4px); } #overlay.active { opacity: 1; pointer-events: auto; } #bottom-sheet { position: absolute; bottom: -100%; left: 0; width: 100%; background: rgba(245, 245, 247, 0.95); border-top-left-radius: 28px; border-top-right-radius: 28px; padding: 24px 20px 32px; box-shadow: 0 -10px 40px rgba(0,0,0,0.15); pointer-events: auto; transition: bottom 0.4s cubic-bezier(0.32, 0.72, 0, 1); touch-action: pan-y; backdrop-filter: blur(25px) saturate(200%); border-top: 1px solid rgba(255,255,255,0.7); } #bottom-sheet.active { bottom: 0; } .sheet-handle { width: 42px; height: 5px; background: rgba(0, 0, 0, 0.15); border-radius: 3px; margin: 0 auto 20px; } .header-bar { position: relative; margin-bottom: 24px; display: flex; align-items: center; justify-content: center; } .sheet-title { font-weight: 700; font-size: 17px; color: #1d1d1f; } #btn-close { position: absolute; right: 0; width: 28px; height: 28px; background: rgba(0,0,0,0.06); border-radius: 50%; display: flex; justify-content: center; align-items: center; font-size: 16px; cursor: pointer; } .input-group { display: flex; gap: 14px; margin-bottom: 24px; } .input-box { flex: 1; display: flex; flex-direction: column; gap: 8px; } .input-box label { font-size: 13px; color: #86868b; font-weight: 600; } .input-box input { width: 100%; padding: 14px 12px; border: 1.5px solid rgba(0,0,0,0.04); border-radius: 14px; font-size: 16px; outline: none; background: #ffffff; color: #1d1d1f; font-weight: 600; font-family: monospace; transition: all 0.25s ease; } .input-box input:focus { border-color: #34c759; box-shadow: 0 0 0 4px rgba(52, 199, 89, 0.15); } .btn-group { display: flex; gap: 14px; } button { flex: 1; padding: 16px; border: none; border-radius: 16px; font-weight: 600; font-size: 16px; cursor: pointer; transition: transform 0.2s; } button:active { transform: scale(0.96); } #btn-save { background: linear-gradient(135deg, #32d74b, #28a745); color: #ffffff; box-shadow: 0 6px 16px rgba(40, 167, 69, 0.25); } #btn-reset { background: #e8f0fe; color: #007aff; } .coffee-area { margin-top: 24px; text-align: center; } .coffee-link { font-size: 13px; color: #86868b; text-decoration: none; border-bottom: 1px solid rgba(134, 134, 139, 0.3); padding-bottom: 2px; transition: color 0.2s; } .coffee-link:active { color: #1d1d1f; } .coffee-qr-box { display: none; margin-top: 16px; transition: all 0.3s ease; } .coffee-qr-box img { width: 140px; height: 140px; border-radius: 12px; box-shadow: 0 4px 16px rgba(0,0,0,0.1); } .coffee-tips { font-size: 12px; color: #999; margin-top: 8px; font-weight: 500; } `; shadowRoot.appendChild(style); const overlay = document.createElement('div'); overlay.id = 'overlay'; shadowRoot.appendChild(overlay); const fab = document.createElement('div'); fab.id = 'fab'; fab.innerHTML = ``; shadowRoot.appendChild(fab); const sheet = document.createElement('div'); sheet.id = 'bottom-sheet'; sheet.innerHTML = `