Passport Hacking

The passport system in Sweden collapsed earlier this year when pandemic travel restrictions lifted and half the country tried to renew their passports at once. In March I tried to book an appointment to get passports for the kids so they could visit their extended family for the first time. The date I got was in October.

Waiting room with fluorescent lights and an LED sign showing current queue positions. Wooden benches in the foreground. Behind them are several booths with curtains around them for taking flash photos inside.
In Sweden you have to go to one of these special offices where a cop literally watches you pose for your passport photo.

Pass für alle

By May the crisis was so bad that Pass für alle went viral. This was a bit of JavaScript that could automatically refresh the passport booking page and grab earlier slots.

It helped a few Stockholm people I knew get a better appointment, but it wasn't working for me down in Skåne. In Stockholm there was more of everything: more passport offices, more cancellations, more new booking slots available. In Skåne there was less activity, so the script needed to run longer to get results. And there's only one passport office per town here, so the logistics are more complicated.

I really wanted to get the kids to the UK during the summer if possible so that we wouldn't spend the whole trip indoors. So I set about building my own Skåne-friendly version of Pass für alle.

Beep boop

The first thing I did was make it beep. Skåne's slower pace meant it wasn't practical to sit and watch the screen. The beeping meant the laptop could be across the room and I'd know how it was going without looking.

Beep beep

First up: some constant high pitched beeping.

setInterval(() => {
  sfx(pow2(9), "triangle", pow2(8))
}, pow2(10))
setInterval(() => {
  sfx(pow2(9), "triangle", pow2(8))
}, pow2(11))
Beep beep

That made for a nice loud heartbeat so that the sudden silence would be noticeable if anything broke and it stopped running. It's quite a high-pitched and annoying sound, but it had to compete with the noise from two small kids.

Boop boooooop

The most common thing to happen after reloading the page was for no appointments to be found. This needed a noise too.

sfx(20, "square", 500)
  .then(() => wait(10))
  .then(() => sfx(40, "square", 4000))
Boop booooop.

I kept the pitch low for this one. The script failed like 99.99% of the time so this didn't need a lot of attention. Plus from a musical perspective it combined quite nicely with the high pitch of the page load heartbeat like this.

Beep beep boop

Sometimes there would be an appointment a few towns away. As long as it was late enough to get there in time by train this was great news! A nice high pitched alert sound announced this scenario.

sfx(600, "sawtooth", 400)
  .then(() => wait(10))
  .then(() => sfx(400, "sawtooth", 420))
  .then(() => wait(10))
  .then(() => sfx(200, "sawtooth", 440))
Beep beep boop.

Boop boop beep

The best case scenario was an appointment here in Malmö. A triumphant little chirp was the sound for this.

sfx(400, "triangle", 500)
  .then(() => wait(10))
  .then(() => sfx(500, "triangle", 220))
  .then(() => wait(10))
  .then(() => sfx(600, "triangle", 240))
Boop boop beep!

The finished product

If you're interested, you can read the full source code. For a few days I ran that for several hours at a time. Here's a little ten second taste of that experience.

The secret ingredient is violence.

Climactic Ending

Around about the same time as I got this running, the police increased their capacity and added a bunch of new times. The instant they did that I got a next-day booking the old fashioned way. lol.