A little while ago, I found myself struggling to bring order to my tasks at work. I'd tried many different organizational systems. Some didn't suit my work style, others were way too complicated - adding to my daily tasks rather than making them easier. I decided to put together a system that worked for me.
I divide my tasks for the day into three buckets: Tasks I must do today, Tasks I should do today, Tasks I can do today. Every day, I rewrite and carry over any incomplete tasks to the next day. It's simple, but it works for me!
I took the simple pen-and-paper tools and made them digital. The features of Must/Should/Can are straightforward, as is system itself:
- Account Creation and Login
- Task Creation, Editing, and Prioritization
- Task Resets
- Task Archiving and Deleting
- Ruby on Rails as the framework for the API
- ActiveModelSerializers to build JSON views
- PostgreSQL as the database
- The bcrypt gem to improve password security in tandem with the ActiveRecord
- React / Create React App
- React Router v6 - For client-side routing
- Styled Components to style the application
While building Must/Should/Can, it did not escape my attention that a user's tasks could be very private, so there was a need to protect them as much as possible. To ensure that privacy, I not only implemented user authorization and password authentication, I protected their passwords with the ActiveRecord
If you're storing passwords in any system, it is a very bad idea to store them in plaintext anywhere in your application. Doing so exposes you and your users to potential data losses, which is a Bad Thing. The
has_secure_password feature adds methods to an ActiveRecord model that make setting and authenticating securely hashed and salted passwords on your user models easy.
Under the hood,
has_secure_password uses the
bcrypt gem to hash and salt your user's passwords. This process makes it very difficult for bad actors to access your users' password data, even if they manage to steal your database.
Hashing is the process of taking data and processing it to create a new value, usually of a fixed length (sometimes called a fingerprint). The process is unidirectional, meaning once a value has been hashed, it is incredibly impractical (with current technology) to reverse the process to derive the original value from the hash. For example, using bcrypt, the password
Wolfgang the puppy might hash to the value
$2a$12$j29LhAzasXWN7glfGjp9NuFXcOYBCffkE4RWcQJwBFzxsAsUsQ2nK. This unidirectionality is what makes hashed passwords more secure than plaintext passwords - a hacker will need to do extra work to break the encryption involved.
Or they might have a Rainbow Table, which is a precomputed set of values that will let an attacker look up the password based on a given hash. If the hashing function is known to the attacker, hashing alone won't be enough to protect a user's password, since the same input value will always produce the same output hash.
This is why bcrypt will also salt a password before storing the hash in your database. A salt is data added to the input of a hash function. In bcrypt's implementation, a unique salt is added to every password on generation. This means that an attacker would need to use a different pre-computed Rainbow Table for every single password, which is computationally prohibitive.
All of this means that, properly implemented, using
bcrypt in your application is one important step protect you and your users from bad actors.
I plan to introduce the ability to add notes to tasks so you can, for example, sketch out an agenda for a meeting, or divide tasks into subtasks. I also plan to enhance the archive with grouping and sorting. Later on, I'll enhance the user's account management experience, letting them reset their password and edit their user name.