I’ve found myself tinkering with WordPress stuff a lot lately. Here’s another quick change I made for nicer shortlinks with a shorter domain that I have.
This was inspired by trawling through jwz’ archives and hacks. This post in particular.
The first piece of this puzzle is adding this location block to the nginx configs for bhh.sh. There’s probably a better way to do this to handle more types or remove the extra redirect.
The other half is filtering the shortlink on the WordPress end. I’ve added this to the functions.php of my theme. Basic logic here is based on jwz’ base64 shortlinks, just minus the base64 and dumping the post ID right in there.
I’ve been tinkering around with IndieWeb integration on this site and wanted to document some notes getting all this running with a block theme.
Theme
I’m running a mildly customized version of Pulitzer. I’ve used the Create Block Theme plugin to export my changes and have published it as a standalone child theme here.
Changes are mainly typography and header/footer changes. I’ve raised the font sizes across the board and switched to using system fonts to avoid shipping font files. Modern Font Stacks is lovely and I found this tiny plugin to pull all the families in to the font library.
I’ve also started extending Pulitzer’s existing block bindings. I’m testing this as a stand-in for Syndication Links:
I’m using IndieBlocks to provide microformats markup throughout my site. I’m also using the Note and Like post types. I’ve decided to keep those out of my main blog feed. Here’s the configs.
Syndication Links
The Syndication Links plugin handles publishing the actual syndication posts, and I use the hidden links for the markup. The clickable links are currently displayed with a block binding.
IndieAuth
This requires essentially no configuration, but I did find a nasty bug in the plugin code and helped debug a bit. Logging in with IndieAuth was hanging indefinitely, getting killed by php-fpm, and throwing a 504 timeout. I’m not super familiar with the code but this is the PR that fixed it.
Shoutout to dshanske for helping me figure this one out and releasing a new plugin version with the fix!
Bridgy
I’m using both Bridgy and Bridgy Fed. I’m currently trying out POSSE for my mastodon and bluesky posts with Bridgy and publishing them as Notes here on this site. These are the publish targets I use via Syndication Links:
My solution for keeping Notes and Likes out of my main blog feed was making sure to show them in my author feed in the IndieBlocks settings and adding a rel=feed link to my author page in the header.
The other solution I tried for this was using MF2 Feed and including them as rel=alternate but Bridgy doesn’t support mf2+json feeds yet. There’s an open issue to add support for this use case.
One remaining thing that I haven’t figured out yet is pulling the syndication links out of the logs into the proper post meta. Still haven’t narrowed this down fully but it works perfectly fine when publishing with a Micropub client like Quill or IndiePass, so it feels like something to do with the block editor.
Had a strange bug where the Navigation block stopped working on certain pages. Didn’t find the actual cause but it fixed itself when I disabled the Gutenberg plugin.
[… we] estimate that DNSSEC validation is performed around 1% of the time, given the DNS query profile of today’s data
I run my own authoritative nameservers and have had a slight nagging feeling that I should’ve enabled DNSSEC years ago. It’s been on my perpetual to-do list but I’ve never gotten around to it. I’ve definitely caused some outages trying to get DNSSEC to work.
Came across this article and it confirms that my procrastination was pretty OK in this specific case.
I post the results from the pinball tournaments I run on our site, which usually involves copying a previous post and updating all the info by hand. I took some time this week to put together a script that reads the results from matchplay and builds a post with all the right info.
It’s not enough to publish as a git repo or anything and I just wanted to have a place to keep it so it’s here for now.
at this point it seems like most of the tech community is familiar with matrix, the “open network for decentralized communication”. lots of projects and communities have migrated from a host of other platforms, including irc, discord and slack with the promise that their new spaces will be free forever. i first discovered matrix in 2021 and have dedicated a lot of time trying to understand exactly how it works, as well as trawling through github issues to try and understand whether we should consider matrix safe. i’ve also evaluated conduit as well as dendrite and tried a number of clients.
first of all, a quick primer on what matrix actually is. even though element market matrix as the foundation of a chat app, it’s far more complicated than that. under the hood, matrix is actually a distributed partially-replicated graph database. a matrix “room” is actually a directed acyclic graph (“dag”) made up of events which can contain things like messages, user membership states and bans and other things. servers participating in a room are eventually consistent, that is, they should replicate enough state so that everyone sees roughly the same thing.
in order to “send” something into a room, a server that is participating in a room can also try to append events onto the graph. since every participating server needs to be able to verify what they are receiving from another server actually makes sense, a set of auth rules are defined in the spec to determine when to allow or to drop certain events. events are cryptographically signed by the sending server so that other servers can check those origins too. every server participating in a room needs to perform these checks, in the hope that if all servers agree, that newly created events will be happily accepted by all participating servers.
however, over time, i have collected together quite a list of issues that i consider to be either unsolved or dangerous. without further ado, here is my list of things to consider and reasons why you might not want to use matrix:
the graph is append-only by design and events that get sent into the room can not ever be guaranteed to be deleted, so a matrix room can potentially end up accumulating history endlessly. for some applications this is desirable, but for chat and other applications it removes any possibility of deniability. deleting history is a very hard problem in matrix because dropping whole events can create gaps in the graph which servers either need to complete event auth or may struggle to skip over when backfilling history.
if you do want to delete something, you can send a redaction event which asks other servers very nicely to delete the content of the event, but redactions are advisory and a badly behaving server participating in a room could simply ignore the redaction request, instead holding onto the entire history. it’s basically impossible to know at the point of asking for a deletion whether this has happened or not.
however, servers that choose to ignore redactions, or fail to process them for some other reason, can leak supposedly-deleted data to other servers later on. if a new server joins the room for the first time or wants to backfill history, it can ask any server in the room for help doing so, including the badly-behaved server. nothing requires a server to return the redacted skeleton event, it can opt to return the full unredacted event if it wishes. in fact this might even happen purely by accident.
certain events, like membership changes, bans or pretty much any event that exercises some control over another user can’t be deleted ever as they become woven into the “auth chain” of future events, and in order for a server to independently verify each event, they need to be able to prove how the event was allowed to happen, iteratively, back to the beginning of the room. every time a user joins, leaves, changes their name or avatar, gets kicked, banned, kicks or bans someone else or changes critical room settings, traces of these actions become burned into the room history permanently.
as with most places on the internet, spam is inevitable, so another fun way to attack a room is just to join hundreds or thousands of bots to the room, making the room graph very complex and difficult to compute, which in turn means that servers waste lots of cpu time and clients have lots more work to do, especially in encrypted rooms. the only way to discard all of this spam complexity is to recreate the room.
even room history is a best-effort endeavor. while the room graph itself provides some causal ordering, as some events need to follow other authenticating events, it’s exceptionally hard to linearize history if you don’t know the entire history of the room partially. tiebreaks used in the server also include fields like depth and the origin timestamp, which can both be forged. so unsurprisingly, different servers can see messages arriving in a different order to each other. most of the time there is nothing you can do about this.
speaking of forging things, it is also somewhat possible to insert messages into history by crafting events in the graph that refer to older ancestor events and, as long as it looks vaguely plausible (like with a sane depth and/or timestamp value), other servers will accept these events without much question and users may not be able to tell the difference if these events eventually get backfilled onto their own server’s copy of the room history.
another thing that is worth noting is that end-to-end encryption in matrix is completely optional. this is pretty much required as public rooms would be extremely heavy and probably completely unusable otherwise, but the only thing trying to ensure that your dms are encrypted are clients and even they don’t have to if they don’t want to. anything in a federated room that isn’t end-to-end encrypted can end up replicated in plain-text and also end up as part of a semi-permanent history.
the end-to-end encryption is also annoyingly fragile as it depends on device list updates to be delivered between servers reliably. a failure to sync these correctly will result in broken encryption in rooms where others cannot decrypt your messages and this seems to be a constant source of encryption bugs.
sometimes these device list updates updates also leak information about your device, like which matrix client you are using or which operating system/platform you are on. some homeservers seem to have started trying to filter this information recently, but as always, there’s no guarantees.
the entire matrix api surface is http and json. for clients and client developers this makes things nice and simple, but the federation api also uses http and json and also tries to be cryptographically secure. for signing events and requests to work, matrix expects the json to be in canonical form, except the spec doesn’t actually define what the canonical json form is strictly, so there’s every possibility different implementations will end up generating different signatures for the same event.
oh wait, that actually happened. turns out that matrix homeservers written in different languages have json interoperability issues, so you might just get random events or requests that fail signature checks between different types of matrix servers because no one knows exactly how to get it right. synapse, the flagship implementation, simply relies on python’s sort_keys and calls it a day, to hilarious effect, and even other matrix devs working for element haven’t been able to figure out how to match this behavior in other implementations like dendrite.
those signature checks also rely on server signing keys which can be expired and replaced, except the signing key expiry is completely arbitrary so you can simply set an expiry date for your server signing key in the past and watch as new servers are now totally unwilling to authenticate any events from your server, resulting in split-brained rooms. feeding certain key expiry information to certain servers and not others might even make for a novel eclipse attack.
split-brained rooms are actually a common occurrence too, as the distributed nature of matrix requires a kind of consensus algorithm (known as “state resolution”) in order to work out what to do when a server ends up with more than one conflicting set of state. the algorithm is not watertight and relies on some preconditions (like event signatures being accurately checked across servers) so when certain edge-cases occur in this algorithm, which they often do, a “state reset” can occur which can end up kicking users out of rooms or reverting state changes. at this point state resets are an on-going meme with no solution in sight.
worse than that, state resets happen quite a bit more often when servers written in different languages interoperate because of the json interoperability issues, and it’s also possible to force them to happen in some cases by joining a room, making some power actions and then setting your signing key to expire before they happened. some servers will believe the events if they passed the signature check at the time, other servers will drop the events if they learn about the key expiry first, and then chaos ensues as servers try to request state snapshots from each other, eventually breaking the room to the point that those servers may never agree again!
this has happened to amusing effect more than once, as room admins and moderators have lost their powers over public rooms many times due to state resets, leaving them unable to defend themselves and their communities against spam, harassment and other types of attacks. in some cases, the core matrix team have had to try to forcefully shut down rooms on their own instances and recreate them on more than one occasion, hoping people will rejoin. the big bad Matrix HQ room has been the subject of attacks multiple times now and so have other community rooms.
speaking of shutting down rooms, you can’t actually force a room to be shut down across the federation. if there are three servers in a room and one of them wants to shut down the room, there’s no way to stop the other two servers from continuing along just as they were. this is good news if you care about internet freedom, sure. this is bad news if people start to abuse instances with unsavory rooms or content. in certain legislations this could present a serious problem.
speaking of moderation, this is notoriously difficult too, as moderation relies entirely on the functioning of the event auth system and breaks down if state resets happen or if someone abuses their power. this has seemingly resulted in problems with trying to moderate or clean up attacked rooms before. these changes can be extremely hard to revert, especially if there are other servers participating in the room, as the room will eventually try to converge on what the state resolution algorithm thinks the best state is, which isn’t necessarily the state that you want.
pretty much any user on your homeserver can upload media to your server’s media repository at pretty much any time, and media downloads are unauthenticated by default. as a result, you can often just generate a HTTP link to the media. someone might be using your media repository as their personal sharing box at your expense and you may not even realize.
you can also ask someone else’s homeserver to replicate media by asking that homeserver to return a copy of it. based on the content ID and the origin server name in the URL, the homeserver will download the media from the origin and likely cache it locally in the process. that could end up being a fun denial-of-service.
in addition to that, media uploads are unverified by default. if you are running your own matrix instance, there’s a good chance that nothing is scanning that media for unsavory content (like csam or viruses) unless you have also installed a separate content scanner. this is a separate package and is not a core part of the synapse distribution, nor any other homeserver that is available today.
actually the eager replication of media could end up potentially being quite a massive headache, since all it takes is for one of your users to request media from an undesirable room for your homeserver to also serve up copies of it, at which point you could become liable for hosting copies of illegal media like csam or copyrighted material without necessarily knowing it.
i want to note that this list is not completely exhaustive and i may follow up with more items at a later date. however, i have found what i believe to be quite a number of reasons to be skeptical of matrix and i would struggle very much to want to recommend it to a new community or enterprise looking for a communication platform. most of the issues here i’ve ever witnessed first hand or have been following through a series of github issues on various matrix repositories, issues which the matrix devs seem to have been largely ignoring for literal years now.
Here’s how I got a self-hosted PDS (personal data server) running without docker.
This can be useful if you want to run the PDS on an existing machine or just don’t like docker. I came up with these steps by emulating what the installer script does.
My setup uses nginx and a wildcard TLS cert for my PDS domain.
Get the code
Clone the PDS repo
$ git clone https://github.com/bluesky-social/pds
Set up nginx
I use certbot to issue wildcard certs for my domains. See my wildcard cert script here. Note that you will need to set up credentials for your nameservers. I’m not aware of a way in nginx to issue certs on-demand like the example caddy config does.
This is our pinball machine. We’ve owned it for about 3 years at this point. One of the previous owners covered the cabinet for some reason with this faux woodgrain paintjob. I’ve been meaning to do something with it since we got it and today happened to be that time.
My buddy Joey sent me a text the other day after he saw it for the first time offering to help me get it restored so of course I took him up on it.
It’s not done yet but we made a good amount of progress with some light sanding and latex paint remover.
Bonus dog in this pic. It’s in pretty good condition under the 2 layers of paint and at least one layer of a clear coat. Looking forward to seeing the finished product!
Haven’t written anything here this year yet. Here’s my uses page!
Hardware
My desktop is a custom build that I put together about a year ago (Jan 2023). Here’s the part list on pcpartpicker. It’s super beefy and runs any- and everything with no complaints. Getting to this point was a little painful as the graphics card I bought was open box from Micro Center. After two RMAs, MSI ended up sending me a brand new card.
Important Specs:
i9-13900k
RTX 4080
64 GB RAM
For a laptop I have a Framework 13. I’ve been super happy with that as an on-the-go device.
My phone is a Pixel 6a. It does the trick, but I’m still angry they removed the headphone jack.
I have a random collection of old laptops and desktops that I’m using as a home proxmox cluster. This site is hosted on one of the computers on that rack.
any homelab folks out there?feeling glad that electricity is relatively cheap here
I do email in Thunderbird on desktop, and Aqua Mail on my phone.
Most days, I’ll boot into windows 11 on my desktop to remote into my $dayjob development VM (the VMware remote client runs better on windows). I also have a linux dual-boot setup but I hardly bother rebooting to switch. I’ve been playing videogames quite a bit lately and haven’t taken the time to set up linux gaming on the other drive.
My laptop is running Fedora and I’m currently running KDE. GNOME is also fine. Use what you like 🙂
Text editor is vim and/or sublime text. I use Visual Studio and Jetbrains Rider for the C# I do at work.
I use fish shell as my main interactive shell, and some of the most common tools I use are ripgrep, fzf, and a bunch of aliases and shell scripts I’ve built up over the years.
For IRC, I use WeeChat. I’ve written previously about my setup. I use weechat-android on my phone to keep up to date.
Password manager is KeepassXC, and keepassdx on android. I use Syncthing for my files, including my keepass db file, and all the associated files in my pubdir (separate synced dirs).
My phone number is on jmp.chat, so I use XMPP to send and receive SMS. I run the cheogram client on my phone to integrate with the system dialer. On desktop, I tend to SMS from my weechat via bitlbee.
This site is WordPress, but it was previously in several different incarnations, starting from a very old WordPress site, then I switched at some point to bashblog. That grew tiring to deal with once you have more than a handful of posts. I switched to hugo, which I also wrote about. I guess I’m more of a GUI guy than I thought because I ended up going back to WordPress at some point last year.
Since I got deep into pinball over the last couple years, I use Match Play to run the two weekly tournaments here in TC. The tcpinball.org site is also WordPress, and I use the Jetpack plugin to publish new posts on the various social media pages we have for that.