@follenfang/fupload 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fupload/SKILL.md +4 -4
- package/fupload/references/blackbox.md +3 -1
- package/fupload/scripts/fupload_cli/__init__.py +1 -1
- package/fupload/scripts/fupload_cli/blackbox.py +129 -101
- package/fupload/scripts/fupload_cli/blackbox_web.py +522 -0
- package/fupload/scripts/fupload_cli/cli.py +19 -9
- package/fupload/scripts/fupload_cli/schema.py +14 -3
- package/npm/bin/fupload.mjs +3 -1
- package/npm/lib/python-requirements.txt +1 -0
- package/npm/lib/python.mjs +59 -19
- package/npm/skill-manifest.json +17 -17
- package/package.json +1 -1
- package/fupload/scripts/fupload_cli/blackbox_auth.py +0 -159
package/npm/lib/python.mjs
CHANGED
|
@@ -46,9 +46,13 @@ export function discoverPython({ platform = process.platform, minimumMinor = 9 }
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export function runPython(python, script, args, options = {}) {
|
|
49
|
-
|
|
49
|
+
const run = options.run || spawnSync;
|
|
50
|
+
const env = options.runtimeRoot
|
|
51
|
+
? runtimeEnvironment(options.runtimeRoot, options.env || process.env)
|
|
52
|
+
: options.env || process.env;
|
|
53
|
+
return run(python.command, [...python.args, script, ...args], {
|
|
50
54
|
cwd: options.cwd || process.cwd(),
|
|
51
|
-
env
|
|
55
|
+
env,
|
|
52
56
|
stdio: options.stdio || "inherit",
|
|
53
57
|
encoding: options.encoding,
|
|
54
58
|
shell: false,
|
|
@@ -82,45 +86,68 @@ function readMarker(root) {
|
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
function
|
|
89
|
+
function runtimeEnvironment(root, env) {
|
|
90
|
+
return {
|
|
91
|
+
...env,
|
|
92
|
+
PLAYWRIGHT_BROWSERS_PATH: path.join(root, "browsers"),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function probeRuntime(executable, root, env, run = spawnSync) {
|
|
86
97
|
if (!fs.existsSync(executable)) {
|
|
87
98
|
return null;
|
|
88
99
|
}
|
|
89
100
|
const result = run(executable, [
|
|
90
101
|
"-c",
|
|
91
|
-
"import importlib.metadata,sys; import qcloud_cos; print('.'.join(map(str,sys.version_info[:3]))
|
|
92
|
-
], {
|
|
102
|
+
"import importlib.metadata,json,pathlib,sys; import qcloud_cos; from playwright.sync_api import sync_playwright; p=sync_playwright().start(); executable=p.chromium.executable_path; p.stop(); print(json.dumps({'python_version': '.'.join(map(str,sys.version_info[:3])), 'cos_version': importlib.metadata.version('cos-python-sdk-v5'), 'playwright_version': importlib.metadata.version('playwright'), 'chromium_executable': executable})); sys.exit(0 if pathlib.Path(executable).is_file() else 1)",
|
|
103
|
+
], {
|
|
104
|
+
encoding: "utf8",
|
|
105
|
+
env: runtimeEnvironment(root, env),
|
|
106
|
+
shell: false,
|
|
107
|
+
windowsHide: true,
|
|
108
|
+
});
|
|
93
109
|
if (result.status !== 0) {
|
|
94
110
|
return null;
|
|
95
111
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
let details;
|
|
113
|
+
try {
|
|
114
|
+
details = JSON.parse(result.stdout.trim());
|
|
115
|
+
} catch {
|
|
99
116
|
return null;
|
|
100
117
|
}
|
|
101
|
-
|
|
118
|
+
const match = details.python_version?.match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
119
|
+
if (!match || !details.cos_version || !details.playwright_version || !details.chromium_executable) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
version: match.slice(1).map(Number),
|
|
124
|
+
dependencyVersion: details.cos_version,
|
|
125
|
+
playwrightVersion: details.playwright_version,
|
|
126
|
+
chromiumExecutable: details.chromium_executable,
|
|
127
|
+
};
|
|
102
128
|
}
|
|
103
129
|
|
|
104
|
-
function inspectRuntime({ root, platform, requirementsHash, run }) {
|
|
130
|
+
function inspectRuntime({ root, platform, requirementsHash, env, run }) {
|
|
105
131
|
const marker = readMarker(root);
|
|
106
132
|
if (marker?.schema !== PYTHON_RUNTIME_SCHEMA || marker.requirements_sha256 !== requirementsHash) {
|
|
107
133
|
return null;
|
|
108
134
|
}
|
|
109
135
|
const command = pythonRuntimeExecutable(root, platform);
|
|
110
|
-
const probe = probeRuntime(command, run);
|
|
136
|
+
const probe = probeRuntime(command, root, env, run);
|
|
111
137
|
if (!probe || probe.version[0] !== 3 || probe.version[1] < 9) {
|
|
112
138
|
return null;
|
|
113
139
|
}
|
|
114
|
-
return { command, args: [],
|
|
140
|
+
return { command, args: [], ...probe };
|
|
115
141
|
}
|
|
116
142
|
|
|
117
143
|
function bounded(value) {
|
|
118
144
|
return String(value || "").trim().slice(0, 4000);
|
|
119
145
|
}
|
|
120
146
|
|
|
121
|
-
function runChecked(run, command, args, message) {
|
|
147
|
+
function runChecked(run, command, args, message, options = {}) {
|
|
122
148
|
const result = run(command, args, {
|
|
123
149
|
encoding: "utf8",
|
|
150
|
+
...options,
|
|
124
151
|
shell: false,
|
|
125
152
|
windowsHide: true,
|
|
126
153
|
});
|
|
@@ -191,7 +218,7 @@ export function ensurePythonRuntime({
|
|
|
191
218
|
const parent = path.dirname(root);
|
|
192
219
|
const lock = acquireRuntimeLock(root);
|
|
193
220
|
try {
|
|
194
|
-
const current = inspectRuntime({ root, platform, requirementsHash, run });
|
|
221
|
+
const current = inspectRuntime({ root, platform, requirementsHash, env, run });
|
|
195
222
|
if (current) {
|
|
196
223
|
return { status: "current", root, requirements, python: current };
|
|
197
224
|
}
|
|
@@ -205,13 +232,19 @@ export function ensurePythonRuntime({
|
|
|
205
232
|
const backup = path.join(parent, `.python-backup-${nonce}`);
|
|
206
233
|
fs.mkdirSync(parent, { recursive: true });
|
|
207
234
|
let movedOld = false;
|
|
235
|
+
let created;
|
|
208
236
|
try {
|
|
209
237
|
runChecked(run, base.command, [...base.args, "-m", "venv", staging], "Could not create the Fuploader Python runtime");
|
|
210
238
|
const stagingPython = pythonRuntimeExecutable(staging, platform);
|
|
211
239
|
runChecked(run, stagingPython, [
|
|
212
240
|
"-m", "pip", "install", "--disable-pip-version-check", "--no-input", "--requirement", requirements,
|
|
213
241
|
], "Could not install Fuploader Python dependencies");
|
|
214
|
-
|
|
242
|
+
runChecked(run, stagingPython, [
|
|
243
|
+
"-m", "playwright", "install", "chromium",
|
|
244
|
+
], "Could not install Fuploader Chromium", {
|
|
245
|
+
env: runtimeEnvironment(staging, env),
|
|
246
|
+
});
|
|
247
|
+
const installed = probeRuntime(stagingPython, staging, env, run);
|
|
215
248
|
if (!installed) {
|
|
216
249
|
throw new Error("The Fuploader Python runtime did not pass its dependency probe.");
|
|
217
250
|
}
|
|
@@ -220,6 +253,8 @@ export function ensurePythonRuntime({
|
|
|
220
253
|
requirements_sha256: requirementsHash,
|
|
221
254
|
python_version: installed.version.join("."),
|
|
222
255
|
dependency_version: installed.dependencyVersion,
|
|
256
|
+
playwright_version: installed.playwrightVersion,
|
|
257
|
+
chromium_executable: path.relative(staging, installed.chromiumExecutable),
|
|
223
258
|
});
|
|
224
259
|
if (fs.existsSync(root)) {
|
|
225
260
|
fs.renameSync(root, backup);
|
|
@@ -234,16 +269,21 @@ export function ensurePythonRuntime({
|
|
|
234
269
|
}
|
|
235
270
|
throw error;
|
|
236
271
|
}
|
|
272
|
+
created = inspectRuntime({ root, platform, requirementsHash, env, run });
|
|
273
|
+
if (!created) {
|
|
274
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
275
|
+
if (movedOld) {
|
|
276
|
+
fs.renameSync(backup, root);
|
|
277
|
+
movedOld = false;
|
|
278
|
+
}
|
|
279
|
+
throw new Error("The installed Fuploader Python runtime failed final validation.");
|
|
280
|
+
}
|
|
237
281
|
if (movedOld) {
|
|
238
282
|
fs.rmSync(backup, { recursive: true, force: true });
|
|
239
283
|
}
|
|
240
284
|
} finally {
|
|
241
285
|
fs.rmSync(staging, { recursive: true, force: true });
|
|
242
286
|
}
|
|
243
|
-
const created = inspectRuntime({ root, platform, requirementsHash, run });
|
|
244
|
-
if (!created) {
|
|
245
|
-
throw new Error("The installed Fuploader Python runtime failed final validation.");
|
|
246
|
-
}
|
|
247
287
|
return { status: "installed", root, requirements, python: created };
|
|
248
288
|
} finally {
|
|
249
289
|
lock.release();
|
package/npm/skill-manifest.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "fupload.npm-skill-manifest.v1",
|
|
3
3
|
"package_name": "@follenfang/fupload",
|
|
4
|
-
"package_version": "0.0.
|
|
5
|
-
"skill_version": "0.0.
|
|
6
|
-
"tree_sha256": "
|
|
4
|
+
"package_version": "0.0.8",
|
|
5
|
+
"skill_version": "0.0.8",
|
|
6
|
+
"tree_sha256": "19b487eaba532263a849d4bfd48f4f40166edbf156f5317e5dbcc040fdc9819e",
|
|
7
7
|
"files": [
|
|
8
8
|
{
|
|
9
9
|
"path": "agents/openai.yaml",
|
|
@@ -77,8 +77,8 @@
|
|
|
77
77
|
},
|
|
78
78
|
{
|
|
79
79
|
"path": "references/blackbox.md",
|
|
80
|
-
"bytes":
|
|
81
|
-
"sha256": "
|
|
80
|
+
"bytes": 2966,
|
|
81
|
+
"sha256": "ea95e8826af8e54c82343c404f9c97a611ab8ec3fb0282b561907c50169e4307"
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
"path": "references/curseforge.md",
|
|
@@ -108,22 +108,22 @@
|
|
|
108
108
|
{
|
|
109
109
|
"path": "scripts/fupload_cli/__init__.py",
|
|
110
110
|
"bytes": 49,
|
|
111
|
-
"sha256": "
|
|
111
|
+
"sha256": "7f13892a82918a297a8af731adf5b20a540dd3a873d089bf133225a0a642a840"
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
|
-
"path": "scripts/fupload_cli/
|
|
115
|
-
"bytes":
|
|
116
|
-
"sha256": "
|
|
114
|
+
"path": "scripts/fupload_cli/blackbox_web.py",
|
|
115
|
+
"bytes": 19392,
|
|
116
|
+
"sha256": "4a849fb297f045b81d261f4456542c165a3c0d9a77f963dbfcbc1c9dad8fec65"
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
"path": "scripts/fupload_cli/blackbox.py",
|
|
120
|
-
"bytes":
|
|
121
|
-
"sha256": "
|
|
120
|
+
"bytes": 17089,
|
|
121
|
+
"sha256": "4487141898ba6a080d2120c1df9ad83c290528e9b462acb22d6c0f89dbbd117c"
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
"path": "scripts/fupload_cli/cli.py",
|
|
125
|
-
"bytes":
|
|
126
|
-
"sha256": "
|
|
125
|
+
"bytes": 25982,
|
|
126
|
+
"sha256": "79c5de939e3a7e7d0ed49d79fcce6c22e78c1a5abcf8eae5422dbd78f7c7bf2d"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"path": "scripts/fupload_cli/curseforge.py",
|
|
@@ -167,8 +167,8 @@
|
|
|
167
167
|
},
|
|
168
168
|
{
|
|
169
169
|
"path": "scripts/fupload_cli/schema.py",
|
|
170
|
-
"bytes":
|
|
171
|
-
"sha256": "
|
|
170
|
+
"bytes": 37399,
|
|
171
|
+
"sha256": "5538eaf099bf9e7cae5f8142faecf827d41da698ae574b5597d17756da23e331"
|
|
172
172
|
},
|
|
173
173
|
{
|
|
174
174
|
"path": "scripts/fupload_cli/transport.py",
|
|
@@ -187,8 +187,8 @@
|
|
|
187
187
|
},
|
|
188
188
|
{
|
|
189
189
|
"path": "SKILL.md",
|
|
190
|
-
"bytes":
|
|
191
|
-
"sha256": "
|
|
190
|
+
"bytes": 23242,
|
|
191
|
+
"sha256": "ad3813733c9fd7aac62683f704bf1adc25982b6d45a14e4d749b6734a2bee3c3"
|
|
192
192
|
}
|
|
193
193
|
]
|
|
194
194
|
}
|
package/package.json
CHANGED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
"""Authentication helpers for the Heybox desktop Workshop client."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
import hashlib, json, platform, secrets, sqlite3, time
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from urllib.parse import parse_qs, urlparse
|
|
6
|
-
from .errors import FuploadError
|
|
7
|
-
|
|
8
|
-
API_BASE = "https://workshopapi.xiaoheihe.cn"
|
|
9
|
-
CLIENT_VERSION = "1.14.1"
|
|
10
|
-
_CONFIG_AES_KEY = bytes.fromhex("5f1d7f11e6e90dbb5c2f0c1e614a6a8c4b9e16b50fa724e4c54d6f25b1208b93")
|
|
11
|
-
_ALPHABET = "AB45STUVWZEFGJ6CH01D237IXYPQRKLMN89"
|
|
12
|
-
|
|
13
|
-
def _n8(value: str, limit: int) -> str:
|
|
14
|
-
table = _ALPHABET[:limit]
|
|
15
|
-
return "".join(table[ord(ch) % len(table)] for ch in value)
|
|
16
|
-
def _i8(value: str) -> str:
|
|
17
|
-
return "".join(_ALPHABET[ord(ch) % len(_ALPHABET)] for ch in value)
|
|
18
|
-
def _interleave(parts):
|
|
19
|
-
return "".join(part[i] for i in range(max(map(len, parts))) for part in parts if i < len(part))
|
|
20
|
-
def _mix(values):
|
|
21
|
-
def p(x): return ((x << 1) ^ 27) & 255 if x & 128 else (x << 1) & 255
|
|
22
|
-
def hm(x): return p(x) ^ x
|
|
23
|
-
def qg(x): return hm(p(x))
|
|
24
|
-
def dx(x): return qg(hm(p(x)))
|
|
25
|
-
def mw(x): return dx(x) ^ qg(x) ^ hm(x)
|
|
26
|
-
a,b,c,d,*rest=values
|
|
27
|
-
return [mw(a)^dx(b)^qg(c)^hm(d), hm(a)^mw(b)^dx(c)^qg(d), qg(a)^hm(b)^mw(c)^dx(d), dx(a)^qg(b)^hm(c)^mw(d), *rest]
|
|
28
|
-
def hkey(path: str, timestamp: int, nonce: str) -> str:
|
|
29
|
-
normalized = "/" + "/".join(x for x in path.split("/") if x) + "/"
|
|
30
|
-
digest = hashlib.md5(_interleave([_n8(str(timestamp), -2), _i8(normalized), _i8(nonce)]).encode()).hexdigest()
|
|
31
|
-
return _n8(digest[:5], -4) + "%02d" % (sum(_mix([ord(x) for x in digest[-6:]])) % 100)
|
|
32
|
-
|
|
33
|
-
def _decrypt_user_pkey(value: str) -> str:
|
|
34
|
-
"""Decrypt the desktop config's ``iv:ciphertext`` AES-256-CBC value.
|
|
35
|
-
|
|
36
|
-
Older Chromium cookie databases contain the already decrypted pkey, so this
|
|
37
|
-
helper deliberately returns ordinary values unchanged and only attempts
|
|
38
|
-
crypto for the new config format.
|
|
39
|
-
"""
|
|
40
|
-
if not isinstance(value, str) or ":" not in value:
|
|
41
|
-
return value
|
|
42
|
-
iv_hex, ciphertext_hex = value.split(":", 1)
|
|
43
|
-
try:
|
|
44
|
-
iv = bytes.fromhex(iv_hex)
|
|
45
|
-
ciphertext = bytes.fromhex(ciphertext_hex)
|
|
46
|
-
if len(iv) != 16 or not ciphertext or len(ciphertext) % 16:
|
|
47
|
-
return value
|
|
48
|
-
except ValueError:
|
|
49
|
-
return value
|
|
50
|
-
try:
|
|
51
|
-
from Crypto.Cipher import AES
|
|
52
|
-
plaintext = AES.new(_CONFIG_AES_KEY, AES.MODE_CBC, iv).decrypt(ciphertext)
|
|
53
|
-
except ImportError:
|
|
54
|
-
try:
|
|
55
|
-
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
56
|
-
decryptor = Cipher(algorithms.AES(_CONFIG_AES_KEY), modes.CBC(iv)).decryptor()
|
|
57
|
-
plaintext = decryptor.update(ciphertext) + decryptor.finalize()
|
|
58
|
-
except ImportError as exc:
|
|
59
|
-
raise FuploadError(
|
|
60
|
-
"AES support is required to read the Heybox desktop session",
|
|
61
|
-
kind="environment_error",
|
|
62
|
-
details={"install": "Crypto or cryptography"},
|
|
63
|
-
) from exc
|
|
64
|
-
if not plaintext:
|
|
65
|
-
return value
|
|
66
|
-
pad = plaintext[-1]
|
|
67
|
-
if not 1 <= pad <= 16 or plaintext[-pad:] != bytes([pad]) * pad:
|
|
68
|
-
raise FuploadError("Heybox desktop pkey could not be decrypted", kind="authentication_error")
|
|
69
|
-
try:
|
|
70
|
-
return plaintext[:-pad].decode("utf-8")
|
|
71
|
-
except UnicodeDecodeError as exc:
|
|
72
|
-
raise FuploadError("Heybox desktop pkey is invalid", kind="authentication_error") from exc
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def _read_json(path: Path) -> dict:
|
|
76
|
-
try:
|
|
77
|
-
data = json.loads(path.read_text(encoding="utf-8"))
|
|
78
|
-
except (OSError, UnicodeError, ValueError):
|
|
79
|
-
return {}
|
|
80
|
-
return data if isinstance(data, dict) else {}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def _load_cookie_db(profile: Path) -> dict[str, str]:
|
|
84
|
-
db = profile / "Network/Cookies"
|
|
85
|
-
try:
|
|
86
|
-
with sqlite3.connect("file:%s?mode=ro" % db, uri=True) as con:
|
|
87
|
-
rows = con.execute("select name,value from cookies where host_key like '%xiaoheihe.cn'").fetchall()
|
|
88
|
-
except (OSError, sqlite3.Error):
|
|
89
|
-
return {}
|
|
90
|
-
return {str(k): str(v) for k, v in rows if k in {"user_heybox_id", "user_pkey", "x_xhh_tokenid"} and v}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def _read_sentry_identity(profile: Path) -> dict[str, str]:
|
|
94
|
-
identity: dict[str, str] = {}
|
|
95
|
-
scope = profile / "sentry/scope_v3.json"
|
|
96
|
-
try:
|
|
97
|
-
crumbs = _read_json(scope).get("scope", {}).get("breadcrumbs", [])
|
|
98
|
-
for crumb in reversed(crumbs):
|
|
99
|
-
raw = crumb.get("data",{}).get("url","")
|
|
100
|
-
if "x_app=heybox_pc" in raw:
|
|
101
|
-
query = parse_qs(urlparse(raw).query)
|
|
102
|
-
allowed = {
|
|
103
|
-
"app", "client_type", "device_id", "exe_version", "heybox_id",
|
|
104
|
-
"os_type", "os_version", "version", "web_version", "x_app",
|
|
105
|
-
"x_client_type", "x_client_version", "x_os_type",
|
|
106
|
-
}
|
|
107
|
-
identity = {k: v[-1] for k, v in query.items() if k in allowed and v}
|
|
108
|
-
break
|
|
109
|
-
except (OSError, ValueError, TypeError):
|
|
110
|
-
pass
|
|
111
|
-
return identity
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def load_session(profile: Path | None = None):
|
|
115
|
-
"""Load the current desktop session without exposing credential material.
|
|
116
|
-
|
|
117
|
-
Heybox 1.14 stores its authoritative session in ``config.json``. The
|
|
118
|
-
Chromium database is retained as a compatibility fallback because older
|
|
119
|
-
installations and upgrade paths may not have written the new config yet.
|
|
120
|
-
"""
|
|
121
|
-
profile = profile or Path.home() / "AppData/Roaming/heybox-pc-launcher"
|
|
122
|
-
config = _read_json(profile / "config.json")
|
|
123
|
-
db_cookies = _load_cookie_db(profile)
|
|
124
|
-
cookies: dict[str, str] = dict(db_cookies)
|
|
125
|
-
config_cookies = config.get("cookies")
|
|
126
|
-
if isinstance(config_cookies, list):
|
|
127
|
-
for item in config_cookies:
|
|
128
|
-
if not isinstance(item, dict):
|
|
129
|
-
continue
|
|
130
|
-
name, value = item.get("name"), item.get("value")
|
|
131
|
-
if isinstance(name, str) and isinstance(value, str) and value:
|
|
132
|
-
if name in {"user_heybox_id", "user_pkey", "x_xhh_tokenid"}:
|
|
133
|
-
cookies[name] = value
|
|
134
|
-
acc_config = config.get("acc_config")
|
|
135
|
-
if isinstance(acc_config, dict) and acc_config.get("xhh_token_id"):
|
|
136
|
-
cookies["x_xhh_tokenid"] = str(acc_config["xhh_token_id"])
|
|
137
|
-
if cookies.get("user_pkey"):
|
|
138
|
-
cookies["user_pkey"] = _decrypt_user_pkey(cookies["user_pkey"])
|
|
139
|
-
account = config.get("account") if isinstance(config.get("account"), dict) else {}
|
|
140
|
-
if not cookies.get("user_heybox_id") and account.get("heybox_id"):
|
|
141
|
-
cookies["user_heybox_id"] = str(account["heybox_id"])
|
|
142
|
-
if not {"user_heybox_id", "user_pkey", "x_xhh_tokenid"} <= set(cookies):
|
|
143
|
-
raise FuploadError("Heybox desktop login state is incomplete", kind="authentication_error")
|
|
144
|
-
|
|
145
|
-
identity = _read_sentry_identity(profile)
|
|
146
|
-
version = identity.get("version") or CLIENT_VERSION
|
|
147
|
-
identity = {
|
|
148
|
-
"x_client_type": "pc",
|
|
149
|
-
"x_os_type": "Windows",
|
|
150
|
-
"x_app": "heybox_pc",
|
|
151
|
-
"version": version,
|
|
152
|
-
"exe_version": identity.get("exe_version") or version,
|
|
153
|
-
"os_version": identity.get("os_version") or platform.platform(aliased=True),
|
|
154
|
-
**identity,
|
|
155
|
-
}
|
|
156
|
-
identity["version"] = version
|
|
157
|
-
identity["exe_version"] = identity.get("exe_version") or version
|
|
158
|
-
identity["heybox_id"] = cookies["user_heybox_id"]
|
|
159
|
-
return cookies, identity
|