Don’t know about anyone else but I find Teams REALLY useful. EXCEPT when I am trying to get something done. I’m also starting to find Microsoft products better and better. Maybe it is my old age. Windows 10 has way more stuff built-in than, I think, a lot of people realise. One feature I really like is Focus Assist, which basically switches of notifications. However, Teams does not seem to support Focus Assist and I was getting very annoyed, so I looked into it…

Turns out, it does but you need to toggle what sort of notifications Teams uses: https://support.microsoft.com/en-us/office/change-your-notifications-style-in-teams-0da93820-93d0-4da3-86b6-fc28d19908e3

So, I had a minor disaster. This is what went wrong and how I fixed it.

We use the amazing WordPress Redirection plugin. We recently started a survey and the best way to contact the participants was by letter. We had to include a URL to the survey. Some people were mistyping the URL. For example:

/direct-payments-servey
/direct-payments-urvey
/directpayment-survery/
/directpaymentsurvey
/directpaymentssurvey

The correct URL is /direct-payments-survey/

To fix this, at 8:10am this morning, I threw up a very hasty regex redirect and went to have my breakfast, slapping myself on the back. It matches all the errors and, I thought, would catch most other typos. Here it is:

^/(directpayment|direct-payment).*

Problem is it also caught the target URL and an endless redirect ensued. The page was down for 9 hours.

After my trials a little while back trying to get to grips with not matching strings in a regex I had a good idea for how to fix it.

^/(?!direct-payments-survey)(directpayment|direct-payment).*

It was that easy. Here is the regex on regex101 as usual.

The silver lining here is that I now have a very reusable fix when I need to match something very close to the target URL. I’ve had this problem in the past and often just created a completely different URL. Even then this was not foolproof as WordPress keeps it’s own records of old URLs and redirects.

Well, who knew Cloudwatch would be so much fun to tinker with?! Not me!

I have been slowly refining my Cloudwatch dashboard: adding new alarms, expanding the scope of the log watch, all that good stuff. It is very satisfying. Over the last week or so I have also set-up fail2ban because (according to my audit log via Cloudwatch ?) sshd was getting hammered. As previously mentioned, this box is not well resourced, so I wanted to nip that in the bud. But does the cost of running fail2ban outweigh the benefits? Hard to say!

Anyway, I am getting quite a lot of email from fail2ban. This is good because I know it is working but I’d rather not have the email and still be able to easily check it was working… so Cloudwatch!

I added the fail2ban log to the config and used the Logs Insights tool to explore. This is typical line:

2021-04-30 17:58:06.631, "2021-04-30 18:58:06,208 fail2ban.filter [100432]: INFO [sshd] Found 205.185.119.236 - 2021-04-30 18:58:05"

We could use the date/time a few more times, right? I decided this was the time to jump into the parse command in the CloudWatch Logs Insights query language (rolls off the tongue that). I knew I was going to need another regex within about 10 seconds. But, damn, if the examples aren’t thin on the ground. I googled and found virtually nothing although this post did help a bit.

So, to regex101.com I went. I exported a few lines from the log to test and I must be getting quite a lot better because I got the basics working pretty quickly:

\[sshd\]\ (?<action>[a-zA-z]*)\ (?<ip_address>[\d\.]*)

Then this query in Cloudwatch Logs Insights did the job:

parse @message /\[sshd\]\ (?<action>[a-zA-z]*)\ (?<ip_address>[\d\.]*)/

| display @timestamp, action, ip_address

| limit 200

Unfortunately, I find reading timestamp pretty hard so a bit more tinkering:

parse @message /(?<date>\d\d\d\d-\d\d-\d\d)\ (?<time>\d\d:\d\d:\d\d).*\[sshd\]\ (?<action>[a-zA-z]*)\ (?<ip_address>[\d\.]*)/

| display date, time, action, ip_address

| limit 200

Excellent! It was running for about 5 minutes and it suddenly produced a blank line. Of course, [sshd] in the log refers to the jail. I have several set up so…

parse @message /(?<date>\d\d\d\d-\d\d-\d\d)\ (?<time>\d\d:\d\d:\d\d).*\[(?<jail>sshd|recidive|mysqld-auth)\]\ (?<action>[a-zA-z]*)\ (?<ip_address>[\d\.]*)/

