sweedworks

← all sources

checkassets.py

Every script and stylesheet, byte for byte

115 lines. This is the file the build actually runs, copied verbatim at build time.

  1. 1"""Compare every served asset, byte for byte, against the file I generated.
  2. 2 
  3. 3verify.py checks the tokenizer bundles on disk. checklive.py checks that the
  4. 4HTML arrives unmodified. Nothing checked the scripts and stylesheets in
  5. 5transit — and Cloudflare provably rewrites HTML on the way out, so "it is
  6. 6correct on disk" is not the same claim as "it is correct when it reaches a
  7. 7reader". Cloudflare has features that rewrite JavaScript (Rocket Loader, and
  8. 8minification in older plans); if one were ever switched on, every gradient
  9. 9check and tokenizer comparison on this site would be verifying a file nobody
  10. 10receives.
  11. 11 
  12. 12 python3 checkassets.py
  13. 13"""
  14. 14 
  15. 15import hashlib
  16. 16import os
  17. 17import re
  18. 18import subprocess
  19. 19import sys
  20. 20 
  21. 21HERE = os.path.dirname(os.path.abspath(__file__))
  22. 22ROOT = os.path.abspath(os.path.join(HERE, ".."))
  23. 23BASE = "https://sweedworks.com"
  24. 24 
  25. 25PAGES = ["index.html", "tokens/index.html", "vocabulary/index.html",
  26. 26 "predict/index.html", "cost/index.html", "learn/index.html",
  27. 27 "attention/index.html", "about/index.html", "changes/index.html"]
  28. 28 
  29. 29# Assets no page links directly but which readers still receive.
  30. 30EXTRA = ["/vendor/gpt-tokenizer/o200k_base.js",
  31. 31 "/vendor/gpt-tokenizer/cl100k_base.js",
  32. 32 "/feed.xml", "/sitemap.xml", "/robots.txt", "/favicon.svg",
  33. 33 "/favicon.ico", "/404.html"]
  34. 34 
  35. 35ASSET_RE = re.compile(r'(?:href|src)="(/[^"]+\.(?:js|css|svg|ico|png|xml|txt))')
  36. 36 
  37. 37 
  38. 38def local_path(url):
  39. 39 return os.path.join(ROOT, url.split("?")[0].lstrip("/"))
  40. 40 
  41. 41 
  42. 42def fetch(url):
  43. 43 out = subprocess.run(["curl", "-sS", "--compressed", "-o", "-", BASE + url],
  44. 44 capture_output=True, timeout=120)
  45. 45 return out.stdout
  46. 46 
  47. 47 
  48. 48def main():
  49. 49 wanted = set(EXTRA)
  50. 50 for page in PAGES:
  51. 51 src = open(os.path.join(ROOT, page), encoding="utf-8").read()
  52. 52 for m in ASSET_RE.finditer(src):
  53. 53 wanted.add(m.group(1).split("?")[0])
  54. 54 
  55. 55 problems, notes, checked = [], [], 0
  56. 56 for url in sorted(wanted):
  57. 57 path = local_path(url)
  58. 58 if not os.path.isfile(path):
  59. 59 problems.append(f"{url}: referenced but not on disk")
  60. 60 continue
  61. 61 mine = open(path, "rb").read()
  62. 62 served = fetch(url)
  63. 63 checked += 1
  64. 64 if served == mine:
  65. 65 continue
  66. 66 
  67. 67 # HTML is rewritten in transit by Cloudflare, which /about/ discloses.
  68. 68 # Accept that difference only if it really is that injection: the
  69. 69 # marker must be present, and everything else must survive line for
  70. 70 # line. Anything more is a finding.
  71. 71 if url.endswith(".html") or url.endswith("/"):
  72. 72 text = served.decode("utf-8", "replace")
  73. 73 original = mine.decode("utf-8", "replace")
  74. 74 residue = text
  75. 75 for line in original.splitlines():
  76. 76 residue = residue.replace(line, "", 1)
  77. 77 residue = residue.strip()
  78. 78 if "__CF$cv$params" in residue and len(residue) < 2000:
  79. 79 notes.append(f"{url}: {len(residue):,} bytes injected in "
  80. 80 f"transit (Cloudflare, disclosed)")
  81. 81 continue
  82. 82 problems.append(f"{url}: HTML altered in transit in a way that is "
  83. 83 f"not the disclosed injection ({len(residue):,} "
  84. 84 f"bytes: {residue[:120]!r})")
  85. 85 continue
  86. 86 # Not identical. Say how, because "differs" is not actionable.
  87. 87 note = (f"{url}: served {len(served):,} bytes, generated "
  88. 88 f"{len(mine):,} bytes")
  89. 89 if len(served) == 0:
  90. 90 note += " — empty response"
  91. 91 elif mine in served:
  92. 92 note += " — something was appended or prepended in transit"
  93. 93 else:
  94. 94 note += (f" — content differs (sha256 "
  95. 95 f"{hashlib.sha256(served).hexdigest()[:12]} vs "
  96. 96 f"{hashlib.sha256(mine).hexdigest()[:12]})")
  97. 97 problems.append(note)
  98. 98 
  99. 99 print(f"compared {checked} assets byte for byte")
  100. 100 for n in notes:
  101. 101 print(f" note {n}")
  102. 102 print()
  103. 103 if problems:
  104. 104 print(f"{len(problems)} problem(s):")
  105. 105 for p in problems:
  106. 106 print(f" - {p}")
  107. 107 return 1
  108. 108 print("Every script, stylesheet and data file arrives exactly as generated. "
  109. 109 "Only HTML is rewritten in transit, which /about/ discloses.")
  110. 110 return 0
  111. 111 
  112. 112 
  113. 113if __name__ == "__main__":
  114. 114 sys.exit(main())