@leeguoo/pwtk-network-debugger 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +3 -3
- package/dist/index.esm.js +189 -29
- package/dist/index.js +3 -3
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -6671,10 +6671,17 @@ function decrypt(encryptedData, keyStr) {
|
|
|
6671
6671
|
return encryptedData;
|
|
6672
6672
|
}
|
|
6673
6673
|
class NetworkInterceptor {
|
|
6674
|
-
constructor() {
|
|
6674
|
+
constructor(options = {}) {
|
|
6675
6675
|
this.requests = /* @__PURE__ */ new Map();
|
|
6676
6676
|
this.listeners = [];
|
|
6677
6677
|
this.decryptConfig = { enabled: false };
|
|
6678
|
+
this.STORAGE_KEY = "network_debugger_requests";
|
|
6679
|
+
this.MAX_STORAGE_SIZE = 100;
|
|
6680
|
+
this.persistenceEnabled = true;
|
|
6681
|
+
this.persistenceEnabled = options.persistence !== false;
|
|
6682
|
+
if (this.persistenceEnabled) {
|
|
6683
|
+
this.loadFromStorage();
|
|
6684
|
+
}
|
|
6678
6685
|
this.interceptXHR();
|
|
6679
6686
|
this.interceptFetch();
|
|
6680
6687
|
}
|
|
@@ -6686,6 +6693,12 @@ class NetworkInterceptor {
|
|
|
6686
6693
|
if (config?.slkExtractor) {
|
|
6687
6694
|
this.decryptConfig.slkExtractor = config.slkExtractor;
|
|
6688
6695
|
}
|
|
6696
|
+
if (config?.autoFetchKeys !== void 0) {
|
|
6697
|
+
this.decryptConfig.autoFetchKeys = config.autoFetchKeys;
|
|
6698
|
+
}
|
|
6699
|
+
if (config?.keyApiUrl) {
|
|
6700
|
+
this.decryptConfig.keyApiUrl = config.keyApiUrl;
|
|
6701
|
+
}
|
|
6689
6702
|
}
|
|
6690
6703
|
addListener(listener) {
|
|
6691
6704
|
this.listeners.push(listener);
|
|
@@ -6701,6 +6714,9 @@ class NetworkInterceptor {
|
|
|
6701
6714
|
}
|
|
6702
6715
|
clearRequests() {
|
|
6703
6716
|
this.requests.clear();
|
|
6717
|
+
if (this.persistenceEnabled) {
|
|
6718
|
+
this.clearStorage();
|
|
6719
|
+
}
|
|
6704
6720
|
}
|
|
6705
6721
|
generateRequestId() {
|
|
6706
6722
|
return Math.random().toString(36).substr(2, 9);
|
|
@@ -6714,18 +6730,39 @@ class NetworkInterceptor {
|
|
|
6714
6730
|
}
|
|
6715
6731
|
});
|
|
6716
6732
|
}
|
|
6717
|
-
tryDecrypt(data, headers) {
|
|
6733
|
+
async tryDecrypt(data, headers) {
|
|
6718
6734
|
if (!this.decryptConfig.enabled || !data) {
|
|
6719
6735
|
return null;
|
|
6720
6736
|
}
|
|
6721
6737
|
try {
|
|
6722
6738
|
let key = "";
|
|
6723
|
-
|
|
6739
|
+
let slk = "";
|
|
6740
|
+
if (headers.cid && this.decryptConfig.autoFetchKeys !== false) {
|
|
6741
|
+
try {
|
|
6742
|
+
const apiUrl = this.decryptConfig.keyApiUrl || "https://gw-card-pay.buyacard.cc/ip/getSK";
|
|
6743
|
+
const response = await fetch(apiUrl, {
|
|
6744
|
+
headers: {
|
|
6745
|
+
cid: headers.cid,
|
|
6746
|
+
client: headers.client || "S_WEB",
|
|
6747
|
+
device: headers.device || "Web",
|
|
6748
|
+
language: headers.language || "CN"
|
|
6749
|
+
}
|
|
6750
|
+
});
|
|
6751
|
+
const result = await response.json();
|
|
6752
|
+
if (result.success && result.data) {
|
|
6753
|
+
const num = result.data;
|
|
6754
|
+
key = num.slice(2, 3) + num.slice(5, 6) + num.slice(8, 9);
|
|
6755
|
+
console.log("NetworkDebugger: 自动获取密钥成功:", key, "原始值:", num);
|
|
6756
|
+
}
|
|
6757
|
+
} catch (e) {
|
|
6758
|
+
console.warn("NetworkDebugger: 自动获取密钥失败:", e);
|
|
6759
|
+
}
|
|
6760
|
+
}
|
|
6761
|
+
if (!key && this.decryptConfig.keyExtractor) {
|
|
6724
6762
|
key = this.decryptConfig.keyExtractor(headers);
|
|
6725
|
-
} else {
|
|
6763
|
+
} else if (!key) {
|
|
6726
6764
|
key = headers.keys || headers.cid || "";
|
|
6727
6765
|
}
|
|
6728
|
-
let slk = "";
|
|
6729
6766
|
if (this.decryptConfig.slkExtractor) {
|
|
6730
6767
|
slk = this.decryptConfig.slkExtractor(headers);
|
|
6731
6768
|
} else {
|
|
@@ -6733,13 +6770,48 @@ class NetworkInterceptor {
|
|
|
6733
6770
|
}
|
|
6734
6771
|
const fullKey = key + slk;
|
|
6735
6772
|
if (fullKey) {
|
|
6736
|
-
|
|
6773
|
+
const decrypted = decrypt(typeof data === "string" ? data : JSON.stringify(data), fullKey);
|
|
6774
|
+
if (decrypted !== data) {
|
|
6775
|
+
console.log("NetworkDebugger: 解密成功", { key, slk, fullKey });
|
|
6776
|
+
return decrypted;
|
|
6777
|
+
}
|
|
6737
6778
|
}
|
|
6738
6779
|
} catch (error) {
|
|
6739
6780
|
console.warn("NetworkDebugger: Decryption failed:", error);
|
|
6740
6781
|
}
|
|
6741
6782
|
return null;
|
|
6742
6783
|
}
|
|
6784
|
+
// 持久化存储方法
|
|
6785
|
+
saveToStorage() {
|
|
6786
|
+
if (!this.persistenceEnabled) return;
|
|
6787
|
+
try {
|
|
6788
|
+
const requests = Array.from(this.requests.values()).sort((a, b) => b.timestamp - a.timestamp).slice(0, this.MAX_STORAGE_SIZE);
|
|
6789
|
+
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(requests));
|
|
6790
|
+
} catch (e) {
|
|
6791
|
+
console.warn("NetworkDebugger: Failed to save to localStorage:", e);
|
|
6792
|
+
}
|
|
6793
|
+
}
|
|
6794
|
+
loadFromStorage() {
|
|
6795
|
+
try {
|
|
6796
|
+
const stored = localStorage.getItem(this.STORAGE_KEY);
|
|
6797
|
+
if (stored) {
|
|
6798
|
+
const requests = JSON.parse(stored);
|
|
6799
|
+
requests.forEach((req) => {
|
|
6800
|
+
this.requests.set(req.id, req);
|
|
6801
|
+
});
|
|
6802
|
+
console.log(`NetworkDebugger: 从存储中恢复了 ${requests.length} 条请求记录`);
|
|
6803
|
+
}
|
|
6804
|
+
} catch (e) {
|
|
6805
|
+
console.warn("NetworkDebugger: Failed to load from localStorage:", e);
|
|
6806
|
+
}
|
|
6807
|
+
}
|
|
6808
|
+
clearStorage() {
|
|
6809
|
+
try {
|
|
6810
|
+
localStorage.removeItem(this.STORAGE_KEY);
|
|
6811
|
+
} catch (e) {
|
|
6812
|
+
console.warn("NetworkDebugger: Failed to clear storage:", e);
|
|
6813
|
+
}
|
|
6814
|
+
}
|
|
6743
6815
|
interceptXHR() {
|
|
6744
6816
|
const originalXHR = window.XMLHttpRequest;
|
|
6745
6817
|
const self2 = this;
|
|
@@ -6772,9 +6844,17 @@ class NetworkInterceptor {
|
|
|
6772
6844
|
timestamp: startTime
|
|
6773
6845
|
};
|
|
6774
6846
|
if (body) {
|
|
6775
|
-
|
|
6847
|
+
self2.tryDecrypt(body, requestHeaders).then((decrypted) => {
|
|
6848
|
+
if (decrypted !== null) {
|
|
6849
|
+
requestData.decryptedRequest = decrypted;
|
|
6850
|
+
self2.requests.set(requestId, requestData);
|
|
6851
|
+
self2.saveToStorage();
|
|
6852
|
+
self2.notifyListeners(requestData);
|
|
6853
|
+
}
|
|
6854
|
+
}).catch((e) => console.warn("解密请求失败:", e));
|
|
6776
6855
|
}
|
|
6777
6856
|
self2.requests.set(requestId, requestData);
|
|
6857
|
+
self2.saveToStorage();
|
|
6778
6858
|
self2.notifyListeners(requestData);
|
|
6779
6859
|
return originalSend.call(this, body);
|
|
6780
6860
|
};
|
|
@@ -6803,9 +6883,17 @@ class NetworkInterceptor {
|
|
|
6803
6883
|
requestData.responseBody = xhr.responseText;
|
|
6804
6884
|
}
|
|
6805
6885
|
if (requestData.responseBody) {
|
|
6806
|
-
|
|
6886
|
+
self2.tryDecrypt(requestData.responseBody, { ...requestHeaders, ...responseHeaders }).then((decrypted) => {
|
|
6887
|
+
if (decrypted !== null) {
|
|
6888
|
+
requestData.decryptedResponse = decrypted;
|
|
6889
|
+
self2.requests.set(requestId, requestData);
|
|
6890
|
+
self2.saveToStorage();
|
|
6891
|
+
self2.notifyListeners(requestData);
|
|
6892
|
+
}
|
|
6893
|
+
}).catch((e) => console.warn("解密响应失败:", e));
|
|
6807
6894
|
}
|
|
6808
6895
|
self2.requests.set(requestId, requestData);
|
|
6896
|
+
self2.saveToStorage();
|
|
6809
6897
|
self2.notifyListeners(requestData);
|
|
6810
6898
|
}
|
|
6811
6899
|
}
|
|
@@ -6859,9 +6947,17 @@ class NetworkInterceptor {
|
|
|
6859
6947
|
timestamp: startTime
|
|
6860
6948
|
};
|
|
6861
6949
|
if (requestBody) {
|
|
6862
|
-
|
|
6950
|
+
self2.tryDecrypt(requestBody, requestHeaders).then((decrypted) => {
|
|
6951
|
+
if (decrypted !== null) {
|
|
6952
|
+
requestData.decryptedRequest = decrypted;
|
|
6953
|
+
self2.requests.set(requestId, requestData);
|
|
6954
|
+
self2.saveToStorage();
|
|
6955
|
+
self2.notifyListeners(requestData);
|
|
6956
|
+
}
|
|
6957
|
+
}).catch((e) => console.warn("解密请求失败:", e));
|
|
6863
6958
|
}
|
|
6864
6959
|
self2.requests.set(requestId, requestData);
|
|
6960
|
+
self2.saveToStorage();
|
|
6865
6961
|
self2.notifyListeners(requestData);
|
|
6866
6962
|
try {
|
|
6867
6963
|
const response = await originalFetch.call(this, input, init);
|
|
@@ -6885,15 +6981,23 @@ class NetworkInterceptor {
|
|
|
6885
6981
|
updatedRequestData.responseBody = responseText;
|
|
6886
6982
|
}
|
|
6887
6983
|
if (updatedRequestData.responseBody) {
|
|
6888
|
-
|
|
6984
|
+
self2.tryDecrypt(
|
|
6889
6985
|
updatedRequestData.responseBody,
|
|
6890
6986
|
{ ...requestHeaders, ...responseHeaders }
|
|
6891
|
-
)
|
|
6987
|
+
).then((decrypted) => {
|
|
6988
|
+
if (decrypted !== null) {
|
|
6989
|
+
updatedRequestData.decryptedResponse = decrypted;
|
|
6990
|
+
self2.requests.set(requestId, updatedRequestData);
|
|
6991
|
+
self2.saveToStorage();
|
|
6992
|
+
self2.notifyListeners(updatedRequestData);
|
|
6993
|
+
}
|
|
6994
|
+
}).catch((e) => console.warn("解密响应失败:", e));
|
|
6892
6995
|
}
|
|
6893
6996
|
} catch (error) {
|
|
6894
6997
|
updatedRequestData.error = `Failed to read response: ${error}`;
|
|
6895
6998
|
}
|
|
6896
6999
|
self2.requests.set(requestId, updatedRequestData);
|
|
7000
|
+
self2.saveToStorage();
|
|
6897
7001
|
self2.notifyListeners(updatedRequestData);
|
|
6898
7002
|
}
|
|
6899
7003
|
return response;
|
|
@@ -6904,6 +7008,7 @@ class NetworkInterceptor {
|
|
|
6904
7008
|
updatedRequestData.error = error instanceof Error ? error.message : String(error);
|
|
6905
7009
|
updatedRequestData.duration = endTime - startTime;
|
|
6906
7010
|
self2.requests.set(requestId, updatedRequestData);
|
|
7011
|
+
self2.saveToStorage();
|
|
6907
7012
|
self2.notifyListeners(updatedRequestData);
|
|
6908
7013
|
}
|
|
6909
7014
|
throw error;
|
|
@@ -6932,28 +7037,72 @@ class WasmLoader {
|
|
|
6932
7037
|
}
|
|
6933
7038
|
this.loading = true;
|
|
6934
7039
|
try {
|
|
6935
|
-
const
|
|
6936
|
-
|
|
6937
|
-
|
|
7040
|
+
const wasmPaths = [
|
|
7041
|
+
wasmUrl,
|
|
7042
|
+
"/mimlib.wasm",
|
|
7043
|
+
"/dist/mimlib.wasm",
|
|
7044
|
+
"/assets/mimlib.wasm",
|
|
7045
|
+
"https://gw-card-pay.buyacard.cc/mimlib.wasm"
|
|
7046
|
+
].filter(Boolean);
|
|
7047
|
+
const jsPaths = [
|
|
7048
|
+
jsUrl,
|
|
7049
|
+
"/wasm_exec.js",
|
|
7050
|
+
"/dist/wasm_exec.js",
|
|
7051
|
+
"/assets/wasm_exec.js",
|
|
7052
|
+
"https://gw-card-pay.buyacard.cc/wasm_exec.js"
|
|
7053
|
+
].filter(Boolean);
|
|
7054
|
+
let jsLoaded = false;
|
|
7055
|
+
for (const jsPath of jsPaths) {
|
|
7056
|
+
try {
|
|
7057
|
+
await this.loadScript(jsPath);
|
|
7058
|
+
if (typeof window.Go !== "undefined") {
|
|
7059
|
+
jsLoaded = true;
|
|
7060
|
+
console.log("NetworkDebugger: wasm_exec.js 加载成功:", jsPath);
|
|
7061
|
+
break;
|
|
7062
|
+
}
|
|
7063
|
+
} catch (e) {
|
|
7064
|
+
console.warn("NetworkDebugger: 尝试加载", jsPath, "失败:", e);
|
|
7065
|
+
continue;
|
|
7066
|
+
}
|
|
7067
|
+
}
|
|
7068
|
+
if (!jsLoaded) {
|
|
7069
|
+
throw new Error("Unable to load wasm_exec.js from any path");
|
|
7070
|
+
}
|
|
6938
7071
|
if (typeof window.Go === "undefined") {
|
|
6939
7072
|
throw new Error("Go WebAssembly runtime not available");
|
|
6940
7073
|
}
|
|
6941
7074
|
const go = new window.Go();
|
|
6942
|
-
let wasmModule;
|
|
6943
|
-
|
|
7075
|
+
let wasmModule = null;
|
|
7076
|
+
for (const wasmPath of wasmPaths) {
|
|
6944
7077
|
try {
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
7078
|
+
if (WebAssembly.instantiateStreaming) {
|
|
7079
|
+
try {
|
|
7080
|
+
wasmModule = await WebAssembly.instantiateStreaming(
|
|
7081
|
+
fetch(wasmPath),
|
|
7082
|
+
go.importObject
|
|
7083
|
+
);
|
|
7084
|
+
console.log("NetworkDebugger: WebAssembly 加载成功:", wasmPath);
|
|
7085
|
+
break;
|
|
7086
|
+
} catch (streamError) {
|
|
7087
|
+
console.warn("instantiateStreaming 失败,尝试传统方式:", streamError);
|
|
7088
|
+
const wasmBuffer = await fetch(wasmPath).then((response) => response.arrayBuffer());
|
|
7089
|
+
wasmModule = await WebAssembly.instantiate(wasmBuffer, go.importObject);
|
|
7090
|
+
console.log("NetworkDebugger: WebAssembly 加载成功(传统方式):", wasmPath);
|
|
7091
|
+
break;
|
|
7092
|
+
}
|
|
7093
|
+
} else {
|
|
7094
|
+
const wasmBuffer = await fetch(wasmPath).then((response) => response.arrayBuffer());
|
|
7095
|
+
wasmModule = await WebAssembly.instantiate(wasmBuffer, go.importObject);
|
|
7096
|
+
console.log("NetworkDebugger: WebAssembly 加载成功(传统方式):", wasmPath);
|
|
7097
|
+
break;
|
|
7098
|
+
}
|
|
7099
|
+
} catch (error) {
|
|
7100
|
+
console.warn("NetworkDebugger: 尝试加载", wasmPath, "失败:", error);
|
|
7101
|
+
continue;
|
|
6953
7102
|
}
|
|
6954
|
-
}
|
|
6955
|
-
|
|
6956
|
-
|
|
7103
|
+
}
|
|
7104
|
+
if (!wasmModule) {
|
|
7105
|
+
throw new Error("Unable to load WebAssembly from any path");
|
|
6957
7106
|
}
|
|
6958
7107
|
go.run(wasmModule.instance);
|
|
6959
7108
|
this.loaded = true;
|
|
@@ -8064,8 +8213,15 @@ class NetworkDebugger {
|
|
|
8064
8213
|
},
|
|
8065
8214
|
decrypt: {
|
|
8066
8215
|
enabled: true,
|
|
8216
|
+
autoFetchKeys: true,
|
|
8217
|
+
keyApiUrl: "https://gw-card-pay.buyacard.cc/ip/getSK",
|
|
8067
8218
|
...config.decrypt
|
|
8068
8219
|
},
|
|
8220
|
+
persistence: {
|
|
8221
|
+
enabled: true,
|
|
8222
|
+
maxRecords: 100,
|
|
8223
|
+
...config.persistence
|
|
8224
|
+
},
|
|
8069
8225
|
...config
|
|
8070
8226
|
};
|
|
8071
8227
|
try {
|
|
@@ -8073,11 +8229,15 @@ class NetworkDebugger {
|
|
|
8073
8229
|
this.wasmLoader = new WasmLoader();
|
|
8074
8230
|
await this.wasmLoader.loadWasm(this.config.wasm.wasmUrl, this.config.wasm.jsUrl);
|
|
8075
8231
|
}
|
|
8076
|
-
this.interceptor = new NetworkInterceptor(
|
|
8232
|
+
this.interceptor = new NetworkInterceptor({
|
|
8233
|
+
persistence: this.config.persistence?.enabled
|
|
8234
|
+
});
|
|
8077
8235
|
if (this.config.decrypt?.enabled) {
|
|
8078
8236
|
this.interceptor.enableDecryption({
|
|
8079
8237
|
keyExtractor: this.config.decrypt.keyExtractor || this.defaultKeyExtractor,
|
|
8080
|
-
slkExtractor: this.config.decrypt.slkExtractor || this.defaultSlkExtractor
|
|
8238
|
+
slkExtractor: this.config.decrypt.slkExtractor || this.defaultSlkExtractor,
|
|
8239
|
+
autoFetchKeys: this.config.decrypt.autoFetchKeys,
|
|
8240
|
+
keyApiUrl: this.config.decrypt.keyApiUrl
|
|
8081
8241
|
});
|
|
8082
8242
|
}
|
|
8083
8243
|
if (this.config.autoStart !== false) {
|