| display date, time, jail, action, ip_address

| limit 200

And that does the job nicely at the moment. You can find an explanation of the regex on regex101.

Once I am a bit more confident, I’ll start filtering on the action, so I can just see bans and unbans:

| filter action = "Ban" or action ="Unban"

Had a bit of trouble with what should have been a simple regex today.

I removed a whole bunch of Pages from our site today, and they were all sat under the same parent. I wanted to redirect the now missing pages to the parent. I came up with this:

^\/dignity-care-reports\/[a-z-]*(\/?)

It worked fine in that it redirected the sub-pages but the parent was now in a redirect loop. So, I headed over to regex101.com to investigate. I quickly found that, yes, this regex did match the parent URL.

The great thing about regex101 is that it gives an explanation of what each of your tokens is doing and I quickly saw:

* matches the previous token between zero and unlimited times

And there’s the problem! Now I just needed any sort of match after that second / to stop the redirect loop and a ‘+’ does the job:

^\/dignity-care-reports\/[a-z-]+(\/?)

You can see the example here: https://regex101.com/r/IfIPpn/1

Now I just need to remember that * can match zero times!

This site runs on CentOS 8, on an AWS t2.micro EC2 instance. It’s all free tier at the moment as this is very much a trial run/learning experience.

It’s taken several attempts over the last few months to get the instance running nice and stable. I was getting regular out-of-memory errors, with mysqld just killing itself. It would then get caught in an endless suicidal loop because the restart of the service caused another out-of-memory error.

However, I’m not sure that mysqld was really at fault. I don’t think php-fpm was very well configured. When I set the site up I followed a few tutorials that didn’t really explain how to clean-up afterwards and I ended up running way more php-fpm threads/children than needed for such a tiny, low traffic site. Since I did that, I have not had a crash and have not had to restart the instance.

Chart showing EC2 memory used. It averages around 60% and tops out at 62%

Yesterday, I was finally able to get an AWS Cloudwatch dashboard set up that actually showed me what was going on. That part was surprisingly easy compared to setting up Cloudwatch itself, which, even following AWS’ on tutorials, was a bit of shot in the dark.

As I said, it all seems pretty stable now so I am adding new WP plugins etc very slowly so I can see if any one thing causes a problem.

Found a weird WordPress bug today. I exported ALL from my old WP hosted blog and imported everything here. It all went fine except all the Post counts for imported Tags in the Tags screen were zero. I found this old post with a similar problem but no solution.

I figured it just needed a nudge to force it to recount the Tags, so simply did a Bulk Edit and added a dummy tag to all my Posts. Checked the Tags and bingo! Then I just deleted the dummy tag.

Thoughts on accessibility

Recently, I have been thinking about website accessibility (a11y) even more than usual. I always have accessibility in mind but I only occasionally focus on it specifically. For example, a few months ago I reviewed our use of icon images on the website and hid them from screen readers.

On 23rd September 2020 all public websites in the UK will need to meet certain accessibility requirements and provide an accessibility statement. Over the next 6 months I’ll be focusing on a few specific areas of accessibility. My main concerns with our site, as it currently stands, are URL formatting and colour contrast.

Our site runs on WordPress and I am huge opponent of plugin bloat. The more plugins you have, the more potential attack vectors there are. I see countless 404 errors from malware scripts looking for (presumably) compromised plugin files. On that basis, anything I can do myself, I want to do myself. Therefore, I am definitely not a fan of these huge accessibility plugins that promise everything and the kitchen sink.

It’s also important to be aware that web browsers will take accessibility hints from the operating system. Remember that ,before a user with a visual impairment arrives at your website, they must already have their OS and browser configured in a way that facilitates that. The first step is to respect your users’ existing configurations.

One of the lowest hanging fruit, in this regard, is dark mode. Until recently, dark mode was only found in some mobile apps, usually those for reading. When everyone started  freaking out about “blue light,” night mode – warmer, less blue colorisation – was introduced at the OS level. Now dark mode is also readily available at the OS level too. I personally prefer dark mode on my portable devices and dark mode is an easy win for users with light sensitivity.

Into the dark

