Some time ago I published in here a post where I was speaking about me getting a bit of an idea on how to work with Desktop apps in 2022, after years of Web Development (and with a massive disgust for electron apps).
As mentioned there, one of my projects to learn more about AvaloniaUI and MVVM was to create my own local Password Manager, here I will speak more about why and how I made it work.
What
I got Assasin's Creed Unity on a steam sale this summer, and since I am quite busy with life at the moment I put it off installing it and playing it for a while. Then I did and it was shit (I wrote a review about it here).
One of the main issues I had with this game though, wasn't game related, but more of an integration bug.
When you startup up the game Steam asks Ubisoft-launcher to launch the game, so you need to log in to your Ubisoft account to launch it.
Sometimes it forgets your password, fine, you recover it from your saved passwords and copy-paste it.
Then you get bored of killing people while flying from rooftop to rooftop and you just quit the game.
Ubisoft forgot your password and won't save to the cloud your files.
You need to get your password again. boring.
I wish there was a local running password manager that wouldn't cost a fortune.
Oh! I am a developer, why don't I do one myself?
I love to name my side projects with Sicilian terms, and since this was about me having a bad memory I called it
Muscurd-i
which pronounced in English sounds like m'u scurdaj
which mean 'I forgot it'.
How
So since a new item in my toolbelt was Avalonia and Dotnet, I decided to create this app with it, so I would be able to build and run the same app on Mac, Win and Linux.
The app itself was really simple in my head:
A small 3 screens app:
Login, List of Password, Add a New Password.
The Login would ask you for a master password and if you managed to get it right it would show you the list of your added password that you will be able to search and copy to your clipboard.
You would also need the possibility to add a new password on the third screen.
Security
How do you store passwords you ask?
Well, not in clear text certainly.
My main idea was this:
So UI would allow to get the clear text and Encrypt when stored.
So if someone got hold of the db file (I am using LiteDB) won't be able to use them unless they guessed the encryption key.
But how to do that?
Well, it is quite annoying to find stuff for Dotnet, a load of code you can find around is quite old and deprecated but eventually, I did find a tutorial on the new Aes Encryption Lib. And worked my way to upgrade a shitty deprecated code example on StackOverflow.
Producing this little static boy:
public static class Crypto
{
public static string Encrypt(string plainText, MasterPassword password) {}
public static string? Decrypt(string encryptedText, MasterPassword password) {}
}
so I can get set and get the password from and to the database using the MasterPassword.
Funny thing is that I am using the master password as the encryption key, so it needs to be 32 Ascii characters, so I can get the right number of bytes to encrypt the string with AES.
To do that but also to avoid being a completely impossible to remember password I made it so is 4 words of 4 letters, and 4 digits, so something like
yoyo-baba-nana-caca-1234
Would be a nice master password, of course, it will be possible brute force guess it, but that is valid for everything.
Misc
I TDD-ed both functionalities:
Muscurdi.Tests/Models/MasterPasswordTests.cs
Muscurdi.Tests/Libs/MasterPasswordHelperTests.cs
Muscurdi.Tests/Libs/CryptoTests.cs
And after few days of playing around with Avalonia it was ready to rumble, kind of:
I know if kind of looks like shit, but I improved it with loads of CSS-like and some FontAwesome integration.
This last one was amazing, I could see so much of HTML things I had done before:
<Button Command="{Binding GoToAdd}" Classes="IconBtn">
<i:Icon Value="fa fa-plus" FontSize="16" />
</Button>
And now it looks a bit better I would say.
As a bonus feature I added a list of 4 letter words that generates a random password for you.
Up to the user whether to use it as inspiration or complete remove it.
Other things I learned
There were no docs on the MaskedTextBox, only some of WPF so I decided to be a good boy scout and write them myself with my second PR on AvaloniaDoc.
Dotnet build commands on platform that are not Windows do not always work properly.
I tried to make the app run by itself without the cli opening in the background, and on Linux didn't work, tried the same on Windows and build the app for Linux/Mac and Windows and it worked like a charm, so I decided to delegate the build process to a GH action.
So now every time I create a tag/release on Github I will get those bin compiled and published ready to be downloaded like here:
Even though we do some quite heavy building and bundling and trimming, the apps unzipped are still around 90Mb, not quite big as an electron app, but still quite annoying.
In Conclusion
I liked working on this small project and I am now looking forward to finishing another private secret Avalonia project I am working on.
Here is the repo for anyone who wants to try it.
I already found a few bugs, like you can open multiple instances and I might want to add also the username not only the password, but I will get around to it whenever I have a bit more time.
until next time.
Top comments (0)