Directed Acyclic (Social Network) Graphs

I (begrudgingly) still have an Instagram account. You’d never know that unless you’re on Instagram, though. I (happily) have a personal website (in fact, if you’re reading this, you’re probably on it right now)! You would know that if you were to view my Instagram account. This is not an accident. As you may or may not be aware, both Instagram and this website exist as part of the world wide web, a collection of documents and resources connected by hyperlinks (or just links, as we refer to them in this century as) embedded within them. Links are one-way streets; much like Wikipedia, once you’ve gone down the rabbit hole, there’s no coming back. The only reason you can go back and forth across links in a browser is because it keeps track of the ones you’ve followed and order in which you’ve done so in its history. This information isn’t encoded anywhere in the link itself.

Since the emergence of Google and its PageRank algorithm, links have become the currency of the internet. Over the past two decades, this expression has taken on greater meaning. The proliferation of affiliate links primarily by Amazon meant that site owners could convert the Internet’s currency could be converted into fiat currency, though don’t kid yourself into believing that the anyone benefits anywhere near as much as Amazon does. In the past decade, the rise of social media sites has been propelled in part by leveraging the fundamental property of links that we observed earlier to create walled gardens; platforms that are easy to move to, but hard, if not impossible, to leave from.

While certainly not the only one, Instagram is the poster child of this behavior. Try to share a link on Instagram, to construct a gateway out of their realm, I’ll wait. As of time of writing, there’s only one way that I know of, which is to use the one link field that’s available in your bio. Naturally, any profile or post can be shared easily via a link. It wasn’t always like this, of course. Instagram leverages its position as one of the most popular social media sites on the web to force their users’ hands. “What are you going to do? Not use Instagram?” (That’s probably the answer, in all fairness.)

This brings us to the apex question of, “Why?” Why do platforms seek to cordon off their users? Why should you, as a user, care? Again if you’re reading this site, you’re probably aware that social media sites want your attention so they can serve you ads for which they’re paid handsomely, considering how little concrete evidence there is of the efficacy of online advertising in general. Of course, these sites are desperate to improve their numbers, if even by fractions of percentage points. They have also demonstrated countless times over that they have absolutely no respect for you or your privacy, and it’s much easier to track your every online movement to be analyzed for any shred of information about you to be shared with advertisers from the comfort of their own platform. This is, at best, only to the benefit of the platform owners. At worst (and more realistically), it is to the user’s detriment for a number of reasons.

Principally, this kind of “siloing” of information is antithetical to the very nature of the internet, which is meant for sharing between all who participate in it. Practically, users are primarily on these platforms to consume "content". Of course, many of these platforms can offer more content than any user could ever consume, and more importantly don’t care to consume, so the platform will try to select and present what it believes the user will be most likely “to engage with.” In $CURRENT_YEAR, this is achieved through black boxes colloquially referred to as “algorithms.” The user is unable to know exactly why a given piece of content, an article, a video, etc, was presented to them. In more and more cases, the platforms are unable to explain even to themselves how these algorithms come to a conclusion given a set of parameters. This is dangerous for users, and frankly society to greater extent as well.

Every recommendation system, search engine, and the like suffer from bias, an inclination or opinion. To be clear, that’s not inherently bad. It would be impossible to suggest one thing over another without having some criteria to base that decision upon, and because the notion of “better” is ultimately a subjective one, rather than an objective one, it is a bias. These biases becomes bad when they become hidden from users of such a system, as there’s a very good chance that at least some of the biases are again, at best, indifferent to them, and at worst, actively harmful towards them. Many of the ostensible foundations of society (at least in the parts of the world I’ve lived), such as democracy and free markets, are predicated on its members being informed and rational actors. Paradoxically, we live in a time where the people of these societies have access to more information than ever before, yet the “end of history” has been in the rear-view mirror for most of my life. Clearly at least one of our assumptions is wrong. I’d argue that the idea that people today have the ability to be informed in such a way as to make decisions in their best interests rationally is wrong and that most of us are no better than our counterparts were a century ago. Ironically, the tools with the greatest chance of correcting this problem are currently being used to perpetuate it at a scale never before seen in history.

In conclusion, before sharing a link, one should ask themselves where they’re sending others. Understand that, in principle, wherever you send them, they can’t come back. Are you leading them down a dead end? Or worse, into a walled garden? Or are you sending them off to just another node on the graph, rife with opportunity to explore more links to meaningful and enriching information? I’ve always had links to this site on my other presences on the web, such as social media, and I used to have links back to those social media platforms on this site. Given the direction we’ve been heading in, I think that’s for the best.


Rust2018 and the Great CLI Awakening

From Rust2018 and the Great CLI Awakening by Vitiral:

spoiler: simultaniously[sic] refreshing and painful

