André Borie

Freelance Python & Django developer based in London.

Read this first

You don’t need a single-page application

I am really annoyed by the recent trend of making every single website a single-page application even when it is not necessary and makes the product worse. Let’s take the example of the Reddit redesign and see why I think it’s a horrible idea, and then go over a few other websites with the same problem. We’ll ignore the user-hostile design decisions like explicitly degrading functionality and advertising the mobile app, and focus purely on the technical aspects (the user-hostility is a rant for another day).

The “new” Reddit

First let’s take some measurements. This will be done on latest Safari on macOS Mojave with all add-ons (ad blockers, etc) disabled to make sure the website is rendered as the developers intended without any interference. The pages were first loaded to populate any caches and the graphs were taken on the second page load (so most of the assets should be cached).

Screenshot 2019-12-12 at 11.38.40.png


Continue reading →

Blockchains for non-cryptocurrency applications don’t make sense

There’s a lot of hype going around about blockchains and pretty much everyone is attempting to put something (including physical assets) on the blockchain. However, most of these use-cases don’t make sense to me and I’d like to explain why.

Blockchains work for cryptocurrencies because the blockchain is the sole source of truth that proves whether you’re holding the asset. If the blockchain says you (or rather your private key) is entitled to a million coins, then you are indeed a millionnaire, because whoever wants to buy your coins (in exchange for some other asset/good/service) will consult the blockchain to validate that you indeed have those coins and that you transferred it to them during the trade. Later on, when they want to spend those coins, the recipient will in turn consult the blockchain to check whether they’ve been paid.

This breaks down horribly when dealing with...

Continue reading →

Thoughts on the Apple Card & credit cards in general

I’d like to share some thoughts on the newly announced Apple Card, Apple’s attempt at breaking into the consumer finance market, why I do not think it’s as revolutionary as it claims to be, how I believe they could’ve truly revolutionised consumer banking and also some doubts on whether this will take off in non-US markets.

Apple’s innovation and unique selling point seems to be the lack of “over limit” and late payment fees coupled with a modern app and some privacy features which I believe to be marketing fluff. While this is a step in the right direction, I feel the whole idea of a credit card is flawed in today’s day and age, and we can do better if we truly want to disrupt the market.

The purpose of a credit card is to give the cardholder instant access to a pre-approved loan. The fact it’s done through a card is just an implementation detail (which made sense back in the day) but...

Continue reading →

Storing OAuth credentials in Django models

A common requirement for my Django apps is to interact with third-party APIs on behalf of its users, most of which use OAuth for authentication. I now realise Python Social Auth is a solution but I wasn’t aware of it at the time. In any case, here’s my approach in case the aforementioned package doesn’t fit your needs.

My apps use Requests OAuthlib which provides a Requests Session object that does the OAuth magic behind the scenes.



This will store the access & refresh tokens as well as their metadata (expiry, etc), and have the static parameters such as client ID, client secret, on it as attributes.

class BaseOAuthModel(models.Model):
    class Meta:
        abstract = True

    refresh_token = models.TextField()
    access_token = models.TextField()
    expires_at = models.DateTimeField()
    token_type = models.TextField()

    objects =

Continue reading →

Working around iOS’ location services permissions

iOS has a pretty good permission system that gives the user granular control on what personal data apps can access - things like location, contacts, calendars, pictures, etc. As far as I know, these permissions are bulletproof - there are no vulnerabilities there per se.

However, there are ways in which apps can work around them and still get access to things they shouldn’t. I feel like there’s a lack of awareness about this and the current permissions UI is dangerously flawed.

Location services and photos

The native Camera app (and presumably third-party ones*) allows you to geo-tag your pictures with the location they were taken at. The idea sounds great in theory, and there isn’t much to be concerned about - your camera app is trusted, right?

The issue is, every single photo you’ve now taken has location attached which over time would give an attacker a pretty good idea of your...

Continue reading →

Using a GnuPG smart card, Yubikey/NitroKey for SSH on Mac

