├── README.md ├── arkose.js ├── jpg ├── 0.jpg └── 2.jpg ├── main.py ├── requirements.txt ├── test.py ├── tls_client ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-310.pyc │ ├── __version__.cpython-310.pyc │ ├── cffi.cpython-310.pyc │ ├── cookies.cpython-310.pyc │ ├── exceptions.cpython-310.pyc │ ├── response.cpython-310.pyc │ ├── sessions.cpython-310.pyc │ ├── settings.cpython-310.pyc │ └── structures.cpython-310.pyc ├── __version__.py ├── cffi.py ├── cookies.py ├── dependencies │ ├── __init__.py │ ├── tls-client-32.dll │ ├── tls-client-64.dll │ ├── tls-client-amd64.so │ ├── tls-client-arm64.dylib │ ├── tls-client-arm64.so │ ├── tls-client-x86.dylib │ └── tls-client-x86.so ├── exceptions.py ├── response.py ├── sessions.py ├── settings.py ├── structures.py └── ua.txt └── webgl.json /README.md: -------------------------------------------------------------------------------- 1 | **Prerequisites** 2 | 3 | Python 3.8 or higher 4 | Required libraries (can be installed via pip install -r requirements.txt) 5 | 6 | 7 | Arkose Labs captcha (FunCaptcha) 8 | You can use the service https://xevil.net/ to process image recognition. 9 | 10 | 11 | **Usage** 12 | Run the script using the following command: 13 | ``` 14 | python main.py 15 | ``` 16 | 17 | 18 | ***How It Works*** 19 | 20 | Create a Task: 21 | The create_task function sends a POST request to create a task. 22 | On success, it retrieves and logs the taskId. 23 | 24 | Poll Task Status: 25 | The process_task function calls get_task to query the status of the created task. 26 | 27 | The status can be: 28 | 29 | Working: The task is in progress. It will retry after a specified interval. 30 | 31 | Success: The task is completed successfully. The result is logged. 32 | 33 | Failed: The task failed. The script logs the failure and exits. 34 | Unknown status: Logs the unknown status and exits. 35 | 36 | Retry Logic: 37 | If the task is Working, it retries for a maximum of MAX_RETRIES (default: 10) with a RETRY_INTERVAL of 3 seconds between attempts. 38 | 39 | 40 | ![IMAGE 2025-01-13 16_21_21.jpg](https://s2.loli.net/2025/01/13/uTqe6sa2GDEF9z4.jpg) 41 | 42 | 43 | 44 | tg: @fun_solverk 45 | -------------------------------------------------------------------------------- /arkose.js: -------------------------------------------------------------------------------- 1 | Qe=function(t) { 2 | "use strict"; 3 | var e = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]; 4 | function n(t, e) { 5 | var n = t[0] 6 | , r = t[1] 7 | , o = t[2] 8 | , i = t[3]; 9 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r & o | ~r & i) + e[0] - 680876936 | 0) << 7 | n >>> 25) + r | 0) & r | ~n & o) + e[1] - 389564586 | 0) << 12 | i >>> 20) + n | 0) & n | ~i & r) + e[2] + 606105819 | 0) << 17 | o >>> 15) + i | 0) & i | ~o & n) + e[3] - 1044525330 | 0) << 22 | r >>> 10) + o | 0, 10 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r & o | ~r & i) + e[4] - 176418897 | 0) << 7 | n >>> 25) + r | 0) & r | ~n & o) + e[5] + 1200080426 | 0) << 12 | i >>> 20) + n | 0) & n | ~i & r) + e[6] - 1473231341 | 0) << 17 | o >>> 15) + i | 0) & i | ~o & n) + e[7] - 45705983 | 0) << 22 | r >>> 10) + o | 0, 11 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r & o | ~r & i) + e[8] + 1770035416 | 0) << 7 | n >>> 25) + r | 0) & r | ~n & o) + e[9] - 1958414417 | 0) << 12 | i >>> 20) + n | 0) & n | ~i & r) + e[10] - 42063 | 0) << 17 | o >>> 15) + i | 0) & i | ~o & n) + e[11] - 1990404162 | 0) << 22 | r >>> 10) + o | 0, 12 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r & o | ~r & i) + e[12] + 1804603682 | 0) << 7 | n >>> 25) + r | 0) & r | ~n & o) + e[13] - 40341101 | 0) << 12 | i >>> 20) + n | 0) & n | ~i & r) + e[14] - 1502002290 | 0) << 17 | o >>> 15) + i | 0) & i | ~o & n) + e[15] + 1236535329 | 0) << 22 | r >>> 10) + o | 0, 13 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r & i | o & ~i) + e[1] - 165796510 | 0) << 5 | n >>> 27) + r | 0) & o | r & ~o) + e[6] - 1069501632 | 0) << 9 | i >>> 23) + n | 0) & r | n & ~r) + e[11] + 643717713 | 0) << 14 | o >>> 18) + i | 0) & n | i & ~n) + e[0] - 373897302 | 0) << 20 | r >>> 12) + o | 0, 14 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r & i | o & ~i) + e[5] - 701558691 | 0) << 5 | n >>> 27) + r | 0) & o | r & ~o) + e[10] + 38016083 | 0) << 9 | i >>> 23) + n | 0) & r | n & ~r) + e[15] - 660478335 | 0) << 14 | o >>> 18) + i | 0) & n | i & ~n) + e[4] - 405537848 | 0) << 20 | r >>> 12) + o | 0, 15 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r & i | o & ~i) + e[9] + 568446438 | 0) << 5 | n >>> 27) + r | 0) & o | r & ~o) + e[14] - 1019803690 | 0) << 9 | i >>> 23) + n | 0) & r | n & ~r) + e[3] - 187363961 | 0) << 14 | o >>> 18) + i | 0) & n | i & ~n) + e[8] + 1163531501 | 0) << 20 | r >>> 12) + o | 0, 16 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r & i | o & ~i) + e[13] - 1444681467 | 0) << 5 | n >>> 27) + r | 0) & o | r & ~o) + e[2] - 51403784 | 0) << 9 | i >>> 23) + n | 0) & r | n & ~r) + e[7] + 1735328473 | 0) << 14 | o >>> 18) + i | 0) & n | i & ~n) + e[12] - 1926607734 | 0) << 20 | r >>> 12) + o | 0, 17 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r ^ o ^ i) + e[5] - 378558 | 0) << 4 | n >>> 28) + r | 0) ^ r ^ o) + e[8] - 2022574463 | 0) << 11 | i >>> 21) + n | 0) ^ n ^ r) + e[11] + 1839030562 | 0) << 16 | o >>> 16) + i | 0) ^ i ^ n) + e[14] - 35309556 | 0) << 23 | r >>> 9) + o | 0, 18 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r ^ o ^ i) + e[1] - 1530992060 | 0) << 4 | n >>> 28) + r | 0) ^ r ^ o) + e[4] + 1272893353 | 0) << 11 | i >>> 21) + n | 0) ^ n ^ r) + e[7] - 155497632 | 0) << 16 | o >>> 16) + i | 0) ^ i ^ n) + e[10] - 1094730640 | 0) << 23 | r >>> 9) + o | 0, 19 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r ^ o ^ i) + e[13] + 681279174 | 0) << 4 | n >>> 28) + r | 0) ^ r ^ o) + e[0] - 358537222 | 0) << 11 | i >>> 21) + n | 0) ^ n ^ r) + e[3] - 722521979 | 0) << 16 | o >>> 16) + i | 0) ^ i ^ n) + e[6] + 76029189 | 0) << 23 | r >>> 9) + o | 0, 20 | r = ((r += ((o = ((o += ((i = ((i += ((n = ((n += (r ^ o ^ i) + e[9] - 640364487 | 0) << 4 | n >>> 28) + r | 0) ^ r ^ o) + e[12] - 421815835 | 0) << 11 | i >>> 21) + n | 0) ^ n ^ r) + e[15] + 530742520 | 0) << 16 | o >>> 16) + i | 0) ^ i ^ n) + e[2] - 995338651 | 0) << 23 | r >>> 9) + o | 0, 21 | r = ((r += ((i = ((i += (r ^ ((n = ((n += (o ^ (r | ~i)) + e[0] - 198630844 | 0) << 6 | n >>> 26) + r | 0) | ~o)) + e[7] + 1126891415 | 0) << 10 | i >>> 22) + n | 0) ^ ((o = ((o += (n ^ (i | ~r)) + e[14] - 1416354905 | 0) << 15 | o >>> 17) + i | 0) | ~n)) + e[5] - 57434055 | 0) << 21 | r >>> 11) + o | 0, 22 | r = ((r += ((i = ((i += (r ^ ((n = ((n += (o ^ (r | ~i)) + e[12] + 1700485571 | 0) << 6 | n >>> 26) + r | 0) | ~o)) + e[3] - 1894986606 | 0) << 10 | i >>> 22) + n | 0) ^ ((o = ((o += (n ^ (i | ~r)) + e[10] - 1051523 | 0) << 15 | o >>> 17) + i | 0) | ~n)) + e[1] - 2054922799 | 0) << 21 | r >>> 11) + o | 0, 23 | r = ((r += ((i = ((i += (r ^ ((n = ((n += (o ^ (r | ~i)) + e[8] + 1873313359 | 0) << 6 | n >>> 26) + r | 0) | ~o)) + e[15] - 30611744 | 0) << 10 | i >>> 22) + n | 0) ^ ((o = ((o += (n ^ (i | ~r)) + e[6] - 1560198380 | 0) << 15 | o >>> 17) + i | 0) | ~n)) + e[13] + 1309151649 | 0) << 21 | r >>> 11) + o | 0, 24 | r = ((r += ((i = ((i += (r ^ ((n = ((n += (o ^ (r | ~i)) + e[4] - 145523070 | 0) << 6 | n >>> 26) + r | 0) | ~o)) + e[11] - 1120210379 | 0) << 10 | i >>> 22) + n | 0) ^ ((o = ((o += (n ^ (i | ~r)) + e[2] + 718787259 | 0) << 15 | o >>> 17) + i | 0) | ~n)) + e[9] - 343485551 | 0) << 21 | r >>> 11) + o | 0, 25 | t[0] = n + t[0] | 0, 26 | t[1] = r + t[1] | 0, 27 | t[2] = o + t[2] | 0, 28 | t[3] = i + t[3] | 0 29 | } 30 | function r(t) { 31 | var e, n = []; 32 | for (e = 0; e < 64; e += 4) 33 | n[e >> 2] = t.charCodeAt(e) + (t.charCodeAt(e + 1) << 8) + (t.charCodeAt(e + 2) << 16) + (t.charCodeAt(e + 3) << 24); 34 | return n 35 | } 36 | function o(t) { 37 | var e, n = []; 38 | for (e = 0; e < 64; e += 4) 39 | n[e >> 2] = t[e] + (t[e + 1] << 8) + (t[e + 2] << 16) + (t[e + 3] << 24); 40 | return n 41 | } 42 | function i(t) { 43 | var e, o, i, a, c, u, s = t.length, f = [1732584193, -271733879, -1732584194, 271733878]; 44 | for (e = 64; e <= s; e += 64) 45 | n(f, r(t.substring(e - 64, e))); 46 | for (o = (t = t.substring(e - 64)).length, 47 | i = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 48 | e = 0; e < o; e += 1) 49 | i[e >> 2] |= t.charCodeAt(e) << (e % 4 << 3); 50 | if (i[e >> 2] |= 128 << (e % 4 << 3), 51 | e > 55) 52 | for (n(f, i), 53 | e = 0; e < 16; e += 1) 54 | i[e] = 0; 55 | return a = (a = 8 * s).toString(16).match(/(.*?)(.{0,8})$/), 56 | c = parseInt(a[2], 16), 57 | u = parseInt(a[1], 16) || 0, 58 | i[14] = c, 59 | i[15] = u, 60 | n(f, i), 61 | f 62 | } 63 | function a(t) { 64 | var e, r, i, a, c, u, s = t.length, f = [1732584193, -271733879, -1732584194, 271733878]; 65 | for (e = 64; e <= s; e += 64) 66 | n(f, o(t.subarray(e - 64, e))); 67 | for (r = (t = e - 64 < s ? t.subarray(e - 64) : new Uint8Array(0)).length, 68 | i = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 69 | e = 0; e < r; e += 1) 70 | i[e >> 2] |= t[e] << (e % 4 << 3); 71 | if (i[e >> 2] |= 128 << (e % 4 << 3), 72 | e > 55) 73 | for (n(f, i), 74 | e = 0; e < 16; e += 1) 75 | i[e] = 0; 76 | return a = (a = 8 * s).toString(16).match(/(.*?)(.{0,8})$/), 77 | c = parseInt(a[2], 16), 78 | u = parseInt(a[1], 16) || 0, 79 | i[14] = c, 80 | i[15] = u, 81 | n(f, i), 82 | f 83 | } 84 | function c(t) { 85 | var n, r = ""; 86 | for (n = 0; n < 4; n += 1) 87 | r += e[t >> 8 * n + 4 & 15] + e[t >> 8 * n & 15]; 88 | return r 89 | } 90 | function u(t) { 91 | var e; 92 | for (e = 0; e < t.length; e += 1) 93 | t[e] = c(t[e]); 94 | return t.join("") 95 | } 96 | function s(t) { 97 | return /[\u0080-\uFFFF]/.test(t) && (t = unescape(encodeURIComponent(t))), 98 | t 99 | } 100 | function f(t, e) { 101 | var n, r = t.length, o = new ArrayBuffer(r), i = new Uint8Array(o); 102 | for (n = 0; n < r; n += 1) 103 | i[n] = t.charCodeAt(n); 104 | return e ? i : o 105 | } 106 | function l(t) { 107 | return String.fromCharCode.apply(null, new Uint8Array(t)) 108 | } 109 | function p(t, e, n) { 110 | var r = new Uint8Array(t.byteLength + e.byteLength); 111 | return r.set(new Uint8Array(t)), 112 | r.set(new Uint8Array(e), t.byteLength), 113 | n ? r : r.buffer 114 | } 115 | function h(t) { 116 | var e, n = [], r = t.length; 117 | for (e = 0; e < r - 1; e += 2) 118 | n.push(parseInt(t.substr(e, 2), 16)); 119 | return String.fromCharCode.apply(String, n) 120 | } 121 | function v() { 122 | this.reset() 123 | } 124 | return u(i("hello")), 125 | "undefined" == typeof ArrayBuffer || ArrayBuffer.prototype.slice || function() { 126 | function e(t, e) { 127 | return (t = 0 | t || 0) < 0 ? Math.max(t + e, 0) : Math.min(t, e) 128 | } 129 | ArrayBuffer.prototype.slice = function(n, r) { 130 | var o, i, a, c, u = this.byteLength, s = e(n, u), f = u; 131 | return r !== t && (f = e(r, u)), 132 | s > f ? new ArrayBuffer(0) : (o = f - s, 133 | i = new ArrayBuffer(o), 134 | a = new Uint8Array(i), 135 | c = new Uint8Array(this,s,o), 136 | a.set(c), 137 | i) 138 | } 139 | }(), 140 | v.prototype.append = function(t) { 141 | return this.appendBinary(s(t)), 142 | this 143 | } 144 | , 145 | v.prototype.appendBinary = function(t) { 146 | this._buff += t, 147 | this._length += t.length; 148 | var e, o = this._buff.length; 149 | for (e = 64; e <= o; e += 64) 150 | n(this._hash, r(this._buff.substring(e - 64, e))); 151 | return this._buff = this._buff.substring(e - 64), 152 | this 153 | } 154 | , 155 | v.prototype.end = function(t) { 156 | var e, n, r = this._buff, o = r.length, i = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 157 | for (e = 0; e < o; e += 1) 158 | i[e >> 2] |= r.charCodeAt(e) << (e % 4 << 3); 159 | return this._finish(i, o), 160 | n = u(this._hash), 161 | t && (n = h(n)), 162 | this.reset(), 163 | n 164 | } 165 | , 166 | v.prototype.reset = function() { 167 | return this._buff = "", 168 | this._length = 0, 169 | this._hash = [1732584193, -271733879, -1732584194, 271733878], 170 | this 171 | } 172 | , 173 | v.prototype.getState = function() { 174 | return { 175 | buff: this._buff, 176 | length: this._length, 177 | hash: this._hash.slice() 178 | } 179 | } 180 | , 181 | v.prototype.setState = function(t) { 182 | return this._buff = t.buff, 183 | this._length = t.length, 184 | this._hash = t.hash, 185 | this 186 | } 187 | , 188 | v.prototype.destroy = function() { 189 | delete this._hash, 190 | delete this._buff, 191 | delete this._length 192 | } 193 | , 194 | v.prototype._finish = function(t, e) { 195 | var r, o, i, a = e; 196 | if (t[a >> 2] |= 128 << (a % 4 << 3), 197 | a > 55) 198 | for (n(this._hash, t), 199 | a = 0; a < 16; a += 1) 200 | t[a] = 0; 201 | r = (r = 8 * this._length).toString(16).match(/(.*?)(.{0,8})$/), 202 | o = parseInt(r[2], 16), 203 | i = parseInt(r[1], 16) || 0, 204 | t[14] = o, 205 | t[15] = i, 206 | n(this._hash, t) 207 | } 208 | , 209 | v.hash = function(t, e) { 210 | return v.hashBinary(s(t), e) 211 | } 212 | , 213 | v.hashBinary = function(t, e) { 214 | var n = u(i(t)); 215 | return e ? h(n) : n 216 | } 217 | , 218 | v.ArrayBuffer = function() { 219 | this.reset() 220 | } 221 | , 222 | v.ArrayBuffer.prototype.append = function(t) { 223 | var e, r = p(this._buff.buffer, t, !0), i = r.length; 224 | for (this._length += t.byteLength, 225 | e = 64; e <= i; e += 64) 226 | n(this._hash, o(r.subarray(e - 64, e))); 227 | return this._buff = e - 64 < i ? new Uint8Array(r.buffer.slice(e - 64)) : new Uint8Array(0), 228 | this 229 | } 230 | , 231 | v.ArrayBuffer.prototype.end = function(t) { 232 | var e, n, r = this._buff, o = r.length, i = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 233 | for (e = 0; e < o; e += 1) 234 | i[e >> 2] |= r[e] << (e % 4 << 3); 235 | return this._finish(i, o), 236 | n = u(this._hash), 237 | t && (n = h(n)), 238 | this.reset(), 239 | n 240 | } 241 | , 242 | v.ArrayBuffer.prototype.reset = function() { 243 | return this._buff = new Uint8Array(0), 244 | this._length = 0, 245 | this._hash = [1732584193, -271733879, -1732584194, 271733878], 246 | this 247 | } 248 | , 249 | v.ArrayBuffer.prototype.getState = function() { 250 | var t = v.prototype.getState.call(this); 251 | return t.buff = l(t.buff), 252 | t 253 | } 254 | , 255 | v.ArrayBuffer.prototype.setState = function(t) { 256 | return t.buff = f(t.buff, !0), 257 | v.prototype.setState.call(this, t) 258 | } 259 | , 260 | v.ArrayBuffer.prototype.destroy = v.prototype.destroy, 261 | v.ArrayBuffer.prototype._finish = v.prototype._finish, 262 | v.ArrayBuffer.hash = function(t, e) { 263 | var n = u(a(new Uint8Array(t))); 264 | return e ? h(n) : n 265 | } 266 | , 267 | v 268 | } 269 | 270 | data=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 271 | 272 | let genkey = function (t, e) { 273 | function transformString(str) { 274 | let transformed = '' 275 | for (let i = 0; i < str.length; i += 2) { 276 | let e = str.charCodeAt(i) 277 | let n = str.charCodeAt(i + 1) 278 | transformed += String.fromCharCode((data[e] << 4) + data[n]) 279 | } 280 | return transformed 281 | } 282 | let u = t + transformString(e) 283 | let s = [] 284 | s[0] = Qe().hashBinary(u, true) 285 | let f = s[0] 286 | for (let l = 1; l < 3; l++) { 287 | s[l] = Qe().hashBinary(s[l - 1] + u, true) 288 | f += s[l] 289 | } 290 | function toUint8Array(str) { 291 | let array = new Uint8Array(str.length) 292 | for (let i = 0; i < str.length; ++i) { 293 | array[i] = str.charCodeAt(i) 294 | } 295 | return array 296 | } 297 | return toUint8Array(f.substring(0, 32)) 298 | } 299 | 300 | randsigbyte=function(e) { 301 | for (var r, n = [], i = function(e) { 302 | var r = 987654321 303 | , n = 4294967295; 304 | return function() { 305 | var i = ((r = 36969 * (65535 & r) + (r >> 16) & n) << 16) + (e = 18e3 * (65535 & e) + (e >> 16) & n) & n; 306 | return i /= 4294967296, 307 | (i += .5) * (Math.random() > .5 ? 1 : -1) 308 | } 309 | }, o = 0; o < e; o += 4) { 310 | var s = i(4294967296 * (r || Math.random())); 311 | r = 987654071 * s(), 312 | n.push(4294967296 * s() | 0) 313 | } 314 | return n 315 | } 316 | 317 | var x64Add = function (t, r) { 318 | (t = [t[0] >>> 16, 65535 & t[0], t[1] >>> 16, 65535 & t[1]]), 319 | (r = [r[0] >>> 16, 65535 & r[0], r[1] >>> 16, 65535 & r[1]]); 320 | var e = [0, 0, 0, 0]; 321 | return ((e[3] += t[3] + r[3]), 322 | (e[2] += e[3] >>> 16), 323 | (e[3] &= 65535), 324 | (e[2] += t[2] + r[2]), 325 | (e[1] += e[2] >>> 16), 326 | (e[2] &= 65535), 327 | (e[1] += t[1] + r[1]), 328 | (e[0] += e[1] >>> 16), 329 | (e[1] &= 65535), 330 | (e[0] += t[0] + r[0]), 331 | (e[0] &= 65535), 332 | [(e[0] << 16) | e[1], (e[2] << 16) | e[3]]); 333 | }, 334 | 335 | x64Multiply = function (t, r) { 336 | (t = [t[0] >>> 16, 65535 & t[0], t[1] >>> 16, 65535 & t[1]]), 337 | (r = [r[0] >>> 16, 65535 & r[0], r[1] >>> 16, 65535 & r[1]]); 338 | var e = [0, 0, 0, 0]; 339 | return ((e[3] += t[3] * r[3]), 340 | (e[2] += e[3] >>> 16), 341 | (e[3] &= 65535), 342 | (e[2] += t[2] * r[3]), 343 | (e[1] += e[2] >>> 16), 344 | (e[2] &= 65535), 345 | (e[2] += t[3] * r[2]), 346 | (e[1] += e[2] >>> 16), 347 | (e[2] &= 65535), 348 | (e[1] += t[1] * r[3]), 349 | (e[0] += e[1] >>> 16), 350 | (e[1] &= 65535), 351 | (e[1] += t[2] * r[2]), 352 | (e[0] += e[1] >>> 16), 353 | (e[1] &= 65535), 354 | (e[1] += t[3] * r[1]), 355 | (e[0] += e[1] >>> 16), 356 | (e[1] &= 65535), 357 | (e[0] += t[0] * r[3] + t[1] * r[2] + t[2] * r[1] + t[3] * r[0]), 358 | (e[0] &= 65535), 359 | [(e[0] << 16) | e[1], (e[2] << 16) | e[3]]); 360 | }, 361 | 362 | x64Rotl = function (t, r) { 363 | return 32 === (r %= 64) 364 | ? [t[1], t[0]] 365 | : r < 32 366 | ? [ 367 | (t[0] << r) | (t[1] >>> (32 - r)), 368 | (t[1] << r) | (t[0] >>> (32 - r)), 369 | ] 370 | : ((r -= 32), 371 | [ 372 | (t[1] << r) | (t[0] >>> (32 - r)), 373 | (t[0] << r) | (t[1] >>> (32 - r)), 374 | ]); 375 | }, 376 | 377 | x64LeftShift = function (t, r) { 378 | return 0 === (r %= 64) 379 | ? t 380 | : r < 32 381 | ? [(t[0] << r) | (t[1] >>> (32 - r)), t[1] << r] 382 | : [t[1] << (r - 32), 0]; 383 | }, 384 | 385 | x64Xor = function (t, r) { 386 | return [t[0] ^ r[0], t[1] ^ r[1]]; 387 | }, 388 | 389 | x64Fmix = function (t) { 390 | return ((t = x64Xor(t, [0, t[0] >>> 1])), 391 | (t = x64Multiply(t, [4283543511, 3981806797])), 392 | (t = x64Xor(t, [0, t[0] >>> 1])), 393 | (t = x64Multiply(t, [3301882366, 444984403])), 394 | (t = x64Xor(t, [0, t[0] >>> 1]))); 395 | }, 396 | 397 | x64hash128 = function (t, r) { 398 | r = r || 0; 399 | for (var e = (t = t || "").length % 16, o = t.length - e, x = [0, r], c = [0, r], h = [0, 0], a = [0, 0], d = [2277735313, 289559509], i = [1291169091, 658871167], l = 0; l < o; l += 16) 400 | (h = [ 401 | (255 & t.charCodeAt(l + 4)) | 402 | ((255 & t.charCodeAt(l + 5)) << 8) | 403 | ((255 & t.charCodeAt(l + 6)) << 16) | 404 | ((255 & t.charCodeAt(l + 7)) << 24), 405 | (255 & t.charCodeAt(l)) | 406 | ((255 & t.charCodeAt(l + 1)) << 8) | 407 | ((255 & t.charCodeAt(l + 2)) << 16) | 408 | ((255 & t.charCodeAt(l + 3)) << 24), 409 | ]), 410 | (a = [ 411 | (255 & t.charCodeAt(l + 12)) | 412 | ((255 & t.charCodeAt(l + 13)) << 8) | 413 | ((255 & t.charCodeAt(l + 14)) << 16) | 414 | ((255 & t.charCodeAt(l + 15)) << 24), 415 | (255 & t.charCodeAt(l + 8)) | 416 | ((255 & t.charCodeAt(l + 9)) << 8) | 417 | ((255 & t.charCodeAt(l + 10)) << 16) | 418 | ((255 & t.charCodeAt(l + 11)) << 24), 419 | ]), 420 | (h = x64Multiply(h, d)), 421 | (h = x64Rotl(h, 31)), 422 | (h = x64Multiply(h, i)), 423 | (x = x64Xor(x, h)), 424 | (x = x64Rotl(x, 27)), 425 | (x = x64Add(x, c)), 426 | (x = x64Add(x64Multiply(x, [0, 5]), [0, 1390208809])), 427 | (a = x64Multiply(a, i)), 428 | (a = x64Rotl(a, 33)), 429 | (a = x64Multiply(a, d)), 430 | (c = x64Xor(c, a)), 431 | (c = x64Rotl(c, 31)), 432 | (c = x64Add(c, x)), 433 | (c = x64Add(x64Multiply(c, [0, 5]), [0, 944331445])); 434 | switch (((h = [0, 0]), (a = [0, 0]), e)) { 435 | case 15: 436 | a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 14)], 48)); 437 | case 14: 438 | a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 13)], 40)); 439 | case 13: 440 | a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 12)], 32)); 441 | case 12: 442 | a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 11)], 24)); 443 | case 11: 444 | a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 10)], 16)); 445 | case 10: 446 | a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 9)], 8)); 447 | case 9: 448 | (a = x64Xor(a, [0, t.charCodeAt(l + 8)])), 449 | (a = x64Multiply(a, i)), 450 | (a = x64Rotl(a, 33)), 451 | (a = x64Multiply(a, d)), 452 | (c = x64Xor(c, a)); 453 | case 8: 454 | h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 7)], 56)); 455 | case 7: 456 | h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 6)], 48)); 457 | case 6: 458 | h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 5)], 40)); 459 | case 5: 460 | h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 4)], 32)); 461 | case 4: 462 | h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 3)], 24)); 463 | case 3: 464 | h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 2)], 16)); 465 | case 2: 466 | h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 1)], 8)); 467 | case 1: 468 | (h = x64Xor(h, [0, t.charCodeAt(l)])), 469 | (h = x64Multiply(h, d)), 470 | (h = x64Rotl(h, 31)), 471 | (h = x64Multiply(h, i)), 472 | (x = x64Xor(x, h)); 473 | } 474 | return ((x = x64Xor(x, [0, t.length])), 475 | (c = x64Xor(c, [0, t.length])), 476 | (x = x64Add(x, c)), 477 | (c = x64Add(c, x)), 478 | (x = x64Fmix(x)), 479 | (c = x64Fmix(c)), 480 | (x = x64Add(x, c)), 481 | (c = x64Add(c, x)), 482 | ("00000000" + (x[0] >>> 0).toString(16)).slice(-8) + 483 | ("00000000" + (x[1] >>> 0).toString(16)).slice(-8) + 484 | ("00000000" + (c[0] >>> 0).toString(16)).slice(-8) + 485 | ("00000000" + (c[1] >>> 0).toString(16)).slice(-8)); 486 | }; -------------------------------------------------------------------------------- /jpg/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/jpg/0.jpg -------------------------------------------------------------------------------- /jpg/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/jpg/2.jpg -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import string 2 | import sys 3 | from datetime import datetime 4 | import execjs 5 | import requests 6 | import base64 7 | import json 8 | import threading 9 | import queue 10 | import uuid 11 | import ctypes 12 | import os 13 | import time 14 | import colr 15 | from colorama import Fore as b 16 | import datetime as dt 17 | from typing import Dict, Optional 18 | import tls_client 19 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 20 | from cryptography.hazmat.backends import default_backend 21 | from cryptography.hazmat.primitives import padding 22 | from colorama import Fore as f 23 | from threading import Lock 24 | from fastapi import FastAPI, HTTPException, Request, Header 25 | from fastapi.responses import JSONResponse 26 | from fastapi.middleware.cors import CORSMiddleware 27 | import traceback 28 | import hashlib 29 | import logging 30 | import random 31 | from concurrent.futures import ThreadPoolExecutor 32 | import binascii 33 | from Crypto.Cipher import AES 34 | from Crypto.Util.Padding import pad, unpad 35 | from javascript import require 36 | import contextlib 37 | import struct 38 | from io import BytesIO 39 | import secrets 40 | 41 | 42 | jsdom = require('jsdom') 43 | create_script = require("vm").Script 44 | logging.getLogger('werkzeug').setLevel(logging.ERROR) 45 | with open("webgl.json") as file: 46 | webgls = json.loads(file.read()) 47 | 48 | with open("arkose.js") as file: 49 | gctx = execjs.compile(file.read()) 50 | 51 | 52 | class Utils: 53 | solved = 0 54 | fail = 0 55 | spm = 0 56 | errors = 0 57 | supc = 0 58 | xxsupc = 0 59 | 60 | @contextlib.contextmanager 61 | def suppress_output(self): 62 | with open(os.devnull, 'w') as devnull: 63 | old_stdout = sys.stdout 64 | old_stderr = sys.stderr 65 | try: 66 | sys.stdout = devnull 67 | sys.stderr = devnull 68 | yield 69 | finally: 70 | sys.stdout = old_stdout 71 | sys.stderr = old_stderr 72 | 73 | @staticmethod 74 | def generate_user_agent(): 75 | chrome_version = str(random.randint(100, 129)) 76 | return { 77 | 'user_agent': f'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{chrome_version}.0.0.0 Safari/537.36', 78 | 'chrome_version': chrome_version 79 | } 80 | 81 | @staticmethod 82 | def find(data, value) -> str: 83 | for item in data: 84 | if item["key"] == value: 85 | return item["value"] 86 | 87 | @staticmethod 88 | def newrelic_time() -> str: 89 | a, b = str(time.time()).split(".") 90 | return str(a + b[0:5]) 91 | 92 | @staticmethod 93 | def hex(data: str) -> str: 94 | return ''.join(f'{byte:02x}' for byte in data) 95 | 96 | @staticmethod 97 | def convert_salt(words: list, sig_bytes: list) -> list: 98 | salt = b'' 99 | for word in words: 100 | salt += struct.pack('>I', word & 0xFFFFFFFF) 101 | return salt[:sig_bytes] 102 | 103 | @staticmethod 104 | def randsalt(ctx) -> list: 105 | return ctx.call( 106 | 'randsigbyte', 107 | 8, 108 | ) 109 | 110 | @staticmethod 111 | def int_to_bytes(n: str, length: int) -> bytes: 112 | return n.to_bytes(length, byteorder='big', signed=True) 113 | 114 | @staticmethod 115 | def to_sigbytes(words: list, sigBytes: int) -> list: 116 | result = b''.join(Utils.int_to_bytes(word, 4) for word in words) 117 | return result[:sigBytes] 118 | 119 | @staticmethod 120 | def bytes_to_buffer(data: bytes) -> list: 121 | buffer = BytesIO(data) 122 | buffer.seek(0) 123 | content = buffer.read() 124 | return list(content) 125 | 126 | @staticmethod 127 | def random_integer(value: int) -> int: 128 | max_random_value = (2 ** 32 // value) * value 129 | while True: 130 | a = secrets.randbelow(2 ** 32) 131 | if a < max_random_value: 132 | return a % value 133 | 134 | @staticmethod 135 | def dict_to_list(data: dict) -> list: 136 | result = [] 137 | for obj in data: 138 | result.append(data[obj]) 139 | 140 | return result 141 | 142 | @staticmethod 143 | def uint8_array(size: int) -> list: 144 | v = bytearray(size) 145 | for i in range(len(v)): 146 | v[i] = Utils.random_integer(256) 147 | return Utils.bytes_to_buffer(v) 148 | 149 | @staticmethod 150 | def convert_key_to_sigbytes_format(key: bytes) -> list: 151 | key_words = [] 152 | for i in range(0, len(key), 4): 153 | word = struct.unpack('>i', key[i:i + 4])[0] 154 | key_words.append(word) 155 | return key_words 156 | 157 | @staticmethod 158 | def get_coords(num: int) -> tuple: 159 | map = { 160 | 1: [0, 0, 100, 100], 161 | 2: [100, 0, 200, 100], 162 | 3: [200, 0, 300, 100], 163 | 4: [0, 100, 100, 200], 164 | 5: [100, 100, 200, 200], 165 | 6: [200, 100, 300, 200] 166 | } 167 | 168 | x1, y1, x2, y2 = map[num] 169 | x = (x1 + x2) / 2 170 | y = (y1 + y2) / 2 171 | 172 | if random.randint(0, 1): 173 | x += random.uniform(10.00001, 45.99999) 174 | else: 175 | x -= random.uniform(10.00001, 45.99999) 176 | 177 | if random.randint(0, 1): 178 | y += random.randint(0, 45) 179 | else: 180 | y -= random.randint(0, 45) 181 | 182 | return (float(x), int(y)) 183 | 184 | @staticmethod 185 | def grid_answer_dict(answer): 186 | x, y = Utils.get_coords(answer) 187 | 188 | return { 189 | "px": str(round((x / 300), 2)), 190 | "py": str(round((y / 200), 2)), 191 | "x": x, 192 | "y": y 193 | } 194 | 195 | 196 | 197 | class logger: 198 | colors_table = { 199 | "green": "#65fb07", 200 | "red": "#Fb0707", 201 | "yellow": "#c4bc18", 202 | "magenta": "#b207f5", 203 | "blue": "#001aff", 204 | "cyan": "#07baf5", 205 | "gray": "#3a3d40", 206 | "white": "#ffffff", 207 | "pink": "#c203fc", 208 | "light_blue": "#07f0ec", 209 | "orange": "#FFA200", 210 | "purple": "#4500d0" 211 | } 212 | 213 | @staticmethod 214 | def convert(color): 215 | if not color.__contains__("#"): 216 | return logger.colors_table[color] 217 | else: 218 | return color 219 | 220 | @staticmethod 221 | def color(c, obj): 222 | return colr.Colr().hex(logger.convert(c), obj) 223 | 224 | def print(*args: str) -> None: 225 | current_time = dt.datetime.now() 226 | date = current_time.strftime(f'%H:%M:%S') 227 | print( 228 | f"{logger.color('white', date)} {f.BLUE}| {b.BLUE}{logger.color('purple', 'Funcaptcha')}{b.RESET} | {' | '.join(args)}".replace( 229 | "|", f"{f.LIGHTBLACK_EX}|{f.WHITE}")) 230 | 231 | 232 | class solver_stats: 233 | @staticmethod 234 | def calc_cpm(): 235 | 236 | while True: 237 | try: 238 | before = Utils.solved 239 | time.sleep(15) 240 | after = Utils.solved 241 | Utils.spm = (after - before) * 4 242 | except Exception as e: 243 | print(f"Error in calc_cpm: {e}") 244 | Utils.spm = 0 245 | 246 | @staticmethod 247 | def rate(part, total): 248 | try: 249 | return str(round(part / total * 100, 4)) if total > 0 else "0.0000" 250 | except Exception as e: 251 | print(f"Error in rate calculation: {e}") 252 | return "unknown" 253 | 254 | @staticmethod 255 | def title(): 256 | 257 | import platform 258 | is_windows = platform.system() == "Windows" 259 | 260 | def clear_screen(): 261 | if is_windows: 262 | os.system("cls") 263 | else: 264 | os.system("clear") 265 | 266 | clear_screen() 267 | 268 | second = 0 269 | minute = 0 270 | hours = 0 271 | days = 0 272 | 273 | while True: 274 | second += 1 275 | if second == 60: 276 | second = 0 277 | minute += 1 278 | if minute == 60: 279 | minute = 0 280 | hours += 1 281 | if hours == 24: 282 | hours = 0 283 | days += 1 284 | 285 | elapsed = f"{str(days).zfill(2)}:{str(hours).zfill(2)}:{str(minute).zfill(2)}:{str(second).zfill(2)}" 286 | 287 | if is_windows: 288 | try: 289 | ctypes.windll.kernel32.SetConsoleTitleW( 290 | f"Funcaptcha | solved: {str(Utils.solved)} | fail: {str(Utils.fail)} | spm: {str(Utils.spm)} | sup: {solver_stats.rate(Utils.supc, Utils.supc + Utils.xxsupc)}% | suc: {solver_stats.rate(Utils.solved, Utils.solved + Utils.fail)}% | errors: {Utils.errors} | elapsed: {elapsed}" 291 | ) 292 | except Exception as e: 293 | print(f"Failed to set console title: {e}") 294 | 295 | else: 296 | print( 297 | f"Elapsed: {elapsed} | solved: {Utils.solved} | fail: {Utils.fail} | spm: {Utils.spm} | sup: {solver_stats.rate(Utils.supc, Utils.supc + Utils.xxsupc)}% | suc: {solver_stats.rate(Utils.solved, Utils.solved + Utils.fail)}% | errors: {Utils.errors}", 298 | end="\r", 299 | ) 300 | 301 | time.sleep(1) 302 | 303 | 304 | class Arkose: 305 | @staticmethod 306 | def decrypt_data(data, main): 307 | ciphertext = base64.b64decode(data['ct']) 308 | iv_bytes = binascii.unhexlify(data['iv']) 309 | salt_bytes = binascii.unhexlify(data['s']) 310 | salt_words = Arkose.from_sigbytes(salt_bytes) 311 | key_words = Arkose.generate_other_key(main, salt_words) 312 | key_bytes = Utils.to_sigbytes(key_words, 32) 313 | iv_bytes = Utils.to_sigbytes(key_words[-4:], 16) 314 | cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes) 315 | plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) 316 | return plaintext 317 | 318 | @staticmethod 319 | def from_sigbytes(sigBytes: bytes) -> list: 320 | padded_length = (len(sigBytes) + 3) // 4 * 4 321 | padded_bytes = sigBytes.ljust(padded_length, b'\0') 322 | 323 | words = [int.from_bytes(padded_bytes[i:i + 4], byteorder='big') for i in range(0, len(padded_bytes), 4)] 324 | return words 325 | 326 | @staticmethod 327 | def encrypt_double(self, main: str, extra: str) -> str: 328 | salt_words = Utils.randsalt(gctx) 329 | key_words = Arkose.generate_other_key(main, salt_words) 330 | key_bytes = Utils.to_sigbytes(key_words, 32) 331 | iv_bytes = Utils.to_sigbytes(key_words[-4:], 16) 332 | salt_bytes = Utils.to_sigbytes(salt_words, 8) 333 | cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes) 334 | ciphertext = cipher.encrypt(pad(extra.encode('utf-8'), AES.block_size)) 335 | 336 | return json.dumps({ 337 | "ct": base64.b64encode(ciphertext).decode(), 338 | "iv": Utils.hex(iv_bytes), 339 | "s": Utils.hex(salt_bytes) 340 | }).replace(" ", "") 341 | 342 | def is_flagged(data): 343 | if not data or not isinstance(data, list): 344 | return False 345 | values = [value for d in data for value in d.values()] 346 | if not values: 347 | return False 348 | 349 | def ends_with_uppercase(value): 350 | return value and value[-1] in string.ascii_uppercase 351 | 352 | return all(ends_with_uppercase(value) for value in values) 353 | 354 | @staticmethod 355 | def t_guess(self, session_token: str, guesses: list, dapibCode: str) -> str: 356 | sess, ion = session_token.split(".") 357 | answers = [] 358 | for guess in guesses: 359 | if "index" in str(guesses): 360 | answers.append({"index": json.loads(guess)["index"], sess: ion, }) 361 | else: 362 | guess = json.loads(guess) 363 | answers.append({"px": guess['px'], "py": guess['py'], "x": guess['x'], "y": guess['y'], sess: ion}) 364 | 365 | resource_loader = jsdom.ResourceLoader({ 366 | "userAgent": self.useragent 367 | }) 368 | vm = jsdom.JSDOM("", { 369 | "runScripts": "dangerously", 370 | "resources": resource_loader, 371 | "pretendToBeVisual": True, 372 | "storageQuota": 10000000 373 | 374 | }).getInternalVMContext() 375 | 376 | create_script(""" 377 | response=null; 378 | 379 | window.parent.ae={"answer":answers} 380 | 381 | window.parent.ae[("dapibRecei" + "ve")]=function(data) { 382 | response=JSON.stringify(data); 383 | } 384 | """.replace("answers", json.dumps(answers).replace('"index"', 'index'))).runInContext(vm) 385 | 386 | create_script(dapibCode).runInContext(vm) 387 | result = json.loads(create_script("response").runInContext(vm)) 388 | 389 | if Arkose.is_flagged(result["tanswer"]): 390 | for array in result["tanswer"]: 391 | for item in array: 392 | array[item] = array[item][:-1] 393 | 394 | return Arkose.encrypt_double(self, session_token, json.dumps(result["tanswer"]).replace(" ", "")) 395 | 396 | @staticmethod 397 | def generate_key_(password: str, salt: bytes, key_size: int, iterations: int) -> bytes: 398 | hasher = hashlib.md5() 399 | key = b'' 400 | block = None 401 | 402 | while len(key) < key_size: 403 | if block: 404 | hasher.update(block) 405 | hasher.update(password.encode()) 406 | hasher.update(salt) 407 | block = hasher.digest() 408 | hasher = hashlib.md5() 409 | 410 | for _ in range(1, iterations): 411 | hasher.update(block) 412 | block = hasher.digest() 413 | hasher = hashlib.md5() 414 | 415 | key += block 416 | 417 | return key[:key_size] 418 | 419 | @staticmethod 420 | def generate_other_key(data: str, salt: list) -> list: 421 | sig_bytes = 8 422 | key_size = 48 423 | iterations = 1 424 | salt = Utils.convert_salt(salt, sig_bytes) 425 | key = Arkose.generate_key_(data, salt, key_size, iterations) 426 | 427 | return Utils.convert_key_to_sigbytes_format(key) 428 | 429 | @staticmethod 430 | def encrypt_ct(text: bytes, key: bytes, iv: bytes) -> bytes: 431 | encryptor = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()).encryptor() 432 | padder = padding.PKCS7(algorithms.AES.block_size).padder() 433 | padded_plain_text = padder.update(text) + padder.finalize() 434 | cipher_text = encryptor.update(padded_plain_text) + encryptor.finalize() 435 | return cipher_text 436 | 437 | @staticmethod 438 | def generate_key(ctx: execjs.compile, s_value: str, useragent: str) -> list: 439 | key = Utils.dict_to_list(ctx.call( 440 | 'genkey', 441 | useragent, 442 | s_value 443 | )) 444 | return key 445 | 446 | @staticmethod 447 | def make_encrypted_dict(self, data: str) -> str: 448 | s_value = Utils.hex(Utils.uint8_array(8)) 449 | iv_value = Utils.uint8_array(16) 450 | key = Arkose.generate_key( 451 | gctx, 452 | s_value, 453 | f"{self.useragent}{self.x_ark_value}" 454 | ) 455 | 456 | result = Arkose.encrypt_ct( 457 | text=bytes(data.encode()), 458 | key=bytes(key), 459 | iv=bytes(iv_value) 460 | ) 461 | 462 | return json.dumps({ 463 | "ct": base64.b64encode(result).decode(), 464 | "s": s_value, 465 | "iv": Utils.hex(iv_value) 466 | }).replace(" ", "") 467 | 468 | @staticmethod 469 | def x_ark_value() -> str: 470 | now = int(time.time()) 471 | return str(now - (now % 21600)) 472 | 473 | @staticmethod 474 | def generate_pt(): 475 | start_time = time.time() 476 | time.sleep(random.uniform(0.04, 0.07)) 477 | end_time = time.time() 478 | 479 | pt = end_time - start_time 480 | return pt 481 | 482 | @staticmethod 483 | def generate_aht(num_trials=random.randint(1, 7)): 484 | total_time = 0 485 | 486 | for _ in range(num_trials): 487 | pt = Arkose.generate_pt() 488 | total_time += pt 489 | 490 | aht = total_time / num_trials 491 | return aht 492 | 493 | @staticmethod 494 | def generate_cs(): 495 | return uuid.uuid4().hex[:10] 496 | 497 | @staticmethod 498 | def generate_g(): 499 | return uuid.uuid4().hex[:12] 500 | 501 | @staticmethod 502 | def generate_h(cs, g): 503 | data_to_hash = cs + g 504 | h = hashlib.sha256(data_to_hash.encode()).hexdigest() 505 | return h 506 | 507 | 508 | 509 | 510 | class Funcaptcha: 511 | def __init__( 512 | self, 513 | apiurl: str, 514 | siteurl: str, 515 | sitekey: str, 516 | data: dict, 517 | blob: str, 518 | custom_cookies: dict, 519 | custom_locale: str, 520 | proxy: Optional[str] = None, 521 | ) -> None: 522 | 523 | self.base64_img = None 524 | ua_data = Utils.generate_user_agent() 525 | print(ua_data) 526 | self.useragent = ua_data['user_agent'] 527 | self.siteurl = siteurl 528 | self.sitekey = sitekey 529 | self.apiurl = apiurl 530 | self.blob = blob 531 | self.clientKey = "abc123" 532 | self.funserver = "http://127.0.0.1:6789/process_image" 533 | 534 | 535 | self.base_headers = { 536 | "User-Agent": self.useragent, 537 | } 538 | 539 | self.session = tls_client.Session( 540 | client_identifier="chrome_120", 541 | random_tls_extension_order=True 542 | ) 543 | if custom_cookies: 544 | self.session.cookies.update(custom_cookies) 545 | 546 | self.available_locales = [ 547 | "en-IN", "en-US", 548 | ] 549 | if custom_locale: 550 | self.locale = custom_locale 551 | else: 552 | self.locale = random.choice(self.available_locales) 553 | 554 | if proxy: 555 | self.session.proxies = {"http": proxy, "https": proxy} 556 | self.session.trust_env = False 557 | 558 | self.x_ark_value = Arkose.x_ark_value() 559 | 560 | captchadata = self.session.get(f"{self.apiurl}/v2/{self.sitekey}/api.js", headers={ 561 | 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 562 | 'accept-language': f'en-US,en;q=0.9,{self.locale};q=0.8,{self.locale.split("-")[0]};q=0.7', 563 | 'upgrade-insecure-requests': '1', 564 | **self.base_headers, 565 | }).text.split("/enforcement.") 566 | 567 | self.capi_version = captchadata[0].split('"')[-1] 568 | self.enforcement_hash = captchadata[1].split('.html')[0] 569 | self.window__ancestor_origins = data["window__ancestor_origins"] 570 | self.window__tree_index = data["window__tree_index"] 571 | self.client_config__sitedata_location_href = data["client_config__sitedata_location_href"] 572 | self.window__tree_structure = data["window__tree_structure"] 573 | 574 | self.session.headers = { 575 | "Accept-Encoding": "gzip, deflate, br, zstd", 576 | "Accept-Language": f"{self.locale},{self.locale.split('-')[0]};q=0.9,en-US;q=0.8,en;q=0.7", 577 | "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", 578 | "Host": self.apiurl.split('https://')[1], 579 | "Referer": f"{self.apiurl}/v2/{self.capi_version}/enforcement.{self.enforcement_hash}.html", 580 | "x-ark-esync-value": self.x_ark_value, 581 | **self.base_headers, 582 | } 583 | 584 | def make_mm(self): 585 | x = random.randint(100, 150) 586 | y = random.randint(30, 90) 587 | 588 | return base64.b64encode(json.dumps({ 589 | "mbio": f"38{random.randint(10, 70)},0,{x},{y};38{random.randint(80, 90)},1,{x},{y};38{random.randint(92, 99)},2,{x},{y};", 590 | "tbio": f"34{random.randint(10, 99)},0,{x},{y};", 591 | "kbio": "" 592 | }).replace(" ", "").encode()).decode() 593 | 594 | def answer(self, result, answers, i): 595 | data = { 596 | 'session_token': self.session_token, 597 | 'game_token': self.gameid, 598 | 'sid': self.r_continent, 599 | 'guess': result, 600 | 'render_type': 'canvas', 601 | 'analytics_tier': '40', 602 | 'bio': self.make_mm(), 603 | 'is_compatibility_mode': 'false', 604 | } 605 | 606 | if self.dapibCode: 607 | data['tguess'] = Arkose.t_guess(self, self.session_token, answers, self.dapibCode) 608 | 609 | response = self.session.post(f'{self.apiurl}/fc/ca/', data=data, headers={ 610 | "Accept-Language": f"{self.locale},{self.locale.split('-')[0]};q=0.9,en-US;q=0.8,en;q=0.7", 611 | "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", 612 | "Host": self.apiurl.split("https://")[1], 613 | "Origin": self.apiurl, 614 | "Referer": f"{self.apiurl}/fc/assets/ec-game-core/game-core/1.22.0/standard/index.html?session={self.token}&r={self.r_continent}&meta=3&meta_width=300&metabgclr=transparent&metaiconclr=%23555555&guitextcolor=%23000000&pk={self.sitekey}&dc=1&at=40&ag=101&cdn_url=https%3A%2F%2F{self.apiurl.split('https://')[1]}%2Fcdn%2Ffc&lurl=https%3A%2F%2Faudio-{self.r_continent}.arkoselabs.com&surl=https%3A%2F%2F{self.apiurl.split('https://')[1]}&smurl=https%3A%2F%2F{self.apiurl.split('https://')[1]}%2Fcdn%2Ffc%2Fassets%2Fstyle-manager&theme=default", 615 | "Sec-Fetch-Site": "same-origin", 616 | "X-NewRelic-Timestamp": Utils.newrelic_time(), 617 | "X-Requested-ID": Arkose.encrypt_double(self, f"REQUESTED{self.token}ID", json.dumps({"sc": [ 618 | random.randint(100, 300), 619 | random.randint(100, 300) 620 | ]}).replace(" ", "")), 621 | "X-Requested-With": "XMLHttpRequest", 622 | **self.base_headers, 623 | }) 624 | return response.json() 625 | 626 | def callback(self, data): 627 | self.session.post(f"{self.apiurl}/fc/a/", data=data, headers={ 628 | "Accept-Language": f"{self.locale},{self.locale.split('-')[0]};q=0.9,en-US;q=0.8,en;q=0.7", 629 | "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", 630 | "Origin": self.apiurl, 631 | "Referer": f"{self.apiurl}/fc/assets/ec-game-core/game-core/1.22.0/standard/index.html?session={self.token}&r={self.r_continent}&meta=7&meta_height=325&metabgclr=%23ffffff&metaiconclr=%23757575&mainbgclr=%23ffffff&maintxtclr=%231B1B1B&guitextcolor=%23747474&lang={self.locale.split('-')[0]}&pk={self.sitekey}&at=40&ag=101&cdn_url=https%3A%2F%2F{self.apiurl.split('https://')[1]}%2Fcdn%2Ffc&lurl=https%3A%2F%2Faudio-{self.r_continent}.arkoselabs.com&surl=https%3A%2F%2F{self.apiurl.split('https://')[1]}&smurl=https%3A%2F%2F{self.apiurl.split('https://')[1]}%2Fcdn%2Ffc%2Fassets%2Fstyle-manager&theme=default", 632 | "Sec-Fetch-Site": "same-origin", 633 | "X-NewRelic-Timestamp": Utils.newrelic_time(), 634 | "X-Requested-With": "XMLHttpRequest", 635 | **self.base_headers, 636 | }) 637 | 638 | def solve(self): 639 | try: 640 | self.solve_time = time.time() 641 | challenge_data = self._generate_challenge() 642 | if "DENIED ACCESS" in str(challenge_data): 643 | return {"success": False, "err": "invalid blob", "token": None} 644 | 645 | del self.session.headers["Content-Type"] 646 | del self.session.headers["x-ark-esync-value"] 647 | self.token = challenge_data["token"].split("|")[0] 648 | logger.print("Token:", f.LIGHTGREEN_EX + self.token) 649 | self.r_continent = challenge_data["token"].split("|r=")[1].split("|")[0] 650 | self.session.get(f'{self.apiurl}/fc/gc/', params={'token': self.token}) 651 | 652 | self.session.headers.update({ 653 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", 654 | "Sec-Fetch-Dest": "iframe", 655 | "Sec-Fetch-Mode": "navigate", 656 | "Upgrade-Insecure-Requests": "1" 657 | }) 658 | referer = self.session.get( 659 | f'{self.apiurl}/fc/assets/ec-game-core/game-core/1.22.0/standard/index.html', 660 | params={ 661 | 'session': self.token, 662 | 'r': self.r_continent, 663 | 'meta': '3', 664 | 'meta_width': '300', 665 | 'metabgclr': 'transparent', 666 | 'metaiconclr': '#555555', 667 | 'guitextcolor': '#000000', 668 | 'pk': self.sitekey, 669 | 'dc': '1', 670 | 'at': '40', 671 | 'ag': '101', 672 | 'cdn_url': f'{self.apiurl}/cdn/fc', 673 | 'lurl': f'https://audio-{self.r_continent}.arkoselabs.com', 674 | 'surl': self.apiurl, 675 | 'smurl': f'{self.apiurl}/cdn/fc/assets/style-manager', 676 | 'theme': 'default' 677 | }).url 678 | self.callback( 679 | {"sid": self.r_continent, "session_token": self.token, "analytics_tier": "40", "disableCookies": "true", 680 | "render_type": "canvas", "is_compatibility_mode": "false", "category": "Site URL", 681 | "action": f"{self.apiurl}/v2/{self.capi_version}/enforcement.{self.enforcement_hash}.html"}) 682 | 683 | if "sup=1|" in challenge_data["token"]: 684 | self.session.headers.update({ 685 | "Sec-Fetch-Dest": "script", 686 | "Sec-Fetch-Mode": "no-cors", 687 | "Sec-Fetch-Site": "same-origin" 688 | }) 689 | 690 | self.session.get( 691 | f"{self.apiurl}/fc/a/", 692 | params={ 693 | "callback": f"__jsonp_{str(int(time.time() * 1000))}", 694 | "category": "loaded", 695 | "action": "game loaded", 696 | "session_token": self.token, 697 | "data[public_key]": self.sitekey, 698 | "data[site]": self.siteurl 699 | } 700 | ) 701 | logger.print("Suppressed", "Waves: 0", f.LIGHTGREEN_EX + self.token) 702 | Utils.solved += 1 703 | Utils.supc += 1 704 | 705 | return {"success": True, "err": None, "token": challenge_data["token"], 706 | "procces_time": time.time() - self.solve_time} 707 | 708 | Utils.xxsupc += 1 709 | self.session.headers.update({ 710 | "referer": referer, 711 | "content-type": "application/x-www-form-urlencoded; charset=UTF-8", 712 | "origin": self.apiurl, 713 | "x-newrelic-timestamp": Utils.newrelic_time(), 714 | "x-requested-with": "XMLHttpRequest", 715 | }) 716 | 717 | result = self._task_data() 718 | 719 | del self.session.headers["content-type"] 720 | del self.session.headers["origin"] 721 | del self.session.headers["x-newrelic-timestamp"] 722 | del self.session.headers["x-requested-with"] 723 | 724 | self.gameid = result["challengeID"] 725 | self.session_token = result["session_token"] 726 | self.callback( 727 | {"sid": self.r_continent, "session_token": self.token, "analytics_tier": "40", "disableCookies": "true", 728 | "game_token": self.gameid, "game_type": "4", "render_type": "canvas", "is_compatibility_mode": "false", 729 | "category": "loaded", "action": "game loaded"}) 730 | 731 | try: 732 | game = result["game_data"]["instruction_string"] 733 | except: 734 | game = result["game_data"]["game_variant"] 735 | 736 | waves = str(result["game_data"]["waves"]) 737 | logger.print(f"Type: {game} Quantity: {waves}") 738 | if int(waves) >= 20: 739 | logger.print(game, ':', str(waves)) 740 | return {"success": False, "err": "too many waves"} 741 | 742 | if result.get("dapib_url"): 743 | self.dapibCode = self.session.get(result["dapib_url"]).text 744 | self.session.get( 745 | f"{self.apiurl}/params/sri/dapib/{result['dapib_url'].split(f'{self.r_continent}/')[1].split('.js')[0]}") 746 | 747 | else: 748 | self.dapibCode = 0 749 | 750 | cs = Arkose.generate_cs() 751 | g = Arkose.generate_g() 752 | self.callback( 753 | {"sid": self.r_continent, "session_token": self.token, "analytics_tier": "40", "disableCookies": "true", 754 | "game_token": self.gameid, "game_type": "4", "render_type": "canvas", "is_compatibility_mode": "false", 755 | "category": "begin app", "action": "user clicked verify", "cs_": cs, 756 | "ct_": str(random.randint(10, 99)), "g_": g, "h_": Arkose.generate_h(cs, g), 757 | "pt_": Arkose.generate_pt(), "aht_": Arkose.generate_aht()}) 758 | 759 | image_encryption_enabled = result["game_data"]["customGUI"].get('encrypted_mode') 760 | if image_encryption_enabled: 761 | self.image_decryption_key = self.session.post(f'{self.apiurl}/fc/ekey/', data={ 762 | 'session_token': self.session_token, 763 | 'game_token': self.gameid, 764 | 'sid': self.r_continent 765 | }).json()['decryption_key'] 766 | 767 | answers = [] 768 | test = [] 769 | total_images = len(result["game_data"]["customGUI"]["_challenge_imgs"]) 770 | logger.print(f"Type: {game} Number: {waves}") 771 | logger.print(f"Total number of images to be processed: {total_images}") 772 | 773 | for img_index, img in enumerate(result["game_data"]["customGUI"]["_challenge_imgs"]): 774 | if image_encryption_enabled: 775 | self.base64_img = Arkose.decrypt_data(self.session.get(img).json(), self.image_decryption_key).decode() 776 | else: 777 | val = self.session.cookies.get('_cfuvid') 778 | self.session.headers.update({ 779 | "Cookie": f"_cfuvid={val}" 780 | }) 781 | 782 | attempt = 0 783 | max_attempts = 10 784 | 785 | while attempt < max_attempts: 786 | try: 787 | response = self.session.get(img) 788 | if response.status_code == 200: 789 | self.base64_img = base64.b64encode(response.content).decode('utf-8') 790 | break 791 | elif response.status_code == 403: 792 | logger.print(f"Attempt {attempt + 1} failed with 403. Retrying...") 793 | else: 794 | logger.print( 795 | f"Attempt {attempt + 1} failed with status code {response.status_code}. Retrying...") 796 | 797 | except requests.exceptions.RequestException as e: 798 | logger.print(f"Attempt {attempt + 1} failed due to exception: {e}") 799 | 800 | attempt += 1 801 | time.sleep(1) 802 | 803 | if attempt == max_attempts: 804 | raise Exception(f"Failed to fetch image after {max_attempts} attempts") 805 | 806 | payload = { 807 | "clientKey": self.clientKey, 808 | "task": { 809 | 'type': 'FunCaptcha', 810 | 'image': self.base64_img, 811 | 'question': game, 812 | } 813 | } 814 | try: 815 | response = requests.post(self.funserver, json=payload, timeout=10) 816 | response_data = response.json() 817 | if response.status_code == 200 and response_data.get("errorId") == 0: 818 | solution = response_data.get("solution", {}) 819 | predicted_index = solution.get("predicted_index", None) 820 | print(f"Image {img_index + 1}/{total_images} Predicted index:", predicted_index) 821 | else: 822 | print(f"Request failed: {response.status_code}") 823 | return {"success": False, "err": "prediction failed", "token": None} 824 | 825 | except Exception as e: 826 | print(f"Error during request for image {img_index + 1}: {e}") 827 | return {"success": False, "err": f"prediction error: {str(e)}", "token": None} 828 | 829 | index = predicted_index 830 | logger.print(f"Image {img_index + 1} index: {index}") 831 | if result["game_data"]["gameType"] == 3: 832 | index += 1 833 | 834 | test.append(str(index)) 835 | 836 | if result["game_data"]["gameType"] == 4: 837 | answers.append(json.dumps({"index": index}).replace(" ", "")) 838 | elif result["game_data"]["gameType"] == 3: 839 | answers.append(json.dumps(Utils.grid_answer_dict(index)).replace(" ", "")) 840 | 841 | logger.print(f"All images processed, submitting answer: [{','.join(test)}]") 842 | 843 | if len(answers) != total_images: 844 | logger.print(f"Error: Got {len(answers)} answers, expected {total_images}") 845 | return {"success": False, "err": "incomplete answers", "token": None} 846 | 847 | solveresult = self.answer( 848 | result=Arkose.encrypt_double(self, self.session_token, str([",".join(answers)]).replace("'", "")), 849 | answers=answers, 850 | i=index 851 | ) 852 | 853 | if image_encryption_enabled: 854 | self.image_decryption_key = solveresult.get('decryption_key') 855 | 856 | if solveresult["solved"]: 857 | logger.print( 858 | game, 859 | f"Waves: {waves}", 860 | f"Answers: {str(len(test))}:[{','.join(test)}]", 861 | f.LIGHTGREEN_EX + self.token 862 | ) 863 | Utils.solved += 1 864 | return { 865 | "game": game, 866 | "waves": waves, 867 | "success": True, 868 | "err": None, 869 | "token": challenge_data["token"], 870 | "procces_time": time.time() - self.solve_time, 871 | } 872 | else: 873 | logger.print( 874 | game, 875 | f"Waves: {waves}", 876 | f"Answers: {str(len(test))}:[{','.join(test)}]", 877 | f.RED + "Failed_to_solve." 878 | ) 879 | Utils.fail += 1 880 | return { 881 | "game": game, 882 | "waves": waves, 883 | "success": False, 884 | "err": "ai_fail", 885 | "token": None, 886 | } 887 | 888 | 889 | 890 | except Exception as err: 891 | logger.print(traceback.format_exc()) 892 | Utils.errors += 1 893 | return {"success": False, "err": "internal error", "token": None} 894 | 895 | def _task_data(self): 896 | return self.session.post(f"{self.apiurl}/fc/gfct/", data={ 897 | 'token': self.token, 898 | 'sid': self.r_continent, 899 | 'render_type': 'canvas', 900 | 'lang': '', 901 | 'isAudioGame': 'false', 902 | 'is_compatibility_mode': 'false', 903 | 'apiBreakerVersion': 'green', 904 | 'analytics_tier': '40', 905 | }).json() 906 | 907 | def md5_hash(self, data): 908 | md5_hash = hashlib.md5() 909 | md5_hash.update(data.encode('utf-8')) 910 | return md5_hash.hexdigest() 911 | 912 | def process_fp(self, fpdata): 913 | result = [] 914 | for item in fpdata: 915 | result.append(item.split(":")[1]) 916 | return ';'.join(result) 917 | 918 | def proccess_webgl2(self, data): 919 | result = [] 920 | 921 | for item in data: 922 | result.append(item["key"]) 923 | result.append(item["value"]) 924 | 925 | return ','.join(result) + ',webgl_hash_webgl,' 926 | 927 | def find(self, data, key): 928 | for item in data: 929 | if item["key"] == key: 930 | return item["value"] 931 | 932 | def random_pixel_depth(self): 933 | pixel_depths = [24, 30] 934 | return random.choice(pixel_depths) 935 | 936 | def bda(self): 937 | time_now = time.time() 938 | 939 | resolutions = [ 940 | (3440, 1440, 3440, 1400), 941 | (1924, 1007, 1924, 1007), 942 | (1920, 1080, 1920, 1040), 943 | (1280, 720, 1280, 672), 944 | (1920, 1080, 1920, 1032), 945 | (1366, 651, 1366, 651), 946 | (1366, 768, 1366, 738), 947 | (1920, 1080, 1920, 1050) 948 | ] 949 | height, width, awidth, aheight = random.choice(resolutions) 950 | 951 | webgl_data = random.choice(webgls) 952 | 953 | self.cfp = webgl_data["fe"]["CFP"] 954 | 955 | fp1 = [ 956 | "DNT:unknown", 957 | f"L:{self.locale}", 958 | "D:24", 959 | "PR:1", 960 | f"S:{height},{width}", 961 | f"AS:{awidth},{aheight}", 962 | "TO:480", 963 | "SS:true", 964 | "LS:true", 965 | "IDB:true", 966 | "B:false", 967 | "ODB:false", 968 | "CPUC:unknown", 969 | "PK:Win32", 970 | f"CFP:{self.cfp}", 971 | "FR:false", 972 | "FOS:false", 973 | "FB:false", 974 | "JSF:Arial,Arial Black,Arial Narrow,Calibri,Cambria,Cambria Math,Comic Sans MS,Consolas,Courier,Courier New,Georgia,Helvetica,Impact,Lucida Console,Lucida Sans Unicode,Microsoft Sans Serif,MS Gothic,MS PGothic,MS Sans Serif,MS Serif,Palatino Linotype,Segoe Print,Segoe Script,Segoe UI,Segoe UI Light,Segoe UI Semibold,Segoe UI Symbol,Tahoma,Times,Times New Roman,Trebuchet MS,Verdana,Wingdings", 975 | "P:Chrome PDF Viewer,Chromium PDF Viewer,Microsoft Edge PDF Viewer,PDF Viewer,WebKit built-in PDF", 976 | "T:0,false,false", 977 | f"H:{random.randint(2, 20)}", 978 | "SWF:false" 979 | ] 980 | 981 | webgl = random.choice(random.choice(webgls)["enhanced_fp"]) 982 | enhanced_fp = [ 983 | { 984 | "key": "webgl_extensions", 985 | "value": webgl["webgl_extensions"] 986 | }, 987 | { 988 | "key": "webgl_extensions_hash", 989 | "value": webgl["webgl_extensions_hash"] 990 | }, 991 | { 992 | "key": "webgl_renderer", 993 | "value": webgl["webgl_renderer"] 994 | }, 995 | { 996 | "key": "webgl_vendor", 997 | "value": webgl["webgl_vendor"] 998 | }, 999 | { 1000 | "key": "webgl_version", 1001 | "value": webgl["webgl_version"] 1002 | }, 1003 | { 1004 | "key": "webgl_shading_language_version", 1005 | "value": webgl["webgl_shading_language_version"] 1006 | }, 1007 | { 1008 | "key": "webgl_aliased_line_width_range", 1009 | "value": webgl["webgl_aliased_line_width_range"] 1010 | }, 1011 | { 1012 | "key": "webgl_aliased_point_size_range", 1013 | "value": webgl["webgl_aliased_point_size_range"] 1014 | }, 1015 | { 1016 | "key": "webgl_antialiasing", 1017 | "value": "yes" 1018 | }, 1019 | { 1020 | "key": "webgl_bits", 1021 | "value": webgl["webgl_bits"] 1022 | }, 1023 | { 1024 | "key": "webgl_max_params", 1025 | "value": webgl["webgl_max_params"] 1026 | }, 1027 | { 1028 | "key": "webgl_max_viewport_dims", 1029 | "value": webgl["webgl_max_viewport_dims"] 1030 | }, 1031 | { 1032 | "key": "webgl_unmasked_vendor", 1033 | "value": webgl["webgl_unmasked_vendor"] 1034 | }, 1035 | { 1036 | "key": "webgl_unmasked_renderer", 1037 | "value": webgl["webgl_unmasked_renderer"] 1038 | }, 1039 | { 1040 | "key": "webgl_vsf_params", 1041 | "value": webgl["webgl_vsf_params"] 1042 | }, 1043 | { 1044 | "key": "webgl_vsi_params", 1045 | "value": webgl["webgl_vsi_params"] 1046 | }, 1047 | { 1048 | "key": "webgl_fsf_params", 1049 | "value": webgl["webgl_fsf_params"] 1050 | }, 1051 | { 1052 | "key": "webgl_fsi_params", 1053 | "value": webgl["webgl_fsi_params"] 1054 | }] 1055 | 1056 | enhanced_fp.append({ 1057 | "key": "webgl_hash_webgl", 1058 | "value": gctx.call("x64hash128", self.proccess_webgl2(enhanced_fp)) 1059 | }) 1060 | 1061 | enhanced_fp_more = [ 1062 | { 1063 | "key": "user_agent_data_brands", 1064 | "value": "Chromium,Not;A=Brand,Google Chrome" 1065 | }, 1066 | { 1067 | "key": "user_agent_data_mobile", 1068 | "value": False 1069 | }, 1070 | { 1071 | "key": "navigator_connection_downlink", 1072 | "value": 10 1073 | }, 1074 | { 1075 | "key": "navigator_connection_downlink_max", 1076 | "value": None 1077 | }, 1078 | { 1079 | "key": "network_info_rtt", 1080 | "value": 50 1081 | }, 1082 | { 1083 | "key": "network_info_save_data", 1084 | "value": False 1085 | }, 1086 | { 1087 | "key": "network_info_rtt_type", 1088 | "value": None 1089 | }, 1090 | { 1091 | "key": "screen_pixel_depth", 1092 | "value": self.random_pixel_depth() 1093 | }, 1094 | { 1095 | "key": "navigator_device_memory", 1096 | "value": 8 1097 | }, 1098 | { 1099 | "key": "navigator_pdf_viewer_enabled", 1100 | "value": True 1101 | }, 1102 | { 1103 | "key": "navigator_languages", 1104 | "value": "en-US,en" 1105 | }, 1106 | { 1107 | "key": "window_inner_width", 1108 | "value": 0 1109 | }, 1110 | { 1111 | "key": "window_inner_height", 1112 | "value": 0 1113 | }, 1114 | { 1115 | "key": "window_outer_width", 1116 | "value": int(width) 1117 | }, 1118 | { 1119 | "key": "window_outer_height", 1120 | "value": int(height) 1121 | }, 1122 | { 1123 | "key": "browser_detection_firefox", 1124 | "value": False 1125 | }, 1126 | { 1127 | "key": "browser_detection_brave", 1128 | "value": False 1129 | }, 1130 | { 1131 | "key": "browser_api_checks", 1132 | "value": [ 1133 | "permission_status: true", 1134 | "eye_dropper: true", 1135 | "audio_data: true", 1136 | "writable_stream: true", 1137 | "css_style_rule: true", 1138 | "navigator_ua: true", 1139 | "barcode_detector: false", 1140 | "display_names: true", 1141 | "contacts_manager: false", 1142 | "svg_discard_element: false", 1143 | "usb: defined", 1144 | "media_device: defined", 1145 | "playback_quality: true" 1146 | ] 1147 | }, 1148 | { 1149 | "key": "browser_object_checks", 1150 | "value": self.md5_hash("chrome") 1151 | }, 1152 | { 1153 | "key": "29s83ih9", 1154 | "value": self.md5_hash("false") + "⁣" 1155 | }, 1156 | { 1157 | "key": "audio_codecs", 1158 | "value": "{\"ogg\":\"probably\",\"mp3\":\"probably\",\"wav\":\"probably\",\"m4a\":\"maybe\",\"aac\":\"probably\"}" 1159 | }, 1160 | { 1161 | "key": "audio_codecs_extended_hash", 1162 | "value": self.md5_hash( 1163 | '{"audio/mp4; codecs=\\"mp4a.40\\"":{"canPlay":"maybe","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.1\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.2\\"":{"canPlay":"probably","mediaSource":true},"audio/mp4; codecs=\\"mp4a.40.3\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.4\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.5\\"":{"canPlay":"probably","mediaSource":true},"audio/mp4; codecs=\\"mp4a.40.6\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.7\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.8\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.9\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.12\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.13\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.14\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.15\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.16\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.17\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.19\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.20\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.21\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.22\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.23\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.24\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.25\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.26\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.27\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.28\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.29\\"":{"canPlay":"probably","mediaSource":true},"audio/mp4; codecs=\\"mp4a.40.32\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.33\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.34\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.35\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.40.36\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"mp4a.66\\"":{"canPlay":"probably","mediaSource":false},"audio/mp4; codecs=\\"mp4a.67\\"":{"canPlay":"probably","mediaSource":true},"audio/mp4; codecs=\\"mp4a.68\\"":{"canPlay":"probably","mediaSource":false},"audio/mp4; codecs=\\"mp4a.69\\"":{"canPlay":"probably","mediaSource":false},"audio/mp4; codecs=\\"mp4a.6B\\"":{"canPlay":"probably","mediaSource":false},"audio/mp4; codecs=\\"mp3\\"":{"canPlay":"probably","mediaSource":false},"audio/mp4; codecs=\\"flac\\"":{"canPlay":"probably","mediaSource":true},"audio/mp4; codecs=\\"bogus\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"aac\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"ac3\\"":{"canPlay":"","mediaSource":false},"audio/mp4; codecs=\\"A52\\"":{"canPlay":"","mediaSource":false},"audio/mpeg; codecs=\\"mp3\\"":{"canPlay":"probably","mediaSource":false},"audio/wav; codecs=\\"0\\"":{"canPlay":"","mediaSource":false},"audio/wav; codecs=\\"2\\"":{"canPlay":"","mediaSource":false},"audio/wave; codecs=\\"0\\"":{"canPlay":"","mediaSource":false},"audio/wave; codecs=\\"1\\"":{"canPlay":"","mediaSource":false},"audio/wave; codecs=\\"2\\"":{"canPlay":"","mediaSource":false},"audio/x-wav; codecs=\\"0\\"":{"canPlay":"","mediaSource":false},"audio/x-wav; codecs=\\"1\\"":{"canPlay":"probably","mediaSource":false},"audio/x-wav; codecs=\\"2\\"":{"canPlay":"","mediaSource":false},"audio/x-pn-wav; codecs=\\"0\\"":{"canPlay":"","mediaSource":false},"audio/x-pn-wav; codecs=\\"1\\"":{"canPlay":"","mediaSource":false},"audio/x-pn-wav; codecs=\\"2\\"":{"canPlay":"","mediaSource":false}}') 1164 | }, 1165 | { 1166 | "key": "video_codecs", 1167 | "value": "{\"ogg\":\"\",\"h264\":\"probably\",\"webm\":\"probably\",\"mpeg4v\":\"\",\"mpeg4a\":\"\",\"theora\":\"\"}" 1168 | }, 1169 | { 1170 | "key": "video_codecs_extended_hash", 1171 | "value": self.md5_hash( 1172 | '{"video/mp4; codecs=\\"hev1.1.6.L93.90\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"hvc1.1.6.L93.90\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"hev1.1.6.L93.B0\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"hvc1.1.6.L93.B0\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"vp09.00.10.08\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"vp09.00.50.08\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"vp09.01.20.08.01\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"vp09.01.20.08.01.01.01.01.00\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"vp09.02.10.10.01.09.16.09.01\\"":{"canPlay":"probably","mediaSource":true},"video/mp4; codecs=\\"av01.0.08M.08\\"":{"canPlay":"probably","mediaSource":true},"video/webm; codecs=\\"vorbis\\"":{"canPlay":"probably","mediaSource":true},"video/webm; codecs=\\"vp8\\"":{"canPlay":"probably","mediaSource":true},"video/webm; codecs=\\"vp8.0\\"":{"canPlay":"probably","mediaSource":false},"video/webm; codecs=\\"vp8.0, vorbis\\"":{"canPlay":"probably","mediaSource":false},"video/webm; codecs=\\"vp8, opus\\"":{"canPlay":"probably","mediaSource":true},"video/webm; codecs=\\"vp9\\"":{"canPlay":"probably","mediaSource":true},"video/webm; codecs=\\"vp9, vorbis\\"":{"canPlay":"probably","mediaSource":true},"video/webm; codecs=\\"vp9, opus\\"":{"canPlay":"probably","mediaSource":true},"video/x-matroska; codecs=\\"theora\\"":{"canPlay":"","mediaSource":false},"application/x-mpegURL; codecs=\\"avc1.42E01E\\"":{"canPlay":"","mediaSource":false},"video/ogg; codecs=\\"dirac, vorbis\\"":{"canPlay":"","mediaSource":false},"video/ogg; codecs=\\"theora, speex\\"":{"canPlay":"","mediaSource":false},"video/ogg; codecs=\\"theora, vorbis\\"":{"canPlay":"","mediaSource":false},"video/ogg; codecs=\\"theora, flac\\"":{"canPlay":"","mediaSource":false},"video/ogg; codecs=\\"dirac, flac\\"":{"canPlay":"","mediaSource":false},"video/ogg; codecs=\\"flac\\"":{"canPlay":"probably","mediaSource":false},"video/3gpp; codecs=\\"mp4v.20.8, samr\\"":{"canPlay":"","mediaSource":false}}') 1173 | }, 1174 | { 1175 | "key": "media_query_dark_mode", 1176 | "value": False 1177 | }, 1178 | { 1179 | "key": "css_media_queries", 1180 | "value": 0 1181 | }, 1182 | { 1183 | "key": "css_color_gamut", 1184 | "value": "srgb" 1185 | }, 1186 | { 1187 | "key": "css_contrast", 1188 | "value": "no-preference" 1189 | }, 1190 | { 1191 | "key": "css_monochrome", 1192 | "value": False 1193 | }, 1194 | { 1195 | "key": "css_pointer", 1196 | "value": "fine" 1197 | }, 1198 | { 1199 | "key": "css_grid_support", 1200 | "value": False 1201 | }, 1202 | { 1203 | "key": "headless_browser_phantom", 1204 | "value": False 1205 | }, 1206 | { 1207 | "key": "headless_browser_selenium", 1208 | "value": False 1209 | }, 1210 | { 1211 | "key": "headless_browser_nightmare_js", 1212 | "value": False 1213 | }, 1214 | { 1215 | "key": "headless_browser_generic", 1216 | "value": 4 1217 | }, 1218 | { 1219 | "key": "1l2l5234ar2", 1220 | "value": str(int(time_now * 1000)) + "⁣" 1221 | }, 1222 | { 1223 | "key": "document__referrer", 1224 | "value": self.siteurl + "/" 1225 | }, 1226 | { 1227 | "key": "window__ancestor_origins", 1228 | "value": self.window__ancestor_origins 1229 | }, 1230 | { 1231 | "key": "window__tree_index", 1232 | "value": self.window__tree_index 1233 | }, 1234 | { 1235 | "key": "window__tree_structure", 1236 | "value": self.window__tree_structure 1237 | }, 1238 | { 1239 | "key": "window__location_href", 1240 | "value": f"{self.apiurl}/v2/{self.capi_version}/enforcement.{self.enforcement_hash}.html" 1241 | }, 1242 | { 1243 | "key": "client_config__sitedata_location_href", 1244 | "value": self.client_config__sitedata_location_href 1245 | }, 1246 | { 1247 | "key": "client_config__language", 1248 | "value": None 1249 | }, 1250 | { 1251 | "key": "client_config__surl", 1252 | "value": self.apiurl 1253 | }, 1254 | { 1255 | "key": "c8480e29a", 1256 | "value": self.md5_hash(self.apiurl) + "⁢" 1257 | }, 1258 | { 1259 | "key": "client_config__triggered_inline", 1260 | "value": False 1261 | }, 1262 | { 1263 | "key": "mobile_sdk__is_sdk", 1264 | "value": False 1265 | }, 1266 | { 1267 | "key": "audio_fingerprint", 1268 | "value": webgl["audio_fingerprint"] 1269 | }, 1270 | { 1271 | "key": "navigator_battery_charging", 1272 | "value": True 1273 | }, 1274 | { 1275 | "key": "media_device_kinds", 1276 | "value": ["audioinput", "videoinput", "audiooutput"] 1277 | }, 1278 | { 1279 | "key": "media_devices_hash", 1280 | "value": "199eba60310b53c200cc783906883c67" 1281 | }, 1282 | { 1283 | "key": "navigator_permissions_hash", 1284 | "value": self.md5_hash( 1285 | "accelerometer|background-sync|camera|clipboard-read|clipboard-write|geolocation|gyroscope|magnetometer|microphone|midi|notifications|payment-handler|persistent-storage") 1286 | }, 1287 | { 1288 | "key": "math_fingerprint", 1289 | "value": self.md5_hash( 1290 | "1.4474840516030247,0.881373587019543,1.1071487177940904,0.5493061443340548,1.4645918875615231,-0.40677759702517235,-0.6534063185820197,9.199870313877772e+307,1.718281828459045,100.01040630344929,0.4828823513147936,1.9275814160560204e-50,7.888609052210102e+269,1.2246467991473532e-16,-0.7181630308570678,11.548739357257748,9.199870313877772e+307,-3.3537128705376014,0.12238344189440875") 1291 | }, 1292 | { 1293 | "key": "supported_math_functions", 1294 | "value": self.md5_hash( 1295 | "abs,acos,acosh,asin,asinh,atan,atanh,atan2,ceil,cbrt,expm1,clz32,cos,cosh,exp,floor,fround,hypot,imul,log,log1p,log2,log10,max,min,pow,random,round,sign,sin,sinh,sqrt,tan,tanh,trunc") 1296 | }, 1297 | { 1298 | "key": "screen_orientation", 1299 | "value": "landscape-primary" 1300 | }, 1301 | { 1302 | "key": "rtc_peer_connection", 1303 | "value": 5 1304 | }, 1305 | { 1306 | "key": "4b4b269e68", 1307 | "value": str(uuid.uuid4()) # window.location.hash 1308 | }, 1309 | { 1310 | "key": "6a62b2a558", 1311 | "value": self.enforcement_hash 1312 | }, 1313 | { 1314 | "key": "speech_default_voice", 1315 | "value": "Microsoft David - English (United States) || en-US" 1316 | }, 1317 | { 1318 | "key": "speech_voices_hash", 1319 | "value": str(uuid.uuid4().hex) 1320 | }, 1321 | { 1322 | "key": "4ca87df3d1", 1323 | "value": "Ow==" 1324 | }, 1325 | { 1326 | "key": "867e25e5d4", 1327 | "value": "Ow==" 1328 | }, 1329 | { 1330 | "key": "d4a306884c", 1331 | "value": "Ow==" 1332 | }] 1333 | 1334 | for item in enhanced_fp_more: 1335 | enhanced_fp.append(item) 1336 | 1337 | fp = [ 1338 | { 1339 | "key": "api_type", 1340 | "value": "js" 1341 | }, 1342 | { 1343 | "key": "f", 1344 | "value": gctx.call("x64hash128", self.process_fp(fp1), 0) 1345 | }, 1346 | { 1347 | "key": "n", 1348 | "value": base64.b64encode(str(int(time_now)).encode()).decode() 1349 | }, 1350 | { 1351 | "key": "wh", 1352 | "value": f"{secrets.token_hex(16)}|{secrets.token_hex(16)}" 1353 | }, 1354 | { 1355 | "key": "enhanced_fp", 1356 | "value": enhanced_fp 1357 | }, 1358 | { 1359 | "key": "fe", 1360 | "value": fp1 1361 | }, 1362 | { 1363 | "key": "ife_hash", 1364 | "value": gctx.call("x64hash128", ", ".join(fp1), 38) 1365 | }, 1366 | { 1367 | "key": "jsbd", 1368 | "value": "{\"HL\":6,\"NCE\":true,\"DT\":\"\",\"NWD\":\"false\",\"DMTO\":1,\"DOTO\":1}" 1369 | } 1370 | ] 1371 | 1372 | return base64.b64encode(Arkose.make_encrypted_dict(self, json.dumps(fp, separators=(',', ':'), 1373 | ensure_ascii=False)).encode()).decode() 1374 | 1375 | def _generate_challenge(self) -> None: 1376 | random.seed(random.randint(0, 2 ** 64 - 1)) 1377 | 1378 | task = { 1379 | "bda": self.bda(), 1380 | "public_key": self.sitekey, 1381 | "site": self.siteurl, 1382 | "userbrowser": self.useragent, 1383 | "capi_version": self.capi_version, 1384 | "capi_mode": "inline", 1385 | "style_theme": "default", 1386 | "rnd": str(random.uniform(0, 1)), 1387 | 'language': self.locale.split("-")[0] 1388 | } 1389 | 1390 | if self.blob: 1391 | task["data[blob]"] = self.blob 1392 | headers = { 1393 | 'accept-language': f'en-US,en;q=0.9,{self.locale};q=0.8,{self.locale.split("-")[0]};q=0.7', 1394 | 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 1395 | 'origin': self.apiurl, 1396 | **self.base_headers, 1397 | 'x-ark-esync-value': self.x_ark_value, 1398 | } 1399 | return self.session.post( 1400 | f'{self.apiurl}/fc/gt2/public_key/{self.sitekey}', 1401 | data=task, 1402 | headers=headers 1403 | 1404 | ).json() 1405 | 1406 | 1407 | solver_stats_instance = solver_stats() 1408 | threading.Thread(target=solver_stats_instance.title).start() 1409 | threading.Thread(target=solver_stats_instance.calc_cpm).start() 1410 | 1411 | max_workers = 50 1412 | executor = ThreadPoolExecutor(max_workers=max_workers) 1413 | task_queue = queue.Queue() 1414 | 1415 | 1416 | class preset: 1417 | def get(self): 1418 | return { 1419 | "outlook_register": { 1420 | "siteurl": "https://iframe.arkoselabs.com", 1421 | "sitekey": "B7D8911C-5CC8-A9A3-35B0-554ACEE604DA", 1422 | "apiurl": "https://client-api.arkoselabs.com", 1423 | "data": { 1424 | "window__ancestor_origins": [ 1425 | "https://iframe.arkoselabs.com", 1426 | "https://signup.live.com" 1427 | ], 1428 | "client_config__sitedata_location_href": "https://iframe.arkoselabs.com/B7D8911C-5CC8-A9A3-35B0-554ACEE604DA/index.html", 1429 | "window__tree_structure": "[[],[],[[]]]", 1430 | 'window__tree_index': [2, 0] 1431 | }, 1432 | }, 1433 | 1434 | } 1435 | 1436 | 1437 | class TokenManager: 1438 | def __init__(self): 1439 | self.tokens = { 1440 | "123456": {"balance": 99999999.0}, 1441 | } 1442 | self.token_lock = Lock() 1443 | 1444 | def validate_token(self, token: str) -> Dict[str, float]: 1445 | with self.token_lock: 1446 | if token not in self.tokens: 1447 | raise HTTPException(status_code=401, detail="Invalid API token") 1448 | return self.tokens[token] 1449 | 1450 | def deduct_balance(self, token: str, amount: float = 1.0) -> None: 1451 | with self.token_lock: 1452 | if self.tokens[token]["balance"] < amount: 1453 | raise HTTPException(status_code=403, detail="Insufficient balance") 1454 | self.tokens[token]["balance"] -= amount 1455 | 1456 | def get_balance(self, token: str) -> float: 1457 | with self.token_lock: 1458 | return self.tokens[token]["balance"] 1459 | 1460 | 1461 | class TaskCleaner: 1462 | def __init__(self, task_manager, max_age_hours=24, cleanup_interval_minutes=30): 1463 | self.task_manager = task_manager 1464 | self.max_age_hours = max_age_hours 1465 | self.cleanup_interval = cleanup_interval_minutes * 60 # Convert to seconds 1466 | self.running = False 1467 | self.cleanup_thread = None 1468 | 1469 | def start(self): 1470 | if not self.running: 1471 | self.running = True 1472 | self.cleanup_thread = threading.Thread(target=self._cleanup_loop, daemon=True) 1473 | self.cleanup_thread.start() 1474 | 1475 | def stop(self): 1476 | self.running = False 1477 | if self.cleanup_thread: 1478 | self.cleanup_thread.join() 1479 | 1480 | def _cleanup_loop(self): 1481 | 1482 | while self.running: 1483 | try: 1484 | self._perform_cleanup() 1485 | except Exception as e: 1486 | logging.error(f"Error in task cleanup: {e}") 1487 | time.sleep(self.cleanup_interval) 1488 | 1489 | def _perform_cleanup(self): 1490 | 1491 | current_time = datetime.now() 1492 | tasks_to_remove = [] 1493 | 1494 | with self.task_manager.lock: 1495 | for task_id, task_data in self.task_manager.tasks.items(): 1496 | 1497 | if task_data["status"] == "Working": 1498 | continue 1499 | 1500 | if "finished" in task_data: 1501 | finished_time = datetime.fromisoformat(task_data["finished"].replace("Z", "+00:00")) 1502 | age = (current_time - finished_time).total_seconds() / 3600 # Convert to hours 1503 | 1504 | if age >= self.max_age_hours: 1505 | tasks_to_remove.append(task_id) 1506 | 1507 | for task_id in tasks_to_remove: 1508 | del self.task_manager.tasks[task_id] 1509 | 1510 | if tasks_to_remove: 1511 | logging.info(f"Cleaned up {len(tasks_to_remove)} old tasks") 1512 | 1513 | 1514 | class TaskManager: 1515 | def __init__(self, max_age_hours=24, cleanup_interval_minutes=30): 1516 | self.tasks = {} 1517 | self.lock = Lock() 1518 | self.cleaner = TaskCleaner(self, max_age_hours, cleanup_interval_minutes) 1519 | self.cleaner.start() 1520 | 1521 | def add_task(self, task_id, task_data): 1522 | with self.lock: 1523 | self.tasks[task_id] = { 1524 | "data": task_data, 1525 | "status": "Working", 1526 | "response": None, 1527 | "attempts": 0, 1528 | "error": None, 1529 | "created": datetime.utcnow().isoformat() + "Z" 1530 | } 1531 | 1532 | def update_task(self, task_id: str, status: str, response: Dict = None, error: str = None): 1533 | with self.lock: 1534 | if task_id in self.tasks: 1535 | self.tasks[task_id].update({ 1536 | "status": status, 1537 | "response": response, 1538 | "error": error, 1539 | "finished": datetime.utcnow().isoformat() + "Z" 1540 | }) 1541 | 1542 | def get_task(self, task_id: str) -> Dict: 1543 | with self.lock: 1544 | return self.tasks.get(task_id) 1545 | 1546 | def get_stats(self) -> Dict: 1547 | with self.lock: 1548 | total_tasks = len(self.tasks) 1549 | working_tasks = sum(1 for task in self.tasks.values() if task["status"] == "Working") 1550 | completed_tasks = sum(1 for task in self.tasks.values() if task["status"] == "Success") 1551 | failed_tasks = sum(1 for task in self.tasks.values() if task["status"] == "Failed") 1552 | 1553 | return { 1554 | "total_tasks": total_tasks, 1555 | "working_tasks": working_tasks, 1556 | "completed_tasks": completed_tasks, 1557 | "failed_tasks": failed_tasks 1558 | } 1559 | 1560 | def __del__(self): 1561 | if hasattr(self, 'cleaner'): 1562 | self.cleaner.stop() 1563 | 1564 | 1565 | app = FastAPI() 1566 | token_manager = TokenManager() 1567 | task_manager = TaskManager(max_age_hours=2, cleanup_interval_minutes=3) 1568 | 1569 | app.add_middleware( 1570 | CORSMiddleware, 1571 | allow_origins=["*"], 1572 | allow_credentials=True, 1573 | allow_methods=["*"], 1574 | allow_headers=["*"], 1575 | ) 1576 | 1577 | 1578 | class ConcurrentTaskProcessor: 1579 | def __init__(self, max_workers=50): 1580 | self.executor = ThreadPoolExecutor(max_workers=max_workers) 1581 | self.task_queue = queue.Queue() 1582 | self._start_workers() 1583 | 1584 | def _start_workers(self): 1585 | self.workers = [] 1586 | for _ in range(50): 1587 | worker = threading.Thread(target=self._worker_thread) 1588 | worker.daemon = True 1589 | worker.start() 1590 | self.workers.append(worker) 1591 | 1592 | def _worker_thread(self): 1593 | while True: 1594 | task_id, task_data, api_token = self.task_queue.get() 1595 | try: 1596 | self._process_task(task_id, task_data, api_token) 1597 | except Exception as e: 1598 | logging.error(f"Task processing error: {e}") 1599 | finally: 1600 | self.task_queue.task_done() 1601 | 1602 | def _process_task(self, task_id: str, task_data: Dict, api_token: str): 1603 | try: 1604 | preset_data = None 1605 | if task_data["siteKey"] == "B7D8911C-5CC8-A9A3-35B0-554ACEE604DA": 1606 | preset_data = preset().get()["outlook_register"] 1607 | 1608 | if not preset_data: 1609 | raise ValueError(f"Unsupported siteKey: {task_data['siteKey']}") 1610 | 1611 | solver = Funcaptcha( 1612 | apiurl=preset_data["apiurl"], 1613 | siteurl=preset_data["siteurl"], 1614 | sitekey=task_data["siteKey"], 1615 | data=preset_data["data"], 1616 | blob=task_data.get("data", ""), 1617 | proxy=task_data.get("proxy", "http://127.0.0.1:7890"), 1618 | custom_cookies=None, 1619 | custom_locale=None, 1620 | ) 1621 | 1622 | result = solver.solve() 1623 | 1624 | if result.get("success"): 1625 | response = { 1626 | "token": result["token"], 1627 | "details": { 1628 | "instruction": result.get("game", ""), 1629 | "waveCount": result.get("waves", 0) 1630 | } 1631 | } 1632 | task_manager.update_task(task_id, "Success", response) 1633 | token_manager.deduct_balance(api_token) 1634 | else: 1635 | error_msg = result.get("err", "Failed to solve captcha") 1636 | task_manager.update_task(task_id, "Failed", error=error_msg) 1637 | 1638 | except Exception as e: 1639 | logging.error(f"Task processing error: {str(e)}") 1640 | task_manager.update_task(task_id, "Failed", error=str(e)) 1641 | 1642 | def add_task(self, task_id: str, task_data: Dict, api_token: str): 1643 | self.task_queue.put((task_id, task_data, api_token)) 1644 | 1645 | 1646 | concurrent_processor = ConcurrentTaskProcessor(max_workers=50) 1647 | 1648 | 1649 | @app.post("/v2/tasks") 1650 | async def create_task(request: Request, authorization: str = Header(...)): 1651 | if not authorization.startswith("Bearer "): 1652 | raise HTTPException(status_code=401, detail="Invalid Authorization header") 1653 | 1654 | api_token = authorization[7:] 1655 | token_manager.validate_token(api_token) 1656 | 1657 | try: 1658 | body = await request.json() 1659 | task_id = str(uuid.uuid4()) 1660 | 1661 | if not all(k in body for k in ["captchaType", "siteReferer", "siteKey"]): 1662 | raise HTTPException(status_code=400, detail="Missing required fields") 1663 | 1664 | if body["captchaType"] != "FunCaptcha": 1665 | raise HTTPException(status_code=400, detail="Invalid captcha type") 1666 | 1667 | task_data = { 1668 | "taskId": task_id, 1669 | "price": "0.01", 1670 | "deducted": False, 1671 | "captchaType": "FunCaptcha", 1672 | "request": body, 1673 | "status": "Working", 1674 | "created": datetime.utcnow().isoformat() + "Z", 1675 | "timestamp": time.time(), 1676 | "token": api_token, 1677 | "siteReferer": body["siteReferer"], 1678 | "siteKey": body["siteKey"], 1679 | "data": body.get("data") 1680 | } 1681 | 1682 | task_manager.add_task(task_id, task_data) 1683 | concurrent_processor.add_task(task_id, task_data, api_token) 1684 | 1685 | task_data["remainingBalance"] = token_manager.get_balance(api_token) 1686 | return JSONResponse(task_data) 1687 | 1688 | except Exception as e: 1689 | logging.error(f"Create task error: {str(e)}") 1690 | raise HTTPException(status_code=400, detail=str(e)) 1691 | 1692 | 1693 | @app.get("/v2/tasks/{task_id}") 1694 | async def get_task(task_id: str, authorization: str = Header(...)): 1695 | if not authorization.startswith("Bearer "): 1696 | raise HTTPException(status_code=401, detail="Invalid Authorization header") 1697 | 1698 | api_token = authorization[7:] 1699 | token_manager.validate_token(api_token) 1700 | 1701 | task = task_manager.get_task(task_id) 1702 | if not task: 1703 | raise HTTPException(status_code=404, detail="Task not found") 1704 | 1705 | response = { 1706 | "status": task["status"], 1707 | "task_id": task_id 1708 | } 1709 | 1710 | if task["status"] == "Success": 1711 | response["response"] = task["response"] 1712 | elif task["error"]: 1713 | response["error"] = task["error"] 1714 | 1715 | return JSONResponse(response) 1716 | 1717 | 1718 | if __name__ == "__main__": 1719 | import uvicorn 1720 | 1721 | uvicorn.run(app, host="0.0.0.0", port=6699) 1722 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | javascript 2 | fastapi 3 | uvicorn 4 | pycryptodome 5 | cryptography 6 | colr 7 | colorama 8 | requests 9 | PyExecJS -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | import logging 4 | 5 | # Configure logging 6 | logging.basicConfig(level=logging.INFO) 7 | 8 | API_BASE_URL = "http://127.0.0.1:6699/v2" 9 | API_TOKEN = "123456" 10 | 11 | # Headers with Authorization 12 | HEADERS = { 13 | "Authorization": f"Bearer {API_TOKEN}", 14 | "Content-Type": "application/json", 15 | } 16 | 17 | MAX_RETRIES = 10 # Maximum number of retries 18 | RETRY_INTERVAL = 3 # Retry interval in seconds 19 | 20 | 21 | def create_task(): 22 | """Create a task""" 23 | url = f"{API_BASE_URL}/tasks" 24 | payload = { 25 | "captchaType": "FunCaptcha", 26 | "siteReferer": "site_referer", 27 | "siteKey": "site_key_here", 28 | "data": "blob_value", 29 | "proxy": "proxy_value", 30 | } 31 | 32 | response = requests.post(url, json=payload, headers=HEADERS) 33 | if response.status_code == 200: 34 | result_data = response.json() 35 | logging.info("Task created successfully:") 36 | logging.info(result_data) 37 | return result_data.get("taskId") 38 | else: 39 | logging.error(f"Failed to create task: {response.status_code}") 40 | logging.error(response.json()) 41 | return None 42 | 43 | 44 | def get_task(task_id): 45 | """Query task status""" 46 | url = f"{API_BASE_URL}/tasks/{task_id}" 47 | 48 | response = requests.get(url, headers=HEADERS) 49 | if response.status_code == 200: 50 | return response.json() 51 | else: 52 | logging.error(f"Failed to fetch task status: {response.status_code}") 53 | logging.error(response.json()) 54 | return None 55 | 56 | 57 | def process_task(): 58 | """Create a task and poll for its status""" 59 | task_id = create_task() 60 | if not task_id: 61 | logging.error("Unable to create task, exiting process.") 62 | return None 63 | 64 | attempts = 0 65 | while attempts < MAX_RETRIES: 66 | result_data = get_task(task_id) 67 | if not result_data: 68 | logging.error("Failed to fetch task status, exiting process.") 69 | return None 70 | 71 | status = result_data.get("status") 72 | if status == "Working": 73 | attempts += 1 74 | logging.info(f"Task is in progress, retrying... (Attempt {attempts}/{MAX_RETRIES})") 75 | time.sleep(RETRY_INTERVAL) 76 | elif status == "Success": 77 | logging.info(f"Task completed successfully! Result: {result_data['response']}") 78 | return result_data["response"] 79 | elif status == "Failed": 80 | logging.error("Task failed: captcha recognition unsuccessful!") 81 | return None 82 | else: 83 | logging.error(f"Unknown status: {status}, exiting process.") 84 | return None 85 | 86 | logging.error("Max retries reached, task not completed.") 87 | return None 88 | 89 | 90 | if __name__ == "__main__": 91 | process_task() 92 | -------------------------------------------------------------------------------- /tls_client/__init__.py: -------------------------------------------------------------------------------- 1 | # _____ __ __ ___ _ _ _ 2 | # /__ \/ / / _\ / __\ (_) ___ _ __ | |_ 3 | # / /\/ / \ \ _____ / / | | |/ _ \ '_ \| __| 4 | # / / / /____\ \_____/ /___| | | __/ | | | |_ 5 | # \/ \____/\__/ \____/|_|_|\___|_| |_|\__| 6 | 7 | # Disclaimer: 8 | # Big shout out to Bogdanfinn for open sourcing his tls-client in Golang. 9 | # Also to requests, as most of the cookie handling is copied from it. :'D 10 | # I wanted to keep the syntax as similar as possible to requests, as most people use it and are familiar with it! 11 | # Links: 12 | # tls-client: https://github.com/bogdanfinn/tls-client 13 | # requests: https://github.com/psf/requests 14 | 15 | from .sessions import Session -------------------------------------------------------------------------------- /tls_client/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__pycache__/__version__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/__version__.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__pycache__/cffi.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/cffi.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__pycache__/cookies.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/cookies.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__pycache__/exceptions.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/exceptions.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__pycache__/response.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/response.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__pycache__/sessions.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/sessions.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__pycache__/settings.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/settings.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__pycache__/structures.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/__pycache__/structures.cpython-310.pyc -------------------------------------------------------------------------------- /tls_client/__version__.py: -------------------------------------------------------------------------------- 1 | # _____ __ __ ___ _ _ _ 2 | # /__ \/ / / _\ / __\ (_) ___ _ __ | |_ 3 | # / /\/ / \ \ _____ / / | | |/ _ \ '_ \| __| 4 | # / / / /____\ \_____/ /___| | | __/ | | | |_ 5 | # \/ \____/\__/ \____/|_|_|\___|_| |_|\__| 6 | 7 | __title__ = "tls_client" 8 | __description__ = "Advanced Python HTTP Client." 9 | __version__ = "1.0.1" 10 | __author__ = "Florian Zager" 11 | __license__ = "MIT" -------------------------------------------------------------------------------- /tls_client/cffi.py: -------------------------------------------------------------------------------- 1 | from sys import platform 2 | from platform import machine 3 | import ctypes 4 | import os 5 | 6 | 7 | if platform == 'darwin': 8 | file_ext = '-arm64.dylib' if machine() == "arm64" else '-x86.dylib' 9 | elif platform in ('win32', 'cygwin'): 10 | file_ext = '-64.dll' if 8 == ctypes.sizeof(ctypes.c_voidp) else '-32.dll' 11 | else: 12 | if machine() == "aarch64": 13 | file_ext = '-arm64.so' 14 | elif "x86" in machine(): 15 | file_ext = '-x86.so' 16 | else: 17 | file_ext = '-amd64.so' 18 | 19 | root_dir = os.path.abspath(os.path.dirname(__file__)) 20 | library = ctypes.cdll.LoadLibrary(f'{root_dir}/dependencies/tls-client{file_ext}') 21 | 22 | # extract the exposed request function from the shared package 23 | request = library.request 24 | request.argtypes = [ctypes.c_char_p] 25 | request.restype = ctypes.c_char_p 26 | 27 | freeMemory = library.freeMemory 28 | freeMemory.argtypes = [ctypes.c_char_p] 29 | freeMemory.restype = ctypes.c_char_p 30 | 31 | destroySession = library.destroySession 32 | destroySession.argtypes = [ctypes.c_char_p] 33 | destroySession.restype = ctypes.c_char_p 34 | -------------------------------------------------------------------------------- /tls_client/cookies.py: -------------------------------------------------------------------------------- 1 | from .structures import CaseInsensitiveDict 2 | 3 | from http.cookiejar import CookieJar, Cookie 4 | from typing import MutableMapping, Union, Any 5 | from urllib.parse import urlparse, urlunparse 6 | from http.client import HTTPMessage 7 | import copy 8 | 9 | try: 10 | import threading 11 | except ImportError: 12 | import dummy_threading as threading 13 | 14 | 15 | class MockRequest: 16 | """ 17 | Mimic a urllib2.Request to get the correct cookie string for the request. 18 | """ 19 | 20 | def __init__(self, request_url: str, request_headers: CaseInsensitiveDict): 21 | self.request_url = request_url 22 | self.request_headers = request_headers 23 | self._new_headers = {} 24 | self.type = urlparse(self.request_url).scheme 25 | 26 | def get_type(self): 27 | return self.type 28 | 29 | def get_host(self): 30 | return urlparse(self.request_url).netloc 31 | 32 | def get_origin_req_host(self): 33 | return self.get_host() 34 | 35 | def get_full_url(self): 36 | # Only return the response's URL if the user hadn't set the Host 37 | # header 38 | if not self.request_headers.get("Host"): 39 | return self.request_url 40 | # If they did set it, retrieve it and reconstruct the expected domain 41 | host = self.request_headers["Host"] 42 | parsed = urlparse(self.request_url) 43 | # Reconstruct the URL as we expect it 44 | return urlunparse( 45 | [ 46 | parsed.scheme, 47 | host, 48 | parsed.path, 49 | parsed.params, 50 | parsed.query, 51 | parsed.fragment, 52 | ] 53 | ) 54 | 55 | def is_unverifiable(self): 56 | return True 57 | 58 | def has_header(self, name): 59 | return name in self.request_headers or name in self._new_headers 60 | 61 | def get_header(self, name, default=None): 62 | return self.request_headers.get(name, self._new_headers.get(name, default)) 63 | 64 | def add_unredirected_header(self, name, value): 65 | self._new_headers[name] = value 66 | 67 | def get_new_headers(self): 68 | return self._new_headers 69 | 70 | @property 71 | def unverifiable(self): 72 | return self.is_unverifiable() 73 | 74 | @property 75 | def origin_req_host(self): 76 | return self.get_origin_req_host() 77 | 78 | @property 79 | def host(self): 80 | return self.get_host() 81 | 82 | 83 | class MockResponse: 84 | """ 85 | Wraps a httplib.HTTPMessage to mimic a urllib.addinfourl. 86 | The objective is to retrieve the response cookies correctly. 87 | """ 88 | 89 | def __init__(self, headers): 90 | self._headers = headers 91 | 92 | def info(self): 93 | return self._headers 94 | 95 | def getheaders(self, name): 96 | self._headers.getheaders(name) 97 | 98 | 99 | class CookieConflictError(RuntimeError): 100 | """There are two cookies that meet the criteria specified in the cookie jar. 101 | Use .get and .set and include domain and path args in order to be more specific. 102 | """ 103 | 104 | 105 | class RequestsCookieJar(CookieJar, MutableMapping): 106 | """ Origin: requests library (https://github.com/psf/requests) 107 | Compatibility class; is a cookielib.CookieJar, but exposes a dict 108 | interface. 109 | 110 | This is the CookieJar we create by default for requests and sessions that 111 | don't specify one, since some clients may expect response.cookies and 112 | session.cookies to support dict operations. 113 | 114 | Requests does not use the dict interface internally; it's just for 115 | compatibility with external client code. All requests code should work 116 | out of the box with externally provided instances of ``CookieJar``, e.g. 117 | ``LWPCookieJar`` and ``FileCookieJar``. 118 | 119 | Unlike a regular CookieJar, this class is pickleable. 120 | 121 | .. warning:: dictionary operations that are normally O(1) may be O(n). 122 | """ 123 | 124 | def get(self, name, default=None, domain=None, path=None): 125 | """Dict-like get() that also supports optional domain and path args in 126 | order to resolve naming collisions from using one cookie jar over 127 | multiple domains. 128 | 129 | .. warning:: operation is O(n), not O(1). 130 | """ 131 | try: 132 | return self._find_no_duplicates(name, domain, path) 133 | except KeyError: 134 | return default 135 | 136 | def set(self, name, value, **kwargs): 137 | """Dict-like set() that also supports optional domain and path args in 138 | order to resolve naming collisions from using one cookie jar over 139 | multiple domains. 140 | """ 141 | # support client code that unsets cookies by assignment of a None value: 142 | if value is None: 143 | remove_cookie_by_name( 144 | self, name, domain=kwargs.get("domain"), path=kwargs.get("path") 145 | ) 146 | return 147 | 148 | c = create_cookie(name, value, **kwargs) 149 | self.set_cookie(c) 150 | return c 151 | 152 | def iterkeys(self): 153 | """Dict-like iterkeys() that returns an iterator of names of cookies 154 | from the jar. 155 | 156 | .. seealso:: itervalues() and iteritems(). 157 | """ 158 | for cookie in iter(self): 159 | yield cookie.name 160 | 161 | def keys(self): 162 | """Dict-like keys() that returns a list of names of cookies from the 163 | jar. 164 | 165 | .. seealso:: values() and items(). 166 | """ 167 | return list(self.iterkeys()) 168 | 169 | def itervalues(self): 170 | """Dict-like itervalues() that returns an iterator of values of cookies 171 | from the jar. 172 | 173 | .. seealso:: iterkeys() and iteritems(). 174 | """ 175 | for cookie in iter(self): 176 | yield cookie.value 177 | 178 | def values(self): 179 | """Dict-like values() that returns a list of values of cookies from the 180 | jar. 181 | 182 | .. seealso:: keys() and items(). 183 | """ 184 | return list(self.itervalues()) 185 | 186 | def iteritems(self): 187 | """Dict-like iteritems() that returns an iterator of name-value tuples 188 | from the jar. 189 | 190 | .. seealso:: iterkeys() and itervalues(). 191 | """ 192 | for cookie in iter(self): 193 | yield cookie.name, cookie.value 194 | 195 | def items(self): 196 | """Dict-like items() that returns a list of name-value tuples from the 197 | jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a 198 | vanilla python dict of key value pairs. 199 | 200 | .. seealso:: keys() and values(). 201 | """ 202 | return list(self.iteritems()) 203 | 204 | def list_domains(self): 205 | """Utility method to list all the domains in the jar.""" 206 | domains = [] 207 | for cookie in iter(self): 208 | if cookie.domain not in domains: 209 | domains.append(cookie.domain) 210 | return domains 211 | 212 | def list_paths(self): 213 | """Utility method to list all the paths in the jar.""" 214 | paths = [] 215 | for cookie in iter(self): 216 | if cookie.path not in paths: 217 | paths.append(cookie.path) 218 | return paths 219 | 220 | def multiple_domains(self): 221 | """Returns True if there are multiple domains in the jar. 222 | Returns False otherwise. 223 | 224 | :rtype: bool 225 | """ 226 | domains = [] 227 | for cookie in iter(self): 228 | if cookie.domain is not None and cookie.domain in domains: 229 | return True 230 | domains.append(cookie.domain) 231 | return False # there is only one domain in jar 232 | 233 | def get_dict(self, domain=None, path=None): 234 | """Takes as an argument an optional domain and path and returns a plain 235 | old Python dict of name-value pairs of cookies that meet the 236 | requirements. 237 | 238 | :rtype: dict 239 | """ 240 | dictionary = {} 241 | for cookie in iter(self): 242 | if (domain is None or cookie.domain == domain) and ( 243 | path is None or cookie.path == path 244 | ): 245 | dictionary[cookie.name] = cookie.value 246 | return dictionary 247 | 248 | def __contains__(self, name): 249 | try: 250 | return super().__contains__(name) 251 | except CookieConflictError: 252 | return True 253 | 254 | def __getitem__(self, name): 255 | """Dict-like __getitem__() for compatibility with client code. Throws 256 | exception if there are more than one cookie with name. In that case, 257 | use the more explicit get() method instead. 258 | 259 | .. warning:: operation is O(n), not O(1). 260 | """ 261 | return self._find_no_duplicates(name) 262 | 263 | def __setitem__(self, name, value): 264 | """Dict-like __setitem__ for compatibility with client code. Throws 265 | exception if there is already a cookie of that name in the jar. In that 266 | case, use the more explicit set() method instead. 267 | """ 268 | self.set(name, value) 269 | 270 | def __delitem__(self, name): 271 | """Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s 272 | ``remove_cookie_by_name()``. 273 | """ 274 | remove_cookie_by_name(self, name) 275 | 276 | def set_cookie(self, cookie, *args, **kwargs): 277 | if ( 278 | hasattr(cookie.value, "startswith") 279 | and cookie.value.startswith('"') 280 | and cookie.value.endswith('"') 281 | ): 282 | cookie.value = cookie.value.replace('\\"', "") 283 | return super().set_cookie(cookie, *args, **kwargs) 284 | 285 | def update(self, other): 286 | """Updates this jar with cookies from another CookieJar or dict-like""" 287 | if isinstance(other, CookieJar): 288 | for cookie in other: 289 | self.set_cookie(copy.copy(cookie)) 290 | else: 291 | super().update(other) 292 | 293 | def _find(self, name, domain=None, path=None): 294 | """Requests uses this method internally to get cookie values. 295 | 296 | If there are conflicting cookies, _find arbitrarily chooses one. 297 | See _find_no_duplicates if you want an exception thrown if there are 298 | conflicting cookies. 299 | 300 | :param name: a string containing name of cookie 301 | :param domain: (optional) string containing domain of cookie 302 | :param path: (optional) string containing path of cookie 303 | :return: cookie.value 304 | """ 305 | for cookie in iter(self): 306 | if cookie.name == name: 307 | if domain is None or cookie.domain == domain: 308 | if path is None or cookie.path == path: 309 | return cookie.value 310 | 311 | raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}") 312 | 313 | def _find_no_duplicates(self, name, domain=None, path=None): 314 | """Both ``__get_item__`` and ``get`` call this function: it's never 315 | used elsewhere in Requests. 316 | 317 | :param name: a string containing name of cookie 318 | :param domain: (optional) string containing domain of cookie 319 | :param path: (optional) string containing path of cookie 320 | :raises KeyError: if cookie is not found 321 | :raises CookieConflictError: if there are multiple cookies 322 | that match name and optionally domain and path 323 | :return: cookie.value 324 | """ 325 | toReturn = None 326 | for cookie in iter(self): 327 | if cookie.name == name: 328 | if domain is None or cookie.domain == domain: 329 | if path is None or cookie.path == path: 330 | if toReturn is not None: 331 | # if there are multiple cookies that meet passed in criteria 332 | raise CookieConflictError( 333 | f"There are multiple cookies with name, {name!r}" 334 | ) 335 | # we will eventually return this as long as no cookie conflict 336 | toReturn = cookie.value 337 | 338 | if toReturn: 339 | return toReturn 340 | raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}") 341 | 342 | def __getstate__(self): 343 | """Unlike a normal CookieJar, this class is pickleable.""" 344 | state = self.__dict__.copy() 345 | # remove the unpickleable RLock object 346 | state.pop("_cookies_lock") 347 | return state 348 | 349 | def __setstate__(self, state): 350 | """Unlike a normal CookieJar, this class is pickleable.""" 351 | self.__dict__.update(state) 352 | if "_cookies_lock" not in self.__dict__: 353 | self._cookies_lock = threading.RLock() 354 | 355 | def copy(self): 356 | """Return a copy of this RequestsCookieJar.""" 357 | new_cj = RequestsCookieJar() 358 | new_cj.set_policy(self.get_policy()) 359 | new_cj.update(self) 360 | return new_cj 361 | 362 | def get_policy(self): 363 | """Return the CookiePolicy instance used.""" 364 | return self._policy 365 | 366 | 367 | def remove_cookie_by_name(cookiejar: RequestsCookieJar, name: str, domain: str = None, path: str = None): 368 | """Removes a cookie by name, by default over all domains and paths.""" 369 | clearables = [] 370 | for cookie in cookiejar: 371 | if cookie.name != name: 372 | continue 373 | if domain is not None and domain != cookie.domain: 374 | continue 375 | if path is not None and path != cookie.path: 376 | continue 377 | clearables.append((cookie.domain, cookie.path, cookie.name)) 378 | 379 | for domain, path, name in clearables: 380 | cookiejar.clear(domain, path, name) 381 | 382 | 383 | def create_cookie(name: str, value: str, **kwargs: Any) -> Cookie: 384 | """Make a cookie from underspecified parameters.""" 385 | result = { 386 | "version": 0, 387 | "name": name, 388 | "value": value, 389 | "port": None, 390 | "domain": "", 391 | "path": "/", 392 | "secure": False, 393 | "expires": None, 394 | "discard": True, 395 | "comment": None, 396 | "comment_url": None, 397 | "rest": {"HttpOnly": None}, 398 | "rfc2109": False, 399 | } 400 | 401 | badargs = set(kwargs) - set(result) 402 | if badargs: 403 | raise TypeError( 404 | f"create_cookie() got unexpected keyword arguments: {list(badargs)}" 405 | ) 406 | 407 | result.update(kwargs) 408 | result["port_specified"] = bool(result["port"]) 409 | result["domain_specified"] = bool(result["domain"]) 410 | result["domain_initial_dot"] = result["domain"].startswith(".") 411 | result["path_specified"] = bool(result["path"]) 412 | 413 | return Cookie(**result) 414 | 415 | 416 | def cookiejar_from_dict(cookie_dict: dict) -> RequestsCookieJar: 417 | """transform a dict to CookieJar""" 418 | cookie_jar = RequestsCookieJar() 419 | if cookie_dict is not None: 420 | for name, value in cookie_dict.items(): 421 | cookie_jar.set_cookie(create_cookie(name=name, value=value)) 422 | return cookie_jar 423 | 424 | 425 | def merge_cookies(cookiejar: RequestsCookieJar, cookies: Union[dict, RequestsCookieJar]) -> RequestsCookieJar: 426 | """Merge cookies in session and cookies provided in request""" 427 | if type(cookies) is dict: 428 | cookies = cookiejar_from_dict(cookies) 429 | 430 | for cookie in cookies: 431 | cookiejar.set_cookie(cookie) 432 | 433 | return cookiejar 434 | 435 | def extract_cookies_to_jar( 436 | request_url: str, 437 | request_headers: CaseInsensitiveDict, 438 | cookie_jar: RequestsCookieJar, 439 | response_headers: dict 440 | ) -> RequestsCookieJar: 441 | response_cookie_jar = cookiejar_from_dict({}) 442 | 443 | req = MockRequest(request_url, request_headers) 444 | # mimic HTTPMessage 445 | http_message = HTTPMessage() 446 | http_message._headers = [] 447 | for header_name, header_values in response_headers.items(): 448 | for header_value in header_values: 449 | http_message._headers.append( 450 | (header_name, header_value) 451 | ) 452 | res = MockResponse(http_message) 453 | response_cookie_jar.extract_cookies(res, req) 454 | 455 | merge_cookies(cookie_jar, response_cookie_jar) 456 | return response_cookie_jar 457 | -------------------------------------------------------------------------------- /tls_client/dependencies/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/dependencies/__init__.py -------------------------------------------------------------------------------- /tls_client/dependencies/tls-client-32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/dependencies/tls-client-32.dll -------------------------------------------------------------------------------- /tls_client/dependencies/tls-client-64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/dependencies/tls-client-64.dll -------------------------------------------------------------------------------- /tls_client/dependencies/tls-client-amd64.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/dependencies/tls-client-amd64.so -------------------------------------------------------------------------------- /tls_client/dependencies/tls-client-arm64.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/dependencies/tls-client-arm64.dylib -------------------------------------------------------------------------------- /tls_client/dependencies/tls-client-arm64.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/dependencies/tls-client-arm64.so -------------------------------------------------------------------------------- /tls_client/dependencies/tls-client-x86.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/dependencies/tls-client-x86.dylib -------------------------------------------------------------------------------- /tls_client/dependencies/tls-client-x86.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uizlrfwg/ffun-solverk/b3e6c60bf3e8fa1eae4d4e1a35e267ba4cfd9812/tls_client/dependencies/tls-client-x86.so -------------------------------------------------------------------------------- /tls_client/exceptions.py: -------------------------------------------------------------------------------- 1 | 2 | class TLSClientExeption(IOError): 3 | """General error with the TLS client""" -------------------------------------------------------------------------------- /tls_client/response.py: -------------------------------------------------------------------------------- 1 | from .cookies import cookiejar_from_dict, RequestsCookieJar 2 | from .structures import CaseInsensitiveDict 3 | 4 | from typing import Union 5 | import json 6 | import base64 7 | 8 | 9 | class Response: 10 | """object, which contains the response to an HTTP request.""" 11 | 12 | def __init__(self): 13 | 14 | # Reference of URL the response is coming from (especially useful with redirects) 15 | self.url = None 16 | 17 | # Integer Code of responded HTTP Status, e.g. 404 or 200. 18 | self.status_code = None 19 | 20 | # String of responded HTTP Body. 21 | self.text = None 22 | 23 | # Case-insensitive Dictionary of Response Headers. 24 | self.headers = CaseInsensitiveDict() 25 | 26 | # A CookieJar of Cookies the server sent back. 27 | self.cookies = cookiejar_from_dict({}) 28 | 29 | self._content = False 30 | 31 | def __enter__(self): 32 | return self 33 | 34 | def __repr__(self): 35 | return f"" 36 | 37 | def json(self, **kwargs): 38 | """parse response body to json (dict/list)""" 39 | return json.loads(self.text, **kwargs) 40 | 41 | @property 42 | def content(self): 43 | """Content of the response, in bytes.""" 44 | 45 | if self._content is False: 46 | if self._content_consumed: 47 | raise RuntimeError("The content for this response was already consumed") 48 | 49 | if self.status_code == 0: 50 | self._content = None 51 | else: 52 | self._content = b"".join(self.iter_content(10 * 1024)) or b"" 53 | self._content_consumed = True 54 | return self._content 55 | 56 | 57 | def build_response(res: Union[dict, list], res_cookies: RequestsCookieJar) -> Response: 58 | """Builds a Response object """ 59 | response = Response() 60 | # Add target / url 61 | response.url = res["target"] 62 | # Add status code 63 | response.status_code = res["status"] 64 | # Add headers 65 | response_headers = {} 66 | if res["headers"] is not None: 67 | for header_key, header_value in res["headers"].items(): 68 | if len(header_value) == 1: 69 | response_headers[header_key] = header_value[0] 70 | else: 71 | response_headers[header_key] = header_value 72 | response.headers = response_headers 73 | # Add cookies 74 | response.cookies = res_cookies 75 | # Add response body 76 | response.text = base64.b64decode(res["body"].split(',')[1]).decode(errors='ignore') 77 | # Add response content (bytes) 78 | response._content = base64.b64decode(res["body"].split(',')[1]) 79 | return response -------------------------------------------------------------------------------- /tls_client/sessions.py: -------------------------------------------------------------------------------- 1 | from .cffi import request, freeMemory, destroySession 2 | from .cookies import cookiejar_from_dict, merge_cookies, extract_cookies_to_jar 3 | from .exceptions import TLSClientExeption 4 | from .response import build_response, Response 5 | from .settings import ClientIdentifiers 6 | from .structures import CaseInsensitiveDict 7 | from .__version__ import __version__ 8 | 9 | from typing import Any, Dict, List, Optional, Union 10 | from json import dumps, loads 11 | import urllib.parse 12 | import base64 13 | import ctypes 14 | import uuid 15 | import urllib3 16 | 17 | 18 | class Session: 19 | 20 | def __init__( 21 | self, 22 | client_identifier: ClientIdentifiers = "chrome_120", 23 | ja3_string: Optional[str] = None, 24 | h2_settings: Optional[Dict[str, int]] = None, 25 | h2_settings_order: Optional[List[str]] = None, 26 | supported_signature_algorithms: Optional[List[str]] = None, 27 | supported_delegated_credentials_algorithms: Optional[List[str]] = None, 28 | supported_versions: Optional[List[str]] = None, 29 | key_share_curves: Optional[List[str]] = None, 30 | cert_compression_algo: str = None, 31 | additional_decode: str = None, 32 | pseudo_header_order: Optional[List[str]] = None, 33 | connection_flow: Optional[int] = None, 34 | priority_frames: Optional[list] = None, 35 | header_order: Optional[List[str]] = None, 36 | header_priority: Optional[List[str]] = None, 37 | random_tls_extension_order: Optional = False, 38 | force_http1: Optional = False, 39 | catch_panics: Optional = False, 40 | debug: Optional = False, 41 | certificate_pinning: Optional[Dict[str, List[str]]] = None, 42 | ) -> None: 43 | self._session_id = str(uuid.uuid4()) 44 | # --- Standard Settings ---------------------------------------------------------------------------------------- 45 | 46 | # Case-insensitive dictionary of headers, send on each request 47 | self.headers = CaseInsensitiveDict( 48 | { 49 | "User-Agent": f"tls-client/{__version__}", 50 | "Accept-Encoding": "gzip, deflate, br", 51 | "Accept": "*/*", 52 | "Connection": "keep-alive", 53 | } 54 | ) 55 | 56 | # Example: 57 | # { 58 | # "http": "http://user:pass@ip:port", 59 | # "https": "http://user:pass@ip:port" 60 | # } 61 | self.proxies = {} 62 | 63 | # Dictionary of querystring data to attach to each request. The dictionary values may be lists for representing 64 | # multivalued query parameters. 65 | self.params = {} 66 | 67 | # CookieJar containing all currently outstanding cookies set on this session 68 | self.cookies = cookiejar_from_dict({}) 69 | 70 | # Timeout 71 | self.timeout_seconds = 30 72 | 73 | # Certificate pinning 74 | self.certificate_pinning = certificate_pinning 75 | 76 | # --- Advanced Settings ---------------------------------------------------------------------------------------- 77 | 78 | # Examples: 79 | # Chrome --> chrome_103, chrome_104, chrome_105, chrome_106 80 | # Firefox --> firefox_102, firefox_104 81 | # Opera --> opera_89, opera_90 82 | # Safari --> safari_15_3, safari_15_6_1, safari_16_0 83 | # iOS --> safari_ios_15_5, safari_ios_15_6, safari_ios_16_0 84 | # iPadOS --> safari_ios_15_6 85 | # 86 | # for all possible client identifiers, check out the settings.py 87 | self.client_identifier = client_identifier 88 | 89 | # Set JA3 --> TLSVersion, Ciphers, Extensions, EllipticCurves, EllipticCurvePointFormats 90 | # Example: 91 | # 771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0 92 | self.ja3_string = ja3_string 93 | # 设置 JA3 指纹 94 | # self.ja3_string = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0" 95 | 96 | # HTTP2 Header Frame Settings 97 | # Possible Settings: 98 | # HEADER_TABLE_SIZE 99 | # SETTINGS_ENABLE_PUSH 100 | # MAX_CONCURRENT_STREAMS 101 | # INITIAL_WINDOW_SIZE 102 | # MAX_FRAME_SIZE 103 | # MAX_HEADER_LIST_SIZE 104 | # 105 | # Example: 106 | # { 107 | # "HEADER_TABLE_SIZE": 65536, 108 | # "MAX_CONCURRENT_STREAMS": 1000, 109 | # "INITIAL_WINDOW_SIZE": 6291456, 110 | # "MAX_HEADER_LIST_SIZE": 262144 111 | # } 112 | self.h2_settings = h2_settings 113 | 114 | # HTTP2 Header Frame Settings Order 115 | # Example: 116 | # [ 117 | # "HEADER_TABLE_SIZE", 118 | # "MAX_CONCURRENT_STREAMS", 119 | # "INITIAL_WINDOW_SIZE", 120 | # "MAX_HEADER_LIST_SIZE" 121 | # ] 122 | self.h2_settings_order = h2_settings_order 123 | 124 | 125 | self.supported_signature_algorithms = supported_signature_algorithms 126 | 127 | 128 | self.supported_delegated_credentials_algorithms = supported_delegated_credentials_algorithms 129 | 130 | 131 | self.supported_versions = supported_versions 132 | 133 | 134 | self.key_share_curves = key_share_curves 135 | 136 | # Cert Compression Algorithm 137 | # Examples: "zlib", "brotli", "zstd" 138 | self.cert_compression_algo = cert_compression_algo 139 | 140 | self.additional_decode = additional_decode 141 | 142 | 143 | self.pseudo_header_order = pseudo_header_order 144 | 145 | # Connection Flow / Window Size Increment 146 | # Example: 147 | # 15663105 148 | self.connection_flow = connection_flow 149 | 150 | self.priority_frames = priority_frames 151 | 152 | 153 | self.header_order = header_order 154 | 155 | self.header_priority = header_priority 156 | 157 | # randomize tls extension order 158 | self.random_tls_extension_order = random_tls_extension_order 159 | 160 | # force HTTP1 161 | self.force_http1 = force_http1 162 | 163 | # catch panics 164 | # avoid the tls client to print the whole stacktrace when a panic (critical go error) happens 165 | self.catch_panics = catch_panics 166 | 167 | # debugging 168 | self.debug = debug 169 | 170 | def __enter__(self): 171 | return self 172 | 173 | def __exit__(self, *args): 174 | self.close() 175 | 176 | def close(self) -> str: 177 | destroy_session_payload = { 178 | "sessionId": self._session_id 179 | } 180 | 181 | destroy_session_response = destroySession(dumps(destroy_session_payload).encode('utf-8')) 182 | # we dereference the pointer to a byte array 183 | destroy_session_response_bytes = ctypes.string_at(destroy_session_response) 184 | # convert our byte array to a string (tls client returns json) 185 | destroy_session_response_string = destroy_session_response_bytes.decode('utf-8') 186 | # convert response string to json 187 | destroy_session_response_object = loads(destroy_session_response_string) 188 | 189 | freeMemory(destroy_session_response_object['id'].encode('utf-8')) 190 | 191 | return destroy_session_response_string 192 | 193 | def execute_request( 194 | self, 195 | method: str, 196 | url: str, 197 | params: Optional[dict] = None, # Optional[dict[str, str]] 198 | data: Optional[Union[str, dict]] = None, 199 | headers: Optional[dict] = None, # Optional[dict[str, str]] 200 | cookies: Optional[dict] = None, # Optional[dict[str, str]] 201 | json: Optional[dict] = None, # Optional[dict] 202 | files=None, 203 | allow_redirects: Optional[bool] = True, 204 | insecure_skip_verify: Optional[bool] = False, 205 | timeout_seconds: Optional[int] = None, 206 | proxy: Optional[dict] = None # Optional[dict[str, str]] 207 | ) -> Response: 208 | # --- URL ------------------------------------------------------------------------------------------------------ 209 | # Prepare URL - add params to url 210 | if params is not None: 211 | url = f"{url}?{urllib.parse.urlencode(params, doseq=True)}" 212 | if headers is None: headers = {} 213 | # --- Request Body --------------------------------------------------------------------------------------------- 214 | # Prepare request body - build request body 215 | # Data has priority. JSON is only used if data is None. 216 | if data is None and json is not None: 217 | if type(json) in [dict, list]: 218 | json = dumps(json) 219 | request_body = json 220 | content_type = "application/json" 221 | elif data is None and files is not None: 222 | request_body, content_type = urllib3.encode_multipart_formdata(files) 223 | elif data is not None and type(data) not in [str, bytes]: 224 | request_body = urllib.parse.urlencode(data, doseq=True) 225 | content_type = "application/x-www-form-urlencoded" 226 | else: 227 | request_body = data 228 | content_type = None 229 | # set content type if it isn't set 230 | if content_type is not None and "content-type" not in self.headers and "content-type" not in headers: 231 | headers["Content-Type"] = content_type 232 | 233 | # --- Headers -------------------------------------------------------------------------------------------------- 234 | if self.headers is None: 235 | headers = CaseInsensitiveDict(headers) 236 | elif headers is None: 237 | headers = self.headers 238 | else: 239 | merged_headers = CaseInsensitiveDict(self.headers) 240 | merged_headers.update(headers) 241 | 242 | # Remove items, where the key or value is set to None. 243 | none_keys = [k for (k, v) in merged_headers.items() if v is None or k is None] 244 | for key in none_keys: 245 | del merged_headers[key] 246 | 247 | headers = merged_headers 248 | 249 | # --- Cookies -------------------------------------------------------------------------------------------------- 250 | cookies = cookies or {} 251 | # Merge with session cookies 252 | cookies = merge_cookies(self.cookies, cookies) 253 | # turn cookie jar into dict 254 | # in the cookie value the " gets removed, because the fhttp library in golang doesn't accept the character 255 | request_cookies = [ 256 | {'domain': c.domain, 'expires': c.expires, 'name': c.name, 'path': c.path, 257 | 'value': c.value.replace('"', "")} 258 | for c in cookies 259 | ] 260 | 261 | # --- Proxy ---------------------------------------------------------------------------------------------------- 262 | proxy = proxy or self.proxies 263 | 264 | if type(proxy) is dict and "http" in proxy: 265 | proxy = proxy["http"] 266 | elif type(proxy) is str: 267 | proxy = proxy 268 | else: 269 | proxy = "" 270 | 271 | # --- Timeout -------------------------------------------------------------------------------------------------- 272 | # maximum time to wait for a response 273 | 274 | timeout_seconds = timeout_seconds or self.timeout_seconds 275 | 276 | # --- Certificate pinning -------------------------------------------------------------------------------------- 277 | # pins a certificate so that it restricts which certificates are considered valid 278 | 279 | certificate_pinning = self.certificate_pinning 280 | 281 | # --- Request -------------------------------------------------------------------------------------------------- 282 | is_byte_request = isinstance(request_body, (bytes, bytearray)) 283 | request_payload = { 284 | "sessionId": self._session_id, 285 | "followRedirects": allow_redirects, 286 | "forceHttp1": self.force_http1, 287 | "withDebug": self.debug, 288 | "catchPanics": self.catch_panics, 289 | "headers": dict(headers), 290 | "headerOrder": self.header_order, 291 | "insecureSkipVerify": insecure_skip_verify, 292 | "isByteRequest": is_byte_request, 293 | "isByteResponse": True, 294 | "additionalDecode": self.additional_decode, 295 | "proxyUrl": proxy, 296 | "requestUrl": url, 297 | "requestMethod": method, 298 | "requestBody": base64.b64encode(request_body).decode() if is_byte_request else request_body, 299 | "requestCookies": request_cookies, 300 | "timeoutSeconds": timeout_seconds, 301 | } 302 | if certificate_pinning: 303 | request_payload["certificatePinningHosts"] = certificate_pinning 304 | if self.client_identifier is None: 305 | request_payload["customTlsClient"] = { 306 | "ja3String": self.ja3_string, 307 | "h2Settings": self.h2_settings, 308 | "h2SettingsOrder": self.h2_settings_order, 309 | "pseudoHeaderOrder": self.pseudo_header_order, 310 | "connectionFlow": self.connection_flow, 311 | "priorityFrames": self.priority_frames, 312 | "headerPriority": self.header_priority, 313 | "certCompressionAlgo": self.cert_compression_algo, 314 | "supportedVersions": self.supported_versions, 315 | "supportedSignatureAlgorithms": self.supported_signature_algorithms, 316 | "supportedDelegatedCredentialsAlgorithms": self.supported_delegated_credentials_algorithms, 317 | "keyShareCurves": self.key_share_curves, 318 | } 319 | else: 320 | request_payload["tlsClientIdentifier"] = self.client_identifier 321 | request_payload["withRandomTLSExtensionOrder"] = self.random_tls_extension_order 322 | 323 | # this is a pointer to the response 324 | response = request(dumps(request_payload).encode('utf-8')) 325 | # dereference the pointer to a byte array 326 | response_bytes = ctypes.string_at(response) 327 | # convert our byte array to a string (tls client returns json) 328 | response_string = response_bytes.decode('utf-8') 329 | # convert response string to json 330 | response_object = loads(response_string) 331 | # free the memory 332 | freeMemory(response_object['id'].encode('utf-8')) 333 | # --- Response ------------------------------------------------------------------------------------------------- 334 | # Error handling 335 | if response_object["status"] == 0: 336 | raise TLSClientExeption(response_object["body"]) 337 | # Set response cookies 338 | response_cookie_jar = extract_cookies_to_jar( 339 | request_url=url, 340 | request_headers=headers, 341 | cookie_jar=cookies, 342 | response_headers=response_object["headers"] 343 | ) 344 | # print("DEBUG =>", response_object) 345 | # build response class 346 | return build_response(response_object, response_cookie_jar) 347 | 348 | def get( 349 | self, 350 | url: str, 351 | **kwargs: Any 352 | ) -> Response: 353 | """Sends a GET request""" 354 | return self.execute_request(method="GET", url=url, **kwargs) 355 | 356 | def options( 357 | self, 358 | url: str, 359 | **kwargs: Any 360 | ) -> Response: 361 | """Sends a OPTIONS request""" 362 | return self.execute_request(method="OPTIONS", url=url, **kwargs) 363 | 364 | def head( 365 | self, 366 | url: str, 367 | **kwargs: Any 368 | ) -> Response: 369 | """Sends a HEAD request""" 370 | return self.execute_request(method="HEAD", url=url, **kwargs) 371 | 372 | def post( 373 | self, 374 | url: str, 375 | data: Optional[Union[str, dict]] = None, 376 | json: Optional[dict] = None, 377 | **kwargs: Any 378 | ) -> Response: 379 | """Sends a POST request""" 380 | return self.execute_request(method="POST", url=url, data=data, json=json, **kwargs) 381 | 382 | def put( 383 | self, 384 | url: str, 385 | data: Optional[Union[str, dict]] = None, 386 | json: Optional[dict] = None, 387 | **kwargs: Any 388 | ) -> Response: 389 | """Sends a PUT request""" 390 | return self.execute_request(method="PUT", url=url, data=data, json=json, **kwargs) 391 | 392 | def patch( 393 | self, 394 | url: str, 395 | data: Optional[Union[str, dict]] = None, 396 | json: Optional[dict] = None, 397 | **kwargs: Any 398 | ) -> Response: 399 | """Sends a PATCH request""" 400 | return self.execute_request(method="PATCH", url=url, data=data, json=json, **kwargs) 401 | 402 | def delete( 403 | self, 404 | url: str, 405 | **kwargs: Any 406 | ) -> Response: 407 | """Sends a DELETE request""" 408 | return self.execute_request(method="DELETE", url=url, **kwargs) -------------------------------------------------------------------------------- /tls_client/settings.py: -------------------------------------------------------------------------------- 1 | from typing_extensions import Literal, TypeAlias 2 | 3 | ClientIdentifiers: TypeAlias = Literal[ 4 | # Chrome 5 | "chrome_103", 6 | "chrome_104", 7 | "chrome_105", 8 | "chrome_106", 9 | "chrome_107", 10 | "chrome_108", 11 | "chrome_109", 12 | "chrome_110", 13 | "chrome_111", 14 | "chrome_112", 15 | "chrome_116_PSK", 16 | "chrome_116_PSK_PQ", 17 | "chrome_117", 18 | "chrome_120", 19 | "chrome_129", 20 | # Safari 21 | "safari_15_6_1", 22 | "safari_16_0", 23 | # iOS (Safari) 24 | "safari_ios_15_5", 25 | "safari_ios_15_6", 26 | "safari_ios_16_0", 27 | # iPadOS (Safari) 28 | "safari_ios_15_6", 29 | # FireFox 30 | "firefox_102", 31 | "firefox_104", 32 | "firefox_105", 33 | "firefox_106", 34 | "firefox_108", 35 | "firefox_110", 36 | "firefox_117", 37 | "firefox_120", 38 | # Opera 39 | "opera_89", 40 | "opera_90", 41 | "opera_91", 42 | # OkHttp4 43 | "okhttp4_android_7", 44 | "okhttp4_android_8", 45 | "okhttp4_android_9", 46 | "okhttp4_android_10", 47 | "okhttp4_android_11", 48 | "okhttp4_android_12", 49 | "okhttp4_android_13", 50 | # Custom 51 | "zalando_ios_mobile", 52 | "zalando_android_mobile", 53 | "nike_ios_mobile", 54 | "nike_android_mobile", 55 | "mms_ios", 56 | "mms_ios_2", 57 | "mms_ios_3", 58 | "mesh_ios", 59 | "mesh_ios_2", 60 | "mesh_android", 61 | "mesh_android_2", 62 | "confirmed_ios", 63 | "confirmed_android", 64 | "confirmed_android_2", 65 | ] -------------------------------------------------------------------------------- /tls_client/structures.py: -------------------------------------------------------------------------------- 1 | from typing import MutableMapping, Mapping 2 | from collections import OrderedDict 3 | 4 | 5 | class CaseInsensitiveDict(MutableMapping): 6 | """Origin: requests library (https://github.com/psf/requests) 7 | 8 | A case-insensitive ``dict``-like object. 9 | 10 | Implements all methods and operations of 11 | ``MutableMapping`` as well as dict's ``copy``. Also 12 | provides ``lower_items``. 13 | 14 | All keys are expected to be strings. The structure remembers the 15 | case of the last key to be set, and ``iter(instance)``, 16 | ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` 17 | will contain case-sensitive keys. However, querying and contains 18 | testing is case insensitive:: 19 | 20 | cid = CaseInsensitiveDict() 21 | cid['Accept'] = 'application/json' 22 | cid['aCCEPT'] == 'application/json' # True 23 | list(cid) == ['Accept'] # True 24 | 25 | For example, ``headers['content-encoding']`` will return the 26 | value of a ``'Content-Encoding'`` response header, regardless 27 | of how the header name was originally stored. 28 | 29 | If the constructor, ``.update``, or equality comparison 30 | operations are given keys that have equal ``.lower()``s, the 31 | behavior is undefined. 32 | """ 33 | 34 | def __init__(self, data=None, **kwargs): 35 | self._store = OrderedDict() 36 | if data is None: 37 | data = {} 38 | self.update(data, **kwargs) 39 | 40 | def __setitem__(self, key, value): 41 | # Use the lowercased key for lookups, but store the actual 42 | # key alongside the value. 43 | self._store[key.lower()] = (key, value) 44 | 45 | def __getitem__(self, key): 46 | return self._store[key.lower()][1] 47 | 48 | def __delitem__(self, key): 49 | del self._store[key.lower()] 50 | 51 | def __iter__(self): 52 | return (casedkey for casedkey, mappedvalue in self._store.values()) 53 | 54 | def __len__(self): 55 | return len(self._store) 56 | 57 | def lower_items(self): 58 | """Like iteritems(), but with all lowercase keys.""" 59 | return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items()) 60 | 61 | def __eq__(self, other): 62 | if isinstance(other, Mapping): 63 | other = CaseInsensitiveDict(other) 64 | else: 65 | return NotImplemented 66 | # Compare insensitively 67 | return dict(self.lower_items()) == dict(other.lower_items()) 68 | 69 | # Copy is required 70 | def copy(self): 71 | return CaseInsensitiveDict(self._store.values()) 72 | 73 | def __repr__(self): 74 | return str(dict(self.items())) 75 | -------------------------------------------------------------------------------- /tls_client/ua.txt: -------------------------------------------------------------------------------- 1 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 2 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 3 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.90 Safari/537.36 4 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.116 Safari/537.36 5 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.90 Safari/537.36 6 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.58 Safari/537.36 7 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.58 Safari/537.36 8 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.117 Safari/537.36 9 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 10 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 11 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 12 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 13 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 14 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 15 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 16 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 17 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 18 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.116 Safari/537.36 19 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 20 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 21 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.59 Safari/537.36 22 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 23 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 24 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 25 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 26 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 27 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 28 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 29 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 30 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 31 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 32 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 33 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 34 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 35 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 36 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 37 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 38 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 39 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 40 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 41 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 42 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 43 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 44 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 45 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 46 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 47 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 48 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 49 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 50 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 51 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 52 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.101 Safari/537.36 53 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36 54 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.58 Safari/537.36 55 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 56 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 57 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 58 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 59 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 60 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 61 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 62 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Safari/537.36 63 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Safari/537.36 64 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 65 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.58 Safari/537.36 66 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.101 Safari/537.36 67 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.58 Safari/537.36 68 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 69 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 70 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 71 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 72 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.101 Safari/537.36 73 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 74 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Safari/537.36 75 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 76 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36 77 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 78 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 79 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 80 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 81 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.117 Safari/537.36 82 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 83 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.90 Safari/537.36 84 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Safari/537.36 85 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 86 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 87 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Safari/537.36 88 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 89 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 90 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 91 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 92 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Safari/537.36 93 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 94 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 95 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 96 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 97 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 98 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 99 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.59 Safari/537.36 100 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 101 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 102 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.116 Safari/537.36 103 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Safari/537.36 104 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 105 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 106 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.116 Safari/537.36 107 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.117 Safari/537.36 108 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.59 Safari/537.36 109 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 110 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 111 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 112 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 113 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 114 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 115 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 116 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 117 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.121 Safari/537.36 118 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 119 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 120 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 121 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 122 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 123 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 124 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 125 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 126 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 127 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 128 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 129 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 130 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 131 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 132 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 133 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 134 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 135 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 136 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 137 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 138 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.106 Safari/537.36 139 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 140 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 141 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 142 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 143 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 144 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 145 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36 146 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 147 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 148 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 149 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 150 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.106 Safari/537.36 151 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 152 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 153 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 154 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 155 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36 156 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.121 Safari/537.36 157 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 158 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 159 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 160 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 161 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 162 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 163 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 164 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 165 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 166 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.106 Safari/537.36 167 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36 168 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 169 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 170 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 171 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 172 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 173 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 174 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 175 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 176 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 177 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 178 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 179 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 180 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 181 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 182 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36 183 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 184 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 185 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 186 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36 187 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 188 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 189 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 190 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 191 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 192 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 193 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 194 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 195 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 196 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 197 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36 198 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 199 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 200 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 201 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.63 Safari/537.36 202 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 203 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36 204 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 205 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 206 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 207 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 208 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 209 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36 210 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 211 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 212 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 213 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 214 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 215 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 216 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 217 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 218 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.106 Safari/537.36 219 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 220 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 221 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 222 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36 223 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 224 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 225 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 226 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 227 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 228 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 229 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 230 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 231 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36 232 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 233 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 234 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.63 Safari/537.36 235 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36 236 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36 237 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 238 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 239 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 240 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 241 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 242 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 243 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36 244 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36 245 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 246 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 247 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 248 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537. 249 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 250 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.63 Safari/537.36 251 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 252 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 253 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 254 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 255 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 256 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 257 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 258 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 259 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36 260 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 261 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 262 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.63 Safari/537.36 263 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 264 | Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 265 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 266 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 267 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 268 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 269 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 270 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 271 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 272 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 273 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 274 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 275 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 276 | Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36 277 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 278 | Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 279 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 280 | Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 281 | Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 282 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 283 | Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 284 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36 285 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 286 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 287 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 288 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.116 Safari/537.36 289 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.117 Safari/537.36 290 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 291 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 292 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 293 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 294 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 295 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 296 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36 297 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 298 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.116 Safari/537.36 299 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 300 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 301 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 302 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 303 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 304 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 305 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 306 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 307 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.90 Safari/537.36 308 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 309 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 310 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 311 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 312 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36 313 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.59 Safari/537.36 314 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Safari/537.36 315 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 316 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 317 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36 318 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 319 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 320 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 321 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.101 Safari/537.36 322 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36 323 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 324 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 325 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.101 Safari/537.36 326 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.90 Safari/537.36 327 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 328 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 329 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Safari/537.36 330 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 331 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.101 Safari/537.36 332 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 333 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36 334 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 335 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 336 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 337 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 338 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Safari/537.36 339 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 340 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 341 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.101 Safari/537.36 342 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 343 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 344 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 345 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Safari/537.36 346 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.58 Safari/537.36 347 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 348 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36 349 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 350 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36 351 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 352 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 353 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.58 Safari/537.36 354 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 355 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 356 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 357 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.70 Safari/537.36 358 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 359 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 360 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 361 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 362 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 363 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 364 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 365 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 366 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 367 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36 368 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 369 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 370 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.100 Safari/537.36 371 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 372 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36 373 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.58 Safari/537.36 374 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.59 Safari/537.36 375 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 376 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 377 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.116 Safari/537.36 378 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36 379 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.69 Safari/537.36 380 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 381 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 382 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 383 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 384 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 385 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.90 Safari/537.36 386 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.59 Safari/537.36 387 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.70 Safari/537.36 388 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 389 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36 390 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.69 Safari/537.36 391 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 392 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.36 393 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.70 Safari/537.36 394 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 395 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 396 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 397 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 398 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36 399 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 400 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 401 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 402 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 403 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 404 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 405 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 406 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 407 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 408 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 409 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.63 Safari/537.36 410 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 411 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36 412 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 413 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 414 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 415 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 416 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 417 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 418 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 419 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.122 Safari/537.36 420 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36 421 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 422 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 423 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.119 Safari/537.36 424 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 425 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.63 Safari/537.36 426 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 427 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 428 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36 429 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 430 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 431 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 432 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 433 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 434 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 435 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 436 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.106 Safari/537.36 437 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 438 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 439 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 440 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 441 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.94 Safari/537.36 442 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.72 Safari/537.36 443 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.71 Safari/537.36 444 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 445 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 446 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36 447 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 448 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.106 Safari/537.36 449 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.98 Safari/537.36 450 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 451 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 452 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36 453 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.68 Safari/537.36 454 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36 455 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 456 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 457 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.87 Safari/537.36 458 | Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.87 Safari/537.36 459 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.88 Safari/537.36 460 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 461 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.110 Safari/537.36 462 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36 463 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.75 Safari/537.36 464 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.74 Safari/537.36 465 | Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.62 Safari/537.36 466 | --------------------------------------------------------------------------------