@follenfang/fupload 0.0.25 → 0.0.26

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 CHANGED
@@ -2,7 +2,7 @@
2
2
  name: fupload
3
3
  description: Explicit author-publishing workflow for World of Warcraft plugins, configuration shares, and WA/strings on NewBeeBox, NetEase DD, CurseForge, Heybox Workshop, and ModUs.Creator, including local Creator login reuse and plugin ZIP publishing. Use only when the user explicitly invokes `$fupload`, explicitly asks to use the Fupload Skill, or loads this Skill by path. Do not trigger from ordinary mentions of publishing, NewBeeBox, DD, CurseForge, Heybox, ModUs, plugins, configurations, or WA.
4
4
  metadata:
5
- version: "0.0.25"
5
+ version: "0.0.26"
6
6
  ---
7
7
 
8
8
  # Fupload
@@ -81,7 +81,7 @@ When rebuilding a plugin update/edit form, preserve field presence from the curr
81
81
 
82
82
  Before `plugin update`, traverse `/addon/addon_versions` pages as an optional duplicate guard. If it returns version rows, reject any candidate version already present anywhere in that history before upload; if it is empty or unavailable, retain the current-version check and continue. After update, confirm the submitted version fields from the matching item in the author plugin list, whose `latest_version` is the official update projection. `detail_v2` is supplementary. An empty history never marks a successful private-plugin update as failed and never triggers replay.
83
83
 
84
- Read `plugin categories`, choose `primary_category_id`, then choose only returned `second_category_ids`. Read `plugin game-versions --game-type <id>` and use its stable values. The package accepts `.zip` only. Authorization always uses `file_type=a19-ui-res`, `business_id=addon`, fixed `file_name=addon.zip`, and `mime_type=application/x-zip-compressed`. Plugin image authorization uses `a19-ui-media/img` with an explicit empty wire file name.
84
+ Read `plugin categories`, choose `primary_category_id`, then choose only returned `second_category_ids`. Read `plugin game-versions --game-type <id>` and use its stable values. The package accepts `.zip` only. Before login/upload, local plugin ZIP files are checked for backslash paths in both the central directory and local file headers; DD cannot recognize these paths reliably. Rebuild such ZIPs with forward-slash (`/`) entry names (Windows PowerShell 5 `Compress-Archive` may produce incompatible backslash names). Fupload rejects the package rather than rewriting it. External `detail_url` packages are not downloaded for this check. Authorization always uses `file_type=a19-ui-res`, `business_id=addon`, fixed `file_name=addon.zip`, and `mime_type=application/x-zip-compressed`. Plugin image authorization uses `a19-ui-media/img` with an explicit empty wire file name.
85
85
 
86
86
  ## Configuration share
87
87
 
@@ -1,3 +1,3 @@
1
1
  """Fupload Python CLI."""
2
2
 
3
- __version__ = "0.0.25"
3
+ __version__ = "0.0.26"
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import os
6
+ import struct
6
7
  import zipfile
7
8
  from dataclasses import dataclass, field
8
9
  from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Tuple
@@ -10,6 +11,33 @@ from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Tuple
10
11
  from .errors import ValidationError
11
12
 
12
13
 
14
+ def _validate_dd_plugin_zip(path: str) -> None:
15
+ """Inspect stored paths before Windows ZipInfo normalizes separators."""
16
+ try:
17
+ with open(path, "rb") as source, zipfile.ZipFile(source) as archive:
18
+ for info in archive.infolist():
19
+ if "\\" in info.orig_filename:
20
+ raise ValidationError(
21
+ "DD plugin ZIP contains backslash paths; rebuild the ZIP with forward-slash (/) entry names",
22
+ path="$.file",
23
+ )
24
+ source.seek(info.header_offset)
25
+ header = source.read(30)
26
+ if len(header) != 30 or header[:4] != b"PK\x03\x04":
27
+ raise zipfile.BadZipFile("invalid local file header")
28
+ name_length = struct.unpack_from("<H", header, 26)[0]
29
+ name = source.read(name_length)
30
+ if len(name) != name_length:
31
+ raise zipfile.BadZipFile("truncated local entry name")
32
+ if b"\\" in name:
33
+ raise ValidationError(
34
+ "DD plugin ZIP contains backslash paths in a local file header; rebuild the ZIP with forward-slash (/) entry names",
35
+ path="$.file",
36
+ )
37
+ except (OSError, zipfile.BadZipFile) as exc:
38
+ raise ValidationError("file must be a valid ZIP archive", path="$.file") from exc
39
+
40
+
13
41
  JSON_TYPES = {
14
42
  "string": (str,),
15
43
  "integer": (int,),
@@ -308,6 +336,8 @@ class Schema:
308
336
  ):