I’ve just completed a fairly length “feature sprint” where I added a whole bunch of new functionality to the site. While testing it on my iOS device I decided to switch on Dark Mode in Firefox OS. I was pleasantly surprised! Overall, it looked OK.

The immediate and obvious problem was our logo. Obviously our logo was designed with print in mind (we didn’t design it) so it looks best on a light background. In dark mode I could barely see it on the page.

Fortunately we have been supplied with “rev” versions that work on dark backgrounds too. With that hurdle cleared, how to find out when we’re in dark mode? Fortunately, “the internet” is way ahead of me, and prefers-color-scheme already exists.

prefers-color-scheme is a CSS media feature, so pretty easy to implement. This is a good introduction.

So, I added an “alternate logo” to our WordPress theme, added a new div containing the new brand image (our theme is bootstrap based), and set up the CSS media queries to alter the display property (this is not usually good practice).

media_queries

I work with Firefox, and (to my knowledge) there is no dark mode on desktop without a plugin, so I went to my iOS device. I opened the page in Firefox and switched to dark mode and “boom,” there was my alt logo. Awesome. I turned off dark mode and… the “normal” logo didn’t come back. Huh. Obviously I started checking the code. It looked fine.

I decide to try and check it in Windows 10. Windows has had a “proper” dark mode since 2018. It worked fine. As I turned dark mode on and off in the Settings, Firefox swapped the logo back and forth. Perfect. So, why wasn’t it working on iOS?

TL;DR

Well, all the evidence was right in front of me.

prefers-color-scheme gets the color-scheme from the OS. On my iOS device, I had the OS itself in dark mode already when I tested the new logo. This is what actually caused the alternate logo to appear. Dark mode in Firefox itself can’t “toggle” prefers-color-scheme. Toggling the iOS dark mode on an off worked exactly as in Windows 10.

But…

This leaves a horribly fractured landscape. The Firefox iOS browser, has a dark mode that swaps out the pallette of the page for darker colours, but respects (as it should) the iOS color scheme preference. A user that has dark mode enabled in one place but not the other is going to have a poor experience.

This makes Firefox’s built-in dark mode next to useless. I’ll need to code up alternate CSS rules that respect prefers-color-scheme.

Dark mode, not such a low hanging fruit after all.

Letter to Santa

You’ve probably all seen this joke before. This tweet is the earliest mention I can find but please do correct me in the comments if you have an original source!

There have been a few “take downs” of this joke but this one is probably the most thorough.

My take is that whether you are naughty or nice might be considered special category data and he needs specific consent to process that. He’s presumably collecting the naughty/nice data from elsewhere too, and doesn’t appear to notify anyone that he has obtained it. And I am sure he is making decisions using automated processing to which you haven’t been able to object.

But that is not why I am here today.

I am not a data protection “expert” but I reckon I know more than most. In the UK, the Information Commissioners Office (ICO) is responsible for enforcing the data protection rules. However, there must be thousands of insignificant breaches of the DPA everyday that the ICO will never hear about, let alone touch.

Personally, it makes me VERY cross when people misuse my data. I can’t take any legal action against them but I can name and shame them. So I am going to.

We have a lot of side responsibilities at the small NFP I work for. You know when you’re the only person that is good at doing something so you do it even if it’s not technically your job? That kind of thing.

I do a lot of the maintenance and “fiddling” with our WordPress website. I quite like it. Recently I have hit upon an extremely therapeutic activity: managed 404s.

We have a plugin to manage redirections for missing pages. I don’t exactly want to get to zero 404s but I do want to catch and redirect those I can to meaningful places. Even if it is a 410 response.

The really fun part is the plugin supports regular expressions. When I first started working with the plugin my efforts were limited to basic wildcard matches. Now I have even started with optional groups and substitutions. I’m by no means an expert but it is a great learning enviroment.

Today I have come up with a solution I am quite proud of. For some reason, our developer set the versions on our CSS and JS files to randomise occasionally. I assume this is for some sort of caching purposes. Anyway, this can generate some harmless 404s that I don’t want to be logged.

Using the regular expression 101 website I created this solution. Not much point explaining it here as the site does that very well. Any 404 that matches this pattern is excluded from the 404 logs, which helps me spot meaningful 404s much quicker.

Very pleased