A one time secret app is a tool for sending sensitive information to people. The tool ensures that the secret can only be viewed one time and will expire after a certain amount of time if not read. The tool takes a secret and a passphrase from one user and stores that secret in the database. A user trying to access this secret will need the passphrase as well as the unique ID that is generated by the API to retrieve the passphrase. Once the secret is read it is removed from the database. If a user doesn’t read the secret within a given period of time (7 days by default) the system will automatically purge the secret from the database.
Python API - https://github.com/do-community/python-ots-api
React Frontend - https://github.com/do-community/one-time-secret-frontend
BSD 3 Clause
(What made you decide to build this particular app? What inspired you?)
This app was inspired by a similar app that I had used in college when resetting people’s passwords for them. I realized that the use case for being able to send a secret once is very valuable so I decided to build an app to do just that.
(How did you utilize DigitalOcean’s App Platform? Did you learn something new along the way? Pick up a new skill?)
The API uses DigitalOcean’s App Platform to deploy the service but also uses the Database as a Service offering to provide us with managed Redis for our database.
The API is built using the Flask Web Framework (Python) connected to a Redis database. This API has only two calls, one for creating the secret and one for reading the secret. Flask was a good choice for this application as it needs no login, is relatively small, and interacts with Redis. My litmus test for “Should I use Flask or Django” boils down to “Do I need authentication? Do I need a database?” If I say yes to either of those two I tend to use Django. While this app does need a database, all we need to store is the passphrase and a secret associated with it. This is a perfect use case for using Redis as a key value store. Using the
cryptography library I was able to create an encryption key based off of the passphrase for the secret that is sent. I then take the hash of this passphrase and use that as the key for the encrypted text in the Redis database. This way if the database were to be compromised the data would be relatively safe. Since hashes are a one way function it is highly improbable that someone could get the passphrase out of the key and use it to decrypt the message. The API also generates a UUID for each message so a passphrase can be used by multiple people and not have collisions. As for the expiration time Redis already has us covered. I can set the expiration time when I add the secret to the database and Redis will handle the deletion for me. No extra code needed!
So when a user is ready to retrieve their secret they pass in the ID and the passphrase to the API. The API then hashes the passphrase and does a lookup on the database to see if that ID is in the database. If it is it will then compute the hash of the passphrase and validate that it is indeed the same. Finally it will use the passphrase to decrypt and return the message to the user and delete the secret from the database.
The frontend is built with React and styled with Tailwind. It is split into two different React components:
Create a Secret
Show a Secret
We’re using the useState hooks to take care of our form data. Once a form is submitted, we go ahead and make a POST request to the backend.
It was a ton of fun to join the hackathon. We were able to stream on Twitch while we built this also.