Kasper Grubbe

Read this first

Get attachments from .msg files using Ruby

A colleague had a lot of .msg and .msg.pst email files where they needed to extract the attachments from them, Ruby to the rescue!

I used the msg gem from https://github.com/aquasync/ruby-msg

I put all the files in a directory called emails/ and when the script is done running it will output the attachments to a directory named attachments/.

require 'bundler/inline'
gemfile do
  source 'https://rubygems.org'

   We're using a git reference here because https://github.com/aquasync/ruby-msg/issues/14 is 
   only fixed in master
  gem 'ruby-msg', github: 'aquasync/ruby-msg', ref: '34fb32e43e29b3d5fa535537faf7123a176146a8'

require 'mapi/msg'
require 'fileutils'

directory_path = 'attachments'
FileUtils.rm_rf(directory_path) if Dir.exist?('attachments')

Dir.glob(File.join('emails', '*.{msg,msg.pst}')).each_with_index do |msg_file, mindex|

Continue reading →

Enforcing host parameter usage for URLs in e-mail templates with Hamlcop

At Billetto we have multiple domains for our ticketing website depending on the market, as an example our danish organisation lives at billetto.dk and our swedish counterpart lives at billetto.se.

All of our organisations shares the same infrastructure and the domains routes to the same Ruby on Rails application.

This means that when we send e-mails to our event organisers and ticket buyers, and our e-mails include links back to our websites, we need to make sure that we use the correct domain.

Ruby on Rails have a setting that sets the default domain for links used in e-mails called config.action_mailer.default_url_options:

config.action_mailer.default_url_options = {host: "billetto.dk"}

And this is an example of a haml-template used in our mailers:

  = link_to("Link to order", order_url(id: @order.id))

This means that when host: isn’t set in the template, it defaults to...

Continue reading →

Logging on to WiFi automatically with Raspberry Pi OS (Debian Bookworm)

When I was looking at previous posts, they all seem be about older versions using wpa-supplicant, and it wouldn’t work for me.

I found out that newer distros seem to use NetworkManager to handle networking, and it requires a different setup.

It’s quite easy: Just plop a configuration file into /etc/NetworkManager/system-connections/kasperwifi.nmconnection, and update it matching your network:

uid=A0A43787-0132-44AF-97DC-9ABC92CBA46B  generate your own using uuidgen
autoconnect-retries=0  0 means keep autoconnecting

ssid=Kasper Guest




View →

Building Raspberry Pi images with Packer

I recently had to build a couple of Raspberry Pi images, I decided to try and set it up using Packer so the process was documented, version controlled and automatic.

I searched around for a bit, and found the project named packer-builder-arm by mkaczanowski.

Installing and running

The project is distributed through a Docker image, so it’s quite easy to get started:

$ docker run --rm --privileged -v /dev:/dev -v ${PWD}:/build mkaczanowski/packer-builder-arm:latest build install.json

The examples for the Packer code are a bit outdated inside the project, but for the newest version of Raspberry Pi OS (based on Debian Bookworm) this worked for me:

  "variables": {},
  "builders": [{
    "type": "arm",
    "file_urls" : ["https://downloads.raspberrypi.com/raspios_armhf/images/raspios_armhf-2023-10-10/2023-10-10-raspios-bookworm-armhf.img.xz"],
    "file_checksum_url" :

Continue reading →

Running and installing Ruby in parallel using Rbenv with flock and Buildkite

I am maintaining a few Docker-images that contains all supported versions of Ruby, and they also ship with Jemalloc.

Because I use Buildkite, it is very easy for me to test multiple versions at the same time, but they all run the same setup script:

echo "--- setup rbenv"
source ~/.bash_profile

echo "--- setup ruby"
rbenv local 2.7.7 || rbenv install 2.7.7 && rbenv local 2.7.7

echo "--- bundle setup"
gem query --silent --installed --exact bundler || gem install bundler

echo "--- tests"
ruby tools/test.rb 3.1

This fails for some reason when multiple agents of Buildkite run in parallel, I don’t know if Rbenv or Rubygems gives any guarantees for this sort of usage, but nevertheless it fails.

Instead of digging into the intricacies of Rbenv and Rubygems we could make sure that the code above are only being executed by one agent at a time, we can do this with flock:


Continue reading →

Optimizing bicycling routes with OpenStreetMap and APIs

(There’s a video version of this article available here, where we also do a deep dive into the code behind it, remember to turn on subtitles):

I’ve started playing with data from OpenStreetMap (OSM). It started with me trying to fetch all the places where I could get free water when moving around Copenhagen, which turned out to be a daunting task, because OSM seems to have a lot of different ways to categorise available water. I’ve identified the following tags to look out for:

Tag Documentation amenity=drinking_water https://wiki.openstreetmap.org/wiki/Tag:amenity%3Ddrinking_water man_made=water_tap https://wiki.openstreetmap.org/wiki/Tag:man_made%3Dwater_tap amenity=water_point https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dwater_point drinking_water=* https://wiki.openstreetmap.org/wiki/Key:drinking_water

Contributing back to OpenStreetMap

I soon became...

Continue reading →

How to use Haproxy redis-check with a password

It seems like option redis-check in Haproxy does not support Redis-databases that requires authentication as of 1.9.6 (newest version).

That means that if you want to check the health of password protected redis-servers, you would have to use a tcp-check, so you will have to modify your check like this:

listen redisserver
  bind *:6380
  mode tcp
  server redis_backend someredisserver:11020

  option redis-check


listen redisserver
  bind *:6380
  mode tcp
  server redis_backend someredisserver:11020

  option tcp-check
  tcp-check send AUTH\ aveeeeeryseeeecretpassword\r\n
  tcp-check expect string +OK
  tcp-check send PING\r\n
  tcp-check expect string +PONG

View →

Rick-rolling people looking for free WiFi using an inexpensive ESP8266-chip

(If you are here because you were tricked, you can throw some words my way on rickroll@kaspergrubbe.com or by sending a tweet to @kaspergrubbe)

I found a project on Github named mobile-rr, by a user called idolpx. His project includes a little wifi-chip that includes a piezo buzzer, and when people connect they are promised free wifi, but instead of getting access to the internet, they are shown a video of Rick Astley singing “Never gonna give you up”.

This is a so called Rickrolling prank, and if you have been living under a rock the past decade, the prank involves bait-and-switch where a link on a webpage promises to bring the user to some unrelated material, and bam! they are now listening to the tunes of Rick Astley and they can consider themselves rickrolled.

The original project only beeped when a person was tricked, and if you wanted to know the score, you had to connect to...

Continue reading →

Protecting services with client certificates using Haproxy

What we want to achieve

We want to be able to connect to services inside a private network using client certificates, in this example we will be connecting to Redis.


Install or compile Haproxy

I am using Debian, so this is what I use to compile Haproxy for testing out this setup.

apt-get -y install make gcc g++ libssl-dev

wget http://www.haproxy.org/download/1.8/src/haproxy-1.8.4.tar.gz
tar xzf haproxy-1.8.4.tar.gz
cd haproxy-1.8.4
make TARGET=generic USE_OPENSSL=1
make install PREFIX=/usr/local

Install and configure firewall

I am testing with a Redis-server, but it can be anything. First firewall off everything except for port 22 (ssh) and port 88 (our external redis port):

apt-get -y install ufw

ufw default deny incoming
ufw default allow outgoing
ufw allow 22
ufw allow 88

Install Redis

apt-get -y install redis-server

Since Debian and Debian-related distros have the...

Continue reading →

How to backup your Betaflight configuration between upgrades

Sometimes you will need to upgrade the Betaflight firmware on your quadcopter, normally this process wipes all your settings, and you will have to fill all of them in again.

  • You can use diff in the Betaflight CLI to see which changes you have made that differs from the default settings.
  • diff all includes all 3 PID profiles.
  • You can then take the output and save it into a text-file
  • Upgrade the firmware.
  • Paste the settings from you textfile into the CLI again, type save.
  • Please read the changelog, maybe something have changed!
  • Go fly, have fun!

View →