nibble-cli 0.3.0__tar.gz → 0.3.1__tar.gz
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.
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/PKG-INFO +1 -1
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/nibble_cli.egg-info/PKG-INFO +1 -1
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/nibble_installer.py +61 -0
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/nibble_cli.egg-info/SOURCES.txt +0 -0
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/nibble_cli.egg-info/dependency_links.txt +0 -0
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/nibble_cli.egg-info/entry_points.txt +0 -0
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/nibble_cli.egg-info/top_level.txt +0 -0
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/setup.cfg +0 -0
- {nibble_cli-0.3.0 → nibble_cli-0.3.1}/setup.py +0 -0
|
@@ -14,6 +14,8 @@ import tempfile
|
|
|
14
14
|
import urllib.error
|
|
15
15
|
import urllib.request
|
|
16
16
|
import zipfile
|
|
17
|
+
import hashlib
|
|
18
|
+
import re
|
|
17
19
|
from importlib import metadata
|
|
18
20
|
from pathlib import Path
|
|
19
21
|
|
|
@@ -74,6 +76,64 @@ def _download_asset(url, out_path):
|
|
|
74
76
|
return False
|
|
75
77
|
raise
|
|
76
78
|
|
|
79
|
+
def _download_text(url):
|
|
80
|
+
try:
|
|
81
|
+
with urllib.request.urlopen(url) as resp:
|
|
82
|
+
return resp.read().decode("utf-8", errors="replace")
|
|
83
|
+
except urllib.error.HTTPError as e:
|
|
84
|
+
if e.code == 404:
|
|
85
|
+
return None
|
|
86
|
+
raise
|
|
87
|
+
|
|
88
|
+
def _parse_checksums(text):
|
|
89
|
+
checksums = {}
|
|
90
|
+
for raw_line in text.splitlines():
|
|
91
|
+
line = raw_line.strip()
|
|
92
|
+
if not line or line.startswith("#"):
|
|
93
|
+
continue
|
|
94
|
+
match = re.match(r"^([A-Fa-f0-9]{64})\s+\*?(.+)$", line)
|
|
95
|
+
if not match:
|
|
96
|
+
continue
|
|
97
|
+
checksums[match.group(2).strip()] = match.group(1).lower()
|
|
98
|
+
return checksums
|
|
99
|
+
|
|
100
|
+
def _sha256_file(path):
|
|
101
|
+
h = hashlib.sha256()
|
|
102
|
+
with open(path, "rb") as f:
|
|
103
|
+
for chunk in iter(lambda: f.read(1024 * 64), b""):
|
|
104
|
+
h.update(chunk)
|
|
105
|
+
return h.hexdigest()
|
|
106
|
+
|
|
107
|
+
def _verify_checksum(version, archive_name, archive_path):
|
|
108
|
+
base_url = f"https://github.com/{REPO}/releases/download/v{version}"
|
|
109
|
+
checksum_candidates = [
|
|
110
|
+
"checksums.txt",
|
|
111
|
+
f"{PROJECT}_{version}_checksums.txt",
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
checksum_text = None
|
|
115
|
+
checksum_name = None
|
|
116
|
+
for candidate in checksum_candidates:
|
|
117
|
+
text = _download_text(f"{base_url}/{candidate}")
|
|
118
|
+
if text is not None:
|
|
119
|
+
checksum_text = text
|
|
120
|
+
checksum_name = candidate
|
|
121
|
+
break
|
|
122
|
+
|
|
123
|
+
if checksum_text is None:
|
|
124
|
+
raise RuntimeError(
|
|
125
|
+
f"no checksum file found for v{version} (tried: {', '.join(checksum_candidates)})"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
checksums = _parse_checksums(checksum_text)
|
|
129
|
+
expected = checksums.get(archive_name)
|
|
130
|
+
if expected is None:
|
|
131
|
+
raise RuntimeError(f"checksum for {archive_name} not found in {checksum_name}")
|
|
132
|
+
|
|
133
|
+
actual = _sha256_file(archive_path)
|
|
134
|
+
if actual != expected:
|
|
135
|
+
raise RuntimeError(f"checksum mismatch for {archive_name}")
|
|
136
|
+
|
|
77
137
|
|
|
78
138
|
def _extract_binary(archive_path, dest_binary):
|
|
79
139
|
bin_names = {_binary_name(), PROJECT, f"{PROJECT}.exe"}
|
|
@@ -124,6 +184,7 @@ def ensure_installed():
|
|
|
124
184
|
local = tmpdir / asset
|
|
125
185
|
if _download_asset(url, local):
|
|
126
186
|
archive_path = local
|
|
187
|
+
_verify_checksum(version, asset, local)
|
|
127
188
|
break
|
|
128
189
|
if archive_path is None:
|
|
129
190
|
raise RuntimeError(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|