Install GnuPG and a decent PIN entry program

$ brew install gnupg2 pinentry-mac

Configure GnuPG

We’ll need to tell GnuPG to use the new PIN entry program as well as enable SSH support for its agent.

In ~/.gnupg/gpg-agent.conf:

pinentry-program /usr/local/bin/pinentry-mac

Start the agent on startup

GnuPG has its own mechanism to start the agent the first time you use it, so explicitly starting the agent is no longer necessary. SSH however does not support this mechanism, so if we want to use the GPG agent as an SSH agent we’ll need to make sure it’s always running. A quick change to your shell’s startup scripts (~/.zshrc.local in my case) takes care of that.

We’re exporting the location of the SSH agent socket and then checking whether a valid UNIX socket is in that path. If the check is false we launch the GPG-agent. Note that gpgconf is smart enough to not...

Continue reading →

Three phone number leakage vulnerability

TLDR: a vulnerability in the Three network allows any app on your phone to get your mobile number without your consent - switch to the 3internet APN to defend against this.

Today I noticed a quite worrying vulnerability that would allow any app (and potentially any website, provided they break the same-origin policy) to secretly find out your Three mobile number - the privacy implications of this are obvious - an advertiser could thus track you across all apps even if you delete and reinstall the app, and they could also secretly resell that information to data brokers.

It’s been more than a month since I did my best to privately report it to them (and the ICO) without any success, so here’s the vulnerability in all its glory:

Open that URL on any Three phone and you’ll get a (badly formatted) XML...

Continue reading →

Setting an alternative shell in macOS Terminal

After switching to Zsh on my new Mac I noticed a little issue with the built-in Terminal. When using the default Bash shell, the app could tell whether a process (besides the shell) was running in it and present a confirmation if you tried to close the window:

Screen Shot 2017-06-27 at 02.05.42.png

Do you want to terminate running processes in this window?

Switching to Zsh made the terminal think the shell itself was a running process I cared about and would ask me for confirmation even if nothing else but the shell was running, where as with Bash it would ignore the shell itself and only ask if something else was running.

At first I thought macOS shipped with a special version of Bash that could tell the terminal whether something else was running in it, but it turns out the solution is simple - there’s a list of processes for which the Terminal would not display a confirmation, and you can configure it:

Screen Shot 2017-09-24 at 00.39.15.png

Just add...

Continue reading →

Strongswan VPN for iOS quick-start guide

Here’s a really basic Strongswan configuration for a single client, authenticated using a PSK. This has been successfully tested with iOS 10 but should work on any other decent OS. It can be useful to secure traffic from public Wi-Fi or a compromised/evil mobile carrier.


Compile and install Strongswan with swanctl support, as most distros’ packages don’t yet have that feature enabled.


Save the following as /etc/swanctl/swanctl.conf and adjust it according to your setup. Don’t forget to set a secret PSK.

connections {
    myconn {
        unique = replace
        pools = v4pool, v6pool
        local {
            id =  server's ID, corresponds to "remote ID" on iOS
            auth = psk
        remote {
            id =  client's ID, corresponds to "local ID" on iOS
            auth = psk

Continue reading →

Windows code-signing in 5 minutes or less

Note: this might be unsafe - only use this as a quick reference if you know what you’re doing.

Create the self-signed certificate


Save this into ssl.cfg or similar.


distinguished_name = req_distinguished_name
req_extensions = default_req_extensions



basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, nonRepudiation
extendedKeyUsage = critical, codeSigning, msCodeInd, msCodeCom

Make the certificate and private key

ssl.cfg refers to the file created above. Adjust the subject as necessary.

openssl req -x509 -newkey rsa -keyout testkey.pem -nodes -days 3650 -sha256 -config ssl.cfg -subj "//CN=Demo code-signing certificate" -out testcert.pem

You can get OpenSSL in either Git for Windows or Cmder.

Create a PFX and import it into your personal certificate store

openssl pkcs12 -export -inkey

Continue reading →