Skip to content

Instantly share code, notes, and snippets.

@nileshtrivedi
Last active December 8, 2020 08:25
Show Gist options
  • Save nileshtrivedi/7cd622d4d521986593bff81bfa1e5893 to your computer and use it in GitHub Desktop.
Save nileshtrivedi/7cd622d4d521986593bff81bfa1e5893 to your computer and use it in GitHub Desktop.
Programming: Mostly A Hate Story

Programming: Mostly A Hate Story

I wanted to do digital signatures validation, preferably ed25519, inside PostgreSQL triggers. Here is how it went:

Surely 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.

Installed 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_encrypt and pgp_pub_decrypt methods work. Just remeber to convert keys in ASCII to binary and vice-versa using armor()/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 python3-dev...

FUCK. THIS. SHIT. I'm going to bed.

@dmuth
Copy link

dmuth commented Jan 24, 2019

Oh man, I can relate. That's one reason why I started using a Docker for a lot of my development as of several months ago. Once you get over the initial hump of things like "use environment variables to configure Docker services" and "gotta use pip3 instead of pip for Python 3", you'll find that it becomes much easier. I'm pretty much at the point of using Docker for all of my production work at this point.

So try to stick with Docker (and you'll also want to learn Docker Compose, because it's easier than using --link between two containers) and you should have an easier time with challenges like these.

Feel free to hit me up with any Docker questions, BTW. I'm a pretty big fan of it. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment