@whitesev/utils 2.6.9 → 2.7.1
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/README.md +19 -19
- package/dist/index.amd.js +597 -601
- package/dist/index.amd.js.map +1 -1
- package/dist/index.cjs.js +597 -601
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +597 -601
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +597 -601
- package/dist/index.iife.js.map +1 -1
- package/dist/index.system.js +597 -601
- package/dist/index.system.js.map +1 -1
- package/dist/index.umd.js +597 -601
- package/dist/index.umd.js.map +1 -1
- package/dist/types/src/Utils.d.ts +1 -1
- package/dist/types/src/ajaxHooker/ajaxHooker.d.ts +1 -1
- package/package.json +11 -9
- package/src/Utils.ts +4 -4
- package/src/ajaxHooker/ajaxHooker.js +549 -553
|
@@ -1,187 +1,192 @@
|
|
|
1
|
+
// ==UserScript==
|
|
1
2
|
// @name ajaxHooker
|
|
2
3
|
// @author cxxjackie
|
|
3
|
-
// @version 1.4.
|
|
4
|
-
// @updateLog 修复头条、抖音部分站点下this引用错误的问题。
|
|
4
|
+
// @version 1.4.7
|
|
5
5
|
// @supportURL https://bbs.tampermonkey.net.cn/thread-3284-1-1.html
|
|
6
|
+
// @license GNU LGPL-3.0
|
|
7
|
+
// ==/UserScript==
|
|
6
8
|
|
|
7
|
-
export const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
9
|
+
export const ajaxHooker = function () {
|
|
10
|
+
"use strict";
|
|
11
|
+
const version = "1.4.7";
|
|
12
|
+
const hookInst = {
|
|
13
|
+
hookFns: [],
|
|
14
|
+
filters: [],
|
|
15
|
+
};
|
|
16
|
+
const win = window.unsafeWindow || document.defaultView || window;
|
|
17
|
+
let winAh = win.__ajaxHooker;
|
|
18
|
+
const resProto = win.Response.prototype;
|
|
19
|
+
const xhrResponses = ["response", "responseText", "responseXML"];
|
|
20
|
+
const fetchResponses = ["arrayBuffer", "blob", "formData", "json", "text"];
|
|
21
|
+
const xhrExtraProps = ["responseType", "timeout", "withCredentials"];
|
|
22
|
+
const fetchExtraProps = [
|
|
23
|
+
"cache",
|
|
24
|
+
"credentials",
|
|
25
|
+
"integrity",
|
|
26
|
+
"keepalive",
|
|
27
|
+
"mode",
|
|
28
|
+
"priority",
|
|
29
|
+
"redirect",
|
|
30
|
+
"referrer",
|
|
31
|
+
"referrerPolicy",
|
|
32
|
+
"signal",
|
|
33
|
+
];
|
|
34
|
+
const xhrAsyncEvents = ["readystatechange", "load", "loadend"];
|
|
35
|
+
const getType = {}.toString.call.bind({}.toString);
|
|
36
|
+
const getDescriptor = Object.getOwnPropertyDescriptor.bind(Object);
|
|
37
|
+
const emptyFn = () => {};
|
|
38
|
+
const errorFn = (e) => console.error(e);
|
|
39
|
+
function isThenable(obj) {
|
|
40
|
+
return (
|
|
41
|
+
obj &&
|
|
42
|
+
["object", "function"].includes(typeof obj) &&
|
|
43
|
+
typeof obj.then === "function"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
function catchError(fn, ...args) {
|
|
47
|
+
try {
|
|
48
|
+
const result = fn(...args);
|
|
49
|
+
if (isThenable(result)) return result.then(null, errorFn);
|
|
50
|
+
return result;
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error(err);
|
|
46
53
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
}
|
|
55
|
+
function defineProp(obj, prop, getter, setter) {
|
|
56
|
+
Object.defineProperty(obj, prop, {
|
|
57
|
+
configurable: true,
|
|
58
|
+
enumerable: true,
|
|
59
|
+
get: getter,
|
|
60
|
+
set: setter,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function readonly(obj, prop, value = obj[prop]) {
|
|
64
|
+
defineProp(obj, prop, () => value, emptyFn);
|
|
65
|
+
}
|
|
66
|
+
function writable(obj, prop, value = obj[prop]) {
|
|
67
|
+
Object.defineProperty(obj, prop, {
|
|
68
|
+
configurable: true,
|
|
69
|
+
enumerable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
value: value,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function parseHeaders(obj) {
|
|
75
|
+
const headers = {};
|
|
76
|
+
switch (getType(obj)) {
|
|
77
|
+
case "[object String]":
|
|
78
|
+
for (const line of obj.trim().split(/[\r\n]+/)) {
|
|
79
|
+
const [header, value] = line.split(/(?<=^[^:]+)\s*:\s*/);
|
|
80
|
+
if (!value) continue;
|
|
81
|
+
const lheader = header.toLowerCase();
|
|
82
|
+
headers[lheader] =
|
|
83
|
+
lheader in headers ? `${headers[lheader]}, ${value}` : value;
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
case "[object Headers]":
|
|
87
|
+
for (const [key, val] of obj) {
|
|
88
|
+
headers[key] = val;
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
case "[object Object]":
|
|
92
|
+
return { ...obj };
|
|
55
93
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
94
|
+
return headers;
|
|
95
|
+
}
|
|
96
|
+
function stopImmediatePropagation() {
|
|
97
|
+
this.ajaxHooker_isStopped = true;
|
|
98
|
+
}
|
|
99
|
+
class SyncThenable {
|
|
100
|
+
then(fn) {
|
|
101
|
+
fn && fn();
|
|
102
|
+
return new SyncThenable();
|
|
63
103
|
}
|
|
64
|
-
|
|
65
|
-
|
|
104
|
+
}
|
|
105
|
+
class AHRequest {
|
|
106
|
+
constructor(request) {
|
|
107
|
+
this.request = request;
|
|
108
|
+
this.requestClone = { ...this.request };
|
|
66
109
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
enumerable: true,
|
|
71
|
-
writable: true,
|
|
72
|
-
value: value,
|
|
73
|
-
});
|
|
110
|
+
_recoverRequestKey(key) {
|
|
111
|
+
if (key in this.requestClone) this.request[key] = this.requestClone[key];
|
|
112
|
+
else delete this.request[key];
|
|
74
113
|
}
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
headers[key] = val;
|
|
114
|
+
shouldFilter(filters) {
|
|
115
|
+
const { type, url, method, async } = this.request;
|
|
116
|
+
return (
|
|
117
|
+
filters.length &&
|
|
118
|
+
!filters.find((obj) => {
|
|
119
|
+
switch (true) {
|
|
120
|
+
case obj.type && obj.type !== type:
|
|
121
|
+
case getType(obj.url) === "[object String]" &&
|
|
122
|
+
!url.includes(obj.url):
|
|
123
|
+
case getType(obj.url) === "[object RegExp]" && !obj.url.test(url):
|
|
124
|
+
case obj.method &&
|
|
125
|
+
obj.method.toUpperCase() !== method.toUpperCase():
|
|
126
|
+
case "async" in obj && obj.async !== async:
|
|
127
|
+
return false;
|
|
90
128
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
return headers;
|
|
96
|
-
}
|
|
97
|
-
function stopImmediatePropagation() {
|
|
98
|
-
this.ajaxHooker_isStopped = true;
|
|
129
|
+
return true;
|
|
130
|
+
})
|
|
131
|
+
);
|
|
99
132
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
133
|
+
waitForRequestKeys() {
|
|
134
|
+
if (!this.request.async) {
|
|
135
|
+
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
136
|
+
if (this.shouldFilter(filters)) return;
|
|
137
|
+
hookFns.forEach((fn) => {
|
|
138
|
+
if (getType(fn) === "[object Function]")
|
|
139
|
+
catchError(fn, this.request);
|
|
140
|
+
});
|
|
141
|
+
for (const key in this.request) {
|
|
142
|
+
if (isThenable(this.request[key])) this._recoverRequestKey(key);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
103
145
|
return new SyncThenable();
|
|
104
146
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
this.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
case "async" in obj && obj.async !== async:
|
|
124
|
-
return false;
|
|
147
|
+
const promises = [];
|
|
148
|
+
const ignoreKeys = new Set(["type", "async", "response"]);
|
|
149
|
+
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
150
|
+
if (this.shouldFilter(filters)) return;
|
|
151
|
+
promises.push(
|
|
152
|
+
Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
|
|
153
|
+
() => {
|
|
154
|
+
const requestKeys = [];
|
|
155
|
+
for (const key in this.request)
|
|
156
|
+
!ignoreKeys.has(key) && requestKeys.push(key);
|
|
157
|
+
return Promise.all(
|
|
158
|
+
requestKeys.map((key) =>
|
|
159
|
+
Promise.resolve(this.request[key]).then(
|
|
160
|
+
(val) => (this.request[key] = val),
|
|
161
|
+
() => this._recoverRequestKey(key)
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
);
|
|
125
165
|
}
|
|
126
|
-
|
|
127
|
-
})
|
|
166
|
+
)
|
|
128
167
|
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
168
|
+
});
|
|
169
|
+
return Promise.all(promises);
|
|
170
|
+
}
|
|
171
|
+
waitForResponseKeys(response) {
|
|
172
|
+
const responseKeys =
|
|
173
|
+
this.request.type === "xhr" ? xhrResponses : fetchResponses;
|
|
174
|
+
if (!this.request.async) {
|
|
175
|
+
if (getType(this.request.response) === "[object Function]") {
|
|
176
|
+
catchError(this.request.response, response);
|
|
177
|
+
responseKeys.forEach((key) => {
|
|
178
|
+
if (
|
|
179
|
+
"get" in getDescriptor(response, key) ||
|
|
180
|
+
isThenable(response[key])
|
|
181
|
+
) {
|
|
182
|
+
delete response[key];
|
|
183
|
+
}
|
|
143
184
|
});
|
|
144
|
-
return new SyncThenable();
|
|
145
185
|
}
|
|
146
|
-
|
|
147
|
-
win.__ajaxHooker.hookInsts.forEach(({ hookFns, filters }) => {
|
|
148
|
-
if (this.shouldFilter(filters)) return;
|
|
149
|
-
promises.push(
|
|
150
|
-
Promise.all(hookFns.map((fn) => catchError(fn, this.request))).then(
|
|
151
|
-
() =>
|
|
152
|
-
Promise.all(
|
|
153
|
-
requestKeys.map((key) =>
|
|
154
|
-
Promise.resolve(this.request[key]).then(
|
|
155
|
-
(val) => (this.request[key] = val),
|
|
156
|
-
() => (this.request[key] = this.requestClone[key])
|
|
157
|
-
)
|
|
158
|
-
)
|
|
159
|
-
)
|
|
160
|
-
)
|
|
161
|
-
);
|
|
162
|
-
});
|
|
163
|
-
return Promise.all(promises);
|
|
186
|
+
return new SyncThenable();
|
|
164
187
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this.request.type === "xhr" ? xhrResponses : fetchResponses;
|
|
168
|
-
if (!this.request.async) {
|
|
169
|
-
if (getType(this.request.response) === "[object Function]") {
|
|
170
|
-
catchError(this.request.response, response);
|
|
171
|
-
responseKeys.forEach((key) => {
|
|
172
|
-
if (
|
|
173
|
-
"get" in getDescriptor(response, key) ||
|
|
174
|
-
isThenable(response[key])
|
|
175
|
-
) {
|
|
176
|
-
delete response[key];
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
return new SyncThenable();
|
|
181
|
-
}
|
|
182
|
-
return Promise.resolve(
|
|
183
|
-
catchError(this.request.response, response)
|
|
184
|
-
).then(() =>
|
|
188
|
+
return Promise.resolve(catchError(this.request.response, response)).then(
|
|
189
|
+
() =>
|
|
185
190
|
Promise.all(
|
|
186
191
|
responseKeys.map((key) => {
|
|
187
192
|
const descriptor = getDescriptor(response, key);
|
|
@@ -195,422 +200,413 @@ export const AjaxHooker = function () {
|
|
|
195
200
|
}
|
|
196
201
|
})
|
|
197
202
|
)
|
|
198
|
-
|
|
199
|
-
}
|
|
203
|
+
);
|
|
200
204
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const ah = target.__ajaxHooker;
|
|
212
|
-
if (ah && ah.proxyProps) {
|
|
213
|
-
if (prop in ah.proxyProps) {
|
|
214
|
-
const pDescriptor = ah.proxyProps[prop];
|
|
215
|
-
if ("get" in pDescriptor) return pDescriptor.get();
|
|
216
|
-
if (typeof pDescriptor.value === "function")
|
|
217
|
-
return pDescriptor.value.bind(ah);
|
|
218
|
-
return pDescriptor.value;
|
|
219
|
-
}
|
|
220
|
-
if (typeof target[prop] === "function")
|
|
221
|
-
return target[prop].bind(target);
|
|
222
|
-
}
|
|
205
|
+
}
|
|
206
|
+
const proxyHandler = {
|
|
207
|
+
get(target, prop) {
|
|
208
|
+
const descriptor = getDescriptor(target, prop);
|
|
209
|
+
if (
|
|
210
|
+
descriptor &&
|
|
211
|
+
!descriptor.configurable &&
|
|
212
|
+
!descriptor.writable &&
|
|
213
|
+
!descriptor.get
|
|
214
|
+
)
|
|
223
215
|
return target[prop];
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (
|
|
228
|
-
descriptor &&
|
|
229
|
-
!descriptor.configurable &&
|
|
230
|
-
!descriptor.writable &&
|
|
231
|
-
!descriptor.set
|
|
232
|
-
)
|
|
233
|
-
return true;
|
|
234
|
-
const ah = target.__ajaxHooker;
|
|
235
|
-
if (ah && ah.proxyProps && prop in ah.proxyProps) {
|
|
216
|
+
const ah = target.__ajaxHooker;
|
|
217
|
+
if (ah && ah.proxyProps) {
|
|
218
|
+
if (prop in ah.proxyProps) {
|
|
236
219
|
const pDescriptor = ah.proxyProps[prop];
|
|
237
|
-
pDescriptor.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
target[prop] = value;
|
|
242
|
-
}
|
|
243
|
-
return true;
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
class XhrHooker {
|
|
247
|
-
constructor(xhr) {
|
|
248
|
-
const ah = this;
|
|
249
|
-
Object.assign(ah, {
|
|
250
|
-
originalXhr: xhr,
|
|
251
|
-
proxyXhr: new Proxy(xhr, proxyHandler),
|
|
252
|
-
resThenable: new SyncThenable(),
|
|
253
|
-
proxyProps: {},
|
|
254
|
-
proxyEvents: {},
|
|
255
|
-
});
|
|
256
|
-
xhr.addEventListener("readystatechange", (e) => {
|
|
257
|
-
if (
|
|
258
|
-
ah.proxyXhr.readyState === 4 &&
|
|
259
|
-
ah.request &&
|
|
260
|
-
typeof ah.request.response === "function"
|
|
261
|
-
) {
|
|
262
|
-
const response = {
|
|
263
|
-
finalUrl: ah.proxyXhr.responseURL,
|
|
264
|
-
status: ah.proxyXhr.status,
|
|
265
|
-
responseHeaders: parseHeaders(
|
|
266
|
-
ah.proxyXhr.getAllResponseHeaders()
|
|
267
|
-
),
|
|
268
|
-
};
|
|
269
|
-
const tempValues = {};
|
|
270
|
-
for (const key of xhrResponses) {
|
|
271
|
-
try {
|
|
272
|
-
tempValues[key] = ah.originalXhr[key];
|
|
273
|
-
} catch (err) {}
|
|
274
|
-
defineProp(
|
|
275
|
-
response,
|
|
276
|
-
key,
|
|
277
|
-
() => {
|
|
278
|
-
return (response[key] = tempValues[key]);
|
|
279
|
-
},
|
|
280
|
-
(val) => {
|
|
281
|
-
delete response[key];
|
|
282
|
-
response[key] = val;
|
|
283
|
-
}
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
ah.resThenable = new AHRequest(ah.request)
|
|
287
|
-
.waitForResponseKeys(response)
|
|
288
|
-
.then(() => {
|
|
289
|
-
for (const key of xhrResponses) {
|
|
290
|
-
ah.proxyProps[key] = {
|
|
291
|
-
get: () => {
|
|
292
|
-
if (!(key in response)) response[key] = tempValues[key];
|
|
293
|
-
return response[key];
|
|
294
|
-
},
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
ah.dispatchEvent(e);
|
|
300
|
-
});
|
|
301
|
-
xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
|
|
302
|
-
xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
|
|
303
|
-
for (const evt of xhrAsyncEvents) {
|
|
304
|
-
const onEvt = "on" + evt;
|
|
305
|
-
ah.proxyProps[onEvt] = {
|
|
306
|
-
get: () => ah.proxyEvents[onEvt] || null,
|
|
307
|
-
set: (val) => ah.addEvent(onEvt, val),
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
for (const method of [
|
|
311
|
-
"setRequestHeader",
|
|
312
|
-
"addEventListener",
|
|
313
|
-
"removeEventListener",
|
|
314
|
-
"open",
|
|
315
|
-
"send",
|
|
316
|
-
]) {
|
|
317
|
-
ah.proxyProps[method] = { value: ah[method] };
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
toJSON() {} // Converting circular structure to JSON
|
|
321
|
-
addEvent(type, event) {
|
|
322
|
-
if (type.startsWith("on")) {
|
|
323
|
-
this.proxyEvents[type] = typeof event === "function" ? event : null;
|
|
324
|
-
} else {
|
|
325
|
-
if (typeof event === "object" && event !== null)
|
|
326
|
-
event = event.handleEvent;
|
|
327
|
-
if (typeof event !== "function") return;
|
|
328
|
-
this.proxyEvents[type] = this.proxyEvents[type] || new Set();
|
|
329
|
-
this.proxyEvents[type].add(event);
|
|
220
|
+
if ("get" in pDescriptor) return pDescriptor.get();
|
|
221
|
+
if (typeof pDescriptor.value === "function")
|
|
222
|
+
return pDescriptor.value.bind(ah);
|
|
223
|
+
return pDescriptor.value;
|
|
330
224
|
}
|
|
225
|
+
if (typeof target[prop] === "function")
|
|
226
|
+
return target[prop].bind(target);
|
|
331
227
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
228
|
+
return target[prop];
|
|
229
|
+
},
|
|
230
|
+
set(target, prop, value) {
|
|
231
|
+
const descriptor = getDescriptor(target, prop);
|
|
232
|
+
if (
|
|
233
|
+
descriptor &&
|
|
234
|
+
!descriptor.configurable &&
|
|
235
|
+
!descriptor.writable &&
|
|
236
|
+
!descriptor.set
|
|
237
|
+
)
|
|
238
|
+
return true;
|
|
239
|
+
const ah = target.__ajaxHooker;
|
|
240
|
+
if (ah && ah.proxyProps && prop in ah.proxyProps) {
|
|
241
|
+
const pDescriptor = ah.proxyProps[prop];
|
|
242
|
+
pDescriptor.set ? pDescriptor.set(value) : (pDescriptor.value = value);
|
|
243
|
+
} else {
|
|
244
|
+
target[prop] = value;
|
|
340
245
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
246
|
+
return true;
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
class XhrHooker {
|
|
250
|
+
constructor(xhr) {
|
|
251
|
+
const ah = this;
|
|
252
|
+
Object.assign(ah, {
|
|
253
|
+
originalXhr: xhr,
|
|
254
|
+
proxyXhr: new Proxy(xhr, proxyHandler),
|
|
255
|
+
resThenable: new SyncThenable(),
|
|
256
|
+
proxyProps: {},
|
|
257
|
+
proxyEvents: {},
|
|
258
|
+
});
|
|
259
|
+
xhr.addEventListener("readystatechange", (e) => {
|
|
260
|
+
if (
|
|
261
|
+
ah.proxyXhr.readyState === 4 &&
|
|
262
|
+
ah.request &&
|
|
263
|
+
typeof ah.request.response === "function"
|
|
264
|
+
) {
|
|
265
|
+
const response = {
|
|
266
|
+
finalUrl: ah.proxyXhr.responseURL,
|
|
267
|
+
status: ah.proxyXhr.status,
|
|
268
|
+
responseHeaders: parseHeaders(ah.proxyXhr.getAllResponseHeaders()),
|
|
269
|
+
};
|
|
270
|
+
const tempValues = {};
|
|
271
|
+
for (const key of xhrResponses) {
|
|
272
|
+
try {
|
|
273
|
+
tempValues[key] = ah.originalXhr[key];
|
|
274
|
+
} catch (err) {}
|
|
275
|
+
defineProp(
|
|
276
|
+
response,
|
|
277
|
+
key,
|
|
278
|
+
() => {
|
|
279
|
+
return (response[key] = tempValues[key]);
|
|
280
|
+
},
|
|
281
|
+
(val) => {
|
|
282
|
+
delete response[key];
|
|
283
|
+
response[key] = val;
|
|
284
|
+
}
|
|
349
285
|
);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
286
|
+
}
|
|
287
|
+
ah.resThenable = new AHRequest(ah.request)
|
|
288
|
+
.waitForResponseKeys(response)
|
|
289
|
+
.then(() => {
|
|
290
|
+
for (const key of xhrResponses) {
|
|
291
|
+
ah.proxyProps[key] = {
|
|
292
|
+
get: () => {
|
|
293
|
+
if (!(key in response)) response[key] = tempValues[key];
|
|
294
|
+
return response[key];
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
ah.dispatchEvent(e);
|
|
301
|
+
});
|
|
302
|
+
xhr.addEventListener("load", (e) => ah.dispatchEvent(e));
|
|
303
|
+
xhr.addEventListener("loadend", (e) => ah.dispatchEvent(e));
|
|
304
|
+
for (const evt of xhrAsyncEvents) {
|
|
305
|
+
const onEvt = "on" + evt;
|
|
306
|
+
ah.proxyProps[onEvt] = {
|
|
307
|
+
get: () => ah.proxyEvents[onEvt] || null,
|
|
308
|
+
set: (val) => ah.addEvent(onEvt, val),
|
|
309
|
+
};
|
|
354
310
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
311
|
+
for (const method of [
|
|
312
|
+
"setRequestHeader",
|
|
313
|
+
"addEventListener",
|
|
314
|
+
"removeEventListener",
|
|
315
|
+
"open",
|
|
316
|
+
"send",
|
|
317
|
+
]) {
|
|
318
|
+
ah.proxyProps[method] = { value: ah[method] };
|
|
361
319
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
320
|
+
}
|
|
321
|
+
toJSON() {} // Converting circular structure to JSON
|
|
322
|
+
addEvent(type, event) {
|
|
323
|
+
if (type.startsWith("on")) {
|
|
324
|
+
this.proxyEvents[type] = typeof event === "function" ? event : null;
|
|
325
|
+
} else {
|
|
326
|
+
if (typeof event === "object" && event !== null)
|
|
327
|
+
event = event.handleEvent;
|
|
328
|
+
if (typeof event !== "function") return;
|
|
329
|
+
this.proxyEvents[type] = this.proxyEvents[type] || new Set();
|
|
330
|
+
this.proxyEvents[type].add(event);
|
|
368
331
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
332
|
+
}
|
|
333
|
+
removeEvent(type, event) {
|
|
334
|
+
if (type.startsWith("on")) {
|
|
335
|
+
this.proxyEvents[type] = null;
|
|
336
|
+
} else {
|
|
337
|
+
if (typeof event === "object" && event !== null)
|
|
338
|
+
event = event.handleEvent;
|
|
339
|
+
this.proxyEvents[type] && this.proxyEvents[type].delete(event);
|
|
375
340
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
this.openArgs = args;
|
|
388
|
-
this.resThenable = new SyncThenable();
|
|
389
|
-
[
|
|
390
|
-
"responseURL",
|
|
391
|
-
"readyState",
|
|
392
|
-
"status",
|
|
393
|
-
"statusText",
|
|
394
|
-
...xhrResponses,
|
|
395
|
-
].forEach((key) => {
|
|
396
|
-
delete this.proxyProps[key];
|
|
341
|
+
}
|
|
342
|
+
dispatchEvent(e) {
|
|
343
|
+
e.stopImmediatePropagation = stopImmediatePropagation;
|
|
344
|
+
defineProp(e, "target", () => this.proxyXhr);
|
|
345
|
+
defineProp(e, "currentTarget", () => this.proxyXhr);
|
|
346
|
+
defineProp(e, "srcElement", () => this.proxyXhr);
|
|
347
|
+
this.proxyEvents[e.type] &&
|
|
348
|
+
this.proxyEvents[e.type].forEach((fn) => {
|
|
349
|
+
this.resThenable.then(
|
|
350
|
+
() => !e.ajaxHooker_isStopped && fn.call(this.proxyXhr, e)
|
|
351
|
+
);
|
|
397
352
|
});
|
|
398
|
-
|
|
353
|
+
if (e.ajaxHooker_isStopped) return;
|
|
354
|
+
const onEvent = this.proxyEvents["on" + e.type];
|
|
355
|
+
onEvent && this.resThenable.then(onEvent.bind(this.proxyXhr, e));
|
|
356
|
+
}
|
|
357
|
+
setRequestHeader(header, value) {
|
|
358
|
+
this.originalXhr.setRequestHeader(header, value);
|
|
359
|
+
if (!this.request) return;
|
|
360
|
+
const headers = this.request.headers;
|
|
361
|
+
headers[header] =
|
|
362
|
+
header in headers ? `${headers[header]}, ${value}` : value;
|
|
363
|
+
}
|
|
364
|
+
addEventListener(...args) {
|
|
365
|
+
if (xhrAsyncEvents.includes(args[0])) {
|
|
366
|
+
this.addEvent(args[0], args[1]);
|
|
367
|
+
} else {
|
|
368
|
+
this.originalXhr.addEventListener(...args);
|
|
399
369
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
new AHRequest(request).waitForRequestKeys().then(() => {
|
|
407
|
-
if (request.abort) {
|
|
408
|
-
if (typeof request.response === "function") {
|
|
409
|
-
Object.assign(ah.proxyProps, {
|
|
410
|
-
responseURL: { value: request.url },
|
|
411
|
-
readyState: { value: 4 },
|
|
412
|
-
status: { value: 200 },
|
|
413
|
-
statusText: { value: "OK" },
|
|
414
|
-
});
|
|
415
|
-
xhrAsyncEvents.forEach((evt) =>
|
|
416
|
-
xhr.dispatchEvent(new Event(evt))
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
} else {
|
|
420
|
-
xhr.open(
|
|
421
|
-
request.method,
|
|
422
|
-
request.url,
|
|
423
|
-
request.async,
|
|
424
|
-
...ah.openArgs
|
|
425
|
-
);
|
|
426
|
-
for (const header in request.headers) {
|
|
427
|
-
xhr.setRequestHeader(header, request.headers[header]);
|
|
428
|
-
}
|
|
429
|
-
xhr.send(request.data);
|
|
430
|
-
}
|
|
431
|
-
});
|
|
370
|
+
}
|
|
371
|
+
removeEventListener(...args) {
|
|
372
|
+
if (xhrAsyncEvents.includes(args[0])) {
|
|
373
|
+
this.removeEvent(args[0], args[1]);
|
|
374
|
+
} else {
|
|
375
|
+
this.originalXhr.removeEventListener(...args);
|
|
432
376
|
}
|
|
433
377
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
378
|
+
open(method, url, async = true, ...args) {
|
|
379
|
+
this.request = {
|
|
380
|
+
type: "xhr",
|
|
381
|
+
url: url.toString(),
|
|
382
|
+
method: method.toUpperCase(),
|
|
383
|
+
abort: false,
|
|
384
|
+
headers: {},
|
|
385
|
+
data: null,
|
|
386
|
+
response: null,
|
|
387
|
+
async: !!async,
|
|
388
|
+
};
|
|
389
|
+
this.openArgs = args;
|
|
390
|
+
this.resThenable = new SyncThenable();
|
|
391
|
+
[
|
|
392
|
+
"responseURL",
|
|
393
|
+
"readyState",
|
|
394
|
+
"status",
|
|
395
|
+
"statusText",
|
|
396
|
+
...xhrResponses,
|
|
397
|
+
].forEach((key) => {
|
|
398
|
+
delete this.proxyProps[key];
|
|
399
|
+
});
|
|
400
|
+
return this.originalXhr.open(method, url, async, ...args);
|
|
440
401
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
const init = {};
|
|
449
|
-
if (getType(url) === "[object Request]") {
|
|
450
|
-
for (const prop of fetchInitProps) init[prop] = url[prop];
|
|
451
|
-
if (url.body) init.body = await url.arrayBuffer();
|
|
452
|
-
url = url.url;
|
|
453
|
-
}
|
|
454
|
-
url = url.toString();
|
|
455
|
-
Object.assign(init, options);
|
|
456
|
-
init.method = init.method || "GET";
|
|
457
|
-
init.headers = init.headers || {};
|
|
458
|
-
const request = {
|
|
459
|
-
type: "fetch",
|
|
460
|
-
url: url,
|
|
461
|
-
method: init.method.toUpperCase(),
|
|
462
|
-
abort: false,
|
|
463
|
-
headers: parseHeaders(init.headers),
|
|
464
|
-
data: init.body,
|
|
465
|
-
response: null,
|
|
466
|
-
async: true,
|
|
467
|
-
};
|
|
468
|
-
const req = new AHRequest(request);
|
|
469
|
-
await req.waitForRequestKeys();
|
|
402
|
+
send(data) {
|
|
403
|
+
const ah = this;
|
|
404
|
+
const xhr = ah.originalXhr;
|
|
405
|
+
const request = ah.request;
|
|
406
|
+
if (!request) return xhr.send(data);
|
|
407
|
+
request.data = data;
|
|
408
|
+
new AHRequest(request).waitForRequestKeys().then(() => {
|
|
470
409
|
if (request.abort) {
|
|
471
410
|
if (typeof request.response === "function") {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
await req.waitForResponseKeys(response);
|
|
478
|
-
const key = fetchResponses.find((k) => k in response);
|
|
479
|
-
let val = response[key];
|
|
480
|
-
if (key === "json" && typeof val === "object") {
|
|
481
|
-
val = catchError(JSON.stringify.bind(JSON), val);
|
|
482
|
-
}
|
|
483
|
-
const res = new Response(val, {
|
|
484
|
-
status: 200,
|
|
485
|
-
statusText: "OK",
|
|
411
|
+
Object.assign(ah.proxyProps, {
|
|
412
|
+
responseURL: { value: request.url },
|
|
413
|
+
readyState: { value: 4 },
|
|
414
|
+
status: { value: 200 },
|
|
415
|
+
statusText: { value: "OK" },
|
|
486
416
|
});
|
|
487
|
-
|
|
488
|
-
defineProp(res, "url", () => request.url);
|
|
489
|
-
resolve(res);
|
|
490
|
-
} else {
|
|
491
|
-
reject(new DOMException("aborted", "AbortError"));
|
|
417
|
+
xhrAsyncEvents.forEach((evt) => xhr.dispatchEvent(new Event(evt)));
|
|
492
418
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
init.body = request.data;
|
|
498
|
-
winAh.realFetch.call(win, request.url, init).then((res) => {
|
|
499
|
-
if (typeof request.response === "function") {
|
|
500
|
-
const response = {
|
|
501
|
-
finalUrl: res.url,
|
|
502
|
-
status: res.status,
|
|
503
|
-
responseHeaders: parseHeaders(res.headers),
|
|
504
|
-
};
|
|
505
|
-
fetchResponses.forEach(
|
|
506
|
-
(key) =>
|
|
507
|
-
(res[key] = function () {
|
|
508
|
-
if (key in response) return Promise.resolve(response[key]);
|
|
509
|
-
return resProto[key].call(this).then((val) => {
|
|
510
|
-
response[key] = val;
|
|
511
|
-
return req
|
|
512
|
-
.waitForResponseKeys(response)
|
|
513
|
-
.then(() => (key in response ? response[key] : val));
|
|
514
|
-
});
|
|
515
|
-
})
|
|
516
|
-
);
|
|
419
|
+
} else {
|
|
420
|
+
xhr.open(request.method, request.url, request.async, ...ah.openArgs);
|
|
421
|
+
for (const header in request.headers) {
|
|
422
|
+
xhr.setRequestHeader(header, request.headers[header]);
|
|
517
423
|
}
|
|
518
|
-
|
|
519
|
-
|
|
424
|
+
for (const prop of xhrExtraProps) {
|
|
425
|
+
if (prop in request) xhr[prop] = request[prop];
|
|
426
|
+
}
|
|
427
|
+
xhr.send(request.data);
|
|
428
|
+
}
|
|
520
429
|
});
|
|
521
430
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
return res;
|
|
527
|
-
}
|
|
528
|
-
winAh = win.__ajaxHooker = winAh || {
|
|
529
|
-
version,
|
|
530
|
-
fakeXHR,
|
|
531
|
-
fakeFetch,
|
|
532
|
-
fakeFetchClone,
|
|
533
|
-
realXHR: win.XMLHttpRequest,
|
|
534
|
-
realFetch: win.fetch,
|
|
535
|
-
realFetchClone: resProto.clone,
|
|
536
|
-
hookInsts: new Set(),
|
|
537
|
-
};
|
|
538
|
-
if (winAh.version !== version)
|
|
431
|
+
}
|
|
432
|
+
function fakeXHR() {
|
|
433
|
+
const xhr = new winAh.realXHR();
|
|
434
|
+
if ("__ajaxHooker" in xhr)
|
|
539
435
|
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
436
|
+
xhr.__ajaxHooker = new XhrHooker(xhr);
|
|
437
|
+
return xhr.__ajaxHooker.proxyXhr;
|
|
438
|
+
}
|
|
439
|
+
fakeXHR.prototype = win.XMLHttpRequest.prototype;
|
|
440
|
+
Object.keys(win.XMLHttpRequest).forEach(
|
|
441
|
+
(key) => (fakeXHR[key] = win.XMLHttpRequest[key])
|
|
442
|
+
);
|
|
443
|
+
function fakeFetch(url, options = {}) {
|
|
444
|
+
if (!url) return winAh.realFetch.call(win, url, options);
|
|
445
|
+
return new Promise(async (resolve, reject) => {
|
|
446
|
+
const init = {};
|
|
447
|
+
if (getType(url) === "[object Request]") {
|
|
448
|
+
init.method = url.method;
|
|
449
|
+
init.headers = url.headers;
|
|
450
|
+
if (url.body) init.body = await url.arrayBuffer();
|
|
451
|
+
for (const prop of fetchExtraProps) init[prop] = url[prop];
|
|
452
|
+
url = url.url;
|
|
453
|
+
}
|
|
454
|
+
url = url.toString();
|
|
455
|
+
Object.assign(init, options);
|
|
456
|
+
init.method = init.method || "GET";
|
|
457
|
+
init.headers = init.headers || {};
|
|
458
|
+
const request = {
|
|
459
|
+
type: "fetch",
|
|
460
|
+
url: url,
|
|
461
|
+
method: init.method.toUpperCase(),
|
|
462
|
+
abort: false,
|
|
463
|
+
headers: parseHeaders(init.headers),
|
|
464
|
+
data: init.body,
|
|
465
|
+
response: null,
|
|
466
|
+
async: true,
|
|
467
|
+
};
|
|
468
|
+
const req = new AHRequest(request);
|
|
469
|
+
await req.waitForRequestKeys();
|
|
470
|
+
if (request.abort) {
|
|
471
|
+
if (typeof request.response === "function") {
|
|
472
|
+
const response = {
|
|
473
|
+
finalUrl: request.url,
|
|
474
|
+
status: 200,
|
|
475
|
+
responseHeaders: {},
|
|
476
|
+
};
|
|
477
|
+
await req.waitForResponseKeys(response);
|
|
478
|
+
const key = fetchResponses.find((k) => k in response);
|
|
479
|
+
let val = response[key];
|
|
480
|
+
if (key === "json" && typeof val === "object") {
|
|
481
|
+
val = catchError(JSON.stringify.bind(JSON), val);
|
|
482
|
+
}
|
|
483
|
+
const res = new Response(val, {
|
|
484
|
+
status: 200,
|
|
485
|
+
statusText: "OK",
|
|
486
|
+
});
|
|
487
|
+
defineProp(res, "type", () => "basic");
|
|
488
|
+
defineProp(res, "url", () => request.url);
|
|
489
|
+
resolve(res);
|
|
490
|
+
} else {
|
|
491
|
+
reject(new DOMException("aborted", "AbortError"));
|
|
553
492
|
}
|
|
554
|
-
return
|
|
493
|
+
return;
|
|
555
494
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
495
|
+
init.method = request.method;
|
|
496
|
+
init.headers = request.headers;
|
|
497
|
+
init.body = request.data;
|
|
498
|
+
for (const prop of fetchExtraProps) {
|
|
499
|
+
if (prop in request) init[prop] = request[prop];
|
|
500
|
+
}
|
|
501
|
+
winAh.realFetch.call(win, request.url, init).then((res) => {
|
|
502
|
+
if (typeof request.response === "function") {
|
|
503
|
+
const response = {
|
|
504
|
+
finalUrl: res.url,
|
|
505
|
+
status: res.status,
|
|
506
|
+
responseHeaders: parseHeaders(res.headers),
|
|
507
|
+
};
|
|
508
|
+
fetchResponses.forEach(
|
|
509
|
+
(key) =>
|
|
510
|
+
(res[key] = function () {
|
|
511
|
+
if (key in response) return Promise.resolve(response[key]);
|
|
512
|
+
return resProto[key].call(this).then((val) => {
|
|
513
|
+
response[key] = val;
|
|
514
|
+
return req
|
|
515
|
+
.waitForResponseKeys(response)
|
|
516
|
+
.then(() => (key in response ? response[key] : val));
|
|
517
|
+
});
|
|
518
|
+
})
|
|
519
|
+
);
|
|
563
520
|
}
|
|
564
|
-
|
|
521
|
+
resolve(res);
|
|
522
|
+
}, reject);
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
function fakeFetchClone() {
|
|
526
|
+
const descriptors = Object.getOwnPropertyDescriptors(this);
|
|
527
|
+
const res = winAh.realFetchClone.call(this);
|
|
528
|
+
Object.defineProperties(res, descriptors);
|
|
529
|
+
return res;
|
|
530
|
+
}
|
|
531
|
+
winAh = win.__ajaxHooker = winAh || {
|
|
532
|
+
version,
|
|
533
|
+
fakeXHR,
|
|
534
|
+
fakeFetch,
|
|
535
|
+
fakeFetchClone,
|
|
536
|
+
realXHR: win.XMLHttpRequest,
|
|
537
|
+
realFetch: win.fetch,
|
|
538
|
+
realFetchClone: resProto.clone,
|
|
539
|
+
hookInsts: new Set(),
|
|
540
|
+
};
|
|
541
|
+
if (winAh.version !== version)
|
|
542
|
+
console.warn("检测到不同版本的ajaxHooker,可能发生冲突!");
|
|
543
|
+
win.XMLHttpRequest = winAh.fakeXHR;
|
|
544
|
+
win.fetch = winAh.fakeFetch;
|
|
545
|
+
resProto.clone = winAh.fakeFetchClone;
|
|
546
|
+
winAh.hookInsts.add(hookInst);
|
|
547
|
+
// 针对头条、抖音 secsdk.umd.js 的兼容性处理
|
|
548
|
+
class AHFunction extends Function {
|
|
549
|
+
call(thisArg, ...args) {
|
|
550
|
+
if (
|
|
551
|
+
thisArg &&
|
|
552
|
+
thisArg.__ajaxHooker &&
|
|
553
|
+
thisArg.__ajaxHooker.proxyXhr === thisArg
|
|
554
|
+
) {
|
|
555
|
+
thisArg = thisArg.__ajaxHooker.originalXhr;
|
|
565
556
|
}
|
|
557
|
+
return Reflect.apply(this, thisArg, args);
|
|
566
558
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
);
|
|
576
|
-
Object.setPrototypeOf(
|
|
577
|
-
csrf.nativeXMLHttpRequestSend,
|
|
578
|
-
AHFunction.prototype
|
|
579
|
-
);
|
|
559
|
+
apply(thisArg, args) {
|
|
560
|
+
if (
|
|
561
|
+
thisArg &&
|
|
562
|
+
thisArg.__ajaxHooker &&
|
|
563
|
+
thisArg.__ajaxHooker.proxyXhr === thisArg
|
|
564
|
+
) {
|
|
565
|
+
thisArg = thisArg.__ajaxHooker.originalXhr;
|
|
566
|
+
}
|
|
567
|
+
return Reflect.apply(this, thisArg, args || []);
|
|
580
568
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
569
|
+
}
|
|
570
|
+
function hookSecsdk(csrf) {
|
|
571
|
+
Object.setPrototypeOf(
|
|
572
|
+
csrf.nativeXMLHttpRequestSetRequestHeader,
|
|
573
|
+
AHFunction.prototype
|
|
574
|
+
);
|
|
575
|
+
Object.setPrototypeOf(csrf.nativeXMLHttpRequestOpen, AHFunction.prototype);
|
|
576
|
+
Object.setPrototypeOf(csrf.nativeXMLHttpRequestSend, AHFunction.prototype);
|
|
577
|
+
}
|
|
578
|
+
if (win.secsdk) {
|
|
579
|
+
if (win.secsdk.csrf && win.secsdk.csrf.nativeXMLHttpRequestOpen)
|
|
580
|
+
hookSecsdk(win.secsdk.csrf);
|
|
581
|
+
} else {
|
|
582
|
+
defineProp(win, "secsdk", emptyFn, (secsdk) => {
|
|
583
|
+
delete win.secsdk;
|
|
584
|
+
win.secsdk = secsdk;
|
|
585
|
+
defineProp(secsdk, "csrf", emptyFn, (csrf) => {
|
|
586
|
+
delete secsdk.csrf;
|
|
587
|
+
secsdk.csrf = csrf;
|
|
588
|
+
if (csrf.nativeXMLHttpRequestOpen) hookSecsdk(csrf);
|
|
593
589
|
});
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
return {
|
|
593
|
+
hook: (fn) => hookInst.hookFns.push(fn),
|
|
594
|
+
filter: (arr) => {
|
|
595
|
+
if (Array.isArray(arr)) hookInst.filters = arr;
|
|
596
|
+
},
|
|
597
|
+
protect: () => {
|
|
598
|
+
readonly(win, "XMLHttpRequest", winAh.fakeXHR);
|
|
599
|
+
readonly(win, "fetch", winAh.fakeFetch);
|
|
600
|
+
readonly(resProto, "clone", winAh.fakeFetchClone);
|
|
601
|
+
},
|
|
602
|
+
unhook: () => {
|
|
603
|
+
winAh.hookInsts.delete(hookInst);
|
|
604
|
+
if (!winAh.hookInsts.size) {
|
|
605
|
+
writable(win, "XMLHttpRequest", winAh.realXHR);
|
|
606
|
+
writable(win, "fetch", winAh.realFetch);
|
|
607
|
+
writable(resProto, "clone", winAh.realFetchClone);
|
|
608
|
+
delete win.__ajaxHooker;
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
};
|
|
616
612
|
};
|