aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.htmltest.yml8
-rw-r--r--README.md44
-rw-r--r--TODO.md223
-rwxr-xr-xbin/hook/deploy.rb19
-rw-r--r--bin/hook/etc/webhook.conf4
-rw-r--r--bin/hook/etc/webhook.service6
-rw-r--r--content/articles/about.md42
-rw-r--r--content/articles/site-backend.md139
-rw-r--r--content/posts/2006-03-19-openvpn-article-in-linux-magazine.html15
-rw-r--r--content/posts/2023-05-02-bookworm-and-podman.md2
-rw-r--r--content/posts/2023-12-02-firefox-redux.md21
-rw-r--r--content/posts/2025-05-18-onion-service-mirror.md27
-rw-r--r--content/posts/2025-05-18-trying-tails.md49
-rw-r--r--content/posts/2025-06-07-uninstall-facebook.md132
-rw-r--r--content/posts/2025-06-08-armbian-on-odroid-n2l.md145
-rw-r--r--content/posts/2025-06-08-nginx-caching-and-security-headers.md27
-rw-r--r--content/posts/2025-06-08-old-openvpn-article.md36
-rw-r--r--content/posts/2025-10-04-polycvss-v0.2.0.md143
-rw-r--r--content/projects/polycvss.md10
-rw-r--r--data/projects.yaml5
-rw-r--r--static/favicon.pngbin0 -> 907 bytes
-rw-r--r--static/files/articles/site-backend/pablotron.onion.conf.txt40
-rw-r--r--static/files/articles/site-backend/pablotron.org.conf.txt3
-rw-r--r--static/files/articles/site-backend/script.js.txt43
-rw-r--r--static/files/articles/site-backend/webhook.conf.txt4
-rw-r--r--static/files/pabs.asc46
-rw-r--r--static/files/posts/armbian-on-odroid-n2l/n2l-1024.pngbin0 -> 516107 bytes
-rw-r--r--static/files/posts/armbian-on-odroid-n2l/n2l-1024.webpbin0 -> 71378 bytes
-rw-r--r--static/files/posts/armbian-on-odroid-n2l/n2l.jpgbin0 -> 5520816 bytes
-rw-r--r--static/files/posts/armbian-on-odroid-n2l/odroid-n2l-root_not_logged_in_yet.txt44
-rw-r--r--themes/hugo-pt2021/layouts/partials/carousel.html4
-rw-r--r--themes/hugo-pt2021/layouts/partials/head.html7
-rw-r--r--themes/hugo-pt2021/layouts/partials/header.html3
-rw-r--r--themes/hugo-pt2021/layouts/partials/project_summary.html6
-rw-r--r--themes/hugo-pt2021/layouts/projects/list.html9
-rw-r--r--themes/hugo-pt2021/layouts/shortcodes/pe-figure.html4
-rw-r--r--themes/hugo-pt2021/layouts/shortcodes/pe-picture.html4
38 files changed, 1159 insertions, 157 deletions
diff --git a/.gitignore b/.gitignore
index 1d44537..a4b641e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
resources
public
bin/logo-0/vendor
+tmp
+dist
diff --git a/.htmltest.yml b/.htmltest.yml
new file mode 100644
index 0000000..b235c04
--- /dev/null
+++ b/.htmltest.yml
@@ -0,0 +1,8 @@
+IgnoreURLs:
+- "^/ims/.*\\.svg$"
+
+# used by theme toggle; ignore
+IgnoreInternalEmptyHash: true
+
+# ignore empty alt attributes on decorative images
+IgnoreAltEmpty: true
diff --git a/README.md b/README.md
index d6a5acd..6aa9d08 100644
--- a/README.md
+++ b/README.md
@@ -105,7 +105,7 @@ Notes:
2. Use [`pngquant`][pngquant] to shrink [PNGs][png].
3. Use `gm convert -define web:lossless=true foo.{png,webp}`
to compress PNGs and convert them to `webp`s.
-4. Use `gm convert foo.{png,webp}`
+4. Use `gm convert foo.{jpg,webp}`
to compress JPEGs and convert them to to `webp`s.
5. Use the `pe-figure` shortcode for progressive enhanced `figure` tags
with a fallback image.
@@ -164,6 +164,44 @@ carousel:
The contents of `static/robots.txt` are from [this site][robotstxt-ai]
and used to prevent the entire site from being indexed by LLM crawlers.
+## HTML Linting
+
+Install [htmltest][]:
+
+```bash
+# install htmltest
+go install https://github.com/wjdp/htmltest@latest
+```
+
+Run [htmltest][] to look for broken internal links and other common
+errors:
+
+```bash
+# run hugo, build site in `./dist`
+hugo --minify -d dist
+
+# run htmltest, ignore links to external sites
+htmltest -c .htmltest.yml -s dist
+```
+
+Results are printed to standard output and saved to
+`./tmp/.htmltest/htmltest.log`.
+
+Run [htmltest][] and check external links:
+
+```bash
+# run hugo, build site in `./dist`
+hugo --minify -d dist
+
+# run htmltest, ignore links to external sites
+htmltest -c .htmltest.yml -s dist
+```
+
+References:
+
+- [htmltest][]
+- [Check links in Hugo with htmltest][htmltest-check-links]
+
## Deploy Site
To clone site repo:
@@ -255,3 +293,7 @@ The [Bulma][] [SASS][] is:
"Lossy compression of PNG images."
[robotstxt-ai]: https://robotstxt.com/ai
"AI / LLM User-Agents: Blocking Guide"
+[htmltest]: https://github.com/wjdp/htmltest
+ "HTML linter which checks for broken links and other errors."
+[htmltest-check-links]: https://robb.sh/posts/check-links-in-hugo-with-htmltest/
+ "Check links in Hugo with htmltest"
diff --git a/TODO.md b/TODO.md
index d25dceb..4f48455 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,42 +1,54 @@
# Site TODO
## Notes
-
- use `zf` to fold sections
- use `zc` to expand tem
## general
-- replace `<img>` in old posts with `{{< figure >}}` (partial work
- done on stuff `>= 2019`)
-- fix broken links in posts
-- import files
+- import old files
+ backup: `user.k3:/data/backup/k2/sda6/share/www/pablotron.org/htdocs`
- add "music" somewhere ("songs", keep pmdn.org for personal stuff)
- add sticky footer:
https://css-tricks.com/couple-takes-sticky-footer/
- toc: add title and aria-label
- toc: show on right sidebar on desktop
-- htmltest/htmltidy post-receive hook (already installed as
- web.k3:~/go/bin/htmltest): <https://github.com/wjdp/htmltest>
- monthly link sweep?
- upgrade from bulma 0.9.3 to bulma 1.0.0
<https://bulma.io/documentation/start/migrating-to-v1/>
-- add html linter. see reviews here:
+- projects: better project pages (pull from `README.md`)
+- wkd for pgp
+- home: rename "Archived Posts..." to "Older Posts"
+- archive: rename "Archived Posts..." to "Older Posts"
+- index with pagefind: (<https://pagefind.app/>, <https://www.tbray.org/ongoing/When/202x/2025/11/01/Blog-Search-Pagefind>)
+
+## linting
+- replace `<img>` in old posts with `{{< figure >}}` (partial work
+ done on stuff `>= 2019`)
+- fix broken links in posts
+- htmltest/htmltidy post-receive hook (already installed as
+ `web.k3:~/go/bin/htmltest`)
+- add automatic html linter. see reviews here:
<https://chezsoi.org/lucas/blog/a-review-of-html-linters.html>
+- fix old links with `ia` tool:
+ <https://archive.org/developers/quick-start-cli.html>
+- restore old projects, releases, and picture content from backup
+ directory: `user.k3:/data/backup/k2/sda6/share/www/pablotron.org/htdocs`
+ note: will need to reduce size of `gallery`
## post ideas
- fast document search: postgres fts, `pg_trgm`, and tika (git/test/sift)
(richard asked about this on 2019-07-22, so +1)
- sqlite3 fts search
- compiler surprises: https://godbolt.org/z/ZQbZ2R
-- pwasm
- RewriteMap/docker (gist)
-- ev-crash-course (~/git/ev-crash-course)
- pocket-jim
- greenwashing: ccs/nuclear/hydrogen is a scam
great link: <https://www.vox.com/climate/363076/climate-change-solution-shell-exxon-mobil-carbon-capture>
- plug-in hybrids: find link about people mashing accelerators and
effective mpg being substantially lower than advertised
- lots of good stuff in "science/climate" bookmarks
+ - wind kills birds garbage:
+ <https://codingrelic.geekhold.com/2024/12/wind-turbines-and-bird-deaths.html>
- thoughts on "relevance of classic fuzz testing"
- https://neverworkintheory.org/2021/10/01/the-relevance-of-classic-fuzz-testing.html
- "law of small numbers": http://psychology.iresearchnet.com/social-psychology/decision-making/law-of-small-numbers/
@@ -54,6 +66,14 @@
- tulip mania
- irony: <https://www.jwz.org/blog/2024/11/bitcoin-tulips/>
- nerd sniping
+ - <https://web3isgoinggreat.com>
+ - charlie strauss
+ - <https://www.antipope.org/charlie/blog-static/2022/11/decision-fatigue.html>
+ - <https://www.antipope.org/charlie/blog-static/2013/12/why-i-want-bitcoin-to-die-in-a.html> !! (lots of good stuff content here)
+ - ftc fraud:
+ <https://www.ftc.gov/news-events/news/press-releases/2022/06/new-analysis-finds-consumers-reported-losing-more-1-billion-cryptocurrency-scams-2021>
+ <https://www.ftc.gov/news-events/news/press-releases/2022/06/new-analysis-finds-consumers-reported-losing-more-1-billion-cryptocurrency-scams-2021>
+ (note: bullet in second article is a "pig butchering" scam)
https://www.jwz.org/blog/2022/01/mozilla-blinked/
https://www.wired.com/story/theres-no-good-reason-to-trust-blockchain-technology/
(nicholas weaver article)
@@ -69,7 +89,6 @@
- syzkaller/syzbot:
https://www.youtube.com/watch?v=YwX4UyXnhz0
https://clangbuiltlinux.github.io/CBL-meetup-2020-slides/glider/Fighting_uninitialized_memory_%40_CBL_Meetup_2020.pdf
- http://www.antipope.org/charlie/blog-static/2022/11/decision-fatigue.html
- bpf:
https://ebpf.io/
https://www.brendangregg.com/blog/2021-07-03/how-to-add-bpf-observability.html https://qmonnet.github.io/whirl-offload/2021/09/23/bpftool-features-thread/
@@ -98,7 +117,7 @@
- log4j and dependency usefulness as a function of time for projects
- postgres tiny tricks
- CTEs as optimization barrier:
- https://old.reddit.com/r/programming/comments/suyidt/a_hairy_postgresql_incident/hxdvwl4/
+ <https://old.reddit.com/r/programming/comments/suyidt/a_hairy_postgresql_incident/hxdvwl4/>
- `~* ANY(string_to_array(?))` (comment in reddit w/json array)
- pub/sub?
- domains instead of repeated check constraints
@@ -109,6 +128,10 @@
- timestamptz, long timezone names aware of DST
- RETURNING
- GENERATED STORED tsvector (bookman)
+ - INT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY vs
+ INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY
+ (fix sequence permission nonsense)
+ - EXISTS rather than COUNT() (depz article about this somewhere)
- compare and contrast cyclonedx vs spdx
- (at the moment i like cyclonedx more, it seems less ad-hoc)
- https://cyclonedx.org/docs/1.4/json/
@@ -123,6 +146,9 @@
<https://blog.tidelift.com/the-state-of-package-signing-across-package-managers>
- declarative install (go)
rationale: <https://blog.phylum.io/phylum-discovers-dozens-more-pypi-packages-attempting-to-deliver-w4sp-stealer-in-ongoing-supply-chain-attack>
+ - counterexamples:
+ - rubygems (arbitrary ruby)
+ - rust (arbitrary rust in `build.rs`)
- typosquatting (see sqo vulns from may email)
- starsquatting (requests, phpass): https://medium.com/checkmarx-security/typosquatting-attack-on-requests-one-of-the-most-popular-python-packages-3b0a329a892d
- ref: https://kerkour.com/rust-crate-backdoor
@@ -158,9 +184,7 @@
https://bitbucket.org/brucelet/space-trader/src/master/app/src/main/java/com/brucelet/spacetrader/
and the 70s one w/ source:
https://en.wikipedia.org/wiki/Star_Trader
-- markovian (golang markov chain generator)
- (~/git/test/go/markovian)
-- hq (~/git/hq)
+- hq (`flex:~/git/hq`)
- secure C wiki is confluence!?!?
<https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard>
- fuzzing (afl)
@@ -181,9 +205,7 @@
gambler's ruin (intro to prob, ch 3.5)
constant-time fibonacci
- fzf, ripgrep
-- https://krebsonsecurity.com/2022/08/the-security-pros-and-cons-of-using-email-aliases/
- (email aliases, suggest whitelist instead of blacklist)
-- bad defaults:
+- bad defaults ("knives up in dishwasher"):
- nullable in code/db (see also: <https://carlineng.com/?postid=sql-critique#blog>)
- mutable variables
- fallthrough in switch
@@ -191,35 +213,36 @@
- nullable parameters
- defer (go, c proposal) vs manual freeing
- create openssl 3.x provider, see:
- https://www.openssl.org/docs/manmaster/man7/provider.html
+ <https://www.openssl.org/docs/manmaster/man7/provider.html>
(could use pt-aes, pt-chacha20, md4, md5, sha2, etc)
-- summary of minification work w/ links to posts, reference this
- article:
- https://endtimes.dev/why-your-website-should-be-under-14kb-in-size/
- minikube vs k3s (https://minikube.sigs.k8s.io/docs/handbook/)
-- on passwords (crypto training, https://arstechnica.com/civis/viewtopic.php?f=2&t=1486155&p=41174039#p41174039)
- - lots of bad info floating around (see comments of
- https://arstechnica.com/information-technology/2022/08/plex-imposes-password-reset-after-hackers-steal-data-for-15-million-users/
- https://old.reddit.com/r/programming/comments/wxx674/password_management_firm_lastpass_was_hacked_two/
- etc
- - passkeys (good replacement, too complicated internally)
- - owasp password security cheat sheet, fips 183?
- compare sanitizer api, dompurify, fastest htmlesc
- tiny-binaries redux w/go 1.20, point out grype scanner output for
minimal images
- browser addons:
- (ublock origin)
+ (ff: ublock origin, chrome: ublock origin lite)
https://arstechnica.com/gadgets/2022/09/beloved-browser-extension-acquired-by-non-beloved-antivirus-firm/?comments=1
<https://consentomatic.au.dk/>
cosmetic filter example:
https://github.com/gorhill/uBlock/wiki/Procedural-cosmetic-filters
<https://rubyweekly.com/issues/620>
##table.item:has(p.name > .tag-sponsor)
-- try out various lsms
-- systemd hardening
+ - dark reader
+ - tab stash
+- hardening
+ - try out various lsms
+ - apparmor
+ - lockdown
+ - selinux
+ - systemd hardening (examples: spamassassin config)
+ - owasp guides
+ - disa stigs
+ - dropping system calls (firejail)
+ - opensnitch
- heat pump (pictures/heat-pump-20220930)
- <https://insideevs.com/news/509767/tesla-model3-control-arm-fix/>
- `curl|bash` is madness
+ - vulnerable to clickfix: <https://arstechnica.com/security/2025/11/clickfix-may-be-the-biggest-security-threat-your-family-has-never-heard-of/>
- gosec vs govulncheck
https://github.com/securego/gosec
https://www.pixelstech.net/article/1667102060-Secure-Your-Go-Code-With-Vulnerability-Check-Tool
@@ -238,9 +261,6 @@
- thoughts on tesla: <https://digbysblog.net/2022/11/27/elon-musk-remembered-for-tech-he-destroyed/>
- try out pgsodium:
<https://github.com/michelp/pgsodium>
-- aegis authenticator dance w/ tablet
- <https://github.com/beemdevelopment/Aegis>
- (including installing lineage 20)
- fix-enterprise-episodes.rb
- imagecompare (flex:git/go/test/imagecompare)
- don't expose ssh (imap)
@@ -275,9 +295,13 @@
- sorta: elasticsearch (opensearch), redis
- reddit, stackoverflow
- my tools
+ - hnb
- vim: (2 pragbooks vim books, vimhelp.org, learnvimthehardway)
+ - tried neovim, still like vim more
- irssi
+ - bitlbee (except googlechat broke on 2025-05-25, :/)
- screen
+ - tried tmux, still like screen more
- mutt/offlineimap/notmuch
(dovecot index config for android)
- irb (show irbrc w/3.x mods)
@@ -286,10 +310,12 @@
- perf
- wireguard
- minify, imagemagick/gm, pngquant
+ - `mod_deflate` mime types tweaked to compress svgs
- meson?
- postgres, sqlite
- - firefox (ublock origin, tab stash, firefox sync)
+ - firefox (ublock origin, tab stash, firefox sync, dark reader)
- gnome (extensions: hidetopbar, workspace matrix)
+ - gnome-extensions tool
- podman
- mtr
- programming languages
@@ -299,8 +325,20 @@
- python (matplotlib, sympy, sagemath)
- assembly
- js (es2015)
-- sagemath, jupyterlab
-- ollama
+ - neat tool: qalculate
+ - ref: <https://qalculate.github.io/>
+ - cli and gtk iface
+ - installed on flex
+ - recommended in lwn comments
+ - used for unit conversions
+ - derivatives switch quickly from symbolic to numeric evaluation
+ - sagemath, jupyterlab
+ - ollama
+ - btop (recommended by alonzo)
+ - goaccess: apache log reporting tool
+ - aegis authenticator dance w/ tablet
+ <https://github.com/beemdevelopment/Aegis>
+ (including installing lineage 20)
- compare signify, age, and minisign:
https://flak.tedunangst.com/post/signify
https://blog.gtank.cc/modern-alternatives-to-pgp/
@@ -319,7 +357,6 @@
- firefox terms of use nonsense
https://arstechnica.com/tech-policy/2025/02/firefox-deletes-promise-to-never-sell-personal-data-asks-users-not-to-panic/
https://lwn.net/Articles/1012430/
-- firefox tab groups (new in firefox 136)
- problems w/ tracking apis:
- orwellian name (does not preserve privacy)
- analogies for folks to understand correlation: clue, sudoku, wordle
@@ -416,7 +453,7 @@
- cryptopals introduction (most crypto fatally broken)
- etc
- lots of older stuff is "knives up in dishwasher"
-- ai/llm mania
+- ai/llm mania (slop)
- article name: "ai canard"
- how many fused-multiply adds does it take for sentience?
- ai dropkick
@@ -426,7 +463,6 @@
<https://linux.slashdot.org/story/15/06/30/0058243/interviews-linus-torvalds-answers-your-question>
- summary of goldman sachs report which is negative on LLMs:
<https://www.wheresyoured.at/pop-culture/>
- - (lots of other stuff by ed zitron)
- <https://arstechnica.com/information-technology/2024/07/openai-board-shakeup-microsoft-out-apple-backs-away-amid-ai-partnership-scrutiny/>
(link to brutal goldman sachs report in comments which talks about
technology limits, power consumption limits, and chip limits)
@@ -435,6 +471,16 @@
- data centers use a staggering amount of energy: <https://arstechnica.com/science/2024/08/data-centers-demand-a-massive-amount-of-energy-heres-how-some-states-are-tackling-the-industrys-impact/>
- delusional scammers:
<https://arstechnica.com/information-technology/2024/07/microsoft-cto-defies-critics-ai-progress-not-slowing-down-its-just-warming-up/>
+ - llms suck at debugging:
+ <https://arstechnica.com/ai/2025/04/researchers-find-ai-is-pretty-bad-at-debugging-but-theyre-working-on-it/>
+ (quote from brian kernighan about "clever code":
+ <https://www.linusakesson.net/programming/kernighans-lever/index.php>)
+ - links:
+ - chatgpt <https://www.jwz.org/blog/2023/02/the-bullshit-fountain/>
+ - ai is not intelligence: <https://current.workingdirectory.net/posts/2023/enough-about-ai/>
+ - (lots of other stuff by ed zitron)
+ - "grift bubble":
+ <https://codingrelic.geekhold.com/2025/01/tale-of-two-crises-y2k-and-o3.html>
- pi cases (fish, lemon, and pumpkin, see pics on phone)
- transport-layer shenanigans:
- included in openssl 3.4 (phoronix article)
@@ -462,6 +508,8 @@
seed, openssl disagrees w/ ietf)... "the key issue":
https://openssl-library.org/post/2025-01-21-blog-positionandplans/?utm_source=atom_feed
https://mailarchive.ietf.org/arch/browse/spasm/?q=draft-ietf-lamps-kyber-certificates
+ - sotak, shmieg, and fillipo all have posts on this
+ - ietf email thread too
- fast modular arithmetic
- good book: primes: a computational approach (crandall primes)
- hacker's delight
@@ -479,13 +527,68 @@
- tls for internal hosts w/ certbot and dns-01
- privacy (23andme bs):
https://www.cnn.com/2025/03/25/tech/23andme-bankruptcy-how-to-delete-data/index.html
+- run tails in gnome boxes with persistent storage
+ (see x1 notes for details, but it's `qemu-img convert ... qemu-img resize`)
+ ref: <https://unix.stackexchange.com/questions/517524/install-tails-with-persistent-storage-on-virtualbox>
+- signal in tails:
+ <https://bisco.org/notes/installing-and-running-signal-on-tails/>
+- bot user-agent blocking:
+ <https://www.jwz.org/blog/2025/05/user-agent-blocking/#comment-259206>
+ <https://perishablepress.com/ultimate-ai-block-list/> (linked from comment)
+ (consider modsecurity.org ...)
+- site backend: document custom mime types in `MOD_DEFLATE`
+- site backend: add "blocking llm crawlers" or "blocking llm slop"
+ section with `robots.txt` and more (see jwz above)
+- passwords:
+ - article about storing passwords, password choices
+ - older idea:
+ - on passwords (crypto training, https://arstechnica.com/civis/viewtopic.php?f=2&t=1486155&p=41174039#p41174039)
+ - lots of bad info floating around (see comments of
+ https://arstechnica.com/information-technology/2022/08/plex-imposes-password-reset-after-hackers-steal-data-for-15-million-users/
+ https://old.reddit.com/r/programming/comments/wxx674/password_management_firm_lastpass_was_hacked_two/
+ etc
+ - passkeys (good replacement, too complicated internally)
+ - owasp password security cheat sheet, fips 183?
+ - link to guidance from 800-63b
+ - avoid composition requirements
+ - bits from "storing passwords" from crypto training
+ - cracking luks:
+ - <https://diverto.github.io/2019/11/18/Cracking-LUKS-passphrases>
+ - <http://www.hungry.com/~pere/blog/Some_notes_on_Linux_LUKS_cracking.html>
+ - links to passkeys
+ - diceware, eff word list
+- sequoia-pgp: https://sequoia-pgp.org/
+ - much better command-line iface than gpg: commands are "encrypt",
+ "decrypt", "sign", "verify", etc
+ - still making sense of trust handling
+ - available in debian
+- privacy:
+ - mozilla "privacy preserving" garbage (above)
+ - https://krebsonsecurity.com/2022/08/the-security-pros-and-cons-of-using-email-aliases/
+ (email aliases, suggest whitelist instead of blacklist)
+ - web fingerprinting: <https://www.amiunique.org/fingerprint>
+ eff coveryourtracks: <https://coveryourtracks.eff.org/>
+ - eff surveillance self-defense: <https://ssd.eff.org/>
+ - msn good article about facebook snafu with a gratuitous omission: <https://www.msn.com/en-us/news/technology/meta-found-a-new-way-to-violate-your-privacy-here-s-what-you-can-do/ar-AA1GecPs>
+ - ars comment about ublock origin setting: <https://arstechnica.com/security/2025/06/meta-and-yandex-are-de-anonymizing-android-users-web-browsing-identifiers/?comments=1&post=43767385>
+- spamprobe to spamassassin (notes in v3.txt)
+ - had to disable dnswl check, was causing grief
+ - `sa-check.py`, got 184/200 (~92% true positive rate)
+ - added `sa-train.sh`, runs nightly
+ - updated `~/.mailfilter`
+ - will monitor
+- cwe id in u16, cve id in u32
+ (`~/git/test/rust/nvd-cve/src/lib.rs`)
+- "quick numbers vs accurate numbers"
+ - quick disease test versus blood test
+ - BLS jobs reports
+- `polycvss` article about bit packing and `cvss-calcs`
## linkdump (2022-08-10):
- css bg fade:
<file:///data/home/pabs/git/test/html/css-bg-fade/index.html>
<https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload>
- https://www.mgaudet.ca/technical/2022/8/9/faster-ruby-thoughts-from-the-outside
-- https://www.fuzzingbook.org/
- https://security.googleblog.com/2022/05/retrofitting-temporal-memory-safety-on-c.html
- allocation in go: https://medium.com/eureka-engineering/understanding-allocations-in-go-stack-heap-memory-9a2631b5035d
(src: <https://old.reddit.com/r/golang/comments/wl7qyx/when_writing_functions_when_should_i_pass_by/iju1bhs/>)
@@ -503,8 +606,9 @@
- https://research.nccgroup.com/2022/08/16/wheel-of-fortune-outcome-prediction-taking-the-luck-out-of-gambling/
- https://carlineng.com/?postid=sql-critique#blog
- https://www.openssl.org/blog/blog/2022/08/24/FIPS-validation-certificate-issued/
-- constant-time fibonacci: https://specbranch.com/posts/const-fib/
-- https://fabiandablander.com/r/Fibonacci.html
+- constant-time fibonacci:
+ <https://specbranch.com/posts/const-fib/>
+ <https://fabiandablander.com/r/Fibonacci.html>
- https://specbranch.com/posts/common-perf-numbers/
- (reminds me of "tyranny of metrics"): <https://old.reddit.com/r/programming/comments/x37u7k/be_goodargumentdriven_not_datadriven/>
- chebyshev, taylor series: <https://specbranch.com/posts/faster-div8/>
@@ -554,14 +658,12 @@
- c23:
<https://gustedt.wordpress.com/2022/12/18/checked-integer-arithmetic-in-the-prospect-of-c23/>
<https://queue.acm.org/detail.cfm?id=3588242>
-- chatgpt <https://www.jwz.org/blog/2023/02/the-bullshit-fountain/>
- bitslicing <https://timtaubert.de/blog/2018/08/bitslicing-an-introduction/>
- pqc parameter debates (kyber, turboshake, dilithium)
- <https://paulgeorgiou.org/post/2023/05/sbox-cryptanalysis/>
- <https://ratfactor.com/forth/the_programming_language_that_writes_itself.html>
- <https://www.mattb.nz/w/2023/06/02/calling-time-on-dnssec/>
- "another look at " (15 years of...): <https://www.math.uwaterloo.ca/~ajmeneze/anotherlook/>
-- <https://current.workingdirectory.net/posts/2023/enough-about-ai/>
- <https://mirrors.edge.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html>
- <https://www.sevarg.net/2023/03/25/why-people-hate-tech/>
- 4 pillars of program analysis (slide 5):
@@ -572,6 +674,7 @@
<https://www.jwz.org/blog/2024/06/your-personal-information-is-very-important-to-us/>
- <https://arstechnica.com/gadgets/2024/08/nova-launcher-savior-of-cruft-filled-android-phones-is-on-life-support/>
- software: <https://www.lawfaremedia.org/article/the-crowdstrike-outage-and-market-driven-brittleness>
+- <https://github.com/C2SP/wycheproof>
## done
- add project folders
@@ -696,3 +799,31 @@
https://arstechnica.com/security/2024/09/microsoft-adds-quantum-resistant-algorithms-to-its-core-crypto-library/?comments=1&comments-page=1
- final version of fip203 and fips204
- explanation of math for both? (not done, but covered in post above)
+- goaccess
+- tor: auto-build update hidden service (right now it's static)
+- tor: add `Onion-Location` header
+- summary of minification work w/ links to posts
+ - ref: <https://endtimes.dev/why-your-website-should-be-under-14kb-in-size/>
+ (added to site backend)
+- old projects (obe):
+ - pwasm
+ - ev-crash-course (~/git/ev-crash-course)
+ - markovian (golang markov chain generator)
+ (~/git/test/go/markovian)
+- tor: hidden service (see `tor` section above)
+ <http://pabstordmsrzhushs5drpb5mtb2ml56iyacidsjfebl2jlss65rlbsqd.onion/'>
+ (added to site backend)
+- Projects: make each entry a `<li>`
+- set up logrotate for more granular `goaccess` reports. done, see
+ k3 notes and this gist:
+ <https://gist.github.com/pablotron/57aea9422a56bf59fedb3282bcc96109>
+- vanity `pablotron*.onion` address. done. url is:
+ <http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion/>
+- firefox tab groups (new in firefox 136). done: added to "firefox
+ redux" post
+- link to openvpn article in wayback machine:
+ <https://web.archive.org/web/20070812003116/http://www.linux-mag.com/id/2502>
+ (done: updated `content/posts/2006-03-19-openvpn*.html`)
+- openvpn article wayback link
+- site backend updates (nginx config)
+- armbian on odroid n2l
diff --git a/bin/hook/deploy.rb b/bin/hook/deploy.rb
index e7fcc1f..839b454 100755
--- a/bin/hook/deploy.rb
+++ b/bin/hook/deploy.rb
@@ -26,6 +26,9 @@
# timestamp.
# * `DEPLOY_BUILD_CACHE_SIZE`: Optional, defaults to 5 if unspecified.
# Number of old site builds to keep in the builds directory.
+# * `DEPLOY_BASE_URL`: Optional, defaults to `baseURL` from
+# `config.toml` if unspecified. Used to override the base URL for
+# onion service deployment.
#
# load libraries
@@ -54,6 +57,11 @@ NUM_SECONDS = ENV.fetch('DEPLOY_SKEW_THRESHOLD', '300').to_i
# number of site builds to keep in builds directory
BUILD_CACHE_SIZE = ENV.fetch('DEPLOY_BUILD_CACHE_SIZE', '5').to_i
+# base URL: optional, defaults to baseURL from config.toml if
+# unspecified. used to override the base URL for onion service
+# deployment.
+BASE_URL = ENV.fetch('DEPLOY_BASE_URL', '')
+
# command paths (optional)
FLOCK = ENV.fetch('DEPLOY_FLOCK_PATH', '/usr/bin/flock')
GIT = ENV.fetch('DEPLOY_GIT_PATH', '/usr/bin/git')
@@ -121,9 +129,18 @@ pull_time = timed do
run(FLOCK, SRC_DIR, GIT, 'pull', '--rebase')
end
+# build hugo command
+hugo_cmd = if BASE_URL.length > 0
+ # hugo command with custom base URL
+ [HUGO, '--minify', '-b', BASE_URL, '-d', DST_DIR]
+else
+ # default hugo command
+ [HUGO, '--minify', '-d', DST_DIR]
+end
+
# build site
hugo_time = timed do
- run(HUGO, '--minify', '-d', DST_DIR)
+ run(*hugo_cmd)
end
# update htdocs symlink
diff --git a/bin/hook/etc/webhook.conf b/bin/hook/etc/webhook.conf
index 34c2929..69c5842 100644
--- a/bin/hook/etc/webhook.conf
+++ b/bin/hook/etc/webhook.conf
@@ -9,10 +9,6 @@
"pass-environment-to-command": [{
"source": "string",
- "envname": "DEPLOY_HTDOCS_PATH",
- "name": "/data/www/example.com/htdocs"
- }, {
- "source": "string",
"envname": "DEPLOY_REPO_DIR",
"name": "/data/www/example.com/git"
}, {
diff --git a/bin/hook/etc/webhook.service b/bin/hook/etc/webhook.service
index 20cd6bb..006fa35 100644
--- a/bin/hook/etc/webhook.service
+++ b/bin/hook/etc/webhook.service
@@ -4,11 +4,11 @@ After=network.target
ConditionPathExists=/etc/webhook.conf
[Service]
-# debian/ubuntu version of webhook is comically old, so i'm using the static
-# binary from the github releases page
+# use -verbose to enable debugging
# ExecStart=/usr/local/bin/webhook -port 9000 -hooks /etc/webhook.conf -urlprefix '' -verbose
ExecStart=/usr/local/bin/webhook -port 9000 -hooks /etc/webhook.conf -urlprefix ''
-RunAs=webhook
+
+User=webhook
[Install]
WantedBy=multi-user.target
diff --git a/content/articles/about.md b/content/articles/about.md
index af9053d..f682d49 100644
--- a/content/articles/about.md
+++ b/content/articles/about.md
@@ -89,8 +89,9 @@ I enjoy reading about math, programming, computer security, and science,
writing [Open Source software][oss], tinkering with electronics, [3D
printing][], and creating electronic music.
-In my spare time I run a couple of servers which provide web and email
-hosting for friends and family.
+I have been an avid Linux user since the 1990s. In my spare time
+I run a couple of servers which provide web and email hosting for
+friends and family.
## About This Site
@@ -98,30 +99,35 @@ This has been my web site since 1998. The site name is a combination of
"pablo" (my nickname) and "tron" (technical).
I typically post project updates, longer articles, and links that I find
-interesting.
+interesting. I put a considerable amount of effort into keeping this
+site fast, secure, and responsive.
+
+This site is and will always be free of advertisements and trackers.
More about this site:
- [Archived Posts][]: Older blog posts, grouped by year.
-- [Site Backend][]: Description of the technology behind this site.
+- [Site Backend][]: Explanation of the technology behind this site.
+- [Onion Service][pabstor]: Site mirror, only accessible via [Tor][].
## Links
-* [GitHub][github-me]: My [GitHub][] page.
-* [Keybase][keybase-me]: My [Keybase][] page.
-* [Mastodon][mastodon-me]: My [Mastodon][] page (currently empty).
-* [PGP Key][pgp-key]: My [PGP][] key.
+- [GitHub][github-me]: My [GitHub][] page.
+- [Keybase][keybase-me]: My [Keybase][] page.
+- [Mastodon][mastodon-me]: My [Mastodon][] page (mostly empty).
+- [PGP Key][pgp-key]: My current [PGP][] key. Fingerprint:
+ [021136521548EB198F64FF738E182534CDD1F2B8][pgp-key-keys-openpgp-org].
## Old Sites
Archives of this site and my other sites are available via the [Wayback
Machine][] at the following URLs:
-* [Pre-1999 Site (archive)][ia-efn]: My personal site before 1999. Try
+- [Pre-1999 Site (archive)][ia-efn]: My personal site before 1999. Try
not to giggle (too much).
-* [paulduncan.org (archive)][ia-pdo]: My personal site from 2003 until
- 2017.
-* [pablotron.org (archive)][ia-pto]: Technical content from 1998 until
+- [paulduncan.org (archive)][ia-pdo]: My non-technical personal site
+ from 2003 until 2017.
+- [pablotron.org (archive)][ia-pto]: Technical content from 1998 until
now.
[oss]: https://en.wikipedia.org/wiki/Open-source_software
@@ -135,7 +141,7 @@ Machine][] at the following URLs:
[ia-efn]: https://web.archive.org/web/*/http://efn.org/~p_duncan/
"My personal site before 1999."
[ia-pdo]: https://web.archive.org/web/*/https://paulduncan.org/
- "My personal site from 2003 until 2017."
+ "My non-technical personal site from 2003 until 2017."
[ia-pto]: https://web.archive.org/web/*/https://pablotron.org/
"My personal and technical site from 1998 until the present."
[php]: https://php.net/
@@ -168,3 +174,13 @@ Machine][] at the following URLs:
"Archived Posts"
[site backend]: {{< relref "articles/site-backend.md" >}}
"Site Backend"
+[pabstor]: http://pabstordmsrzhushs5drpb5mtb2ml56iyacidsjfebl2jlss65rlbsqd.onion
+ "Onion service URL for this site."
+[onion service]: https://community.torproject.org/onion-services/
+ "Service that can only be accessed via the Tor network."
+[onion address]: https://en.wikipedia.org/wiki/.onion
+ "Top-level domain for onion services."
+[tor]: https://torproject.org/
+ "The Onion Router"
+[pgp-key-keys-openpgp-org]: https://keys.openpgp.org/search?q=021136521548EB198F64FF738E182534CDD1F2B8
+ "Entry for my PGP key on keys.openpgp.org."
diff --git a/content/articles/site-backend.md b/content/articles/site-backend.md
index 5e752a2..e096e0d 100644
--- a/content/articles/site-backend.md
+++ b/content/articles/site-backend.md
@@ -111,8 +111,6 @@ Here are a few articles which cover guidelines that I follow:
- [Why your website should be under 14kB in size][14kb]
- [5 things you don't need JavaScript for][you-dont-need-js]
-
-
### Images
Images are created as follows:
@@ -134,6 +132,7 @@ Images are created as follows:
Other notes:
- The animated site logo is an [SVG][] generated by [this Ruby script][gen-logo.rb].
+- [Favicon][] is a 907 byte [PNG][] instead of a 4k [ICO][].
- Menubar icons are borrowed from [Bootstrap Icons][].
- I reviewed several [PNG][] compressors in [this post][post-png-compressors].
@@ -297,6 +296,9 @@ redirects removed:
# POST needed for /hooks
Header append "Access-Control-Allow-Methods" "POST, GET, HEAD, OPTIONS"
+ # expose onion service
+ Header set "Onion-Location" "http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion%{REQUEST_URI}s"
+
# cache images, stylesheets, and javascript for 1 year
<FilesMatch "\.(ico|jpg|jpeg|png|gif|webp|svg|js|json|css)$">
Header set Cache-Control "max-age=31536000, public"
@@ -320,7 +322,12 @@ redirects removed:
#### HTTP Compression
-[HTTP compression][] is supported via [mod\_deflate][mod-deflate].
+[HTTP compression][] is supported via [mod\_deflate][mod-deflate]. The
+list of [MIME types][] has been adjusted, like so:
+
+```apache
+AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript text/csv application/json text/json image/svg+xml
+```
It is safe for this site to enable [mod\_deflate][mod-deflate] because
it does not use [cookies][] and is not vulnerable to [BREACH][].
@@ -512,10 +519,6 @@ The generated [HTML][] has been modified to:
"pass-environment-to-command": [{
"source": "string",
- "envname": "DEPLOY_HTDOCS_PATH",
- "name": "/data/www/pablotron.org/builds/current"
- }, {
- "source": "string",
"envname": "DEPLOY_REPO_DIR",
"name": "/data/www/pablotron.org/git"
}, {
@@ -539,6 +542,85 @@ The generated [HTML][] has been modified to:
[Download][webhook.conf]
+## Onion Service
+
+This site is mirrored on the [Tor network][tor] at the following [onion
+address][.onion]:
+
+[http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion/][pablotron.onion]
+
+**Note:** The [onion address][.onion] will only work for [Tor][]-enabled
+browsers like [Tor Browser][].
+
+Configuration Notes:
+
+- Vanity [.onion][] address generated with [mkp224o][].
+- Served with [Nginx][] instead of [Apache][], because [Nginx][]
+ can listen on a [domain socket][].
+- Public site sets [Onion-Location][] response header. Allows
+ [Tor Browser][] users to easily redirect to the [onion
+ address][.onion].
+
+[Nginx][] configuration:
+
+```nginx
+server {
+ listen unix:/var/run/tor/pablotron.sock;
+ server_name pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion;
+ root /store/www/pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion/htdocs;
+ index index.html;
+ access_log /var/log/nginx/pablotron-access.log;
+
+ # enable compression, compress common types
+ gzip on;
+ gzip_types text/html text/plain text/xml text/css text/javascript application/x-javascript text/csv application/json text/json image/svg+xml;
+
+ # security headers (see comments in apache config)
+ add_header "X-Frame-Options" "SAMEORIGIN";
+ add_header "X-Content-Type-Options" "nosniff";
+ add_header "Cross-Origin-Opener-Policy" "same-origin";
+ add_header "Cross-Origin-Resource-Policy" "same-origin";
+ add_header "Access-Control-Allow-Origin" "http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion";
+ add_header "Referrer-Policy" "strict-origin-when-cross-origin";
+ add_header "Permissions-Policy" "camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), usb=()";
+
+ # different from apache; POST method not needed
+ add_header "Access-Control-Allow-Methods" "GET, HEAD, OPTIONS";
+
+ location ~ \.(ico|jpg|jpeg|png|gif|webp|svg|js|json|css)$ {
+ # cache images, stylesheets, and javascript for 1 year
+ # note: caching makes a BIG difference when browsing via tor
+ expires 1y;
+ }
+
+ location ~ \.svg$ {
+ # relax Content-Security-Policy for SVGs to allow
+ # `style-src-attr 'unsafe-inline'`
+ add_header "Content-Security-Policy" "default-src 'self'; img-src 'self'; style-src-attr 'self' 'unsafe-inline'";
+ }
+
+ location ^~ \.svg$ {
+ # default Content-Security-Policy
+ add_header "Content-Security-Policy" "default-src 'self'; img-src 'self' https://pmdn.org";
+ }
+}
+```
+
+[Download][pablotron.onion.conf]
+
+[Tor][] configuration:
+
+```ini
+HiddenServiceDir /var/lib/tor/pablotron/
+HiddenServicePort 80 unix:/var/run/tor/pablotron.sock
+```
+
+References:
+
+- [Set up Your Onion Service][onion-service-setup]
+- [Vanity .onion addresses][vanity-onion-address]
+- [Onion-Location][]
+
## Validation
I periodically use the following tools to verify this site:
@@ -548,12 +630,14 @@ I periodically use the following tools to verify this site:
- [Security Headers][securityheaders.com]: Check [HTTP][]
security headers.
- [SSL Labs SSL Test][ssl-labs-ssl-test]: Check [TLS][] configuration.
+- [htmltest][]: Check for broken links and other common [HTML][] errors.
+- [goaccess][]: Generate summary report of site statistics.
I also manually check the site in the desktop and mobile versions of
[Chrome][] and [Firefox][].
-I am investigated doing automated validation with [htmltest][],
-[htmltidy][], and the [W3C validator][], but have not added them yet.
+I am investigated doing automated validation with [htmltidy][], and the
+[W3C validator][], but have not added them yet.
## Other
@@ -597,6 +681,11 @@ published.
black box.
- 2025-01-30: Added [robots.txt][] info to [Other](#other).
- 2025-03-31: Update wording to reflect the following changes: default to dark mode and remove [`prefers-color-scheme`][prefers-color-scheme] detection.
+- 2025-04-26: Document [PNG][] [favicon][].
+- 2025-05-12: Document [htmltest][] and [goaccess][].
+- 2025-05-18: Add [Onion Service](#onion-service "Onion Service") section.
+- 2025-06-07: Add caching and security headers to [nginx][] config in
+ [Onion Service](#onion-service "Onion Service") section.
[s-hugo-configuration]: #hugo-configuration
"Hugo Configuration"
@@ -818,3 +907,35 @@ published.
"Large Language Model"
[minified]: https://en.wikipedia.org/wiki/Minification_(programming)
"Minification (Wikipedia)"
+[favicon]: https://en.wikipedia.org/wiki/Favicon
+ "favorite icon"
+[ico]: https://en.wikipedia.org/wiki/ICO_(file_format)
+ "ICO icon file format (ICO)"
+[goaccess]: https://goaccess.io/
+ "Fast, real-time web log analyzer."
+[tor]: https://torproject.org/
+ "The Onion Router"
+[onion service]: https://community.torproject.org/onion-services/
+ "Service that can only be accessed via the Tor network."
+[.onion]: https://en.wikipedia.org/wiki/.onion
+ "Top-level domain for onion services."
+[pablotron.onion]: http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion/
+ "Onion service URL for this site."
+[nginx]: https://en.wikipedia.org/wiki/Nginx
+ "NGINX web server."
+[domain socket]: https://en.wikipedia.org/wiki/Unix_domain_socket
+ "Unix domain socket."
+[tcp port]: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_ports
+ "TCP port."
+[pablotron.onion.conf]: /files/articles/site-backend/pablotron.onion.conf.txt
+ "Download Nginx configuration for onion address."
+[mkp224o]: https://github.com/cathugger/mkp224o/
+ "Vanity .onion address generator"
+[onion-service-setup]: https://community.torproject.org/onion-services/setup/
+ "Set up Your Onion Service"
+[vanity-onion-address]: https://community.torproject.org/onion-services/advanced/vanity-addresses/
+ "Vanity .onion address."
+[onion-location]: https://community.torproject.org/onion-services/advanced/onion-location/
+ "Onion-Location HTTP response header."
+[tor browser]: https://en.wikipedia.org/wiki/Tor_(network)#Tor_Browser
+ "Tor browser."
diff --git a/content/posts/2006-03-19-openvpn-article-in-linux-magazine.html b/content/posts/2006-03-19-openvpn-article-in-linux-magazine.html
index 319dd7e..18026de 100644
--- a/content/posts/2006-03-19-openvpn-article-in-linux-magazine.html
+++ b/content/posts/2006-03-19-openvpn-article-in-linux-magazine.html
@@ -5,8 +5,21 @@ title: OpenVPN Article in Linux Magazine
<p>
On the off-chance you haven't heard about it yet, I wrote an article
-on <a href='http://openvpn.net/'>OpenVPN</a> for <a href='http://www.linux-mag.com/'>Linux Magazine</a>.
+on <a href='https://openvpn.net/' title='OpenVPN'>OpenVPN</a> for <a
+ href='https://web.archive.org/http://www.linux-mag.com/'
+ title='Linux Magazine'
+>Linux Magazine</a>.
It's in the April 2006 issue, which has already been mailed to subscribers and should be available at
bookstores and on newsstands any day now.
</p>
+<p>
+<b>Update (2025-06-08):</b> Hello from 19 years later! The
+<a
+ href='https://web.archive.org/'
+ title='Wayback machine'
+>Wayback Machine</a> has an archived copy of the 2006 article: <a
+ href='https://web.archive.org/web/20070812003116/http://www.linux-mag.com/id/2502'
+ title='Casting Your Net with OpenVPN'
+>Casting Your Net with OpenVPN</a>.
+</p>
diff --git a/content/posts/2023-05-02-bookworm-and-podman.md b/content/posts/2023-05-02-bookworm-and-podman.md
index 63b842d..485f03a 100644
--- a/content/posts/2023-05-02-bookworm-and-podman.md
+++ b/content/posts/2023-05-02-bookworm-and-podman.md
@@ -9,7 +9,7 @@ a great release.
I've been looking for a suitable [Docker][] replacement for a few years
because of [their repeated license shenanigans][license-shenanigans].
-Last year I tried switching to [Podman][], but ran into into several
+Last year I tried switching to [Podman][], but ran into several
incompatibilities and minor annoyances.
[Podman 4.3][podman-4.3] ships with [Bookworm][] and seems to fix all
diff --git a/content/posts/2023-12-02-firefox-redux.md b/content/posts/2023-12-02-firefox-redux.md
index 28e51f9..75d78ef 100644
--- a/content/posts/2023-12-02-firefox-redux.md
+++ b/content/posts/2023-12-02-firefox-redux.md
@@ -21,10 +21,12 @@ Chrome to [Firefox][]. Thoughts so far...
### Firefox Cons
-- No tab groups. ~~There are several tab management extensions, but none
- are as elegant as tab groups.~~ (**Update:** [Tab Stash][] is a
- passable alternative for me).
-- Occasional [screen tearing][] on complex pages.
+- ~~No tab groups. There are several tab management extensions, but none
+ are as elegant as tab groups.~~ **Update:** Firefox 136 added tab
+ groups. I also like the [Tab Stash][] extension.
+- Occasional [screen tearing][] on complex pages. I think this is an
+ artifact of Firefox in [X11][], because it does not happen under
+ [Wayland][].
- Chrome has smoother scrolling.
I also worry about [Mozilla][] as an organization; a substantial portion
@@ -57,7 +59,10 @@ monopoly to an advertising company.
interface, supports [uBlock Origin][]. I've used it for years on my
phone and tablet.
-**Update (2023-12-04):** Added note about [Tab Stash][].
+Updates:
+- 2023-12-04: Added note about [Tab Stash][].
+- 2025-06-07: Added note about Tab Groups in Firefox 136 and clarify
+ that screen tearing only happens in [X11][].
[ublock origin]: https://en.wikipedia.org/wiki/UBlock_Origin
"Free and open source browser extension for content filtering and ad blocking."
@@ -104,5 +109,7 @@ monopoly to an advertising company.
"Portable Document Format (PDF)"
[tab stash]: https://addons.mozilla.org/en-US/firefox/addon/tab-stash/
"Tab Stash extension for Firefox"
-
-
+[x11]: https://en.wikipedia.org/wiki/X_Window_System
+ "X Window System"
+[wayland]: https://en.wikipedia.org/wiki/Wayland_(protocol)
+ "Wayland"
diff --git a/content/posts/2025-05-18-onion-service-mirror.md b/content/posts/2025-05-18-onion-service-mirror.md
new file mode 100644
index 0000000..13bfca6
--- /dev/null
+++ b/content/posts/2025-05-18-onion-service-mirror.md
@@ -0,0 +1,27 @@
+---
+slug: onion-service-mirror
+title: "Tor Site Mirror"
+date: "2025-05-18T09:44:21-04:00"
+---
+This site is now mirrored on the [Tor network][] at the following
+[onion address][]:
+
+[http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion/][pablotron.onion]
+
+See [Site Backend - Onion Service][site-backend-onion-service] for more
+details.
+
+**Update (2025-06-02):** New [vanity .onion address][].
+
+[tor network]: https://torproject.org/
+ "The Onion Router"
+[pablotron.onion]: http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion/
+ "Site mirror onion address."
+[site-backend-onion-service]: {{< relref "articles/site-backend" >}}#onion-service
+ "Site Backend, Onion Service"
+[onion address]: https://en.wikipedia.org/wiki/.onion
+ "Top-level domain for onion services."
+[mkp224o]: https://github.com/cathugger/mkp224o/
+ "Vanity .onion address generator"
+[vanity .onion address]: https://community.torproject.org/onion-services/advanced/vanity-addresses/
+ "Vanity .onion address."
diff --git a/content/posts/2025-05-18-trying-tails.md b/content/posts/2025-05-18-trying-tails.md
new file mode 100644
index 0000000..aaee7ee
--- /dev/null
+++ b/content/posts/2025-05-18-trying-tails.md
@@ -0,0 +1,49 @@
+---
+slug: trying-tails
+title: "Trying Tails"
+date: "2025-05-18T09:44:21-04:00"
+draft: true
+---
+Post about fiddling with Tails. Maybe rename to "review of tails"?
+
+tails notes
+- hidetopmenu extension does not work :/
+- screenshot
+- store passwords in keepassxc
+- installed
+ sudo apt-get install vim-{nox,scripts} qalculate-gtk gnome-shell-extension-{autohidetopbar,hide-activities,manager}
+
+- gnome boxes setup
+ - enable efi
+ - resizing img to enable persistent storage
+- tails setup
+ - enable persistent storage
+ - enable admin password (to install stuff)
+ - gnome
+ - dark mode
+ - dark desktop bg
+ - set meta-h to to full height
+ - terminal:
+ - dark theme
+ - disable bell
+ - disable scrollbar
+ - tor browser: loses these settings on restart...
+ - set ddg.onion as default search
+ - set home page and new tab to blank
+ - disable letterboxing (about:config)
+ - sites
+ - ddg.onion
+ - load ddg settings from cloud storage w/password
+ - wikipedia
+ - set dark mode
+ - set wide view
+- working .gitconfig:
+ amnesia@amnesia:~$ cat .gitconfig
+ [http]
+ proxy = socks5h://127.0.0.1:9050/
+ [https]
+ proxy = socks5h://127.0.0.1:9050/
+- save all gnome settings with `dconf dump /` > dconf.txt
+
+- several apps don't honor dark mode
+ - onion circuits
diff --git a/content/posts/2025-06-07-uninstall-facebook.md b/content/posts/2025-06-07-uninstall-facebook.md
new file mode 100644
index 0000000..904d43b
--- /dev/null
+++ b/content/posts/2025-06-07-uninstall-facebook.md
@@ -0,0 +1,132 @@
+---
+slug: uninstall-facebook
+title: "Uninstall Facebook"
+date: "2025-06-07T18:08:27-04:00"
+---
+You should immediately remove the Facebook and Instagram apps from
+your Android devices:
+
+> We disclose a novel tracking method by Meta and Yandex potentially
+> affecting billions of Android users. We found that native Android
+> apps—including Facebook, Instagram, and several Yandex apps including
+> Maps and Browser—silently listen on fixed local ports for tracking
+> purposes.
+>
+> ...
+>
+> This web-to-app ID sharing method **bypasses typical privacy
+> protections such as clearing cookies, Incognito Mode and Android's
+> permission controls. Worse, it opens the door for potentially
+> malicious apps eavesdropping on users’ web activity.** (emphasis mine)
+
+[Source][local mess]
+
+[Ars Technica][] also has [an excellent summary][].
+
+In English: If you have the Facebook app or Instagram app installed on
+your Android device, then Meta may have secretly collected your identity
+and your browsing history.
+
+This is true even if you don't have a Facebook account. It's true even
+if you don't use the Facebook app. It's true even if you took steps to
+hide your browsing history like clearing cookies or using a private
+browser window.
+
+On June 3rd, Meta claimed that the code responsible had "been almost
+complete removed"; this is [weasel wording][] which actually means "the
+code has not been removed".
+
+Even if Meta actually did remove the code from their apps, there are
+still several problems:
+
+1. Meta has an [atrocious privacy record][]. It would be foolish to
+ take Meta at their word and they have a strong incentive to try
+ this again or something similar in the future.
+2. Removing code does not address the information Meta has already
+ collected. This information could be leaked in a data breach or
+ subpoenaed by law enforcement.
+3. Malicious or [trojaned][] apps could listen on the same local ports
+ and collect the same information. The [Local Mess][] researchers
+ demonstrated this with a proof-of-concept app.
+
+Additional privacy recommendations:
+
+1. Prefer web sites over apps. Many services use [deceptive patterns][]
+ to trick you into using an app instead of a web site. They do this
+ because an app can collect more information about you than a web site.
+2. Remove unused and rarely used apps.
+3. Stop using Google Search. I recommend [DuckDuckGo][].
+4. [Stop using Google Chrome][ditch-chrome]. I recommend [Firefox][]
+ with [uBlock Origin][] and some [configuration
+ changes][firefox-privacy]. Some folks swear by [DuckDuckGo Browser][],
+ but I haven't used it myself. See also: [The case for ditching
+ Chrome][vox-chrome]. If you really do need Chrome or Edge, then at
+ least install [uBlock Origin Lite][].
+5. Switch from Microsoft Windows to [Linux][]. I recommend [Ubuntu][]
+ for new users. I use [Debian][debian]. If you really do need
+ Windows, then at least [disable Windows telemetry][].
+6. Switch from text messaging and WhatsApp (owned by Meta) to [Signal][].
+7. Set up [Pi-hole][] on your home network. It has an easy-to-use web
+ interface and can help block ads and tracking on mobile devices and
+ "smart" TVs.
+8. Consider [Tor Browser][] or [Tails][] if the you need more protection
+ and are willing to accept some tradeoffs.
+
+Further reading: [Surveilance Self Defense][ssd]
+
+[local mess]: https://localmess.github.io/
+ "Local Mess: Tracking method used by Facebook, Instagram, and Yandex Android apps which bypasses privacy protection."
+[atrocious privacy record]: https://en.wikipedia.org/wiki/Privacy_concerns_with_Facebook
+ "Privacy concerns with Facebook (Wikipedia)"
+[ars technica]: https://arstechnica.com/security/2025/06/meta-and-yandex-are-de-anonymizing-android-users-web-browsing-identifiers/
+ "Ars Technica"
+[an excellent summary]: https://arstechnica.com/security/2025/06/meta-and-yandex-are-de-anonymizing-android-users-web-browsing-identifiers/
+ "Ars Technica: Meta and Yandex are de-anonymizing Android users’ web browsing identifiers"
+[weasel wording]: https://en.wikipedia.org/wiki/Weasel_word
+ "Weasel word: Word or phrase aimed at creating an impression that something specific and meaningful has been said, when in fact only a vague, ambiguous, or irrelevant claim has been communicated (Wikipedia)"
+[fingerprint]: https://www.amiunique.org/fingerprint
+ "fingerprint"
+[trojaned]: https://en.wikipedia.org/wiki/Trojan_horse_(computing)
+ "Trojan horse (Wikipedia)"
+[firefox]: https://www.mozilla.org/en-US/firefox/new/
+ "Mozilla Firefox web browser"
+[ublock origin]: https://en.wikipedia.org/wiki/UBlock_Origin
+ "uBlock Origin ad-blocker"
+[ditch-chrome]: {{< relref "posts/2023-12-02-firefox-redux.md" >}}#why-ditch-chrome
+ "Why Ditch Chrome?"
+[brave]: https://en.wikipedia.org/wiki/Brave_(web_browser)
+ "Brave web browser"
+[duckduckgo browser]: https://duckduckgo.com/app/
+ "DuckDuckGo web browser"
+[firefox-privacy]: https://cyberinsider.com/firefox-privacy/
+ "Firefox Privacy Checklist"
+[duckduckgo]: https://duckduckgo.com/
+ "DuckDuckGo search engine"
+[tor browser]: https://www.torproject.org/download/
+ "Tor Browser"
+[tor network]: https://www.torproject.org/
+ "Tor network"
+[linux]: https://en.wikipedia.org/wiki/Linux
+ "Linux operating system"
+[debian]: https://debian.org/
+ "Debian Linux"
+[ubuntu]: https://ubuntu.com/
+ "Ubuntu Linux"
+[disable windows telemetry]: https://windowsreport.com/disable-windows-11-telemetry/
+ "Disable Windows 11 telemetry"
+[pi-hole]: https://en.wikipedia.org/wiki/Pi-hole
+ "Pi-hole"
+[raspberry pi]: https://en.wikipedia.org/wiki/Raspberry_Pi
+ "Small single-board computer."
+[signal]: https://signal.org/
+ "Signal secure messenger"
+[ssd]: https://ssd.eff.org/
+ "Surveilance Self Defense"
+[tails]: https://tails.net/
+ "Tails: portable operating system that protects against surveillance and censorship"
+[vox-chrome]: https://www.vox.com/technology/387375/google-chrome-antitrust-privacy-android
+ "The case for ditching Chrome (vox.com)"
+[ublock origin lite]: https://en.wikipedia.org/wiki/UBlock_Origin#uBlock_Origin_Lite
+ "Manifest V3 version of uBlock Origin for Google Chrome, Microsoft Edge, and other Chromium-based browsers."
+[deceptive patterns]: https://www.deceptive.design/types
+ "Types of deceptive patterns"
diff --git a/content/posts/2025-06-08-armbian-on-odroid-n2l.md b/content/posts/2025-06-08-armbian-on-odroid-n2l.md
new file mode 100644
index 0000000..3443adf
--- /dev/null
+++ b/content/posts/2025-06-08-armbian-on-odroid-n2l.md
@@ -0,0 +1,145 @@
+---
+slug: armbian-on-odroid-n2l
+title: "Armbian on Odroid N2L"
+date: "2025-06-08T15:31:00-04:00"
+
+pics:
+ n2l:
+ css: "image"
+ tip: "Odroid N2L running Armbian."
+ sources:
+ - "/files/posts/armbian-on-odroid-n2l/n2l-1024.webp"
+ - src: "/files/posts/armbian-on-odroid-n2l/n2l-1024.png"
+ width: 1024
+ height: 771
+---
+
+Last week I installed [Armbian][] on an [Odroid N2L][]. The
+installation steps, installation results, and fixes for some problems
+are documented below.
+
+### Installation
+
+1. Download and import the [signing key][armbian-key] (fingerprint
+ `DF00FAF1C577104B50BF1D0093D6889F9F0E78D5`): \
+ `wget -O- https://apt.armbian.com/armbian.key | gpg -- import -`
+2. Download the current "Debian 12 (Bookworm)" image and the [detached
+ signature][asc] from the "Minimal/IOT images" section of the [Armbian
+ Odroid N2L page][armbian-n2l].
+3. Verify the [signature][asc]: \
+ `gpg --verify Armbian_community_25.8.0-trunk.8_Odroidn2l_bookworm_current_6.12.28_minimal.img.xz{.asc,}`
+4. Uncompress the image: \
+ `unxz Armbian_community_25.8.0-trunk.8_Odroidn2l_bookworm_current_6.12.28_minimal.img.xz`
+5. Flash the uncompressed image to a [microSD][] card: \
+ `sudo dd if=Armbian_community_25.8.0-trunk.8_Odroidn2l_bookworm_current_6.12.28_minimal.img of=/dev/sda bs=1M status=progress`
+6. Mount the second partition of the [microSD][] card on `/mnt/tmp`: \
+ `sudo mount /dev/sda2 /mnt/tmp`
+7. Use the instructions and template from [Automatic first boot
+ configuration][armbian-autoconfig] to populate
+ `/mnt/tmp/root/.not_logged_in_yet`. My populated autoconfig is
+ [here][populated-autoconfig], but **it did not work as expected**;
+ see below.
+8. Unmount the second partition of the [microSD][] card.
+9. Insert the [microSD][] card into the [Odroid N2L][] and power it on.
+
+### Installation Results
+
+Worked as expected:
+
+- Successfully booted.
+- Successfully connected to [WiFi][] on first boot.
+
+Did not work as expected:
+
+- Did not connect to WiFI on subsequent boots.
+- Did not set the root password. Instead the root password was `1234`.
+- Did not set the user password.
+- Did not set the user SSH key.
+
+### Fixes
+
+To correct these problems I connected a keyboard and monitor and did the
+following:
+
+1. Logged in as `root` with the password `1234`.
+2. Changed the root password and the user password.
+4. Edited `/etc/netplan/20-eth-fixed-mac.yaml` and fixed the
+ errors. The corrected version is below.
+5. Ran `netplan apply` to apply the corrected network configuration.
+6. Rebooted to confirm that networking was working as expected.
+
+Here is the corrected `/etc/netplan/20-eth-fixed-mac.yaml`:
+
+```yaml
+network:
+ version: 2
+```
+&nbsp;
+
+After fixing networking, I did the following:
+
+1. Copied my SSH key.
+2. Edited `/etc/ssh/sshd_config` to disable root logins and password
+ logins.
+3. Ran `apt-get update && apt-get upgrade`.
+4. Installed `unattended-upgrades`.
+5. Rebooted to pick up the latest updates.
+
+<!--
+
+### Conclusion
+
+Many non-[Pi][] [SBCs][sbc] manufacturers stop providing software
+shortly after the hardware is released. Owners are stuck with
+unsupported hardware running out-of-date software.
+
+Case in point: The latest download on the [Odroid N2L wiki][] is Ubuntu
+22.04.
+
+I'm thrilled that [Armbian][]
+
+original unused blather ...
+
+[Armbian][] now supports the [Odroid N2L][] as a [community maintained
+target][armbian-n2l].
+
+Context: A couple of years ago Nadine bought me a pair of [Odroid
+N2Ls][odroid n2l]. [Pi 4s][pi] were scarce because of supply chain
+issues, and the [Odroid N2L][] seemed like a decent substitute.
+
+The problem with non-[Pi][] [SBCs][sbc] is that the manufacturers
+invariably stop providing software updates shortly after release, so you
+are stuck with unsupported hardware running an out of date OS.
+
+As of this writing, the [Odroid N2L wiki][] still has the same software
+that it did when first got the hardware: Ubuntu 22.04.
+-->
+
+[{{< pe-figure "n2l" >}}][n2l-pic]
+
+[armbian]: https://www.armbian.com/
+ "Linux for ARM development boards"
+[odroid n2l]: https://www.hardkernel.com/shop/odroid-n2l-with-4gbyte-ram/
+ "Odroid N2L ARM A73 SBC"
+[pi]: https://en.wikipedia.org/wiki/Raspberry_Pi
+ "Raspberry Pi"
+[sbc]: https://en.wikipedia.org/wiki/Single-board_computer
+ "single-board computer (SBC)"
+[armbian-n2l]: https://www.armbian.com/odroid-n2l/
+ "Armbian for the Odroid N2L"
+[odroid n2l wiki]: https://wiki.odroid.com/getting_started/os_installation_guide#tab__odroid-n2l
+ "Odroid Wiki: Odroid N2L"
+[n2l-pic]: /files/posts/armbian-on-odroid-n2l/n2l.jpg
+ "Odroid N2L running Armbian"
+[armbian-autoconfig]: https://docs.armbian.com/User-Guide_Autoconfig/
+ "Armbian Documentation: Automatic first boot configuration"
+[asc]: https://en.wikipedia.org/wiki/Pretty_Good_Privacy#Digital_signatures
+ "Detached PGP signature"
+[armbian-key]: https://apt.armbian.com/armbian.key
+ "Armbian PGP signing key"
+[populated-autoconfig]: /files/posts/armbian-on-odroid-n2l/odroid-n2l-root_not_logged_in_yet.txt
+ "Populated automatic first boot configuration file"
+[microsd]: https://en.wikipedia.org/wiki/SD_card#microSD
+ "microSD memory card"
+[wifi]: https://en.wikipedia.org/wiki/Wi-Fi
+ "Wireless networking"
diff --git a/content/posts/2025-06-08-nginx-caching-and-security-headers.md b/content/posts/2025-06-08-nginx-caching-and-security-headers.md
new file mode 100644
index 0000000..54cd4a0
--- /dev/null
+++ b/content/posts/2025-06-08-nginx-caching-and-security-headers.md
@@ -0,0 +1,27 @@
+---
+slug: nginx-caching-and-security-headers
+title: "Nginx Caching and Security Headers"
+date: "2025-06-08T13:16:00-04:00"
+---
+
+Yesterday I ported the [caching and security headers][apache-config]
+from the [Apache][] configuration for the public site to the [Nginx][]
+configuration for the [Tor mirror][].
+
+The caching headers are particularly helpful for the [Tor mirror][].
+
+The updated [Nginx][] configuration and additional documentation are
+here: [Site Backend - Onion Service][onion-service].
+
+[apache-config]: {{< relref "articles/site-backend" >}}#apache-configuration
+ "Site Backend - Apache Configuration"
+[apache]: https://apache.org/
+ "Apache web server"
+[nginx]: https://nginx.org/
+ "Nginx web server"
+[onion-service]: {{< relref "articles/site-backend" >}}#onion-service
+ "Site Backend - Onion Service"
+[tor mirror]: {{< relref "posts/2025-05-18-onion-service-mirror" >}}
+ "Tor Site Mirror"
+[tor network]: https://torproject.org/
+ "Tor project"
diff --git a/content/posts/2025-06-08-old-openvpn-article.md b/content/posts/2025-06-08-old-openvpn-article.md
new file mode 100644
index 0000000..67f2ccf
--- /dev/null
+++ b/content/posts/2025-06-08-old-openvpn-article.md
@@ -0,0 +1,36 @@
+---
+slug: old-openvpn-article
+title: "Old OpenVPN Article"
+date: "2025-06-08T11:52:22-04:00"
+---
+
+In 2006 [I wrote an article about OpenVPN][article-post] for the
+now-defunct [Linux Magazine][]. This week I found a copy of the 2006
+article on the [Wayback Machine][]:
+
+[Casting Your Net with OpenVPN (Wayback Machine)][article]
+
+In 2025 you should prefer [Wireguard][] over [OpenVPN][] because
+[Wireguard][] is [faster, more secure, and easier to use][wg-reasons].
+
+Fun factoid: The [AWS Client VPN][] is just an [AWS][]-branded build of
+the [OpenVPN][] client.
+
+[article-post]: {{< relref "posts/2006-03-19-openvpn-article-in-linux-magazine" >}}
+ "OpenVPN Article in Linux Magazine"
+[linux magazine]: https://web.archive.org/http://www.linux-mag.com/
+ "Linux Magazine"
+[wayback machine]: https://web.archive.org/
+ "Wayback Machine"
+[article]: https://web.archive.org/web/20070812003116/http://www.linux-mag.com/id/2502'
+ "Casting Your Net with OpenVPN (Wayback Machine)"
+[aws]: https://aws.amazon.com/
+ "Amazon Web Services (AWS)"
+[aws client vpn]: https://aws.amazon.com/vpn/client-vpn-download/
+ "AWS Client VPN"
+[openvpn]: https://openvpn.net/
+ "OpenVPN"
+[wg-reasons]: {{< relref "posts/2021-11-06-wireguard-is-awesome" >}}
+ "Wireguard is Awesome"
+[wireguard]: https://wireguard.com/
+ "Wireguard"
diff --git a/content/posts/2025-10-04-polycvss-v0.2.0.md b/content/posts/2025-10-04-polycvss-v0.2.0.md
new file mode 100644
index 0000000..49d20f7
--- /dev/null
+++ b/content/posts/2025-10-04-polycvss-v0.2.0.md
@@ -0,0 +1,143 @@
+---
+slug: polycvss-v0.2.0
+title: "polycvss v0.2.0"
+date: "2025-10-04T03:15:48-04:00"
+---
+I just released [polycvss][] version 0.2.0.
+
+[polycvss][] is a [Rust][] library to parse and score [CVSS][] vector
+strings.
+
+Features:
+
+- [CVSS v2][doc-v2], [CVSS v3][doc-v3], and [CVSS v4][doc-v4] support.
+- Version-agnostic parsing and scoring [API][].
+- Memory efficient: Vectors are 8 bytes. Scores and severities are 1 byte.
+- No dependencies by default except the standard library.
+- Optional [serde][] integration via the `serde` build feature.
+- Extensive tests: Tested against thousands of vectors and scores from
+ the [NVD][] [CVSS][] calculators.
+
+Here is an example tool which parses the first command-line argument as
+a [CVSS][] vector string, then prints the score and severity:
+
+```rust
+use polycvss::{Err, Score, Severity, Vector};
+
+fn main() -> Result<(), Err> {
+ let args: Vec<String> = std::env::args().collect(); // get cli args
+
+ if args.len() == 2 {
+ let vec: Vector = args[1].parse()?; // parse string
+ let score = Score::from(vec); // get score
+ let severity = Severity::from(score); // get severity
+ println!("{score} {severity}"); // print score and severity
+ } else {
+ let name = args.first().map_or("app", |s| s); // get app name
+ eprintln!("Usage: {name} [VECTOR]"); // print usage
+ }
+
+ Ok(())
+}
+```
+&nbsp;
+
+Here is the example tool output for a [CVSS v2][doc-v2] vector string, a
+[CVSS v3][doc-v3] vector string, and a [CVSS v4][doc-v4] vector string:
+
+```sh
+# test with cvss v2 vector string
+$ cvss-score "AV:A/AC:H/Au:N/C:C/I:C/A:C"
+6.8 MEDIUM
+
+# test with cvss v3 vector string
+$ cvss-score "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
+9.8 CRITICAL
+
+# test with cvss v4 vector string
+$ cvss-score "CVSS:4.0/AV:L/AC:H/AT:N/PR:N/UI:P/VC:L/VI:L/VA:L/SC:H/SI:H/SA:H"
+5.2 MEDIUM
+```
+&nbsp;
+
+This example tool is included in the [Git repository][] as
+[`src/bin/cvss-score.rs`][cvss-score].
+
+### Links
+
+- [polycvss Git repository][polycvss]
+- [polycvss package on crates.io][crates-io-polycvss]
+- [polycvss API Documentation on docs.rs][docs-rs-polycvss]
+
+**Updates**
+
+- 2025-10-12: [polycvss v0.2.1][]: Add [`polycvss::v4::Nomenclature`][v4-nomenclature] and improve documentation.
+- 2025-10-18: [polycvss v0.3.0][]: Add user-friendly `Error` messages, remove unreleased CVSS v2.x `Version` variants, and improve documentation.
+- 2025-10-19: [polycvss v0.3.1][]: Documentation improvements.
+- 2025-11-16: [polycvss v0.3.2][]: Add `impl From<Vector> for Severity`
+ and `examples/` directory.
+
+[html]: https://en.wikipedia.org/wiki/HTML
+ "HyperText Markup Language"
+[rust]: https://rust-lang.org/
+ "Rust programming language."
+[cvss]: https://www.first.org/cvss/
+ "Common Vulnerability Scoring System (CVSS)"
+[doc-v2]: https://www.first.org/cvss/v2/guide
+ "CVSS v2.0 Documentation"
+[doc-v3]: https://www.first.org/cvss/v3-1/specification-document
+ "CVSS v3.1 Specification"
+[doc-v4]: https://www.first.org/cvss/v4-0/specification-document
+ "Common Vulnerability Scoring System (CVSS) version 4.0 Specification"
+[bit-field]: https://en.wikipedia.org/wiki/Bit_field
+ "Bit field (Wikipedia)"
+[cvss-score]: https://github.com/pablotron/polycvss/blob/main/src/bin/cvss-score.rs
+ "Example command-line tool which parses a CVSS vector and prints the score and severity to standard output."
+[git repository]: https://github.com/pablotron/polycvss
+ "polycvss git repository"
+[polycvss]: https://github.com/pablotron/polycvss
+ "polycvss Rust library"
+[v2-calc]: https://nvd.nist.gov/vuln-metrics/cvss/v2-calculator
+ "NVD CVSS v2 calculator"
+[v3-calc]: https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator
+ "NVD CVSS v3 calculator"
+[v4-calc]: https://nvd.nist.gov/site-scripts/cvss-v4-calculator-main/
+ "NVD CVSS v4 calculator"
+[cargo]: https://doc.rust-lang.org/cargo/
+ "Rust package manager"
+[podman]: https://podman.io/
+ "Podman container management tool"
+[docker]: https://docker.com/
+ "Docker container management tool"
+[api]: https://en.wikipedia.org/wiki/API
+ "Application Programming Interface (API)"
+[linter]: https://en.wikipedia.org/wiki/Lint_(software)
+ "Static code analysis tool to catch common mistakes"
+[src-v2-rs]: src/v2.rs
+ "CVSS v2 parsing and scoring"
+[src-v3-rs]: src/v3.rs
+ "CVSS v3 parsing and scoring"
+[src-v4-rs]: src/v4.rs
+ "CVSS v4 parsing and scoring"
+[nvd]: https://nvd.nist.gov/
+ "National Vulnerability Database (NVD)"
+[cvss-calcs]: https://github.com/pablotron/cvss-calcs
+ "Generate random CVSS vector strings and score them."
+[crates.io]: https://crates.io/
+ "Rust package registry"
+[docs-rs-polycvss]: https://docs.rs/polycvss
+ "polycvss API documentation on docs.rs"
+[crates-io-polycvss]: https://crates.io/crates/polycvss
+ "polycvss on crates.io"
+[serde]: https://serde.rs/
+ "Rust serializing and deserializing framework."
+[polycvss v0.2.1]: https://github.com/pablotron/polycvss/releases/tag/0.2.1
+ "polycvss version 0.2.1"
+[polycvss v0.3.0]: https://github.com/pablotron/polycvss/releases/tag/0.3.0
+ "polycvss version 0.3.0"
+[polycvss v0.3.1]: https://github.com/pablotron/polycvss/releases/tag/0.3.1
+ "polycvss version 0.3.1"
+[polycvss v0.3.2]: https://github.com/pablotron/polycvss/releases/tag/0.3.2
+ "polycvss version 0.3.2"
+[v4-nomenclature]: https://docs.rs/polycvss/latest/polycvss/v4/enum.Nomenclature.html
+ "polycvss::v4::Nomenclature documentation."
diff --git a/content/projects/polycvss.md b/content/projects/polycvss.md
new file mode 100644
index 0000000..eddea7a
--- /dev/null
+++ b/content/projects/polycvss.md
@@ -0,0 +1,10 @@
+---
+title: "polycvss"
+slug: "polycvss"
+active: true
+repo: "https://github.com/pablotron/polycvss"
+text: "Self-contained C11 SHA-3 implementation."
+text: "Rust library for CVSS vector string parsing and score calculation."
+text: "Rust library to parse and score CVSS vector strings."
+---
+Rust library to parse and score CVSS vector strings.
diff --git a/data/projects.yaml b/data/projects.yaml
index 60e8a48..f800edd 100644
--- a/data/projects.yaml
+++ b/data/projects.yaml
@@ -16,6 +16,11 @@
repo: "https://github.com/pablotron/luigi-template"
text: "String templating library for Java, JavaScript, PHP, and Ruby."
+- name: "polycvss"
+ slug: "polycvss"
+ repo: "https://github.com/pablotron/polycvss"
+ text: "Rust library to parse and score CVSS vector strings."
+
- name: "SHA2"
slug: "sha2"
repo: "https://github.com/pablotron/sha2"
diff --git a/static/favicon.png b/static/favicon.png
new file mode 100644
index 0000000..db8a432
--- /dev/null
+++ b/static/favicon.png
Binary files differ
diff --git a/static/files/articles/site-backend/pablotron.onion.conf.txt b/static/files/articles/site-backend/pablotron.onion.conf.txt
new file mode 100644
index 0000000..9c80ede
--- /dev/null
+++ b/static/files/articles/site-backend/pablotron.onion.conf.txt
@@ -0,0 +1,40 @@
+server {
+ listen unix:/var/run/tor/pablotron.sock;
+ server_name pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion;
+ root /store/www/pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion/htdocs;
+ index index.html;
+ access_log /var/log/nginx/pablotron-access.log;
+
+ # enable compression, compress common types
+ gzip on;
+ gzip_types text/html text/plain text/xml text/css text/javascript application/x-javascript text/csv application/json text/json image/svg+xml;
+
+ # security headers (see comments in apache config)
+ add_header "X-Frame-Options" "SAMEORIGIN";
+ add_header "X-Content-Type-Options" "nosniff";
+ add_header "Cross-Origin-Opener-Policy" "same-origin";
+ add_header "Cross-Origin-Resource-Policy" "same-origin";
+ add_header "Access-Control-Allow-Origin" "http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion";
+ add_header "Referrer-Policy" "strict-origin-when-cross-origin";
+ add_header "Permissions-Policy" "camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), usb=()";
+
+ # different from apache; POST method not needed
+ add_header "Access-Control-Allow-Methods" "GET, HEAD, OPTIONS";
+
+ location ~ \.(ico|jpg|jpeg|png|gif|webp|svg|js|json|css)$ {
+ # cache images, stylesheets, and javascript for 1 year
+ # note: caching makes a BIG difference when browsing via tor
+ expires 1y;
+ }
+
+ location ~ \.svg$ {
+ # relax Content-Security-Policy for SVGs to allow
+ # `style-src-attr 'unsafe-inline'`
+ add_header "Content-Security-Policy" "default-src 'self'; img-src 'self'; style-src-attr 'self' 'unsafe-inline'";
+ }
+
+ location ^~ \.svg$ {
+ # default Content-Security-Policy
+ add_header "Content-Security-Policy" "default-src 'self'; img-src 'self' https://pmdn.org";
+ }
+}
diff --git a/static/files/articles/site-backend/pablotron.org.conf.txt b/static/files/articles/site-backend/pablotron.org.conf.txt
index 97a60d2..59ef28c 100644
--- a/static/files/articles/site-backend/pablotron.org.conf.txt
+++ b/static/files/articles/site-backend/pablotron.org.conf.txt
@@ -30,6 +30,9 @@
# POST needed for /hooks
Header append "Access-Control-Allow-Methods" "POST, GET, HEAD, OPTIONS"
+ # expose tor onion service (2025-05-18)
+ Header set "Onion-Location" "http://pablotronfils76sk6pwvyoosvfjbhxe3sn4c654e4na4szidbnbqdyd.onion%{REQUEST_URI}s"
+
# cache images, stylesheets, and javascript for 1 year
<FilesMatch "\.(ico|jpg|jpeg|png|gif|webp|svg|js|json|css)$">
Header set Cache-Control "max-age=31536000, public"
diff --git a/static/files/articles/site-backend/script.js.txt b/static/files/articles/site-backend/script.js.txt
index ae47804..1ab4045 100644
--- a/static/files/articles/site-backend/script.js.txt
+++ b/static/files/articles/site-backend/script.js.txt
@@ -1,26 +1,23 @@
'use strict';
//
-// script.js - script which handles:
+// script.js: minimal JS for pablotron.org
//
-// - check/set dark mode (added 2024-05-27)
-// - enable burger menu support
+// - set theme on page load
+// - bind theme switcher and burger menu event handlers
//
-// original notes regarding burger menu and minification are in the
-// "burger menu" section below
+// current sizes (2025-04-01):
+// - minified: 699 bytes
+// - minified/compressed: 508 bytes
//
-// burger menu (2024-05-27)
-// ------------------------
+// notes below are slightly out of date...
+//
+// theme switcher (2024-05-27)
+// ---------------------------
// does the following:
//
// 1. checks for user setting and use that, if present.
-// 2. otherwise check browser for preferred color scheme and use that.
-//
-// this works in conjunction with the styles in `assets/dark.sass` and
-// has one minor quirk: there is a brief flash when the user transitions
-// to a new page and has dark mode enabled. this can be removed by
-// uncommenting the block at the top of `dark.sass`, but doing this
-// currently breaks the light color scheme :/.
+// 2. otherwise default to dark mode.
//
// refs:
// https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
@@ -56,26 +53,16 @@ const D = document,
M = window.matchMedia,
on = (el, id, fn) => el.addEventListener(id, fn);
-// use theme if set, otherwise fall back to dark mode
-// FIXME: move to DOMContentLoaded?
-//
-// update (2025-03-31): prefer dark mode by default and only set light
-// mode if the user has explicitly selected the light theme using the
-// theme toggle.
-//
-// the old logic also attempted to account for "prefers-color-scheme:
-// light", but i want the default to be dark unless it is explicitly
-// overridden.
-C.add('dark'); // unconditionally set dark mode
+// light theme selected by user?
if (L && L.theme && L.theme === 'light') {
C.remove('dark'); // set light theme
}
-document.addEventListener('DOMContentLoaded', () => {
+D.addEventListener('DOMContentLoaded', () => {
// theme toggle event handler
- on(D.querySelector('.navbar-item[data-id="theme"]'), 'click', (e) => {
+ on(D.querySelector('.navbar-item[data-id="theme"]'), 'click', e => {
e.preventDefault(); // stop event
- L.theme = C.toggle('dark') ? 'dark' : 'light'; // toggle
+ L.theme = C.toggle('dark') ? 'dark' : 'light'; // toggle theme
});
// iterate through burgers, bind to click events
diff --git a/static/files/articles/site-backend/webhook.conf.txt b/static/files/articles/site-backend/webhook.conf.txt
index 254155d..1243946 100644
--- a/static/files/articles/site-backend/webhook.conf.txt
+++ b/static/files/articles/site-backend/webhook.conf.txt
@@ -9,10 +9,6 @@
"pass-environment-to-command": [{
"source": "string",
- "envname": "DEPLOY_HTDOCS_PATH",
- "name": "/data/www/pablotron.org/builds/current"
- }, {
- "source": "string",
"envname": "DEPLOY_REPO_DIR",
"name": "/data/www/pablotron.org/git"
}, {
diff --git a/static/files/pabs.asc b/static/files/pabs.asc
index 9bda0d2..555912f 100644
--- a/static/files/pabs.asc
+++ b/static/files/pabs.asc
@@ -2,27 +2,27 @@
mDMEZPpC4BYJKwYBBAHaRw8BAQdAozyRcx2w+Eb6m6VBVEp3EnfdOsH1SGgY7Bf0
7F7zP2C0H1BhdWwgRHVuY2FuIDxncGdAcGFibG90cm9uLm9yZz6ImQQTFggAQQIb
-AQUJA+MNIAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYhBAIRNlIVSOsZj2T/c44Y
-JTTN0fK4BQJk+kTGAhkBAAoJEI4YJTTN0fK4bnMA/RAZ5S31GTIrZUA3JmZvCvwq
-k3rtWxL6BDhco8yQOdQuAQCM6qSHN4rXr+6ztIe3EvkpWU8lXh1Uc3Krki5kTzQA
-ArQrUGF1bCBEdW5jYW4gKGdpdGh1YikgPGdpdGh1YkBwYWJsb3Ryb24ub3JnPoiW
-BBMWCAA+FiEEAhE2UhVI6xmPZP9zjhglNM3R8rgFAmT6RJ4CGwEFCQPjDSAFCwkI
-BwIGFQoJCAsCBBYCAwECHgECF4AACgkQjhglNM3R8rjyvwD+PbyFukeFU6SMTGa0
-5ciR5WbhXhRHm19f0i+i8dfjRGQA/ifcNa6L+jefQUY5r2eIcjo+5AyANKeQQX1E
-atOoS14HtCtQYXVsIER1bmNhbiAocGVyc29uYWwpIDxwYWJzQHBhYmxvdHJvbi5v
-cmc+iJYEExYIAD4WIQQCETZSFUjrGY9k/3OOGCU0zdHyuAUCZPpEvAIbAQUJA+MN
-IAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCOGCU0zdHyuPdVAQCktsGno4Rs
-2F+mpkBL/XAZygGcXTex87GBk+9UHTIFoAD/W2IxS3sXhG84+dVuXawEjbVAsZnY
-JXgo/Yp89t3FcQO4MwRk+kMGFgkrBgEEAdpHDwEBB0CXyafK+3r6c+foOGSypcN3
-DDpRJ4E08hZrLlMDo66tmYj1BBgWCAAmFiEEAhE2UhVI6xmPZP9zjhglNM3R8rgF
-AmT6QwYCGwIFCQPjDPoAgQkQjhglNM3R8rh2IAQZFggAHRYhBMxaPAkB8qSbHzks
-9w9m3LNb0xXvBQJk+kMGAAoJEA9m3LNb0xXvnlsA/2XAWLXyMSTTGBVLN3V96gpT
-L/jm2fincNSBkk5heOT3AP0SM6I8I7yBN8a9HyRW7of7dISp1DPRej7zjba+w2DW
-D02/AQDOFVyNA8nFU8VIply2q0f5cWremdEyKZsMQOoV7h8YrwEAkZPruamwJOhb
-dERvNLzLRfTy4Ur21AZQCbNDO1PiEgi4OARk+kMWEgorBgEEAZdVAQUBAQdAnLxb
-gFTx1NB4SrLsKOV/3zZkwGiPHhwNy1rf8czSlCUDAQgHiH4EGBYIACYWIQQCETZS
-FUjrGY9k/3OOGCU0zdHyuAUCZPpDFgIbDAUJA+MM6gAKCRCOGCU0zdHyuH71AQCL
-EetpJgsLGwm0qqwPMIwk38h/VfsG5B4cSOiP5KFfKQD+Ko6KWtGkgwS2k8IgqEng
-GdWY8q5PwXp8FHsdOC7QuQI=
-=84QG
+AQULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAIZARYhBAIRNlIVSOsZj2T/c44YJTTN
+0fK4BQJozgCMBQkHliSsAAoJEI4YJTTN0fK4fNkBAN0ytDOHZbjWJIuGRp/VvtAn
+EIz5ngsqEr60uMvv5t7eAQC0AgQ2o2J/AHwou7V0fz2uISH9QSHMGw/Y5Hjn6RX+
+BbQrUGF1bCBEdW5jYW4gKGdpdGh1YikgPGdpdGh1YkBwYWJsb3Ryb24ub3JnPoiW
+BBMWCAA+AhsBBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEAhE2UhVI6xmPZP9z
+jhglNM3R8rgFAmjOAIwFCQeWJKwACgkQjhglNM3R8rilewEA19Lc/7iWIkmIWSTI
+veXUZD0dCNzOg0nhhl7GEMoK/foA/24+KVQUWU2AJka4RNb4glVqo1b6UNq2IOZr
+rLmZv5sLtCtQYXVsIER1bmNhbiAocGVyc29uYWwpIDxwYWJzQHBhYmxvdHJvbi5v
+cmc+iJYEExYIAD4CGwEFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQQCETZSFUjr
+GY9k/3OOGCU0zdHyuAUCaM4AjAUJB5YkrAAKCRCOGCU0zdHyuLUSAQDSQS2OQa/E
+VdAyRd1LR8jR7WPaHAyXbPanOC8x+3AksQEAx3gwp0ZBxAhj7lwlzuqAdxWy1Eiu
++9O1gAcEyDzULgS4MwRk+kMGFgkrBgEEAdpHDwEBB0CXyafK+3r6c+foOGSypcN3
+DDpRJ4E08hZrLlMDo66tmYj1BBgWCAAmAhsCFiEEAhE2UhVI6xmPZP9zjhglNM3R
+8rgFAmjOATAFCQeWJSoAgXYgBBkWCAAdFiEEzFo8CQHypJsfOSz3D2bcs1vTFe8F
+AmT6QwYACgkQD2bcs1vTFe+eWwD/ZcBYtfIxJNMYFUs3dX3qClMv+ObZ+Kdw1IGS
+TmF45PcA/RIzojwjvIE3xr0fJFbuh/t0hKnUM9F6PvONtr7DYNYPCRCOGCU0zdHy
+uGg/AP9Vj/sL5GoNcvgx8d7SdKV+GWAmJnGFAszAkPsA4vCULgD/cSP+mafM9Xdf
+mCEYA2Wcps/nPOkJoXJDfFcyO0vMVwO4OARk+kMWEgorBgEEAZdVAQUBAQdAnLxb
+gFTx1NB4SrLsKOV/3zZkwGiPHhwNy1rf8czSlCUDAQgHiH4EGBYIACYCGwwWIQQC
+ETZSFUjrGY9k/3OOGCU0zdHyuAUCaM4BEwUJB5Yk/QAKCRCOGCU0zdHyuOehAP0W
+QeLan4L834js6/UJ3Cow8T+QLEaJxCKGrEhYOwjrQQD8CU/3XuO6FKRFIZsC57Lw
+uWmtrMiaRtxcEjoL7GEsOw0=
+=qJVW
-----END PGP PUBLIC KEY BLOCK-----
diff --git a/static/files/posts/armbian-on-odroid-n2l/n2l-1024.png b/static/files/posts/armbian-on-odroid-n2l/n2l-1024.png
new file mode 100644
index 0000000..4809ded
--- /dev/null
+++ b/static/files/posts/armbian-on-odroid-n2l/n2l-1024.png
Binary files differ
diff --git a/static/files/posts/armbian-on-odroid-n2l/n2l-1024.webp b/static/files/posts/armbian-on-odroid-n2l/n2l-1024.webp
new file mode 100644
index 0000000..4a91338
--- /dev/null
+++ b/static/files/posts/armbian-on-odroid-n2l/n2l-1024.webp
Binary files differ
diff --git a/static/files/posts/armbian-on-odroid-n2l/n2l.jpg b/static/files/posts/armbian-on-odroid-n2l/n2l.jpg
new file mode 100644
index 0000000..8553d86
--- /dev/null
+++ b/static/files/posts/armbian-on-odroid-n2l/n2l.jpg
Binary files differ
diff --git a/static/files/posts/armbian-on-odroid-n2l/odroid-n2l-root_not_logged_in_yet.txt b/static/files/posts/armbian-on-odroid-n2l/odroid-n2l-root_not_logged_in_yet.txt
new file mode 100644
index 0000000..2f03dae
--- /dev/null
+++ b/static/files/posts/armbian-on-odroid-n2l/odroid-n2l-root_not_logged_in_yet.txt
@@ -0,0 +1,44 @@
+#
+# armbian automatic first boot configuration based on the documentation
+# at https://docs.armbian.com/User-Guide_Autoconfig/
+#
+# NOTE: This configuration did NOT work as expected.
+#
+# In particular, it had the following errors:
+#
+# - did not set the root password. instead the root password was "1234"
+# - did not set the user password
+# - generated a broken network configuration which did not work after
+# the second boot
+#
+
+# Network Settings
+PRESET_NET_CHANGE_DEFAULTS="1"
+
+## Ethernet
+PRESET_NET_ETHERNET_ENABLED="1" # Ignored due to WiFi
+
+## WiFi
+PRESET_NET_WIFI_ENABLED="1"
+PRESET_NET_WIFI_SSID="MY WIFI SSID"
+PRESET_NET_WIFI_KEY="MY WIFI PASSWORD"
+PRESET_NET_WIFI_COUNTRYCODE="US"
+PRESET_CONNECT_WIRELESS="y"
+## Static IP
+PRESET_NET_USE_STATIC="0"
+
+# System
+SET_LANG_BASED_ON_LOCATION="y"
+PRESET_LOCALE="en_US.UTF-8"
+PRESET_TIMEZONE="US/Eastern"
+
+# Root
+PRESET_ROOT_PASSWORD="MY ROOT PASSWORD"
+PRESET_ROOT_KEY=""
+
+# User
+PRESET_USER_NAME="someuser"
+PRESET_USER_PASSWORD="MY USER PASSWORD"
+PRESET_USER_KEY="URL TO SSH KEY"
+PRESET_DEFAULT_REALNAME="Some User"
+PRESET_USER_SHELL="bash"
diff --git a/themes/hugo-pt2021/layouts/partials/carousel.html b/themes/hugo-pt2021/layouts/partials/carousel.html
index 1052160..0174b6b 100644
--- a/themes/hugo-pt2021/layouts/partials/carousel.html
+++ b/themes/hugo-pt2021/layouts/partials/carousel.html
@@ -59,7 +59,7 @@
{{if $src.width}} width='{{- $src.width -}}'{{- end}}
{{if $src.height}} height='{{- $src.height -}}'{{- end}}
- {{if (or $pic.tip $src.tip)}} alt='{{- default $pic.tip $src.tip -}}'{{- end}}
+ alt='{{if (or $pic.tip $src.tip)}}{{- default $pic.tip $src.tip -}}{{- end}}'
/>
{{- end -}}
{{- else -}}
@@ -78,7 +78,7 @@
{{/* emit img */}}
<img
src='{{- $src -}}'
- {{if $pic.tip}} alt='{{- $pic.tip -}}'{{end}}
+ alt='{{if $pic.tip}}{{- $pic.tip -}}{{end}}'
/>
{{- end -}}
{{- end -}}
diff --git a/themes/hugo-pt2021/layouts/partials/head.html b/themes/hugo-pt2021/layouts/partials/head.html
index 29139d5..3aa90d5 100644
--- a/themes/hugo-pt2021/layouts/partials/head.html
+++ b/themes/hugo-pt2021/layouts/partials/head.html
@@ -49,6 +49,13 @@
{{- printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML -}}
{{- end -}}
+ {{/* add png favicon (smaller than ico) */}}
+ <link
+ rel='icon'
+ type='image/png'
+ href='/favicon.png'
+ />
+
{{/* activitypub URL */}}
{{- if .Site.Params.activityPubUrl -}}
<link
diff --git a/themes/hugo-pt2021/layouts/partials/header.html b/themes/hugo-pt2021/layouts/partials/header.html
index 1beeb2d..5073bb2 100644
--- a/themes/hugo-pt2021/layouts/partials/header.html
+++ b/themes/hugo-pt2021/layouts/partials/header.html
@@ -13,6 +13,7 @@
width='37'
height='28'
title='home page'
+ alt='home page'
aria-label='home page'
/>
</a><!-- navbar-item -->
@@ -46,6 +47,7 @@
width='{{$icon_width}}'
height='{{$icon_height}}'
title='{{.help}}'
+ alt='{{.help}}'
aria-label='{{.help}}'
/>
{{- end -}}
@@ -73,6 +75,7 @@
width='{{$icon_width}}'
height='{{$icon_height}}'
title='{{.help}}'
+ alt='{{.help}}'
aria-label='{{.help}}'
/>
{{- end -}}
diff --git a/themes/hugo-pt2021/layouts/partials/project_summary.html b/themes/hugo-pt2021/layouts/partials/project_summary.html
index 54811ac..4219157 100644
--- a/themes/hugo-pt2021/layouts/partials/project_summary.html
+++ b/themes/hugo-pt2021/layouts/partials/project_summary.html
@@ -5,13 +5,13 @@
aria-label='{{.Title}}'
>
{{- .Title -}}
- </a><!-- project-link -->
+ </a><!-- project-link -->:
- <p
+ <span
class='project-text'
title='Project description.'
aria-label='Project description.'
>
{{- .Params.text -}}
- </p><!-- project-text -->
+ </span><!-- project-text -->
</li>
diff --git a/themes/hugo-pt2021/layouts/projects/list.html b/themes/hugo-pt2021/layouts/projects/list.html
index 3d4de89..52d5c7a 100644
--- a/themes/hugo-pt2021/layouts/projects/list.html
+++ b/themes/hugo-pt2021/layouts/projects/list.html
@@ -12,11 +12,6 @@
<div class='content'>
{{- $rows := union (where .Pages "Params.active" true) (where .Pages "Params.active" nil) -}}
{{- if len $rows -}}
- <h3
- title='Current projects that are actively maintained.'
- aria-label='Current projects that are actively maintained.'
- >Current Projects</h3>
-
<ul>
{{- range $rows.ByTitle -}}
{{- if (default true .Params.show) -}}
@@ -28,10 +23,10 @@
{{- $rows := where .Pages.ByTitle "Params.active" false -}}
{{- if len $rows -}}
- <h3
+ <h4
title='Old projects that are no longer maintained.'
aria-label='Old projects that are no longer maintained.'
- >Legacy Projects</h3>
+ >Old Stuff</h4>
<ul>
{{- range $rows.ByTitle -}}
diff --git a/themes/hugo-pt2021/layouts/shortcodes/pe-figure.html b/themes/hugo-pt2021/layouts/shortcodes/pe-figure.html
index 324d11f..b90a260 100644
--- a/themes/hugo-pt2021/layouts/shortcodes/pe-figure.html
+++ b/themes/hugo-pt2021/layouts/shortcodes/pe-figure.html
@@ -66,7 +66,7 @@ enhancement.
{{if $src.width}} width='{{- $src.width -}}'{{- end}}
{{if $src.height}} height='{{- $src.height -}}'{{- end}}
- {{if (or $pic.tip $src.tip)}} alt='{{- default $pic.tip $src.tip -}}'{{- end}}
+ alt='{{if (or $pic.tip $src.tip)}}{{- default $pic.tip $src.tip -}}{{- end}}'
/>
{{- end -}}
{{- else -}}
@@ -90,7 +90,7 @@ enhancement.
{{/* emit img */}}
<img
src='{{- $src -}}'
- {{if $pic.tip}} alt='{{- $pic.tip -}}'{{end}}
+ alt='{{if $pic.tip}}{{- $pic.tip -}}{{end}}'
/>
{{- end -}}
{{- end -}}
diff --git a/themes/hugo-pt2021/layouts/shortcodes/pe-picture.html b/themes/hugo-pt2021/layouts/shortcodes/pe-picture.html
index 3135fcf..b7623ec 100644
--- a/themes/hugo-pt2021/layouts/shortcodes/pe-picture.html
+++ b/themes/hugo-pt2021/layouts/shortcodes/pe-picture.html
@@ -69,7 +69,7 @@ Features:
{{if $src.width}} width='{{- $src.width -}}'{{- end}}
{{if $src.height}} height='{{- $src.height -}}'{{- end}}
- {{if (or $pic.tip $src.tip)}} alt='{{- default $pic.tip $src.tip -}}'{{- end}}
+ alt='{{if (or $pic.tip $src.tip)}}{{- default $pic.tip $src.tip -}}{{- end}}'
/>
{{- end -}}
{{- else -}}
@@ -93,7 +93,7 @@ Features:
{{/* emit img */}}
<img
src='{{- $src -}}'
- {{if $pic.tip}} alt='{{- $pic.tip -}}'{{end}}
+ alt='{{if $pic.tip}}{{- $pic.tip -}}{{end}}'
/>
{{- end -}}
{{- end -}}