commit a745e7a268561719429a837b87272b59cc9a6340 Author: dela Date: Fri Jan 9 15:46:40 2026 +0800 first diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..505a3b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/assets/sdk.js b/assets/sdk.js new file mode 100644 index 0000000..2308f20 --- /dev/null +++ b/assets/sdk.js @@ -0,0 +1,1523 @@ +var SentinelSDK = (function (t) { + "use strict"; + const n = o, + e = (function () { + let t = !0; + return function (n, e) { + const r = t + ? function () { + if (e) { + const t = e[o(1)](n, arguments); + return (e = null), t; + } + } + : function () {}; + return (t = !1), r; + }; + })(), + r = e(void 0, function () { + const t = o; + return r.toString()[t(7)](t(6))[t(2)]()[t(3)](r)[t(7)]("(((.+)+)+)+$"); + }); + function o(t, n) { + const e = c(); + return (o = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + r(); + const i = []; + for (let t = 0; t < 256; ++t) i[n(5)]((t + 256)[n(2)](16)[n(4)](1)); + function c() { + const t = [ + "toLowerCase", + "apply", + "toString", + "constructor", + "slice", + "push", + "(((.+)+)+)+$", + "search", + ]; + return (c = function () { + return t; + })(); + } + const s = (function () { + let t = !0; + return function (n, e) { + const r = t + ? function () { + if (e) { + const t = e.apply(n, arguments); + return (e = null), t; + } + } + : function () {}; + return (t = !1), r; + }; + })(), + u = s(void 0, function () { + const t = d; + return u[t(5)]()[t(3)](t(4))[t(5)]().constructor(u).search(t(4)); + }); + function a() { + const t = [ + "crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported", + "getRandomValues", + "bind", + "search", + "(((.+)+)+)+$", + "toString", + ]; + return (a = function () { + return t; + })(); + } + let f; + u(); + const l = new Uint8Array(16); + function d(t, n) { + const e = a(); + return (d = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + const p = w, + h = (function () { + let t = !0; + return function (n, e) { + const r = t + ? function () { + if (e) { + const t = e[w(3)](n, arguments); + return (e = null), t; + } + } + : function () {}; + return (t = !1), r; + }; + })(), + g = h(void 0, function () { + const t = w; + return g[t(2)]() + [t(5)]("(((.+)+)+)+$") + [t(2)]() + [t(4)](g) + .search("(((.+)+)+)+$"); + }); + function w(t, n) { + const e = y(); + return (w = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + g(); + var m = { + randomUUID: + "undefined" != typeof crypto && + crypto[p(0)] && + crypto[p(0)][p(1)](crypto), + }; + function y() { + const t = [ + "randomUUID", + "bind", + "toString", + "apply", + "constructor", + "search", + ]; + return (y = function () { + return t; + })(); + } + function v(t, n) { + const e = S(); + return (v = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + const b = (function () { + let t = !0; + return function (n, e) { + const r = t + ? function () { + if (e) { + const t = e[v(8)](n, arguments); + return (e = null), t; + } + } + : function () {}; + return (t = !1), r; + }; + })(), + k = b(void 0, function () { + const t = v; + return k[t(7)]()[t(4)](t(0))[t(7)]().constructor(k).search(t(0)); + }); + function S() { + const t = [ + "(((.+)+)+)+$", + "rng", + "random", + "length", + "search", + "randomUUID", + " is out of buffer bounds", + "toString", + "apply", + ]; + return (S = function () { + return t; + })(); + } + function A(t, e, r) { + const o = v; + if (m.randomUUID && !e && !t) return m[o(5)](); + const c = + (t = t || {})[o(2)] ?? + t[o(1)]?.() ?? + (function () { + const t = d; + if (!f) { + if ("undefined" == typeof crypto || !crypto[t(1)]) + throw new Error(t(0)); + f = crypto[t(1)][t(2)](crypto); + } + return f(l); + })(); + if (c.length < 16) throw new Error("Random bytes length must be >= 16"); + return ( + (c[6] = (15 & c[6]) | 64), + (c[8] = (63 & c[8]) | 128), + (function (t, e = 0) { + const r = n; + return (i[t[e + 0]] + + i[t[e + 1]] + + i[t[e + 2]] + + i[t[e + 3]] + + "-" + + i[t[e + 4]] + + i[t[e + 5]] + + "-" + + i[t[e + 6]] + + i[t[e + 7]] + + "-" + + i[t[e + 8]] + + i[t[e + 9]] + + "-" + + i[t[e + 10]] + + i[t[e + 11]] + + i[t[e + 12]] + + i[t[e + 13]] + + i[t[e + 14]] + + i[t[e + 15]])[r(0)](); + })(c) + ); + } + k(); + const C = _; + class O { + answers = new Map(); + [C(61)] = 5e5; + [C(15)] = (function () { + const t = (function () { + let t = !0; + return function (n, e) { + const r = t + ? function () { + if (e) { + const t = e[_(40)](n, arguments); + return (e = null), t; + } + } + : function () {}; + return (t = !1), r; + }; + })(), + n = t(this, function () { + const t = _; + return n[t(64)]()[t(59)](t(7))[t(64)]()[t(33)](n)[t(59)](t(7)); + }); + return n(), "" + Math.random(); + })(); + [C(9)] = A(); + errorPrefix = C(53); + async [C(21)](t) { + this[C(41)](t); + } + async [C(55)](t) { + this[C(41)](t); + } + [C(52)](t) { + const n = C, + e = this[n(41)](t); + return typeof e === n(20) ? e : null; + } + async getEnforcementToken(t, n) { + const e = C; + return this[e(41)](t, n?.[e(37)]); + } + async getRequirementsToken() { + const t = C; + return ( + !this.answers[t(24)](this[t(15)]) && + this.answers[t(0)](this[t(15)], this[t(3)](this[t(15)], "0")), + "gAAAAAC" + (await this[t(19)][t(63)](this[t(15)])) + ); + } + [C(30)]() { + return C(29) + this._generateRequirementsTokenAnswerBlocking(); + } + [C(41)](t, n = !1) { + const e = C, + r = e(32); + if (!t?.proofofwork?.[e(2)]) return null; + const { seed: o, difficulty: i } = t[e(13)]; + if ("string" != typeof o || typeof i !== e(20)) return null; + const c = this.answers[e(63)](o); + if (typeof c === e(20)) return c; + if (n) { + const t = this[e(16)](o, i), + n = r + t; + return this[e(19)][e(0)](o, n), n; + } + return ( + !this.answers[e(24)](o) && this.answers[e(0)](o, this[e(3)](o, i)), + Promise[e(18)]() + [e(51)](async () => { + const t = e; + return r + (await this[t(19)].get(o)); + }) + .then((t) => (this[e(19)].set(o, t), t)) + ); + } + [C(47)] = (t, n, e, r, o) => { + const i = C; + (r[3] = o), (r[9] = Math[i(43)](performance[i(10)]() - t)); + const c = T(r), + s = (function (t) { + const n = _; + let e = 2166136261; + for (let r = 0; r < t[n(31)]; r++) + (e ^= t[n(34)](r)), (e = Math[n(11)](e, 16777619) >>> 0); + return ( + (e ^= e >>> 16), + (e = Math[n(11)](e, 2246822507) >>> 0), + (e ^= e >>> 13), + (e = Math[n(11)](e, 3266489909) >>> 0), + (e ^= e >>> 16), + (e >>> 0).toString(16)[n(48)](8, "0") + ); + })(n + c); + return s[i(1)](0, e.length) <= e ? c + "~S" : null; + }; + [C(8)](t) { + return this.errorPrefix + T(String(t ?? "e")); + } + [C(16)](t, n) { + const e = C, + r = performance.now(); + try { + const o = this[e(35)](); + for (let i = 0; i < this[e(61)]; i++) { + const c = this[e(47)](r, t, n, o, i); + if (c) return c; + } + } catch (t) { + return this[e(8)](t); + } + return this.buildGenerateFailMessage(); + } + async _generateAnswerAsync(t, n) { + const e = C, + r = performance[e(10)](); + try { + let o = null; + const i = this[e(35)](); + for (let c = 0; c < this[e(61)]; c++) { + (!o || o[e(54)]() <= 0) && + (o = await new Promise((t) => { + const n = _, + e = window[n(5)] || x; + e( + (n) => { + t(n); + }, + { timeout: 10 } + ); + })); + const s = this[e(47)](r, t, n, i, c); + if (s) return s; + } + } catch (t) { + return this.buildGenerateFailMessage(t); + } + return this[e(8)](); + } + [C(22)]() { + const t = C; + let n = "e"; + const e = performance[t(10)](); + try { + const n = this[t(35)](); + return (n[3] = 1), (n[9] = Math.round(performance.now() - e)), T(n); + } catch (t) { + n = T(String(t)); + } + return this[t(56)] + n; + } + [C(35)]() { + const t = C; + return [ + screen?.[t(45)] + screen?.height, + "" + new Date(), + performance?.[t(12)]?.[t(25)], + Math?.random(), + navigator.userAgent, + j( + Array.from(document[t(62)]) + [t(57)]((n) => n?.[t(60)]) + [t(4)]((t) => t) + ), + (Array[t(28)](document[t(62)] || []) + [t(57)]((n) => n?.src?.[t(14)]("c/[^/]*/_")) + [t(4)]((n) => n?.[t(31)])[0] ?? [])[0] ?? + document[t(50)].getAttribute(t(23)), + navigator[t(17)], + navigator[t(49)]?.join(","), + Math?.[t(27)](), + E(), + j(Object[t(38)](document)), + j(Object[t(38)](window)), + performance[t(10)](), + this[t(9)], + [...new URLSearchParams(window[t(6)][t(59)])[t(38)]()][t(44)](","), + navigator?.[t(39)], + performance.timeOrigin, + ]; + } + } + function _(t, n) { + const e = M(); + return (_ = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + function j(t) { + const n = C; + return t[Math[n(36)](Math.random() * t[n(31)])]; + } + function E() { + const t = C, + n = j(Object[t(38)](Object[t(65)](navigator))); + try { + return n + "−" + navigator[n][t(64)](); + } catch { + return "" + n; + } + } + function T(t) { + const n = C; + return ( + (t = JSON[n(26)](t)), + window[n(58)] + ? btoa(String[n(42)](...new TextEncoder()[n(46)](t))) + : btoa(unescape(encodeURIComponent(t))) + ); + } + function x(t) { + return ( + setTimeout(() => { + t({ timeRemaining: () => 1, didTimeout: !1 }); + }, 0), + 0 + ); + } + function M() { + const t = [ + "set", + "substring", + "required", + "_generateAnswerAsync", + "filter", + "requestIdleCallback", + "location", + "(((.+)+)+)+$", + "buildGenerateFailMessage", + "sid", + "now", + "imul", + "memory", + "proofofwork", + "match", + "requirementsSeed", + "_generateAnswerSync", + "language", + "resolve", + "answers", + "string", + "initializeAndGatherData", + "_generateRequirementsTokenAnswerBlocking", + "data-build", + "has", + "jsHeapSizeLimit", + "stringify", + "random", + "from", + "gAAAAAC", + "getRequirementsTokenBlocking", + "length", + "gAAAAAB", + "constructor", + "charCodeAt", + "getConfig", + "floor", + "forceSync", + "keys", + "hardwareConcurrency", + "apply", + "_getAnswer", + "fromCharCode", + "round", + "join", + "width", + "encode", + "_runCheck", + "padStart", + "languages", + "documentElement", + "then", + "getEnforcementTokenSync", + "wQ8Lk5FbGpA2NcR9dShT6gYjU7VxZ4D", + "timeRemaining", + "startEnforcement", + "errorPrefix", + "map", + "TextEncoder", + "search", + "src", + "maxAttempts", + "scripts", + "get", + "toString", + "getPrototypeOf", + ]; + return (M = function () { + return t; + })(); + } + var P = new O(); + const R = (function () { + let t = !0; + return function (n, e) { + const r = t + ? function () { + if (e) { + const t = e[yt(18)](n, arguments); + return (e = null), t; + } + } + : function () {}; + return (t = !1), r; + }; + })(), + U = R(void 0, function () { + const t = yt; + return U[t(17)]()[t(15)](t(20))[t(17)]()[t(10)](U)[t(15)](t(20)); + }); + U(); + const I = 0, + N = 1, + q = 2, + D = 3, + $ = 4, + L = 5, + F = 6, + G = 24, + J = 7, + z = 8, + B = 9, + H = 10, + W = 11, + V = 12, + Z = 13, + K = 14, + Q = 15, + Y = 16, + X = 17, + tt = 18, + nt = 19, + et = 23, + rt = 20, + ot = 21, + it = 22, + ct = 25, + st = 26, + ut = 27, + at = 28, + ft = 29, + lt = 30, + dt = 31, + pt = 32, + ht = 33, + gt = new Map(); + let wt = 0; + function mt() { + const t = [ + "clear", + "fromCharCode", + "set", + "abs", + "match", + "bind", + "filter", + "isArray", + "charCodeAt", + "get", + "constructor", + "scripts", + "max", + "stringify", + "shift", + "search", + "length", + "toString", + "apply", + "map", + "(((.+)+)+)+$", + "parse", + "from", + ]; + return (mt = function () { + return t; + })(); + } + function yt(t, n) { + const e = mt(); + return (yt = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + function vt() { + const t = yt; + for (; gt[t(9)](B)[t(16)] > 0; ) { + const [n, ...e] = gt[t(9)](B)[t(14)](); + gt[t(9)](n)(...e), wt++; + } + } + function bt(t) { + return new Promise((n, e) => { + const r = yt; + let o = !1; + setTimeout(() => { + (o = !0), n("" + wt); + }, 100), + gt.set(D, (t) => { + !o && ((o = !0), n(btoa("" + t))); + }), + gt[r(2)]($, (t) => { + !o && ((o = !0), e(btoa("" + t))); + }), + gt[r(2)](lt, (t, n, e, i) => { + const c = r, + s = Array[c(7)](i), + u = s ? e : [], + a = (s ? i : e) || []; + gt.set(t, (...t) => { + const e = c; + if (o) return; + const r = [...gt[e(9)](B)]; + let i; + try { + if (s) + for (let n = 0; n < u[e(16)]; n++) { + const r = u[n], + o = t[n]; + gt[e(2)](r, o); + } + gt[e(2)](B, [...a]), vt(), (i = gt[e(9)](n)); + } catch (t) { + i = "" + t; + } finally { + gt[e(2)](B, r); + } + return i; + }); + }); + try { + gt[r(2)](B, JSON[r(21)](St(atob(t), "" + gt[r(9)](Y)))), vt(); + } catch (t) { + n(btoa(wt + ": " + t)); + } + }); + } + function kt(t) { + (function () { + const t = yt; + gt[t(0)](), + gt[t(2)](I, bt), + gt[t(2)](N, (n, e) => + gt[t(2)](n, St("" + gt[t(9)](n), "" + gt[t(9)](e))) + ), + gt[t(2)](q, (n, e) => gt[t(2)](n, e)), + gt.set(L, (n, e) => { + const r = t, + o = gt[r(9)](n); + Array[r(7)](o) ? o.push(gt[r(9)](e)) : gt[r(2)](n, o + gt[r(9)](e)); + }), + gt[t(2)](ut, (n, e) => { + const r = t, + o = gt[r(9)](n); + Array[r(7)](o) + ? o.splice(o.indexOf(gt[r(9)](e)), 1) + : gt.set(n, o - gt[r(9)](e)); + }), + gt.set(ft, (n, e, r) => gt.set(n, gt.get(e) < gt[t(9)](r))), + gt[t(2)](ht, (n, e, r) => { + const o = t, + i = Number(gt[o(9)](e)), + c = Number(gt.get(r)); + gt[o(2)](n, i * c); + }), + gt.set(F, (n, e, r) => gt[t(2)](n, gt[t(9)](e)[gt[t(9)](r)])), + gt[t(2)](J, (n, ...e) => gt[t(9)](n)(...e[t(19)]((n) => gt[t(9)](n)))), + gt.set(X, (n, e, ...r) => + gt.set(n, gt[t(9)](e)(...r[t(19)]((n) => gt[t(9)](n)))) + ), + gt[t(2)](Z, (n, e, ...r) => { + const o = t; + try { + gt[o(9)](e)(...r); + } catch (t) { + gt[o(2)](n, "" + t); + } + }), + gt[t(2)](z, (n, e) => gt.set(n, gt[t(9)](e))), + gt[t(2)](H, window), + gt[t(2)](W, (n, e) => + gt.set( + n, + (Array[t(22)](document[t(11)] || []) + [t(19)]((n) => n?.src?.[t(4)](gt[t(9)](e))) + [t(6)]((n) => n?.[t(16)])[0] ?? [])[0] ?? null + ) + ), + gt[t(2)](V, (t) => gt.set(t, gt)), + gt[t(2)](K, (n, e) => gt[t(2)](n, JSON[t(21)]("" + gt.get(e)))), + gt[t(2)](Q, (n, e) => gt.set(n, JSON[t(13)](gt[t(9)](e)))), + gt[t(2)](tt, (n) => gt[t(2)](n, atob("" + gt[t(9)](n)))), + gt[t(2)](nt, (t) => gt.set(t, btoa("" + gt.get(t)))), + gt.set(rt, (n, e, r, ...o) => + gt[t(9)](n) === gt[t(9)](e) ? gt.get(r)(...o) : null + ), + gt[t(2)](ot, (n, e, r, o, ...i) => + Math[t(3)](gt.get(n) - gt.get(e)) > gt[t(9)](r) + ? gt[t(9)](o)(...i) + : null + ), + gt.set(et, (n, e, ...r) => + void 0 !== gt[t(9)](n) ? gt[t(9)](e)(...r) : null + ), + gt[t(2)](G, (n, e, r) => + gt[t(2)](n, gt.get(e)[gt[t(9)](r)][t(5)](gt.get(e))) + ), + gt[t(2)](it, (n, e) => { + const r = t, + o = [...gt[r(9)](B)]; + gt[r(2)](B, [...e]); + try { + vt(); + } catch (t) { + gt[r(2)](n, "" + t); + } finally { + gt[r(2)](B, o); + } + }), + gt[t(2)](dt, (n) => { + const e = t, + r = gt[e(9)](n) || 0; + gt[e(2)](n, r + 1); + }), + gt[t(2)](pt, (n, e, r, o, i) => { + const c = t, + s = gt[c(9)](n) || 0, + u = Math[c(12)](0, s - 1); + gt[c(2)](n, u); + const a = gt.get(e) || 0, + f = gt.get(i) || 0; + if (u === a && 1 === f) + try { + const t = String(gt[c(9)](r) ?? ""); + if (!t) return; + const n = St(atob(t), "" + gt.get(o)), + e = JSON.parse(n), + i = [...gt[c(9)](B)]; + gt[c(2)](B, [...e]), vt(), gt[c(2)](B, i); + } catch {} + }), + gt.set(at, () => {}), + gt.set(st, () => {}), + gt[t(2)](ct, () => {}); + })(), + (wt = 0), + gt.set(Y, t); + } + function St(t, n) { + const e = yt; + let r = ""; + for (let o = 0; o < t[e(16)]; o++) + r += String[e(1)](t[e(8)](o) ^ n[e(8)](o % n[e(16)])); + return r; + } + var At = + "undefined" != typeof globalThis + ? globalThis + : "undefined" != typeof window + ? window + : "undefined" != typeof global + ? global + : "undefined" != typeof self + ? self + : {}; + function Ct(t) { + return t && + t.__esModule && + Object.prototype.hasOwnProperty.call(t, "default") + ? t.default + : t; + } + var Ot = Object.freeze({ + __proto__: null, + commonjsGlobal: At, + getAugmentedNamespace: function (t) { + if (t.__esModule) return t; + var n = t.default; + if ("function" == typeof n) { + var e = function t() { + if (this instanceof t) { + var e = [null]; + return ( + e.push.apply(e, arguments), new (Function.bind.apply(n, e))() + ); + } + return n.apply(this, arguments); + }; + e.prototype = n.prototype; + } else e = {}; + return ( + Object.defineProperty(e, "__esModule", { value: !0 }), + Object.keys(t).forEach(function (n) { + var r = Object.getOwnPropertyDescriptor(t, n); + Object.defineProperty( + e, + n, + r.get + ? r + : { + enumerable: !0, + get: function () { + return t[n]; + }, + } + ); + }), + e + ); + }, + getDefaultExportFromCjs: Ct, + getDefaultExportFromNamespaceIfNotNamed: function (t) { + return t && + Object.prototype.hasOwnProperty.call(t, "default") && + 1 === Object.keys(t).length + ? t.default + : t; + }, + getDefaultExportFromNamespaceIfPresent: function (t) { + return t && Object.prototype.hasOwnProperty.call(t, "default") + ? t.default + : t; + }, + }), + _t = {}, + jt = {}; + function Et(t, n) { + var e = qt(); + return (Et = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + var Tt, + xt = Et, + Mt = + ((Tt = !0), + function (t, n) { + var e = Tt + ? function () { + if (n) { + var e = n[Et(37)](t, arguments); + return (n = null), e; + } + } + : function () {}; + return (Tt = !1), e; + }), + Pt = Mt(void 0, function () { + var t = Et; + return Pt[t(9)]()[t(20)](t(39)).toString()[t(38)](Pt)[t(20)](t(39)); + }); + Pt(), + xt(8), + (jt[xt(32)] = function (t, n) { + var e = xt; + if (typeof t !== e(31)) throw new TypeError(e(41)); + for ( + var r = {}, o = n || {}, i = t.split(";"), c = o[e(13)] || Rt, s = 0; + s < i[e(42)]; + s++ + ) { + var u = i[s], + a = u[e(22)]("="); + if (!(a < 0)) { + var f = u[e(12)](0, a)[e(0)](); + if (null == r[f]) { + var l = u[e(12)](a + 1, u[e(42)])[e(0)](); + '"' === l[0] && (l = l[e(6)](1, -1)), (r[f] = Nt(l, c)); + } + } + } + return r; + }), + (jt[xt(33)] = function (t, n, e) { + var r = xt, + o = e || {}, + i = o[r(18)] || Ut; + if ("function" != typeof i) throw new TypeError(r(27)); + if (!It[r(45)](t)) throw new TypeError(r(21)); + var c = i(n); + if (c && !It[r(45)](c)) throw new TypeError(r(7)); + var s = t + "=" + c; + if (null != o[r(17)]) { + var u = o[r(17)] - 0; + if (isNaN(u) || !isFinite(u)) throw new TypeError(r(34)); + s += "; Max-Age=" + Math[r(29)](u); + } + if (o[r(26)]) { + if (!It[r(45)](o[r(26)])) throw new TypeError(r(40)); + s += r(16) + o[r(26)]; + } + if (o[r(5)]) { + if (!It[r(45)](o.path)) throw new TypeError(r(15)); + s += r(14) + o[r(5)]; + } + if (o.expires) { + if (typeof o[r(11)][r(1)] !== r(25)) throw new TypeError(r(3)); + s += "; Expires=" + o[r(11)][r(1)](); + } + if ((o[r(30)] && (s += r(44)), o.secure && (s += r(24)), o[r(19)])) { + switch (typeof o[r(19)] === r(31) ? o[r(19)][r(4)]() : o.sameSite) { + case !0: + s += r(28); + break; + case r(36): + s += r(23); + break; + case r(35): + s += r(28); + break; + case r(10): + s += r(43); + break; + default: + throw new TypeError(r(2)); + } + } + return s; + }); + var Rt = decodeURIComponent, + Ut = encodeURIComponent, + It = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/; + function Nt(t, n) { + try { + return n(t); + } catch (n) { + return t; + } + } + function qt() { + var t = [ + "trim", + "toUTCString", + "option sameSite is invalid", + "option expires is invalid", + "toLowerCase", + "path", + "slice", + "argument val is invalid", + "use strict", + "toString", + "none", + "expires", + "substring", + "decode", + "; Path=", + "option path is invalid", + "; Domain=", + "maxAge", + "encode", + "sameSite", + "search", + "argument name is invalid", + "indexOf", + "; SameSite=Lax", + "; Secure", + "function", + "domain", + "option encode is invalid", + "; SameSite=Strict", + "floor", + "httpOnly", + "string", + "parse", + "serialize", + "option maxAge is invalid", + "strict", + "lax", + "apply", + "constructor", + "(((.+)+)+)+$", + "option domain is invalid", + "argument str must be a string", + "length", + "; SameSite=None", + "; HttpOnly", + "test", + ]; + return (qt = function () { + return t; + })(); + } + function Dt(t, n) { + var e = $t(); + return (Dt = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + function $t() { + var t = [ + "null", + "req", + "hasCookie", + "function", + "getCookie", + "(((.+)+)+)+$", + "Set-Cookie", + "length", + "slice", + "cookies", + "false", + "reduce", + "setCookie", + "replace", + "hasOwnProperty", + "stringify", + "setCookies", + "prototype", + "deleteCookie", + "res", + "undefined", + "search", + "[WARN]: checkCookies was deprecated. It will be deleted in the new version. Use hasCookie instead.", + "constructor", + "commonjsGlobal", + "call", + "setHeader", + "entries", + "split", + "indexOf", + "concat", + "getCookies", + "cookie", + "getHeader", + "[WARN]: setCookies was deprecated. It will be deleted in the new version. Use setCookie instead.", + "warn", + "checkCookies", + "apply", + "toString", + "headers", + "__assign", + "defineProperty", + "getOwnPropertySymbols", + "join", + ]; + return ($t = function () { + return t; + })(); + } + !(function (t) { + var n, + e = Dt, + r = + ((n = !0), + function (t, e) { + var r = n + ? function () { + if (e) { + var n = e[Dt(37)](t, arguments); + return (e = null), n; + } + } + : function () {}; + return (n = !1), r; + }), + o = r(this, function () { + var t = Dt; + return o[t(38)]() + [t(21)]("(((.+)+)+)+$") + [t(38)]() + [t(23)](o) + [t(21)](t(5)); + }); + o(); + var i = + (Ot[e(24)] && Ot[e(24)][e(40)]) || + function () { + var t = e; + return ( + (i = + Object.assign || + function (t) { + for (var n, e = Dt, r = 1, o = arguments[e(7)]; r < o; r++) + for (var i in (n = arguments[r])) + Object[e(17)][e(14)][e(25)](n, i) && (t[i] = n[i]); + return t; + }), + i[t(37)](this, arguments) + ); + }, + c = + (Ot[e(24)] && At.__rest) || + function (t, n) { + var r = e, + o = {}; + for (var i in t) + Object[r(17)][r(14)].call(t, i) && n[r(29)](i) < 0 && (o[i] = t[i]); + if (null != t && typeof Object[r(42)] === r(3)) { + var c = 0; + for (i = Object[r(42)](t); c < i[r(7)]; c++) + n[r(29)](i[c]) < 0 && + Object.prototype.propertyIsEnumerable.call(t, i[c]) && + (o[i[c]] = t[i[c]]); + } + return o; + }; + Object[e(41)](t, "__esModule", { value: !0 }), + (t[e(36)] = + t[e(2)] = + t.removeCookies = + t[e(18)] = + t[e(16)] = + t[e(12)] = + t[e(4)] = + t[e(31)] = + void 0); + var s = jt, + u = function () { + return typeof window !== e(20); + }, + a = function (t) { + var n = e; + void 0 === t && (t = ""); + try { + var r = JSON[n(15)](t); + return /^[\{\[]/.test(r) ? r : t; + } catch (n) { + return t; + } + }; + t[e(31)] = function (t) { + var n, + r = e; + if ((t && (n = t.req), !u())) + return n && n[r(9)] + ? n[r(9)] + : n && n.headers && n[r(39)][r(32)] + ? (0, s.parse)(n.headers[r(32)]) + : {}; + for ( + var o = {}, + i = document.cookie ? document[r(32)][r(28)]("; ") : [], + c = 0, + a = i[r(7)]; + c < a; + c++ + ) { + var f = i[c][r(28)]("="), + l = f[r(8)](1)[r(43)]("="); + o[f[0]] = l; + } + return o; + }; + t[e(4)] = function (n, r) { + var o = (0, t.getCookies)(r)[n]; + if (void 0 !== o) + return (function (t) { + var n = e; + return ( + "true" === t || + (t !== n(10) && + ("undefined" !== t ? (t === n(0) ? null : t) : void 0)) + ); + })( + (function (t) { + return t ? t[e(13)](/(%[0-9A-Z]{2})+/g, decodeURIComponent) : t; + })(o) + ); + }; + t.setCookie = function (t, n, r) { + var o, + f, + l, + d = e; + r && ((f = r[d(1)]), (l = r[d(19)]), (o = c(r, [d(1), d(19)]))); + var p = (0, s.serialize)(t, a(n), i({ path: "/" }, o)); + if (u()) document.cookie = p; + else if (l && f) { + var h = l[d(33)](d(6)); + if ( + (!Array.isArray(h) && (h = h ? [String(h)] : []), + l[d(26)](d(6), h[d(30)](p)), + f && f[d(9)]) + ) { + var g = f[d(9)]; + "" === n ? delete g[t] : (g[t] = a(n)); + } + if (f && f[d(39)] && f.headers[d(32)]) { + g = (0, s.parse)(f[d(39)][d(32)]); + "" === n ? delete g[t] : (g[t] = a(n)), + (f[d(39)][d(32)] = Object[d(27)](g)[d(11)](function (t, n) { + var e = d; + return t[e(30)](""[e(30)](n[0], "=").concat(n[1], ";")); + }, "")); + } + } + }; + t[e(16)] = function (n, r, o) { + var i = e; + return console[i(35)](i(34)), (0, t[i(12)])(n, r, o); + }; + t[e(18)] = function (n, r) { + return (0, t[e(12)])(n, "", i(i({}, r), { maxAge: -1 })); + }; + t.removeCookies = function (n, r) { + return ( + console[e(35)]( + "[WARN]: removeCookies was deprecated. It will be deleted in the new version. Use deleteCookie instead." + ), + (0, t.deleteCookie)(n, r) + ); + }; + t.hasCookie = function (n, e) { + return !!n && (0, t.getCookies)(e).hasOwnProperty(n); + }; + t[e(36)] = function (n, r) { + var o = e; + return console[o(35)](o(22)), (0, t.hasCookie)(n, r); + }; + })(_t), + Ct(_t); + const Lt = sn, + Ft = Lt(5); + const Gt = (function () { + const t = Lt, + n = (function () { + let t = !0; + return function (n, e) { + const r = t + ? function () { + if (e) { + const t = e[sn(48)](n, arguments); + return (e = null), t; + } + } + : function () {}; + return (t = !1), r; + }; + })(), + e = n(this, function () { + const t = sn; + return e[t(33)]() + .search("(((.+)+)+)+$") + [t(33)]() + [t(31)](e) + [t(1)]("(((.+)+)+)+$"); + }); + if ((e(), "undefined" != typeof document)) { + const n = document[t(23)]; + if (n?.[t(22)]) + try { + const e = new URL(n[t(22)]); + if (e[t(41)].includes(t(18))) + return e[t(49)] + "/backend-api/sentinel/"; + } catch {} + } + return Ft; + })(), + Jt = new URL("frame.html", Gt), + zt = (() => { + const t = Lt; + if (window[t(42)] === window) return !1; + try { + const n = new URL(window[t(24)].href); + return Jt[t(41)] === n[t(41)]; + } catch { + return !1; + } + })(); + const Bt = 5e3; + let Ht = null, + Wt = null, + Vt = 0; + const Zt = (t) => (t ? t[Lt(14)](/(%[0-9A-Z]{2})+/g, decodeURIComponent) : t); + function Kt(t, n) { + const e = Lt; + return ( + (t.id = (function () { + const t = _t.getCookies()["oai-did"]; + return void 0 === t ? void 0 : Zt(t); + })()), + (t[e(4)] = n), + JSON[e(37)](t) + ); + } + async function Qt(t, n) { + const e = Lt; + for (let r = 0; r < 3; r++) + try { + const r = await fetch(Gt + e(50), { + method: e(26), + body: Kt({ p: n }, t), + credentials: e(45), + })[e(28)]((t) => t[e(29)]()); + return (Vt = Date[e(35)]()), void (Wt = r); + } catch (o) { + if (r >= 2) return Kt({ e: o[e(38)], p: n, a: r }, t); + } + } + const Yt = Jt[Lt(49)]; + let Xt = null, + tn = !1; + const nn = new Map(); + let en = 0; + function rn() { + const t = Lt, + n = document[t(8)](t(27)); + return ( + (n.style.display = t(32)), + (n.src = Jt[t(21)]), + document[t(20)][t(6)](n), + n + ); + } + function on() { + const t = [ + "string", + "search", + "getRequirementsToken", + "length", + "flow", + "https://chatgpt.com/backend-api/sentinel/", + "appendChild", + "contentWindow", + "createElement", + "__auto", + "__sentinel_token_pending", + "source", + "get", + "race", + "replace", + "delete", + "response", + "set", + "/sentinel/", + "postMessage", + "body", + "href", + "src", + "currentScript", + "location", + "addEventListener", + "POST", + "iframe", + "then", + "json", + "data", + "constructor", + "none", + "toString", + "req_", + "now", + "init", + "stringify", + "message", + "getEnforcementToken", + "__sentinel_init_pending", + "pathname", + "top", + "cachedProof", + "turnstile", + "include", + "load", + "forEach", + "apply", + "origin", + "req", + "token", + ]; + return (on = function () { + return t; + })(); + } + function cn(t, n, e) { + return new Promise((r, o) => { + const i = sn; + function c() { + const i = sn, + c = Lt(34) + ++en; + nn[i(17)](c, { resolve: r, reject: o }), + Xt?.[i(7)]?.[i(19)]({ type: t, flow: n, requestId: c, ...e }, Yt); + } + Xt + ? tn + ? c() + : Xt[i(25)](i(46), () => { + (tn = !0), c(); + }) + : ((Xt = rn()), + Xt[i(25)](i(46), () => { + (tn = !0), c(); + })); + }); + } + function sn(t, n) { + const e = on(); + return (sn = function (t, n) { + return e[(t -= 0)]; + })(t, n); + } + async function un(t) { + const n = Lt; + if (zt) + throw new Error("init() should not be called from within an iframe."); + const e = await P[n(2)](); + return (Ht = e), kt(Ht), cn(n(36), t, { p: e }); + } + async function an(t) { + const n = Lt; + if (zt) + throw new Error("token() should not be called from within an iframe."); + const e = Date[n(35)](); + if (!Wt || e - Vt > 54e4) { + const e = await P[n(2)](); + (Ht = e), kt(Ht); + const r = await cn(n(51), t, { p: e }); + if (typeof r === n(0)) return r; + (Wt = r.cachedChatReq), (Ht = r[n(43)]); + } + try { + const e = await P[n(39)](Wt), + r = Kt( + { + p: e, + t: Wt?.turnstile?.dx ? await bt(Wt[n(44)].dx) : null, + c: Wt.token, + }, + t + ); + return ( + (Wt = null), + setTimeout(async () => { + const e = n, + r = t + e(9), + o = await P[e(2)](); + (Ht = o), kt(Ht), cn(e(36), r, { p: o }); + }, Bt), + r + ); + } catch (n) { + const e = Kt({ e: n.message, p: Wt?.p }, t); + return (Wt = null), e; + } + } + return ( + zt + ? window[Lt(25)]("message", async (t) => { + const n = Lt, + { type: e, flow: r, requestId: o, p: i } = t[n(30)]; + try { + let c; + e === n(36) + ? (c = await Qt(r, i)) + : "token" === e && + (c = await (async function (t, n) { + const e = Lt, + r = Date[e(35)](); + if (!Wt || r - Vt > 54e4) { + const r = await Promise[e(13)]([ + Qt(t, n), + new Promise((e) => + setTimeout(() => e(Kt({ e: "elapsed", p: n }, t)), 4e3) + ), + ]); + if (null != r) return r; + } + return (Vt = 0), { cachedChatReq: Wt, cachedProof: Ht }; + })(r, i)), + t[n(11)]?.[n(19)]( + { type: n(16), requestId: o, result: c }, + { targetOrigin: t[n(49)] } + ); + } catch (e) { + t[n(11)]?.postMessage( + { type: n(16), requestId: o, error: e[n(38)] }, + { targetOrigin: t[n(49)] } + ); + } + }) + : (function () { + const t = Lt; + window.addEventListener(t(38), (n) => { + const e = t; + if (n[e(11)] === Xt?.[e(7)]) { + const { type: t, requestId: r, result: o, error: i } = n[e(30)]; + if (t === e(16) && r && nn.has(r)) { + const { resolve: t, reject: n } = nn[e(12)](r); + i ? n(i) : t(o), nn[e(15)](r); + } + } + }), + !Xt && + ((Xt = rn()), + Xt[t(25)](t(46), () => { + tn = !0; + })); + })(), + (function () { + const t = Lt; + (!window?.[t(10)] || 0 === window?.[t(10)][t(3)]) && + (window?.__sentinel_init_pending?.[t(47)](({ args: n, resolve: e }) => { + un[t(48)](null, n).then(e); + }), + (window[t(40)] = [])), + window?.[t(10)]?.forEach(({ args: n, resolve: e }) => { + const r = t; + an[r(48)](null, n)[r(28)](e); + }), + (window[t(10)] = []); + })(), + (t.init = un), + (t.token = an), + t + ); +})({}); diff --git a/config.py b/config.py new file mode 100644 index 0000000..9c5a715 --- /dev/null +++ b/config.py @@ -0,0 +1,34 @@ +# config.py +"""全局配置""" + +# OpenAI 端点 +AUTH_BASE_URL = "https://auth.openai.com" +SENTINEL_BASE_URL = "https://sentinel.openai.com/sentinel" + +# SDK 路径 +SDK_JS_PATH = "assets/sdk.js" + +# 浏览器指纹配置 +FINGERPRINT_CONFIG = { + 'user_agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0', + 'screen_width': 1920, + 'screen_height': 1080, + 'languages': ['en-US', 'en'], + 'hardware_concurrency': 8, + 'platform': 'Linux x86_64', +} + +# HTTP 配置 +HTTP_CONFIG = { + 'impersonate': 'chrome110', # curl-cffi 的浏览器模拟 + 'timeout': 30, +} + +# PoW 配置 +POW_CONFIG = { + 'max_attempts': 500000, # SDK 默认值 + 'timeout': 60, # 求解超时(秒) +} + +# 调试模式 +DEBUG = True diff --git a/download_sdk.py b/download_sdk.py new file mode 100644 index 0000000..f37e3a0 --- /dev/null +++ b/download_sdk.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# download_sdk.py +"""下载 OpenAI Sentinel SDK""" + +import requests +from pathlib import Path + +SDK_URL = "https://sentinel.openai.com/sentinel/97790f37/sdk.js" +OUTPUT_PATH = Path("assets/sdk.js") + +def download_sdk(): + print(f"Downloading SDK from {SDK_URL}...") + + OUTPUT_PATH.parent.mkdir(exist_ok=True) + + resp = requests.get(SDK_URL) + resp.raise_for_status() + + with open(OUTPUT_PATH, 'wb') as f: + f.write(resp.content) + + print(f"✓ SDK saved to {OUTPUT_PATH}") + print(f" Size: {len(resp.content) / 1024:.1f} KB") + +if __name__ == '__main__': + download_sdk() diff --git a/main.py b/main.py new file mode 100644 index 0000000..9d561dd --- /dev/null +++ b/main.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# main.py +"""OpenAI Sentinel Bypass - 主入口""" + +import sys +import argparse +from modules import OpenAIRegistrar +from config import DEBUG + + +def main(): + parser = argparse.ArgumentParser( + description='OpenAI Registration Automation (Sentinel Bypass)' + ) + + parser.add_argument( + 'email', + help='Email address to register' + ) + + parser.add_argument( + 'password', + help='Password for the account' + ) + + parser.add_argument( + '--session-id', + help='Custom session ID (default: auto-generated UUID)', + default=None + ) + + parser.add_argument( + '--quiet', + action='store_true', + help='Suppress debug output' + ) + + args = parser.parse_args() + + # 设置调试模式 + if args.quiet: + import config + config.DEBUG = False + + # 创建注册器 + registrar = OpenAIRegistrar(session_id=args.session_id) + + # 执行注册 + result = registrar.register(args.email, args.password) + + # 输出结果 + print("\n" + "="*60) + if result['success']: + print("✓ REGISTRATION SUCCESSFUL") + print(f"Email: {args.email}") + if 'data' in result: + print(f"Response: {result['data']}") + else: + print("✗ REGISTRATION FAILED") + print(f"Error: {result.get('error', 'Unknown error')}") + if 'status_code' in result: + print(f"Status code: {result['status_code']}") + print("="*60) + + # 返回退出码 + sys.exit(0 if result['success'] else 1) + + +if __name__ == '__main__': + main() diff --git a/modules/__init__.py b/modules/__init__.py new file mode 100644 index 0000000..0721bae --- /dev/null +++ b/modules/__init__.py @@ -0,0 +1,16 @@ +# modules/__init__.py +"""Sentinel Bypass 模块包""" + +from .fingerprint import BrowserFingerprint +from .js_executor import JSExecutor +from .sentinel_solver import SentinelSolver +from .http_client import HTTPClient +from .register import OpenAIRegistrar + +__all__ = [ + 'BrowserFingerprint', + 'JSExecutor', + 'SentinelSolver', + 'HTTPClient', + 'OpenAIRegistrar', +] diff --git a/modules/fingerprint.py b/modules/fingerprint.py new file mode 100644 index 0000000..c5304ab --- /dev/null +++ b/modules/fingerprint.py @@ -0,0 +1,135 @@ +# modules/fingerprint.py +"""浏览器指纹生成器""" + +import uuid +import random +import time +from datetime import datetime +from typing import Dict, List, Any + +from config import FINGERPRINT_CONFIG + + +class BrowserFingerprint: + """生成符合 SDK 期望的浏览器指纹""" + + def __init__(self, session_id: str = None): + self.session_id = session_id or str(uuid.uuid4()) + self.user_agent = FINGERPRINT_CONFIG['user_agent'] + self.screen_width = FINGERPRINT_CONFIG['screen_width'] + self.screen_height = FINGERPRINT_CONFIG['screen_height'] + self.languages = FINGERPRINT_CONFIG['languages'] + self.hardware_concurrency = FINGERPRINT_CONFIG['hardware_concurrency'] + + def get_config_array(self) -> List[Any]: + """ + 生成 SDK getConfig() 函数返回的 18 元素数组 + + 对应 SDK 源码: + [0]: screen.width + screen.height + [1]: new Date().toString() + [2]: performance.memory.jsHeapSizeLimit (可选) + [3]: nonce (PoW 填充) + [4]: navigator.userAgent + [5]: 随机 script.src + [6]: build ID + [7]: navigator.language + [8]: navigator.languages.join(',') + [9]: 运行时间 (PoW 填充) + [10]: 随机 navigator 属性 + [11]: 随机 document key + [12]: 随机 window key + [13]: performance.now() + [14]: session UUID + [15]: URL search params + [16]: navigator.hardwareConcurrency + [17]: performance.timeOrigin + """ + + # 模拟的 script sources + fake_scripts = [ + "https://sentinel.openai.com/sentinel/97790f37/sdk.js", + "https://chatgpt.com/static/js/main.abc123.js", + "https://cdn.oaistatic.com/_next/static/chunks/main.js", + ] + + # 模拟的 navigator 属性名 + navigator_props = [ + 'hardwareConcurrency', 'language', 'languages', + 'platform', 'userAgent', 'vendor' + ] + + # 模拟的 document keys + document_keys = ['body', 'head', 'documentElement', 'scripts'] + + # 模拟的 window keys + window_keys = ['performance', 'navigator', 'document', 'location'] + + current_time = time.time() * 1000 + + return [ + self.screen_width + self.screen_height, # [0] + str(datetime.now()), # [1] + None, # [2] memory + None, # [3] nonce (placeholder) + self.user_agent, # [4] + random.choice(fake_scripts), # [5] + "97790f37", # [6] build ID + self.languages[0], # [7] + ",".join(self.languages), # [8] + None, # [9] runtime (placeholder) + f"{random.choice(navigator_props)}−{random.randint(1, 16)}", # [10] + random.choice(document_keys), # [11] + random.choice(window_keys), # [12] + current_time, # [13] + self.session_id, # [14] + "", # [15] URL params + self.hardware_concurrency, # [16] + current_time - random.uniform(100, 1000), # [17] timeOrigin + ] + + def get_cookies(self) -> Dict[str, str]: + """生成初始 cookies""" + return { + 'oai-did': self.session_id, + } + + def get_headers(self, with_sentinel: str = None) -> Dict[str, str]: + """生成 HTTP headers""" + + # 基础 headers + headers = { + 'User-Agent': self.user_agent, + 'Accept': 'application/json', + 'Accept-Language': f"{self.languages[0]},{self.languages[1]};q=0.5", + 'Accept-Encoding': 'gzip, deflate, br, zstd', + 'Referer': 'https://auth.openai.com/create-account/password', + 'Content-Type': 'application/json', + 'Origin': 'https://auth.openai.com', + 'Connection': 'keep-alive', + 'Sec-Fetch-Dest': 'empty', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Site': 'same-origin', + 'Priority': 'u=4', + 'Pragma': 'no-cache', + 'Cache-Control': 'no-cache', + } + + # Sentinel token + if with_sentinel: + headers['openai-sentinel-token'] = with_sentinel + + # Datadog RUM tracing (OpenAI 使用) + trace_id = random.randint(10**18, 10**19 - 1) + parent_id = random.randint(10**18, 10**19 - 1) + + headers.update({ + 'traceparent': f'00-0000000000000000{trace_id:016x}-{parent_id:016x}-01', + 'tracestate': 'dd=s:1;o:rum', + 'x-datadog-origin': 'rum', + 'x-datadog-parent-id': str(parent_id), + 'x-datadog-sampling-priority': '1', + 'x-datadog-trace-id': str(trace_id), + }) + + return headers diff --git a/modules/http_client.py b/modules/http_client.py new file mode 100644 index 0000000..16e5b8f --- /dev/null +++ b/modules/http_client.py @@ -0,0 +1,181 @@ +# modules/http_client.py +"""HTTP 客户端(支持 CSRF token)""" + +from typing import Dict, Optional +import requests +from requests.adapters import HTTPAdapter +from urllib3.util.ssl_ import create_urllib3_context +from urllib.parse import unquote + +from .fingerprint import BrowserFingerprint +from config import HTTP_CONFIG, DEBUG + + +class TLSAdapter(HTTPAdapter): + """自定义 TLS 适配器""" + def init_poolmanager(self, *args, **kwargs): + ctx = create_urllib3_context() + ctx.set_ciphers( + 'TLS_AES_128_GCM_SHA256:' + 'TLS_AES_256_GCM_SHA384:' + 'TLS_CHACHA20_POLY1305_SHA256:' + 'ECDHE-ECDSA-AES128-GCM-SHA256:' + 'ECDHE-RSA-AES128-GCM-SHA256' + ) + kwargs['ssl_context'] = ctx + return super().init_poolmanager(*args, **kwargs) + + +class HTTPClient: + """HTTP 客户端(自动处理 CSRF)""" + + def __init__(self, fingerprint: BrowserFingerprint): + self.fingerprint = fingerprint + self.session = requests.Session() + + adapter = TLSAdapter() + self.session.mount('https://', adapter) + + self.cookies = fingerprint.get_cookies() + self.csrf_token = None + + def extract_csrf_from_cookies(self) -> Optional[str]: + """从 cookies 中提取 CSRF token""" + csrf_cookie = self.cookies.get('__Host-next-auth.csrf-token') + + if not csrf_cookie: + return None + + try: + decoded = unquote(csrf_cookie) + token = decoded.split('|')[0] + + if DEBUG: + print(f"[HTTP] Extracted CSRF from cookie: {token[:20]}...") + + return token + except Exception as e: + if DEBUG: + print(f"[HTTP] Failed to extract CSRF: {e}") + return None + + def get(self, url: str, **kwargs) -> requests.Response: + """GET 请求""" + kwargs.setdefault('headers', self.fingerprint.get_headers()) + kwargs.setdefault('cookies', self.cookies) + kwargs.setdefault('timeout', HTTP_CONFIG['timeout']) + + if DEBUG: + print(f"[HTTP] GET {url}") + + resp = self.session.get(url, **kwargs) + + # 更新 cookies + self.cookies.update(resp.cookies.get_dict()) + + # 尝试提取 CSRF + csrf = self.extract_csrf_from_cookies() + if csrf: + self.csrf_token = csrf + + if DEBUG: + print(f"[HTTP] Response: {resp.status_code}") + print(f"Cookies: {list(self.cookies.keys())}") + + return resp + + def get_csrf_token(self) -> Optional[str]: + """ + 获取 CSRF token + + 尝试多种方法: + 1. 从现有 cookie 提取 + 2. 访问 /api/auth/csrf + 3. 如果都失败,返回 None(某些流程可能不需要) + """ + # 1. 从 cookie 提取 + csrf = self.extract_csrf_from_cookies() + if csrf: + self.csrf_token = csrf + return csrf + + # 2. 访问 /api/auth/csrf + if DEBUG: + print("[HTTP] Requesting CSRF token from /api/auth/csrf...") + + try: + url = "https://auth.openai.com/api/auth/csrf" + + resp = self.session.get( + url, + headers=self.fingerprint.get_headers(), + cookies=self.cookies, + timeout=HTTP_CONFIG['timeout'] + ) + + # 更新 cookies + self.cookies.update(resp.cookies.get_dict()) + + # 尝试从 cookie 提取 + csrf = self.extract_csrf_from_cookies() + if csrf: + self.csrf_token = csrf + return csrf + + # 尝试从 JSON 提取 + if resp.status_code == 200: + try: + data = resp.json() + csrf = data.get('csrfToken') + if csrf: + self.csrf_token = csrf + return csrf + except: + pass + + except Exception as e: + if DEBUG: + print(f"[HTTP] Failed to get CSRF token: {e}") + + # 3. 失败,返回 None + if DEBUG: + print("[HTTP] ⚠ CSRF token not available (may not be required)") + + return None + + def post(self, url: str, json_data: Optional[Dict] = None, + sentinel_token: Optional[str] = None, **kwargs) -> requests.Response: + """POST 请求""" + + headers = self.fingerprint.get_headers(with_sentinel=sentinel_token) + + # 添加 CSRF token(如果有) + if self.csrf_token: + headers['openai-sentinel-csrf-token'] = self.csrf_token + + # 添加必需 headers + headers['Referer'] = 'https://auth.openai.com/' + headers['Origin'] = 'https://auth.openai.com' + + kwargs.setdefault('headers', headers) + kwargs.setdefault('cookies', self.cookies) + kwargs.setdefault('timeout', HTTP_CONFIG['timeout']) + + if json_data: + kwargs['json'] = json_data + + if DEBUG: + print(f"[HTTP] POST {url}") + if self.csrf_token: + print(f"[HTTP] With CSRF token: {self.csrf_token[:20]}...") + if sentinel_token: + print(f"[HTTP] With Sentinel token: {sentinel_token[:50]}...") + + resp = self.session.post(url, **kwargs) + + self.cookies.update(resp.cookies.get_dict()) + + if DEBUG: + print(f"[HTTP] Response: {resp.status_code}") + + return resp diff --git a/modules/js_executor.py b/modules/js_executor.py new file mode 100644 index 0000000..b615c8b --- /dev/null +++ b/modules/js_executor.py @@ -0,0 +1,245 @@ +"""JavaScript 执行引擎封装 + +说明: +- OpenAI 的 `assets/sdk.js` 是浏览器脚本,包含多段 anti-debug 代码与 DOM 初始化逻辑。 +- 直接用 PyExecJS/ExecJS 在 Node 环境执行时,常见表现是「compile 成功但 call 卡死」。 +- 这里改为通过 `node -` 运行一段自包含脚本:先做轻量净化 + browser shim,再执行目标函数并强制输出结果。 +""" + +from __future__ import annotations + +import json +import re +import subprocess +from pathlib import Path +from typing import Any, Dict, Optional + +from config import DEBUG, SDK_JS_PATH + + +class JSExecutor: + """通过 Node.js 执行 Sentinel SDK 内部逻辑(支持 async Turnstile VM)""" + + def __init__(self): + self._sdk_code: str = "" + self._load_sdk() + + def _load_sdk(self) -> None: + sdk_path = Path(SDK_JS_PATH) + if not sdk_path.exists(): + raise FileNotFoundError(f"SDK not found at {SDK_JS_PATH}") + + sdk_code = sdk_path.read_text(encoding="utf-8") + sdk_code = self._sanitize_sdk(sdk_code) + sdk_code = self._inject_internal_exports(sdk_code) + + self._sdk_code = sdk_code + + if DEBUG: + print("[JSExecutor] SDK loaded successfully (sanitized)") + + def _sanitize_sdk(self, sdk_code: str) -> str: + """移除会在 Node 环境中导致卡死/超慢的 anti-debug 片段。""" + # 1) 删除少量已知的顶层 anti-debug 直接调用(独占一行) + sdk_code = re.sub(r"(?m)^\s*[rugkU]\(\);\s*$", "", sdk_code) + sdk_code = re.sub(r"(?m)^\s*o\(\);\s*$", "", sdk_code) + + # 2) 删除 `Pt(),` 这种逗号表达式里的 anti-debug 调用(避免语法破坏) + sdk_code = re.sub(r"\bPt\(\),\s*", "", sdk_code) + sdk_code = re.sub(r"\bPt\(\);\s*", "", sdk_code) + + # 3) 删除 class 字段初始化里的 anti-debug 调用:`return n(), "" + Math.random();` + sdk_code = re.sub( + r'return\s+n\(\),\s*""\s*\+\s*Math\.random\(\)\s*;', + 'return "" + Math.random();', + sdk_code, + ) + + # 4) 删除类似 `if ((e(), cond))` 的逗号 anti-debug 调用(保留 cond) + # 仅处理极短标识符,避免误伤正常逻辑;保留 Turnstile VM 的 `vt()`。 + def _strip_comma_call(match: re.Match[str]) -> str: + fn = match.group(1) + if fn == "vt": + return match.group(0) + return "(" + + sdk_code = re.sub( + r"\(\s*([A-Za-z_$][A-Za-z0-9_$]{0,2})\(\)\s*,", + _strip_comma_call, + sdk_code, + ) + return sdk_code + + def _inject_internal_exports(self, sdk_code: str) -> str: + """把 SDK 内部对象导出到 `SentinelSDK` 上,便于在外部调用。""" + # SDK 末尾一般是: + # (t.init = un), + # (t.token = an), + # t + # ); + pattern = re.compile( + r"\(\s*t\.init\s*=\s*un\s*\)\s*,\s*\(\s*t\.token\s*=\s*an\s*\)\s*,\s*t\s*\)", + re.MULTILINE, + ) + + replacement = ( + "(t.init = un)," + "(t.token = an)," + "(t.__O = O)," + "(t.__P = P)," + "(t.__bt = bt)," + "(t.__kt = kt)," + "(t.__Kt = Kt)," + "t)" + ) + + new_code, n = pattern.subn(replacement, sdk_code, count=1) + if n != 1: + raise RuntimeError("Failed to patch SDK exports; SDK format may have changed.") + return new_code + + def _node_script(self, payload: Dict[str, Any], entry: str) -> str: + payload_json = json.dumps(payload, ensure_ascii=False) + + shim = r""" +// --- minimal browser shims for Node --- +if (typeof globalThis.window !== "object") globalThis.window = globalThis; +if (!window.top) window.top = window; +if (!window.location) window.location = { href: "https://auth.openai.com/create-account/password", search: "", pathname: "/create-account/password", origin: "https://auth.openai.com" }; +if (!window.addEventListener) window.addEventListener = function(){}; +if (!window.removeEventListener) window.removeEventListener = function(){}; +if (!window.postMessage) window.postMessage = function(){}; +if (!window.__sentinel_token_pending) window.__sentinel_token_pending = []; +if (!window.__sentinel_init_pending) window.__sentinel_init_pending = []; + +if (typeof globalThis.document !== "object") globalThis.document = {}; +if (!document.scripts) document.scripts = []; +if (!document.cookie) document.cookie = ""; +if (!document.documentElement) document.documentElement = { getAttribute: () => null }; +if (!document.currentScript) document.currentScript = null; +if (!document.body) document.body = { appendChild: function(){}, getAttribute: () => null }; +if (!document.createElement) document.createElement = function(tag){ + return { + tagName: String(tag||"").toUpperCase(), + style: {}, + setAttribute: function(){}, + getAttribute: function(){ return null; }, + addEventListener: function(){}, + removeEventListener: function(){}, + src: "", + contentWindow: { postMessage: function(){}, addEventListener: function(){}, removeEventListener: function(){} }, + }; +}; + +if (typeof globalThis.navigator !== "object") globalThis.navigator = { userAgent: "ua", language: "en-US", languages: ["en-US","en"], hardwareConcurrency: 8 }; +if (typeof globalThis.screen !== "object") globalThis.screen = { width: 1920, height: 1080 }; +if (typeof globalThis.btoa !== "function") globalThis.btoa = (str) => Buffer.from(str, "binary").toString("base64"); +if (typeof globalThis.atob !== "function") globalThis.atob = (b64) => Buffer.from(b64, "base64").toString("binary"); +window.btoa = globalThis.btoa; +window.atob = globalThis.atob; +""" + + wrapper = f""" +const __payload = {payload_json}; + +function __makeSolver(configArray) {{ + const solver = new SentinelSDK.__O(); + solver.sid = configArray?.[14]; + // 强制使用 Python 传入的 configArray,避免依赖真实浏览器对象 + solver.getConfig = () => configArray; + return solver; +}} + +async function __entry() {{ + {entry} +}} + +(async () => {{ + try {{ + const result = await __entry(); + process.stdout.write(JSON.stringify({{ ok: true, result }}), () => process.exit(0)); + }} catch (err) {{ + const msg = (err && (err.stack || err.message)) ? (err.stack || err.message) : String(err); + process.stdout.write(JSON.stringify({{ ok: false, error: msg }}), () => process.exit(1)); + }} +}})(); +""" + return "\n".join([shim, self._sdk_code, wrapper]) + + def _run_node(self, payload: Dict[str, Any], entry: str, timeout_s: int = 30) -> Any: + script = self._node_script(payload, entry) + + if DEBUG: + print("[JSExecutor] Running Node worker...") + + try: + proc = subprocess.run( + ["node", "-"], + input=script, + text=True, + capture_output=True, + timeout=timeout_s, + ) + except FileNotFoundError as e: + raise RuntimeError("Node.js not found on PATH (required for Sentinel SDK execution).") from e + except subprocess.TimeoutExpired as e: + raise TimeoutError(f"Node worker timed out after {timeout_s}s") from e + + stdout = (proc.stdout or "").strip() + if not stdout: + raise RuntimeError(f"Node worker produced no output (stderr={proc.stderr!r})") + + try: + obj = json.loads(stdout) + except json.JSONDecodeError as e: + raise RuntimeError(f"Node worker returned non-JSON output: {stdout[:200]!r}") from e + + if not obj.get("ok"): + raise RuntimeError(obj.get("error", "Unknown JS error")) + + return obj.get("result") + + def solve_pow(self, seed: str, difficulty: str, config_array: list) -> str: + if DEBUG: + print(f"[JSExecutor] Solving PoW: seed={seed[:10]}..., difficulty={difficulty}") + + result = self._run_node( + {"seed": seed, "difficulty": difficulty, "configArray": config_array}, + entry="return __makeSolver(__payload.configArray)._generateAnswerSync(__payload.seed, __payload.difficulty);", + timeout_s=60, + ) + + if DEBUG and isinstance(result, str): + print(f"[JSExecutor] PoW solved: {result[:50]}...") + + return result + + def generate_requirements(self, seed: str, config_array: list) -> str: + result = self._run_node( + {"seed": seed, "configArray": config_array}, + entry=( + "const solver = __makeSolver(__payload.configArray);\n" + "solver.requirementsSeed = __payload.seed;\n" + "return solver._generateRequirementsTokenAnswerBlocking();" + ), + timeout_s=30, + ) + return result + + def execute_turnstile(self, dx_bytecode: str, xor_key: str) -> str: + if DEBUG: + print("[JSExecutor] Executing Turnstile VM...") + + result = self._run_node( + {"dx": dx_bytecode, "xorKey": xor_key}, + entry=( + "SentinelSDK.__kt(__payload.xorKey);\n" + "return await SentinelSDK.__bt(__payload.dx);" + ), + timeout_s=30, + ) + + if DEBUG and isinstance(result, str): + print(f"[JSExecutor] Turnstile result: {result[:50]}...") + + return result diff --git a/modules/register.py b/modules/register.py new file mode 100644 index 0000000..4a8af38 --- /dev/null +++ b/modules/register.py @@ -0,0 +1,242 @@ +# modules/registrar.py (更新版) +"""OpenAI 注册流程控制器""" + +import json +from typing import Dict, Optional +import secrets + +from .fingerprint import BrowserFingerprint +from .sentinel_solver import SentinelSolver +from .http_client import HTTPClient +from config import AUTH_BASE_URL, DEBUG + + +class OpenAIRegistrar: + """完整的 OpenAI 注册流程""" + + def __init__(self, session_id: Optional[str] = None): + self.fingerprint = BrowserFingerprint(session_id) + self.solver = SentinelSolver(self.fingerprint) + self.http_client = HTTPClient(self.fingerprint) + + def _step1_get_cookies_and_csrf(self): + """访问注册页,获取必需的 session cookies""" + if DEBUG: + print("\n=== STEP 1: Getting session cookies ===") + + # 访问注册页(会设置 login_session 等 cookies) + url = f"{AUTH_BASE_URL}/create-account/password" + + headers = self.http_client.fingerprint.get_headers() + headers['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' + + resp = self.http_client.get(url, headers=headers) + + if DEBUG: + print(f"Cookies received: {list(self.http_client.cookies.keys())}") + + # 检查关键 cookies + required_cookies = ['oai-did', 'login_session', 'oai-client-auth-session'] + missing = [c for c in required_cookies if c not in self.http_client.cookies] + + if missing: + print(f"⚠ Warning: Missing cookies: {missing}") + else: + print(f"✓ All required cookies present") + + def _step2_init_sentinel(self): + """初始化 Sentinel(生成 token)""" + if DEBUG: + print("\n=== STEP 2: Initializing Sentinel ===") + + try: + token_data = self.solver.generate_requirements_token() + self.sentinel_token = json.dumps(token_data) + + if DEBUG: + token_str = str(self.sentinel_token) + print(f"✓ Sentinel token: {token_str[:80]}...") + + except Exception as e: + if DEBUG: + print(f"✗ Sentinel initialization failed: {e}") + raise + + def _step3_attempt_register(self, email: str, password: str) -> Dict: + """尝试注册(会触发 enforcement)""" + if DEBUG: + print("\n=== STEP 3: Attempting registration ===") + + url = f"{AUTH_BASE_URL}/api/accounts/user/register" + + # 正确的 payload 格式(根据真实抓包) + payload = { + 'username': email, + 'password': password + } + + # 添加额外的 headers + headers = self.http_client.fingerprint.get_headers(with_sentinel=self.sentinel_token) + headers['Accept'] = 'application/json' + headers['Referer'] = f'{AUTH_BASE_URL}/create-account/password' + headers['Origin'] = AUTH_BASE_URL + + # 添加 Datadog tracing headers(模拟真实浏览器) + headers.update({ + 'traceparent': f'00-0000000000000000{secrets.token_hex(8)}-{secrets.token_hex(8)}-01', + 'tracestate': 'dd=s:1;o:rum', + 'x-datadog-origin': 'rum', + 'x-datadog-parent-id': str(secrets.randbits(63)), + 'x-datadog-sampling-priority': '1', + 'x-datadog-trace-id': str(secrets.randbits(63)) + }) + + resp = self.http_client.session.post( + url, + json=payload, + headers=headers, + cookies=self.http_client.cookies, + ) + + if DEBUG: + print(f"Response status: {resp.status_code}") + + # 更新 cookies + self.http_client.cookies.update(resp.cookies.get_dict()) + + # 403: Enforcement 挑战(预期) + if resp.status_code == 403: + try: + challenge = resp.json() + + if DEBUG: + print(f"✓ Got enforcement challenge!") + print(f" Type: {challenge.get('type', 'unknown')}") + if 'proofofwork' in challenge: + pow_data = challenge['proofofwork'] + print(f" PoW seed: {pow_data.get('seed', 'N/A')}") + print(f" Difficulty: {pow_data.get('difficulty', 'N/A')}") + + return challenge + + except Exception as e: + if DEBUG: + print(f"✗ Failed to parse challenge: {e}") + print(resp.text[:500]) + raise + + # 200: 成功 + elif resp.status_code == 200: + if DEBUG: + print("✓ Registration succeeded!") + return {'success': True, 'data': resp.json()} + + # 409: Invalid session + elif resp.status_code == 409: + error = resp.json() + if DEBUG: + print(f"✗ 409: {error}") + raise Exception(f"Invalid session: {error}") + + # 400: 参数错误 + elif resp.status_code == 400: + error = resp.json() + if DEBUG: + print(f"✗ 400: {error}") + raise Exception(f"Bad request: {error}") + + # 其他错误 + else: + if DEBUG: + print(f"✗ Unexpected status: {resp.status_code}") + print(resp.text[:500]) + raise Exception(f"Unexpected status: {resp.status_code}\n{resp.text}") + + + + + def _step4_solve_challenge(self, challenge: Dict) -> str: + """解决 enforcement 挑战""" + if DEBUG: + print("\n=== STEP 4: Solving enforcement challenge ===") + + sentinel_token = self.solver.solve_enforcement(challenge) + + return sentinel_token + + def _step5_register_with_token(self, email: str, password: str, + sentinel_token: str) -> Dict: + """带 Sentinel token 重新注册""" + if DEBUG: + print("\n=== STEP 5: Registering with Sentinel token ===") + + url = f"{AUTH_BASE_URL}/api/accounts/user/register" + + payload = { + 'username': email, + 'password': password, + 'client_id': 'sentinel' + } + + resp = self.http_client.post( + url, + json_data=payload, + sentinel_token=sentinel_token + ) + + if resp.status_code == 200: + if DEBUG: + print("✓ Registration successful!") + return {'success': True, 'data': resp.json()} + + else: + if DEBUG: + print(f"✗ Registration failed: {resp.status_code}") + print(resp.text) + + return { + 'success': False, + 'status_code': resp.status_code, + 'error': resp.text + } + + def register(self, email: str, password: str) -> Dict: + """完整注册流程""" + if DEBUG: + print(f"\n{'='*60}") + print(f"Registering: {email}") + print(f"Session ID: {self.fingerprint.session_id}") + print(f"{'='*60}") + + try: + # Step 1: 获取 cookies 和 CSRF token + self._step1_get_cookies_and_csrf() + + # Step 2: 初始化 Sentinel(跳过) + self._step2_init_sentinel() + + # Step 3: 尝试注册(获取挑战) + challenge = self._step3_attempt_register(email, password) + + # 如果直接成功了 + if challenge.get('success'): + return challenge + + # Step 4: 解决挑战 + sentinel_token = self._step4_solve_challenge(challenge) + + # Step 5: 带 token 重新注册 + result = self._step5_register_with_token(email, password, sentinel_token) + + return result + + except Exception as e: + if DEBUG: + import traceback + print(f"\n✗ Registration failed with exception:") + traceback.print_exc() + + return { + 'success': False, + 'error': str(e) + } diff --git a/modules/sentinel_solver.py b/modules/sentinel_solver.py new file mode 100644 index 0000000..e75dc0f --- /dev/null +++ b/modules/sentinel_solver.py @@ -0,0 +1,113 @@ +# modules/sentinel_solver.py +"""Sentinel 挑战求解器""" + +import json +import uuid +from typing import Dict, Optional + +from .js_executor import JSExecutor +from .fingerprint import BrowserFingerprint +from config import DEBUG + + +class SentinelSolver: + """协调指纹生成和 JS 执行,生成完整的 Sentinel tokens""" + + def __init__(self, fingerprint: BrowserFingerprint): + self.fingerprint = fingerprint + self.js_executor = JSExecutor() + + def generate_requirements_token(self) -> Dict[str, str]: + """ + 生成 requirements token(初始化时需要) + + Returns: + {'p': 'gAAAAAC...', 'id': 'uuid'} + """ + if DEBUG: + print("[Solver] Generating requirements token...") + + # 生成随机 seed + req_seed = str(uuid.uuid4()) + + # 获取指纹配置 + config_array = self.fingerprint.get_config_array() + + # 调用 JS 求解 + answer = self.js_executor.generate_requirements(req_seed, config_array) + + token = { + 'p': f'gAAAAAC{answer}', + 'id': self.fingerprint.session_id, + } + + if DEBUG: + print(f"[Solver] Requirements token: {token['p'][:30]}...") + + return token + + def solve_enforcement(self, enforcement_config: Dict) -> str: + """ + 解决完整的 enforcement 挑战(PoW + Turnstile) + + Args: + enforcement_config: 服务器返回的挑战配置 + { + 'proofofwork': { + 'seed': '...', + 'difficulty': '0003a', + 'token': '...', # cached token + 'turnstile': { + 'dx': '...' # VM bytecode + } + } + } + + Returns: + 完整的 Sentinel token (JSON string) + """ + if DEBUG: + print("[Solver] Solving enforcement challenge...") + + pow_data = enforcement_config.get('proofofwork', {}) + + # 1. 解决 PoW + seed = pow_data['seed'] + difficulty = pow_data['difficulty'] + + config_array = self.fingerprint.get_config_array() + pow_answer = self.js_executor.solve_pow(seed, difficulty, config_array) + + # 2. 执行 Turnstile(如果有) + turnstile_result = None + turnstile_data = pow_data.get('turnstile') + + if turnstile_data and turnstile_data.get('dx'): + dx_bytecode = turnstile_data['dx'] + xor_key = self.fingerprint.session_id # 通常用 session ID 作为密钥 + + turnstile_result = self.js_executor.execute_turnstile(dx_bytecode, xor_key) + + # 3. 构建最终 token + sentinel_token = { + # enforcement token 前缀为 gAAAAAB(requirements 为 gAAAAAC) + 'p': f'gAAAAAB{pow_answer}', + 'id': self.fingerprint.session_id, + 'flow': 'username_password_create', + } + + # 添加可选字段 + if turnstile_result: + sentinel_token['t'] = turnstile_result + + if pow_data.get('token'): + sentinel_token['c'] = pow_data['token'] + + token_json = json.dumps(sentinel_token) + + if DEBUG: + print(f"[Solver] Sentinel token generated: {token_json[:80]}...") + + return token_json + + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1fad807 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,11 @@ +[project] +name = "autoreg" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "curl-cffi>=0.14.0", + "pyexecjs>=1.5.1", + "requests>=2.32.5", +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..3c7a2f9 --- /dev/null +++ b/uv.lock @@ -0,0 +1,226 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "autoreg" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "curl-cffi" }, + { name = "pyexecjs" }, + { name = "requests" }, +] + +[package.metadata] +requires-dist = [ + { name = "curl-cffi", specifier = ">=0.14.0" }, + { name = "pyexecjs", specifier = ">=1.5.1" }, + { name = "requests", specifier = ">=2.32.5" }, +] + +[[package]] +name = "certifi" +version = "2026.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "curl-cffi" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/c9/0067d9a25ed4592b022d4558157fcdb6e123516083700786d38091688767/curl_cffi-0.14.0.tar.gz", hash = "sha256:5ffbc82e59f05008ec08ea432f0e535418823cda44178ee518906a54f27a5f0f", size = 162633, upload-time = "2025-12-16T03:25:07.931Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/f0/0f21e9688eaac85e705537b3a87a5588d0cefb2f09d83e83e0e8be93aa99/curl_cffi-0.14.0-cp39-abi3-macosx_14_0_arm64.whl", hash = "sha256:e35e89c6a69872f9749d6d5fda642ed4fc159619329e99d577d0104c9aad5893", size = 3087277, upload-time = "2025-12-16T03:24:49.607Z" }, + { url = "https://files.pythonhosted.org/packages/ba/a3/0419bd48fce5b145cb6a2344c6ac17efa588f5b0061f212c88e0723da026/curl_cffi-0.14.0-cp39-abi3-macosx_15_0_x86_64.whl", hash = "sha256:5945478cd28ad7dfb5c54473bcfb6743ee1d66554d57951fdf8fc0e7d8cf4e45", size = 5804650, upload-time = "2025-12-16T03:24:51.518Z" }, + { url = "https://files.pythonhosted.org/packages/e2/07/a238dd062b7841b8caa2fa8a359eb997147ff3161288f0dd46654d898b4d/curl_cffi-0.14.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c42e8fa3c667db9ccd2e696ee47adcd3cd5b0838d7282f3fc45f6c0ef3cfdfa7", size = 8231918, upload-time = "2025-12-16T03:24:52.862Z" }, + { url = "https://files.pythonhosted.org/packages/7c/d2/ce907c9b37b5caf76ac08db40cc4ce3d9f94c5500db68a195af3513eacbc/curl_cffi-0.14.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:060fe2c99c41d3cb7f894de318ddf4b0301b08dca70453d769bd4e74b36b8483", size = 8654624, upload-time = "2025-12-16T03:24:54.579Z" }, + { url = "https://files.pythonhosted.org/packages/f2/ae/6256995b18c75e6ef76b30753a5109e786813aa79088b27c8eabb1ef85c9/curl_cffi-0.14.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b158c41a25388690dd0d40b5bc38d1e0f512135f17fdb8029868cbc1993d2e5b", size = 8010654, upload-time = "2025-12-16T03:24:56.507Z" }, + { url = "https://files.pythonhosted.org/packages/fb/10/ff64249e516b103cb762e0a9dca3ee0f04cf25e2a1d5d9838e0f1273d071/curl_cffi-0.14.0-cp39-abi3-manylinux_2_28_i686.whl", hash = "sha256:1439fbef3500fb723333c826adf0efb0e2e5065a703fb5eccce637a2250db34a", size = 7781969, upload-time = "2025-12-16T03:24:57.885Z" }, + { url = "https://files.pythonhosted.org/packages/51/76/d6f7bb76c2d12811aa7ff16f5e17b678abdd1b357b9a8ac56310ceccabd5/curl_cffi-0.14.0-cp39-abi3-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e7176f2c2d22b542e3cf261072a81deb018cfa7688930f95dddef215caddb469", size = 7969133, upload-time = "2025-12-16T03:24:59.261Z" }, + { url = "https://files.pythonhosted.org/packages/23/7c/cca39c0ed4e1772613d3cba13091c0e9d3b89365e84b9bf9838259a3cd8f/curl_cffi-0.14.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:03f21ade2d72978c2bb8670e9b6de5260e2755092b02d94b70b906813662998d", size = 9080167, upload-time = "2025-12-16T03:25:00.946Z" }, + { url = "https://files.pythonhosted.org/packages/75/03/a942d7119d3e8911094d157598ae0169b1c6ca1bd3f27d7991b279bcc45b/curl_cffi-0.14.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:58ebf02de64ee5c95613209ddacb014c2d2f86298d7080c0a1c12ed876ee0690", size = 9520464, upload-time = "2025-12-16T03:25:02.922Z" }, + { url = "https://files.pythonhosted.org/packages/a2/77/78900e9b0833066d2274bda75cba426fdb4cef7fbf6a4f6a6ca447607bec/curl_cffi-0.14.0-cp39-abi3-win_amd64.whl", hash = "sha256:6e503f9a103f6ae7acfb3890c843b53ec030785a22ae7682a22cc43afb94123e", size = 1677416, upload-time = "2025-12-16T03:25:04.902Z" }, + { url = "https://files.pythonhosted.org/packages/5c/7c/d2ba86b0b3e1e2830bd94163d047de122c69a8df03c5c7c36326c456ad82/curl_cffi-0.14.0-cp39-abi3-win_arm64.whl", hash = "sha256:2eed50a969201605c863c4c31269dfc3e0da52916086ac54553cfa353022425c", size = 1425067, upload-time = "2025-12-16T03:25:06.454Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pyexecjs" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/8e/aedef81641c8dca6fd0fb7294de5bed9c45f3397d67fddf755c1042c2642/PyExecJS-1.5.1.tar.gz", hash = "sha256:34cc1d070976918183ff7bdc0ad71f8157a891c92708c00c5fbbff7a769f505c", size = 13344, upload-time = "2018-01-18T04:33:55.126Z" } + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +]