Authors: Tareq Jallad, Haohan Jiang
This project uses Rust to implement a command line password manager. This CLI application allows the user to create, delete, list, and modify secret entries and secret stores, all through the command line. For user security, all input passwords and usernames are encrypted by a randomly generated RSA Private key.
This project can be built with cargo build
and the binary will be located at target/debug/password_manager
Binary can also be downloaded from the release page
Secret Entry
- A secret entry is a named username and password pair
Secret Store
- A list of secret entries
password_manager -s <NAME> --op init
password_manager -s <NAME> --op create
password_manager -s <NAME> --op list
password_manager -s <NAME> --op delete-store
password_manager -s <NAME> --op delete-entry -e <ENTRY_NAME>
password_manager -s <NAME> --op modify -e <ENTRY_NAME>
password_manager -s <NAME> --op get -e <ENTRY_NAME>
As a new user, I want to create new store with the name foobar
. I have a new World of Warcraft subscription and
want to put my username and password into this password manager to store.
I would first need to create the store with:
password_manager -s foobar --op init
Then, to add the user information into the password manager, I would need to run:
password_manager -s foobar --op create
This will prompt the user to enter in a name for the secret entry and the username and password to store. In this
example, my store name will be called wow
.
When I want to login to World of Warcraft, I can get the secrets with:
password_manager -s foobar --op get -e wow
At the root project level, src
contains the source code for the project. resources
contains
a test file for unit testing.
The entry point for the application. Houses command line argument logic and calls different modules based on user input.
create.rs
delete.rs
get.rs
init.rs
list.rs
modify.rs
Operations directory contains the logic required for each specific operation.
common.rs
encryption.rs
errors.rs
Generics directory contains functionality that is used across the app.
-data_model.rs
Models directory contains the data model that is serialized and deserialized through JSON.
-test_mocks.rs
Mocks directory contains a function that is used to override an external function during unit testing.
test_mocks.rs
contains a function that is only called during unit tests which raises a compiler warning during
build
. So, we decided to suppress the warning with the macro #![allow(dead_code)]
The base directory for this application is: HOME/.passmanager
.
All secrets stores are located at: HOME/.passmanager/.stores/<STORE_NAME>.json
All secret keys are located at: HOME/.passmanager/.keys/<KEY_NAME>.pem
Secrets and secret stores are encrypted in two different ways. First, we encrypt the store name and the entry name. Second, we also encrypt the username and password for each entry using a RSA private key generated specifically for that secret entry.
Secret store names and RSA private keys are stored under hashed value.
Usernames and passwords are encrypted by a RSA public key generated from it's RSA private key. The key is stored under the hashed entry name so that the private key can be retrieved to decrypt the username and password.
Application errors can handled under /generics/errors
. External library errors are caught and re-raised as an internal
error up to the top level caller.
We preformed integration testing by hand. We did not have a library crate and could not figure out a way
to import the project into an integration test module to live in the /tests/
directory. We hand tested
each functionality to ensure functionality.
Unit tests exist within files when appropriate for the function. Certain modules were mocked by selective
imports with #[cfg(test)]
and #[cfg(not(test))]
macros.
We thought that most things in the project went pretty well. Nothing was too troublesome. The problem arose during unit testing of the library functions that the different components used. When researching how to unit test functions, most rust mocking frameworks limited you to mocking only traits and the project was not built with traits in mind.
Perhaps this was an un-rust like way to code the project.
We are satisfied with the results as we believe that we created a great simple app that can be useful to the right target audience. We went into this project with the goal of creating a usable product and to that end I think we succeeded.
This project is available under the MIT license