aim-web2.1.0rc9
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fetch pinned upstream assets ONCE; browsers only load local copies.
|
||||
|
||||
Supply --from-directory for air-gapped deployment. Integrity checks are identical.
|
||||
No npm, Node, CDN requests from the browser, or mutable 'latest' URLs.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import argparse
|
||||
import base64
|
||||
import hashlib
|
||||
import os
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
from urllib.request import urlopen
|
||||
|
||||
ASSETS = {
|
||||
'bootstrap.min.css': (
|
||||
'https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css',
|
||||
'sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB'),
|
||||
'htmx.min.js': (
|
||||
'https://cdn.jsdelivr.net/npm/htmx.org@2.0.10/dist/htmx.min.js',
|
||||
'H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V'),
|
||||
}
|
||||
|
||||
|
||||
def valid(data: bytes, expected: str) -> bool:
|
||||
return base64.b64encode(hashlib.sha384(data).digest()).decode('ascii') == expected
|
||||
|
||||
|
||||
def prepare(destination: Path, offline: Path | None = None, *, reuse: Path | None = None) -> None:
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
for name, (url, integrity) in ASSETS.items():
|
||||
target = destination / name
|
||||
if target.is_file() and valid(target.read_bytes(), integrity):
|
||||
print('Verified local asset:', name)
|
||||
continue
|
||||
if offline:
|
||||
data = (offline / name).read_bytes()
|
||||
elif reuse and (reuse / name).is_file() and not (reuse / name).is_symlink():
|
||||
candidate = (reuse / name).read_bytes()
|
||||
if valid(candidate, integrity):
|
||||
data = candidate
|
||||
print('Reusing verified installed asset:', name)
|
||||
else:
|
||||
with urlopen(url, timeout=30) as response:
|
||||
data = response.read(2_000_001)
|
||||
else:
|
||||
with urlopen(url, timeout=30) as response:
|
||||
data = response.read(2_000_001)
|
||||
if len(data) > 2_000_000 or not valid(data, integrity):
|
||||
raise ValueError(f'Upstream integrity mismatch: {name}. No asset was installed.')
|
||||
fd, filename = tempfile.mkstemp(prefix='.asset-', dir=destination)
|
||||
temporary = Path(filename)
|
||||
try:
|
||||
with os.fdopen(fd, 'wb') as stream:
|
||||
stream.write(data)
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
temporary.chmod(0o644)
|
||||
os.replace(temporary, target)
|
||||
finally:
|
||||
temporary.unlink(missing_ok=True)
|
||||
print('Installed verified local asset:', name)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--from-directory', type=Path)
|
||||
parser.add_argument('--destination', type=Path, default=Path(__file__).resolve().parents[1] / 'src/aim_webgui/static/vendor')
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
prepare(args.destination, args.from_directory)
|
||||
except Exception as exc:
|
||||
parser.exit(1, f'Assets not prepared: {exc}\nUse --from-directory with the exact pinned upstream files for offline installation.\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user