Programming: Mostly A Hate Story
I wanted to do digital signatures validation, preferably ed25519, inside PostgreSQL triggers. Here is how it went:
pgcrypto must be supporting it, right? Most Postgres cloud hosting providers already support pgcrypto so this would be perfect. Right?
Well, pgcrypto only supports PGP and that too excludes digital signatures. Let's give PGP a try anyway and see how far can we go.
gpg to generate the keys and the experience is less than pleasant. Sometimes it gets stuck at the passphrase prompt. The keys are too big, but still I can make pgcrypto's
pgp_pub_decrypt methods work. Just remeber to convert keys in ASCII to binary and vice-versa using
dearmor(). I hate the big key size in RSA, even though GPG defaults to 2048-bit keys and not the more secure 4096-bit ones. Let's look into ed25519 now.
No problem, Postgres supports PL/Python and PL/v8 so it should be easy to code these functions quickly using existing libraries. Turns out, no cloud hosting provider actually supports PL/Python because it doesn't have sandboxing and is therefore an "untrusted" extension. I'd really like to avoid running my own database server so let's give up on PL/Python and check out PL/v8 instead.
Found TweetNaCl.js (https://tweetnacl.js.org/) which implements ed25519. But since PL/v8 is sandboxed, I can't just
require an NPM module within a PostgreSQL function. Thankfully, someone on the Web (https://rymc.io/2016/03/22/a-deep-dive-into-plv8/) figured out how to cobble together a module system for PLv8, compatible with NPM. You, sir, are a life-saver!
Coded up the wrapper methods but it fails due to Uint8Array being not supported. What's going on?
Turns out, the version of PLv8 shipping everywhere (Ubuntu, Mac, AWS, Heroku) is an outdated one which doesn't support Uint8Arrays which libraries like TweetNaCl.js need. Google's CloudSQL doesn't even offer PL/v8 in the first place. Even Debian's seems to be an unmaintained one.
Found some custom libv8 PPA for Ubuntu which has an updated version. Oops.. it's not really meant as a replacement for system V8 and actually goes in /opt instead of /usr/include. Would be too much effort to build PLv8 with this.
Tried compiling V8 on my own, but no, Google has started using this fancy build system called GN which doesn't quite work on my machine. After 30 minutes of downloading and compiling this big project, I am left with one error message where googling isn't of much help. Their issue-tracker feels very crowded and no hope that somebody will actually respond. Idea: I will just use the V8 that ships with NodeJS!
No dice, as they have stopped exposing their internal dependency. Gaah.. PL/V8 seems to be a dead-end. Let me go back to PL/Python. Hmm.. I will have to run my own Postgres. Let me spin up an instance on Linode.
Wow, can't use Linode site with uBlock enabled. Giving them a chance by disabling it. But damn.. not able to ping or connect to the machine. No problem, let me check out Hetzner. I hear they have dropped their prices recently!
Oh, they want to see a picture of my ID proof and credit card. Fuck that shit! Let me try Docker then! Some guy on the Internet has a Dockerfile which includes PL/Python. I will just modify the Dockerfile, include
pip install ed25519, and publish on DockerHub so that I can deploy it on Hyper.sh.
Hyper.sh offers a Postgres dockerfile but has no documentation on how to actually access it. What's the hostname or credentials? Spend some time in their docs.
hyper info doesn't help much. Oh, I'm supposed to attach a floating IP to the container. Screw it.. let me first make the whole thing work in Docker running locally.
Oops, Docker doesn't let me just publish the modified Dockerfile. It wants me to build the image locally and THEN push to Hub. Fine. I'll set up Docker locally. Wow, this thing takes a long time to start up!
Changed the Dockerfile and running
docker build. Took me a while to figure out how to reset postgres password via environment variables and exposing the port outside so that I can access via
psql. I can create extension and define wrapper methods now. Wait, need to double check how to correctly map return types from Python code to PL/sql. I can generate the keypair, but loading a SigningKey gives
AssertionError. Let me compare with Postgres.app.
Oh it works fine in my local Postgres install. What's going on? Wait.. I have Python 2.7 on my machine but the Docker container is using Python 3. Also, I mistakenly used
pip instead of
pip3. Wait, it looks like ed25519 install requires "Python.h" but then why didn't I see an error? Anyway, let me include
python-dev in Dockerfile. Or should it be
FUCK. THIS. SHIT. I'm going to bed.