Ezt a szkriptet nem ajánlott közvetlenül telepíteni. Ez egy könyvtár más szkriptek számára, amik tartalmazzák a // @require https://update.greasyforks.org/scripts/548365/1654735/DeepQuery%20Secure%20Client%20%28sandbox%29.js
hivatkozást.
// ==UserScript==
// @name DeepQuery Secure Client (sandbox)
// @namespace dq.secure.v2.client
// @version 2.0.0
// @description 提供沙箱内的 DeepQuery API,自动签名并与页面核心通信。可 @require 于任意调用脚本顶部。
// @author you
// @match http://*/*
// @match https://*/*
// @include about:blank
// @run-at document-start
// @grant none
// ==/UserScript==
(function () {
'use strict';
/******** 配置:必须与 Core 一致 ********/
const CHANNEL = '__DQ_SECURE_V2__';
// ★★★ 重要:把下面的 KEY_PARTS 替换成你自己的一组(与 Core 完全一致) ★★★
const KEY_PARTS = [
'dW5hcmFuZG9tLWtleS1zZWVkLQ',
'tZXBsZWFzZS1yZXBsYWNlLW1l',
'LXdpdGgtYS1wcm9wZXItb25l'
];
// 是否在本沙箱里提供一个 top.DeepQuery 代理(零改动用)
const EXPOSE_TOP_PROXY = false;
const te = new TextEncoder();
function b64ToU8(b64) {
const pad = b64.length % 4 ? (4 - b64.length % 4) : 0;
const s = b64 + '='.repeat(pad);
const bin = atob(s.replace(/-/g, '+').replace(/_/g, '/'));
const u8 = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) u8[i] = bin.charCodeAt(i);
return u8;
}
const KEY_U8 = b64ToU8(KEY_PARTS.join(''));
async function sha256U8(u8) {
const buf = await crypto.subtle.digest('SHA-256', u8);
return new Uint8Array(buf);
}
async function hmacSignRaw(key, u8) {
const k = await crypto.subtle.importKey(
'raw', key, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
);
const sig = await crypto.subtle.sign('HMAC', k, u8);
return new Uint8Array(sig);
}
const pending = new Map();
function rid() {
return (Date.now().toString(36) + Math.random().toString(36).slice(2, 10)).toUpperCase();
}
function send(payload) {
window.top.postMessage({ [CHANNEL]: payload }, '*');
}
window.addEventListener('message', (e) => {
const msg = e.data && e.data[CHANNEL];
if (!msg || msg.cmd !== 'RESP' || !msg.id) return;
const hit = pending.get(msg.id);
if (!hit) return;
pending.delete(msg.id);
hit.resolve(msg.res);
}, false);
async function request(spec) {
const id = rid();
const ts = Date.now();
const nonce = rid() + Math.random().toString(36).slice(2);
const payload = te.encode(id + '\n' + ts + '\n' + nonce + '\n');
const bodyHash = await sha256U8(te.encode(JSON.stringify(spec || {})));
const toSign = new Uint8Array(payload.length + bodyHash.length);
toSign.set(payload, 0); toSign.set(bodyHash, payload.length);
const sigU8 = await hmacSignRaw(KEY_U8, toSign);
const sigB64 = btoa(String.fromCharCode(...sigU8));
return new Promise((resolve) => {
pending.set(id, { resolve });
send({ cmd: 'REQ', id, ts, nonce, sigB64, spec });
// 可选超时(以 spec.timeout 为基准)
const timeout = typeof spec.timeout === 'number' ? Math.max(200, spec.timeout + 500) : 6000;
setTimeout(() => {
if (pending.has(id)) {
pending.delete(id);
resolve({ ok: false, error: 'TIMEOUT' });
}
}, timeout);
});
}
// 暴露与旧版一致的方法
const DeepQuery = {
async get(spec = {}) { return request(spec); },
async attr({ framePath, chain, name, timeout }) { return request({ framePath, chain, timeout, pick: { attr: name } }); },
async prop({ framePath, chain, name, timeout }) { return request({ framePath, chain, timeout, pick: { prop: name } }); },
async text({ framePath, chain, timeout }) { return request({ framePath, chain, timeout, pick: { text: true } }); },
async html({ framePath, chain, timeout }) { return request({ framePath, chain, timeout, pick: { html: true } }); },
async rect({ framePath, chain, timeout }) { return request({ framePath, chain, timeout, pick: { rect: true } }); },
version: '2.0.0-client'
};
// 方式 A:推荐 —— 在沙箱里直接提供全局 DeepQuery
try { window.DeepQuery = DeepQuery; } catch {}
// 方式 B:零改动(仅本沙箱可见的 top.DeepQuery 代理)
if (EXPOSE_TOP_PROXY) {
try {
// 注意:这个属性只存在于当前 userscript 的沙箱 proxy 上,页面/其它沙箱看不到
Object.defineProperty(window.top, 'DeepQuery', {
configurable: true,
get() { return DeepQuery; }
});
} catch {}
}
try { console.debug('[DeepQuery Secure Client] ready'); } catch {}
})();