Skip to content

Developing

The guestbook has no build step and no dependencies. The page is plain HTML, CSS and one ES module, and the server is one file of Python's standard library.

The files

File What
app/index.html the page: masthead, the signing window, the book, the footer
app/style.css the look, with light and dark from prefers-color-scheme; the sky tile is an inline SVG
app/guestbook.js the doodle pad (Bresenham lines on a 96×48 canvas), signing, the book, the counter
app/fonts/ Pixelify Sans, served from here, with its licence
server/guestbook.py GET /entries, POST /sign, POST /hit, GET/POST /mod
tools/dev.py the page and a throwaway server on one port, with no notify command
tools/deploy.sh copies app/ and the server to the live site and restarts it (the stuffs setup)

What the server checks when someone signs

  1. The hidden hp field is empty. If it isn't, the server says "thanks" and drops the entry without a word.
  2. At least four seconds have passed since the page opened (the page sends its opening time as t).
  3. There's a name and a message of at least two characters. Lengths are capped at 40, 40, 120 and 600 characters, and control characters and direction overrides are taken out.
  4. The website, if any, starts with http:// or https://, and the message has one link at most.
  5. The doodle, if any, is a PNG data URL of exactly 96×48 pixels and under about 30 KB.
  6. That address hasn't signed three times this hour or eight times today.

Then the entry is saved as pending with its own random token, and the notify command runs in the background, so a slow or failed message never loses an entry.

Trying it on your computer

python3 tools/dev.py

That prints an address like http://127.0.0.1:8458/ and a throwaway data folder. Sign it, then open the link from guestbook.log in that folder to let the entry in. Pass a port and a folder to keep the data: python3 tools/dev.py 8458 /tmp/gb.

The page puts everything people write on the page with textContent, never as HTML, and the owner's page escapes everything and sends a strict Content-Security-Policy, so a message can't run anything.