Razer Data Security Update

Dear Sir/Madam,

We were recently made aware of a server misconfiguration that potentially exposed certain customer information from our eCommerce online platform for a short period of time.

Translation: “We definitely leaked your personal information to the world. Those bastards at Google even picked it up, so now it’s cached forever.”

The server misconfiguration had been fixed on 9 September, 2020, prior to the lapse being made public and there is no indication of any unauthorized access to the information.

“We have no idea when we fucked up, but it was probably when we first set up the server. We didn’t realize we should disable public access to Elasticsearch, so we also have no clue if anyone accessed your information. Our lawyers say that’s a good thing: no proper security logs means we also have ‘no indication of any unauthorized access.’”

The server misconfiguration potentially exposed order details, customer and shipping information.

“We definitely leaked your name, where you live, and everything you’ve ordered from us before. You should make sure you lock your doors.”

For avoidance of doubt, no sensitive information such as credit card numbers, bank account details, national identification numbers or passwords was exposed.

“Listen, I know you’re upset, but we could have fucked up even worse.”

In addition, no other information from the servers for our other software or services was exposed.

“We spent a lot more effort on Synapse 3 than we did protecting your personal information, and no one has ever complained about it. The files on your computer are probably fine. You only use it for gaming, right?”

We sincerely apologize for the lapse and have taken all necessary steps to fix the issue as well as conduct a thorough review of our IT security and systems. We remain committed to ensuring the digital safety and security of all our customers.

“We are committed to saying whatever it takes for you to keep buying gaming hardware from us, and not much else. I assume you’ve stopped reading by this point.”

How I Ended Up With 70GB of WiFiDiagnostics Logs

Sometime this winter, I noticed sysdiagnose would randomly max out my CPU and generate WiFiDiagnostics logs in /private/var/tmp/. This happened the most on my work computer, resulting in over 70GB of log files before I discovered them and cleaned them out. Both my work and home computers are connected to ethernet, so with no logical reason for this to happen, I resigned myself to living in log hell and worked on ways to automatically remove them.

Last month, I finally got frustrated enough to search for a proper solution. After toying around with search terms, I ran across a StackOverflow post with my answer:

It looks like cmd+ctrl+option+shift+w triggers a WiFi Diagnostics session.

Ah ha! So a keyboard shortcut introduced in macOS Catalina was the culprit.

I use an application called Karabiner Elements to remap my Caps Lock key to a hyperkey (Control+Option+Command+Shift), and I use the hyperkey to quickly swap between applications. Hyperkey+W was set to my email client, which I open several times a day during work. Every time I opened my email, I was unwittingly generating hundreds of megabytes of WiFi Diagnostic logs. I’m slightly disappointed I didn’t notice the pattern.1

I spent some time searching for a way to disable the diagnostics shortcut, but I never found one. I eventually gave in and changed my email shortcut to something else.2

  1. Dear Apple,

    It would be nice to see a notification that WiFi Diagnostics is running whenever you trigger the keyboard shortcut. 

  2. I should also note that Control+Option+Command+Shift+. will trigger a different set of diagnostics, although this one opens Finder to the log file once it’s finished. 

The Privilege to Ignore

This has been a rough year, and we’re not even halfway through. I’m tired of reading the news because each day brings another depressing event. I’ve started quickly scrolling past to the happier posts, but many people can’t do the same. They can’t escape from their sick loved ones, or the color of their skin, or their gender, or their sexuality, or the natural disasters that have upended their lives.

I can, at least for now, and it’s likely you can too. I can work from home and pay to have my groceries delivered, reducing my chances of getting sick. I can turn off the news and ignore the protests that are occurring half a world away. I can turn on my TV and watch movies and play games, worrying about what to buy next instead of how to afford my mortgage.

It’s important to recognize what a luxury that is. Someone is out there delivering my food so they can pay for their own. Someone is out protesting in the street, fighting for their life, in the US, and Hong Kong, and India. Someone is trying to recover from a fire that took everything from them.

Give back to the people who aren’t as privileged every chance you get. You have plenty of causes to pick from this year, and there are a lot of people who could use your help with a fresh start.

A Quick Rundown on Notarization

I get periodically asked about Apple’s notarization requirements, so I thought I’d amass my knowledge in one place and link people to when they have questions. This is not an extensive overview, but I’ve tried to strike a balance between technical and understandable. Hopefully you’ll find it useful, especially if I’ve just sent you this link.

What is notarization?

Starting with macOS Catalina (10.15), applications that are not distributed through the Mac App Store must be notarized by Apple. In short, after building an application, you need to upload the build to Apple, have them sign it with their certificate, and then download a receipt from them which gets stapled to the application to show that it is notarized. During this process, Apple verifies the application does not contain malware.

Importantly, you can only staple notarization receipts to packaged applications, which are basically fancy folders containing the application’s files. It is not currently possible to staple a receipt to a standalone executable since there is nowhere to store it. The only workaround is to convert the executable into a packaged application.

When most applications are run (see below for exceptions), Apple will verify the stapled receipt. If a receipt wasn’t stapled to the application, macOS will check with Apple’s servers to see if the application is notarized. If a receipt exists, or the server responds positively, then the application will run normally. If both checks fail, macOS will display an error and refuse to run the application.

Screenshot of the alert that appears when an application isn't notarized

How does notarization work?

Notarization is built on top of a technology called Gatekeeper, which is built on top of extended file attributes. Starting with OS X 10.5, files downloaded via certain methods, such as a web browser, receive a quarantine flag. When users launch an application, Gatekeeper checks for the quarantine flag. In macOS 10.15, if the quarantine flag is present, Gatekeeper will verify the application is notarized and prevent it from running if it is not. Previous versions of macOS would only display a warning.

The current implementation introduces a loophole: the quarantine flag is not set for all downloaded files. For example, games downloaded by Steam do not currently have a quarantine flag, so the notarization check is not run for those games. This loophole extends to basically all applications downloaded or updated by custom mechanisms.

What will notarization look like in the future?

In a session from WWDC 2019, an Apple employee recommended that all software be notarized (emphasis mine):

First, sign and notarize all the software that you distribute, even if it doesn’t get quarantined today.

We don’t know if the loophole for Steam and other downloads is intentional and will remain forever, but their wording leaves the possibility of an expanded quarantine in the future, and Apple is the type of company that chooses their words carefully.

We should hopefully receive more information during WWDC20, but it’s probably a safe bet that we’ll see more changes to notarization in the next version of macOS.

How to Programmatically Add Folders to the Spotlight Ignore List

Automating additions to the Spotlight ignore list used to be as simple as using defaults write, but the release of macOS 10.15 Catalina brought some changes that make it slightly more complicated:

  • The VolumeConfiguration.plist file has moved. After upgrading to Catalina, you now have multiple volumes even though Finder shows the volumes combined. The config’s actual location is now: /System/Volumes/Data/.Spotlight-V100/VolumeConfiguration.plist.
  • defaults no longer seems to work on VolumeConfiguration.plist. Instead, it now complains the domain does not exist.

PlistBuddy does still work, although it’s less elegant. Thankfully, there are some straightforward examples in the man pages that we can copy:

sudo /usr/libexec/PlistBuddy -c "Add :Exclusions: string /path/to/folder/" /System/Volumes/Data/.Spotlight-V100/VolumeConfiguration.plist

Once you’re done editing the ignore list, a restart of your computer should trigger Spotlight to detect the changes.1 You may also be able to trigger it by opening the Spotlight Privacy preferences, or just waiting around for the next index.

But… why?

In practice, I’m using this to automatically ignore dependency folders like node_modules in my dotfiles. Quite often, one package I’m working on depends on another, and it’s annoying for Spotlight and Alfred to display a packaged version instead of my development copy. Automating them away on all my machines makes life just a little bit easier.

  1. In previous versions of macOS, you could manually stop and start the “mds” process to trigger the changes, but that silently fails now that mds is considered a protected process. 

Stop Safari from Forcing HTTPS on Localhost

At my previous job, we ran one of our frontend services through an HTTPS proxy to ensure our development environment was as close to production as possible (cookie policies, content security warnings, etc). We also used an HSTS policy to direct browsers to only use the HTTPS version of our site. Unfortunately, when Safari picks up on this, it insists on redirecting all localhost requests to HTTPS.

Ideally, Safari would ignore those directives for special domains such as “localhost” or take the port number into account, but until it does, you can reset the HSTS settings by running these lines in Terminal:

sudo killall nsurlstoraged
rm -f ~/Library/Cookies/HSTS.plist
sudo launchctl start

Note that this shortcut will reset the HSTS settings for all websites. If you’re using a lot of open networks, where people could monitor your traffic, feel free to edit the file manually.

Creating a Background Gradient with SwiftUI

Creating a gradient background in SwiftUI follows a similar process to UIKit: create a set of colors, define a start and endpoint, create a view from that gradient, and then assign it as the background of another view. Thankfully, SwiftUI handles the view creation for you, so the resulting code ends up a lot neater.

For example, in UIKit:

let gradient = CAGradientLayer()
gradient.frame = view.bounds
gradient.colors = [UIColor.white.cgColor,]
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)

let gradientView = UIView()
gradientView.layer.insertSublayer(gradient, at: 0)
view.backgroundView = gradientView

And in SwiftUI:

        gradient: Gradient(colors: [Color.white,]),
        startPoint: .topLeading,
        endPoint: .bottomTrailing

Quickly Open the Current Tmuxinator Project

I got tired of manually typing the name of Tmuxinator projects every time I opened a folder, so I made a quick mux function that opens, edits, or deletes the Tmuxinator project named after the current folder.

It’s not the smartest function—it won’t work great if your folders are named the same—but hopefully it helps you out anyway.

function mux() {
  project=$(pwd | xargs basename)

  if [ "$*" = "" ]; then
    tmuxinator start "$project"
  elif [ "$*" = "edit" ]; then
    tmuxinator edit "$project"
  elif [ "$*" = "delete" ]; then
    tmuxinator delete "$project"
    tmuxinator "$*"


  • mux — starts the project
  • mux edit — creates/edits the project
  • mux delete — deletes the project

All other commands fall through to Tmuxinator.

UIRefreshControl Can Interrupt Scrolling

While implementing infinite scrolling in Get Seated, I ran into a strange side-effect of calling endRefreshing() on a UIRefreshControl that isn’t animating: if the user is scrolling the view, any velocity from the user’s “flick” will be lost and the view will immediately stop scrolling.

It’s easy to hit this glitch if you call endRefreshing() every time new data finishes downloading from your server. Thankfully, UIRefreshControl has a property to detect if it’s currently refreshing. Just verify it returns true before you try to end refreshing.

Swift 3

if self.refreshControl?.isRefreshing == true {

Swift 2

if self.refreshControl?.refreshing == true {

Experiencing Productivity

Shawn Blanc:

Is the stay-at-home dad who spends most of his day changing diapers and cleaning up messes any less productive than his wife who is the CEO of a charity organization?

Sometimes I feel the most productive when I’m doing non-work errands. If you’re trying to break a cycle of non-productivity, don’t forget there are plenty of productive things you can do that may not be directly related to your occupation.

Doing simple household chores can be a great warm-up to addressing bigger challenges. If that’s what gives you motivation and confidence, don’t feel guilty.