home

Building Fuse Filesystem on Discord for Fun and Profit

My “important backups” folder was getting full. We’re talking gigabytes of anime girl pictures, and my hard drive was starting to sound like it was about to throw a read error and die.

It’s too easy to buy a new drive. I’m also too paranoid to just dump my stuff onto a regular cloud provider. But mostly, the idea of building something this pointless was just too funny to ignore.

So I looked at the one place that has, basically, unlimited free media storage: Discord.

The plan was to build a FUSE (Filesystem in Userspace) driver. This would let me mount a Discord channel as a real folder on my Linux machine. The real goal, though, was to make sure every file I uploaded was encrypted, so Discord (or anyone else) couldn’t see what was in them.


disk usage of 100% with 0 available

i had to improvise a little, because I don’t have any screens from old pc

Getting it working

The whole idea hangs on the fact that Discord lets you upload files, and they just… stay there. The big problem is the 8 MB attachment limit (since I’m not paying for Nitro anytime soon). I couldn’t just upload a 200 MB file.

This meant I had two problems to solve:

  1. Chunking: I had to split every single file into 8 MB (or slightly less) pieces.
  2. Metadata: If one file is now 25 different attachments, how do I find them? What about directories, filenames, and timestamps?

I had to build my own filesystem index from scratch. I called it simply Index.Manager (which you can see in the GitHub repo). It’s just a big javascript object that keeps track of “inodes”—files, directories, and all their info.

Oh yeah, I initially tried storing the index in the channel topic because I thought I was being clever. Discord has a 1024 character limit. My index was like 50KB. Took me an embarrassingly long time to figure out why it wasn’t working.

My solution for this was simple. I use two separate channels:

  • databaseChannel: This channel is only for metadata. It has one “master” message. That message’s attachment is the entire Index.Manager object, stringified to JSON and then encrypted. Every time I change a file, I have to download, decrypt, update, re-encrypt, and re-upload this one file. It’s shitty, but hey, it works.
  • filesChannel: This is just the data dump. It’s a huge, messy channel full of thousands of encrypted 8 MB chunks.

When you try to read shiroko.webp, the driver first grabs the encrypted index from the databaseChannel, decrypts it, finds the entry for shiroko.webp, gets the list of attachment IDs, and then starts downloading all 25 chunks from the filesChannel one by one.

It’s as slow as you’d imagine.


diagram shows the Driver orchestrating the entire process by querying the Database Channel for metadata and the Images Channel for file data to serve the user's request.

more or less

Incognito Mode

The encryption was a must-have. I’m no crypto expert, but I can read the node-crypto docs easy. I added a simple Encryption class that uses aes-256-cbc to encrypt every chunk (and the index file) before it ever leaves my machine.

Works.

So, does it work?

Yeah, it actually does. I can mount the directory. I can ls, cat, and cp files into it. The FUSE driver (you can see the Fuse.Driver in the code) handles all the chunking, encrypting, and uploading in the background.

Is it a good idea? Nah.

  • It’s slow. Really slow. Reading a big file means downloading dozens of attachments. Writing a file is even worse, since it has to upload all the new chunks and re-upload the entire database file.
  • Every file operation is just a whole lot of API calls. I put in a basic ratelimitWatchDog to try and avoid getting dunked on, but it’s a flimsy defense at best.
  • II am 99.9% sure this is against the Discord ToS. I’m using a separate account for this, but honestly just waiting for the ban hammer.

I should probably mention the absolute nightmare of debugging buffer concatenation. Spent like 3 hours wondering why every file I read back was corrupted garbage. Turns out I was concatenating the chunk buffers wrong and occasionally dropping bytes at the boundaries. Certified Classic™.

comments powered by Disqus