Tackd - Anonymous File Transfer
Frequently, I find myself needing to transfer files from my laptop or server, over to my personal phone or to other family-member's devices. More than likely, I am unable to simply email or scp a file over to these devices. The files are usually just too large for email transfer. Thus, I have been working on a little rust API that accepts binary data, encrypts said data, then persists the metadata in a MongoDB replicaset, and the binary data in object storage.
The application I created is available at tackd.io, and is written in Rust. The code is hosted on Google Cloud Run, built via Continuous Deployment, utilizes Google Cloud Storage, and connects to an MongoDB Atlas replicaset in which to persist metadata.
How it works
Tackd is an encrypted message service API, which enables parties to anonymously and security transmit and receive data via a RESTful API.
Tackd encrypts payloads with the XChaCha20Poly1305 cipher upon receipt. Indexing data is then persisted in the backing MongoDB database, with the encrypted data stored in Cloud Storage. The encryption key is then returned to the sender, with the key not persisted by Tackd. Data retrieval is possible by any client with the required decryption key. Senders can also include an optional password, which is hashed by Tackd, and required for data retrieval.
When posting files, Tackd accepts a couple of TTL options for data expiration. Senders can either set a max number of reads for a file, or a max lifetime in seconds. The default TTL's are one read, with a max lifetime of one hour. Max lifetimes are capped at one month, and if only the max lifetime if overridden by the sender, then max reads will be set to infinity, or -1.
These parameters are overridden with expires
and reads
query flags. Below are some scenarios when uploading files:
Sender Max Reads | Sender Max Lifetime | Tackd.io Max Reads | Tackd.io Max Lifetime |
---|---|---|---|
N/A | N/A | 1 | 3600 seconds |
10 | N/A | 10 | 3600 seconds |
N/A | 10000 | -1 (inf) | 10000 seconds |
10 | 10000 | 10 | 10000 seconds |
Data Encryption
Since tackd is deployed via lightweight containers, speed of decryption is of utter importance. Therefore, I decided to use the XChaCha20Poly1305 stream cipher to handle the encryption of data. This cipher is much faster than AES, and is simpler to implement, and costs less CPU. A random encryption key is generated when data is pushed to tackd, and is returned to the sender after the encrypted data has been persisted in storage. This key is not persisted by tackd.
Optionally, the sender can also include a required password to unlock the payload. The password is not persisted in plaintext, as only password hash is saved in the metadata database.
Tackd handles the encryption server-side, as the primary use case I imagined when building this service was to handle data uploads via curl, which doesn't have client-side encryption capabilities. However, since tackd treats all data being uploaded as raw binary data, the data can simply be encrypted client side before upload to tackd. The client's encryption key is then required for decryption, as well as tackd's encryption key.
API Resources
Base URL
All API calls should be directed to either a locally running instance, or to the public https://tackd.io
server.
Upload
Upload a file to Tackd.io
POST /upload
Path Parameters
None
Query Parameters
Attribute | Type | Requirement | Notes |
---|---|---|---|
expires | int | optional | Set data expiration time in seconds |
reads | int | optional | Set maximum number of reads for data |
pwd | string | optional | Lock data with additional password |
filename | string | optional | Specify filename for upload |
Response Codes
Type | Code | Notes |
---|---|---|
Success | 200 | Returns json object |
Error | 500 | Internal server error |
Sample Response
{
"message": "Saved",
"url": "https://tackd.io/download/d2e1152b-ef91-4e4a-834c-62c41a4278e9?key=ldR9aQY5pBZThQtgsvb0YqK9xmerCBN0",
"data": {
"id": "d2e1152b-ef91-4e4a-834c-62c41a4278e9",
"key": "ldR9aQY5pBZThQtgsvb0YqK9xmerCBN0",
"expires in": 3600,
"max reads": 1
}
}
File Retrieval
Download a file from Tackd.io
GET /download/{id}
Path Parameters
Attribute | Type | Requirement | Notes |
---|---|---|---|
id | string | required | Specify data id or file to download |
Query Parameters
Attribute | Type | Requirement | Notes |
---|---|---|---|
id | string | optional | ID to get, use if filename is passed in path |
key | string | required | Decryption key |
pwd | string | optional | Unlock data with password |
Response Codes
Type | Code | Notes |
---|---|---|
Success | 200 | Returns binary data |
Error | 401 | Not Found |
Error | 500 | Internal server error |