Repository navigation
v3.16.0 — Unguessable board links, pinned files, delete a board, safer uploads
Board links can't be guessed any more, owners can pin files and delete a board, and uploads are checked by name as well as content. One migration, run automatically on start-up.
Board links that can't be guessed
- New boards get a random code after the name (
/econ-level-200-k7q2m9), so trying course names no longer finds a board and its files. Names may repeat. - Existing boards keep their addresses, so links already shared still work.
- Opening from /start takes the board's link, never its name. "Lost your owner link?" builds the recovery address from that link too, and the board's Manage panel links to recovery.
- Misses are rate-limited per visitor: 60 unknown board addresses and 20 failed opens every 10 minutes.
Pin files, delete a board
- Pin to top. In owner mode, a file's menu has Pin to top. Up to three pinned files lead each section in every sort and search, marked with an amber pin.
- Delete board. Board settings → Delete board, confirmed by typing the board's name (checked on the server too). Its courses and files go at once.
- Recovery email, asked at the right time. Owners see "Don't lose this board" once the board holds files, not on an empty one. Not now hides it for 30 days on that browser.
- "New" on every device. A course a browser has never opened counts the last week as new, so a phone shows what landed while the laptop was in use.
- A plainer upload receipt. No "Your name" field. The receipt shares the course link and names the file ("New in BIO 101: Week 3 slides"), WhatsApp first.
Security
- Uploads are checked by name as well as content. A PDF named
slides.htaor.exeused to pass and keep its name. The extension must now be allowed and match the content, and downloads and ZIPs take their extension from the stored file, which also covers older uploads. - Owners can't be locked out by strangers. Unlock, owner links, recovery and the upload passphrase were limited per board only, so anyone could lock the real owner out. Limits are now per board and per visitor, with a higher per-board ceiling.
- Real visitor addresses behind Cloudflare.
CLIENT_IP_HEADERreadsCF-Connecting-IPfrom trusted proxies only, so rate limits are per student, not per Cloudflare server.*inTRUSTED_PROXIESis still never honoured. - Abuse limits. At most 20 reports an hour per visitor; at most 20 section ZIPs an hour per visitor, and none built without 256 MB free.
- Search takes text only (100 characters, 8 words), with
%and_matched literally. - Secrets stay out of logs. Recovery never makes a link while mail goes to the log, where it was a working owner takeover. Telegram errors are logged without the bot token.
- Dependencies. Laravel, Symfony http-foundation (Cache-Control ReDoS), Guzzle, PSR-7, CommonMark and Flysystem updated; npm audit fix, including Vite's launch-editor advisories.
composer auditandnpm auditreport nothing.
Looks
- Cards are dark panels with a double edge and no dividers; one secondary button style; quieter lists; one soft focus ring on every control.
- A course whose files all sit in one section shows a plain list.
- Fonts load through Vite, so Open Runde shows under the dev server too.
- Who runs it.
OPERATOR_NAMEputs "Made with ♥ for students by …" in the footer and "Who runs SlipNote" on /lecturers. Takedowns promise a review withinTAKEDOWN_TURNAROUND(default "3 working days").
Before you deploy
- Storage volume: check this first. Uploads are saved in
storage/app/private. Mount/var/www/html/storage/app(orstorage/app/private) as a persistent volume. A volume onstorage/app/publicalone loses every upload on redeploy. - Set these two first, in Dokploy → Environment, then deploy.
TRUSTED_PROXIESno longer accepts*. The new per-visitor limits need each visitor's own address, and behind Cloudflare and Traefik that address arrives in Cloudflare'sCF-Connecting-IPheader:The header is read only on requests that come from a trusted proxy (Traefik's Docker network), so a request sent straight to the app can't name its own address. Without these, every request looks like it comes from one address, and the limits act site-wide.TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 CLIENT_IP_HEADER=CF-Connecting-IP - New, optional settings:
OPERATOR_NAME(empty hides it) andTAKEDOWN_TURNAROUND. - One migration (
materials.by_owner,materials.pinned_at) runs automatically on start-up. - PHP itself: PHP 8.4.27 (21 October 2026) fixes two critical remote-code-execution flaws (CVE-2026-109618/109619). Once
serversideup/phppublishes 8.4.27 images, rebuild on them and checkphp -vin the container.
245 tests.