309
337
  scalar_array(name, (str,), "array must contain nonempty strings")
310
338
  if self.name.startswith("fupload.v1.dd"):
339
+ if self.name.startswith("fupload.v1.dd.plugin.") and "file" in value:
340
+ _validate_dd_plugin_zip(value["file"])
311
341
  object_array("associated_acts", {"sn", "act_type"}, ("sn", "act_type"))
312
342
  for name in ("second_category_ids", "vip_levels"):
313
343
  if name in value and any(isinstance(item, bool) or not isinstance(item, int) for item in value[name]):
@@ -191,6 +191,7 @@ def verify_dd_executable(executable: Path) -> Dict[str, str]:
191
191
  [powershell, "-NoProfile", "-NonInteractive", "-Command", script],
192
192
  capture_output=True, text=True, encoding="utf-8", errors="strict",
193
193
  timeout=20, check=False, env=environment,
194
+ creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
194
195
  )
195
196
  if completed.returncode != 0:
196
197
  raise FuploadError("DD Authenticode verification process failed", kind="trust_boundary")
@@ -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.25",
5
- "skill_version": "0.0.25",
6
- "tree_sha256": "a90fdc7fc77bec86d92215bd4adc50d3aef7eb48b6e9cfac1f20051e5eb3a3e5",
4
+ "package_version": "0.0.26",
5
+ "skill_version": "0.0.26",
6
+ "tree_sha256": "4af4e44df9949daa9432d47bc5d7913d6dd58442e8436981c22922a1e365b63f",
7
7
  "files": [
8
8
  {
9
9
  "path": "agents/openai.yaml",
@@ -87,8 +87,8 @@
87
87
  },
88
88
  {
89
89
  "path": "references/dd.md",
90
- "bytes": 21111,
91
- "sha256": "18895d95e5221b3c2243922bbfc6f2e826f9084a0d5d11c37c3eb923a9dd7547"
90
+ "bytes": 21542,
91
+ "sha256": "2bff00091259535980e42fac12f9765f9e51f8beea43dee9bff377c67fa2bce3"
92
92
  },
93
93
  {
94
94
  "path": "references/modus.md",
@@ -113,7 +113,7 @@
113
113
  {
114
114
  "path": "scripts/fupload_cli/__init__.py",
115
115
  "bytes": 50,
116
- "sha256": "33eefade5f5f7a8d274c5106873503d86397e994c0b22a0fad6d27bacd7960de"
116
+ "sha256": "8affb4fcf748b4f6b76907e88051a6a4aa5110146ea5adbe56231509962b1de4"
117
117
  },
118
118
  {
119
119
  "path": "scripts/fupload_cli/blackbox_web.py",
@@ -182,8 +182,8 @@
182
182
  },
183
183
  {
184
184
  "path": "scripts/fupload_cli/schema.py",
185
- "bytes": 55131,
186
- "sha256": "b651963c504896cfef46f65b61d5fb638884aacb14a8e09593162526e239133f"
185
+ "bytes": 56696,
186
+ "sha256": "9d690fea8fe7b249c089a24a6c59d783f83d2ffd0215def770cd9849d09e52f8"
187
187
  },
188
188
  {
189
189
  "path": "scripts/fupload_cli/state_machine.py",
@@ -197,8 +197,8 @@
197
197
  },
198
198
  {
199
199
  "path": "scripts/fupload_cli/trust.py",
200
- "bytes": 9392,
201
- "sha256": "83298b6aaf63144381451b9e486469215aa5fa5fbde115a20c376d5daf4cef11"
200
+ "bytes": 9462,
201
+ "sha256": "79d31833a16d71ec132612a4a2fd2f015770df469e7db06933b3ea530022c97d"
202
202
  },
203
203
  {
204
204
  "path": "scripts/fupload.py",
@@ -208,7 +208,7 @@
208
208
  {
209
209
  "path": "SKILL.md",
210
210
  "bytes": 28729,
211
- "sha256": "24c423a3f33cafc5d98e7efc5be199147088d268673ea03d121bbbc850a5f90e"
211
+ "sha256": "863223ca2e78adb854511a18fea9c9bead7238d5014b229a0ea21a335409fc90"
212
212
  }
213
213
  ]
214
214
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@follenfang/fupload",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "Install and run the Fuploader Agent Skill and Python CLI.",
5
5
  "type": "module",
6
6
  "bin": {