Rust is a fantastic language for writing a Command Line Application (CLI). For the ergonomics of hacking, it has one of the best argument parsers ever, has seriously the best serialization library ever and it compiles to almost any target and goes fast when it runs.

I had a very similar experience rewriting tcc in Rust. The first iteration was written in JavaScript, and was essentially just a wrapper around the Node title-case package using oclif. In my defence, it took (no exaggeration) fifteen minutes to make, however running it felt like it took fifteen minutes to complete (slight exaggeration). I’ve been intrigued by Rust since I first heard about it a few years ago, and have been following its development at a distance. I’ve never felt that I had a good excuse to try it though, until I finally got fed up with tcc 1.0’s performance and took the plunge. I recently saw a fantastic list of excellent resources for learning Rust, and can’t wait to find out all of the anti-patterns I stumbled into in the development of tcc's second iteration.


New Year, New Password Manager, Part Deux

Back during the Before Times™, I set out on a quest to free my passwords and various other credentials from the walled garden of the Apple ecosystem, and was fairly satisfied with my first attempt at a solution. Six months later, and, well, you can probably guess by the fact that you’re reading this that things were not so peachy, and you’d be right. So what went wrong? A few minor quibbles here and there, with one annoyance substantial enough to drive me back to the drawing board: That pandora’s box we all unwittingly unleash upon ourselves the moment we find ourselves with more than one device: synchronization.

In my first post about KeePass, I naïvely hand-waved away the problem of synchronization onto the clients, blissfully unaware of how ill-equipped many were to the task. The principle problem, I believe, lies in the fact that KeePass stores everything in a single binary file. A change to one password affects every password, from the perspective from a client. While backing up one’s database is as simple as copying a file, there was nonetheless much apprehension whenever a sync was required. So, back at the drawing board, I’ve added a requirement of easy conflict resolution. Reviewing my list of available options, I eased my requirement of widespread availability, and settled on pass, "the standard unix password manager".

pass is made with the Unix philosophy in mind; it does one thing, and it does it well, namely retrieving passwords and orchestrating other tools to save (any editor you’d like), encrypt (gpg) passwords in a versioned (git) repository. Oh, and passwords are saved as individual files, because everything is a file. With version control being handled by git, I think it’s safe to say that the “easy conflict resolution” box can be checked.

Synchronization across devices works in a similar fashion to multiple persons collaborating on a project with Git; each device holds a local copy of the password store, pushing and pulling updates to and from one another. For simplicities sake, I’ve opted to establish a central repository hosted on a private server using NGINX.

Providing Password Protection

Although our passwords are individually encrypted, it’s probably still a good idea to password-protect the repository endpoint on the server. There are a variety of ways this can be accomplished; one of the simplest being with htpasswd. Add a user like so (you may omit the -c flag if a credential file already exists):

htpasswd -c /etc/nginx/.htpasswd

Serving the Password Store

Serving a Git repository with NGINX is relatively straight-forward. We can simply pass any requests to git-http-backend via FastCGI. Like password protection, it’s probably a good idea to secure the endpoint with SSL as well. Thankfully, this can be achieved with virtually no effort thanks to Let’s Encrypt. I’ll leave that part of the process as an exercise for the reader.

server {
listen 443 ssl;
root /var/www/pass;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
access_log /var/log/nginx/pass.access.log;
error_log /var/log/nginx/pass.error.log;
auth_basic "Authentication required";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
client_max_body_size 0; # git pushes can be massive, make sure nginx doesn't abruptly cut the connection
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
fastcgi_param GIT_HTTP_EXPORT_ALL "";
fastcgi_param GIT_PROJECT_ROOT /var/www/pass; # directory containing repositories
fastcgi_param PATH_INFO $uri;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_pass unix:/var/run/fcgiwrap.socket; # pass the request to fastcgi

Tug of War

Git relies on the concepts of “pushing” and “pulling” to update others and receive updates from others, respectively. Unfortunately, these are manual processes. We can automate pushing though, through the use of commit hooks, as pass automatically commits changes. Hooks are simply executables, such as a bash script, that are run by git at various stages of the commit process. For our purposes of automatically pushing updates, we can use a post-commit hook. To do so, add an executable file to /path/to/your/.password-store/.git/hooks/post-commit containing the following:

git push origin master

Automating pulling updates is a little more tricky. Perhaps a hook could be written to regularly run git pull, or some solution using push notifications from the server could be architected. I’ll leave this as an exercise to the reader or my future self.

Déjà-vu All Over Again

Because I like the idea of symmetry with the first post, here’s a list of clients I’m currently using:

  • pass, obviously.

  • passff, a Firefox addon for web integration.

  • Pass, an iOS client.


I’m excited to be continuing taking steps towards a more private, personal infrastructure for my data. In particular, pass, with its philosophy of being a focused, composable application, represents freedom not only for my data, but for my workflow and the tools supporting it.