Emoji markers, markdown bold inside code comments, and em-dashes are
gone from source comments, scripts, CI config, the markdown docs and
every served page. Counted before and after:
emoji markers 1432 -> 0
em-dashes 1938 -> 4 (table placeholders and one fenced comment)
Paragraphs that narrated their own revision history into the public
pages ("this said X until <date>", "this row used to say the opposite")
are cut back to the current fact. That history is in git.
The eight generated pages are regenerated from their sources: the spec,
audit, security, self-hosting and engine pages from flamenet-e2e, and
the relay, API, configuration and hosting pages from this repo's docs.
Two of them had been hand-edited after generation and would have
reverted on the next run; those edits now live in the sources.
The diff over Sources/ is comments and string literals only, checked by
filtering the diff for anything else. 694 tests pass before and after.
CONTRIBUTING gets a four-line rule so it does not grow back.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
130 lines
5.2 KiB
Python
Executable File
130 lines
5.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Generate the project's QR codes, and decode them before anyone trusts them.
|
|
|
|
**A QR code is unreadable to the person making it.** "It looks like a QR
|
|
code" is the entire evidence available by eye, which is why `--verify` decodes
|
|
the output with OpenCV, a different library from the one that wrote it. A
|
|
generator checking its own work only proves it is self-consistent.
|
|
|
|
Nothing here calls a third-party QR service. Those log who is generating codes
|
|
for a given URL, and a code that lives on someone else's redirect domain stops
|
|
working when they do.
|
|
|
|
python3 -m venv /tmp/qrenv && /tmp/qrenv/bin/pip install segno pillow
|
|
/tmp/qrenv/bin/python scripts/make-qr.py Public/qr
|
|
/tmp/qrenv/bin/python scripts/make-qr.py Public/qr --verify # needs opencv
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
import segno
|
|
|
|
SITE = "https://flamenetmessenger.com"
|
|
|
|
# Download points at the PAGE, not at the .apk file. A raw APK URL scanned
|
|
# on an iPhone downloads a file the phone cannot open, and on Android it skips
|
|
# the walkthrough of the three prompts it is about to show. /get puts the
|
|
# download one tap away, with that context, on both phones.
|
|
#
|
|
# These were /#get until the install detail moved to its own page. Codes
|
|
# already shared still work, the landing page keeps `id="get"` and links here
|
|
# which is the only reason repointing was safe. Printed codes cannot be
|
|
# redeployed, so treat a change here as one-way and keep the old target alive.
|
|
TARGETS = {
|
|
"flamenet-download": (f"{SITE}/get", "Get Flamenet Messenger",
|
|
"flamenetmessenger.com/get"),
|
|
"flamenet-donate": (f"{SITE}/donate", "Support Flamenet Messenger",
|
|
"flamenetmessenger.com/donate"),
|
|
}
|
|
|
|
BRAND = (91, 76, 209)
|
|
INK = (26, 26, 30)
|
|
MUTED = (110, 110, 120)
|
|
|
|
|
|
def generate(out: str) -> None:
|
|
for name, (url, title, sub) in TARGETS.items():
|
|
# Level H tolerates ~30% damage: printed, stuck on things, photographed
|
|
# at an angle.
|
|
qr = segno.make(url, error="h")
|
|
# An explicit white background, not transparency. segno defaults
|
|
# to transparent, which looks identical on this site (it is light-only)
|
|
# and fails completely the moment the file is used the way a QR file
|
|
# gets used: dropped on a dark slide, printed on coloured stock, pasted
|
|
# into a dark-themed doc. Dark modules on a dark ground is not a
|
|
# degraded code, it is an unreadable one, and the person publishing it
|
|
# cannot see that by looking.
|
|
qr.save(f"{out}/{name}.svg", scale=10, border=4, light="#ffffff")
|
|
qr.save(f"{out}/{name}.png", scale=20, border=4, light="#ffffff")
|
|
print(f"{name} v{qr.version} {url}")
|
|
_card(out, name, url, title, sub)
|
|
|
|
|
|
def _card(out: str, name: str, url: str, title: str, sub: str) -> None:
|
|
"""A captioned version. Two bare codes side by side are a coin flip, and the
|
|
one thing worse than no donate link is a donate link people scan expecting
|
|
the app."""
|
|
try:
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
except ImportError:
|
|
print(" (no pillow, skipping caption card)")
|
|
return
|
|
|
|
def font(size):
|
|
for path in ("/System/Library/Fonts/SFNSDisplay.ttf",
|
|
"/System/Library/Fonts/Helvetica.ttc"):
|
|
try:
|
|
return ImageFont.truetype(path, size)
|
|
except Exception:
|
|
continue
|
|
# Still produces a readable card rather than dying at the last step.
|
|
return ImageFont.load_default()
|
|
|
|
tmp = f"{out}/.{name}.tmp.png"
|
|
segno.make(url, error="h").save(tmp, scale=20, border=2, dark="#1a1a1e")
|
|
code = Image.open(tmp).convert("RGB")
|
|
|
|
pad, cap = 90, 180
|
|
card = Image.new("RGB", (code.width + pad * 2, code.height + pad + cap), "white")
|
|
card.paste(code, (pad, pad))
|
|
d = ImageDraw.Draw(card)
|
|
mid, ty = card.width / 2, pad + code.height + 28
|
|
d.text((mid, ty), title, font=font(58), fill=INK, anchor="ma")
|
|
d.text((mid, ty + 74), sub, font=font(38), fill=MUTED, anchor="ma")
|
|
d.rectangle([0, card.height - 14, card.width, card.height], fill=BRAND)
|
|
card.save(f"{out}/{name}-card.png")
|
|
os.remove(tmp)
|
|
|
|
|
|
def verify(out: str) -> int:
|
|
import cv2
|
|
|
|
expected = {}
|
|
for name, (url, _, _) in TARGETS.items():
|
|
expected[f"{name}.png"] = url
|
|
expected[f"{name}-card.png"] = url
|
|
|
|
det, bad = cv2.QRCodeDetector(), 0
|
|
for filename, want in sorted(expected.items()):
|
|
path = os.path.join(out, filename)
|
|
if not os.path.exists(path):
|
|
print(f"MISSING {filename}")
|
|
bad += 1
|
|
continue
|
|
text, _, _ = det.detectAndDecode(cv2.imread(path))
|
|
ok = text == want
|
|
bad += 0 if ok else 1
|
|
print(("OK " if ok else "WRONG") + f" {filename:32s} {text!r}")
|
|
print("all codes decode to their intended URL" if not bad
|
|
else f"{bad} code(s) wrong, do NOT publish these")
|
|
return 1 if bad else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
target = sys.argv[1] if len(sys.argv) > 1 and not sys.argv[1].startswith("--") else "Public/qr"
|
|
os.makedirs(target, exist_ok=True)
|
|
if "--verify" in sys.argv:
|
|
sys.exit(verify(target))
|
|
generate(target)
|
|
print("\nNow decode them: make-qr.py %s --verify" % target)
|