Clojure Password Manager
Foreword
Welcome to the Clojure Password Manager Tutorial. We will develop a simple Password Manager with only 77 lines of code by using the powerful seesaw library for our GUIs.
As usual we will focus on plain simplicity. Additional features like save & load will be left open for the reader to implement afterwards.
The GUI library
As just mentioned, we will use the seesaw library for our GUIs. Seesaw is pretty much just a wrapper for Java's Swing library, but wrapped in a way that allows us to use it in the most elegant way possible in Clojure.
Reading through the Seesaw REPL Tutorial should be enough to understand everything in this tutorial.
Seesaw setup
The library can be used by adding the following line to our project.clj file:
[seesaw "1.4.4"]
Note: this requires Leiningen.
And then adding it to the use part of our namespace:
(ns noobtuts.core
(:use [seesaw.core])
(:require [clojure.string :as str]))
Note: we will also need clojure's string later on, hence why we already added it to the require part as well.
And then (optionally) calling the native function in the very beginning of our program:
(native!)
Note: this makes the GUI look like a native GUI from the operating system, instead of that blue Java GUI style.
Seesaw helper functions
We will begin by implementing two little helper functions that will make our lives easier later on:
; display function from the seesaw tutorial
(defn display [frame content]
(config! frame :content content)
content)
; simple yes-no dialog wrapper (blocking)
(defn yesno-dialog [msg]
(= :success (-> (dialog :content msg
:option-type :yes-no) pack! show!)))
The display function can be found in the tutorial that was referred to above. The yesno-dialog function simply pops up a dialog with a Yes / No answer option, while also letting us specify the shown message.
Here is how we use it:
(if (yesno-dialog "Is Clojure awesome?")
(prn "it is awesome!")
(prn "invalid answer"))
And this is how the dialog looks like:
The Entry Hash-Map
The Structure
Alright so our password manager will have a whole bunch of entries for all kinds of websites. Each entry should then have an id (or in other words: username) and a pw (or in other words: password) field, so what we need is a hash-map of hash-maps like:
{"www.mysite1.com" {:id "johnDoe", :pw "123"},
"www.mysite2.com" {:id "Anon", :pw "456"}}
Refs
Our entries should also be changeable later on (after adding or removing entries), so we will use a Clojure ref for them. Here is how we work with a ref:
; define a ref
(def r (ref 0))
; access a ref
@r ; => 0
; change a ref
(alter r inc) ; => doesn't work, needs to be in dosync
(dosync (alter r inc)) ; => 1
Note: we will use a ref because the dosync mechanic could come in handy when adding more advanced features to the password manager.
Defining the Entries
Alright so let's define our entries:
; entries (filled with one example already)
(def entries (ref {"noobtuts.com" {:id "user" :pw "123"}}))
Frames
We will need two windows in our software, which are called frames in seesaw. There will be the main frame and there will be an add frame:
The main difference between those frames is that closing frame-add will just make the frame-add invisible, while closing frame-main will quit the program.
So let's define both frames and make one of them quit the Password Manager:
(def frame-main (frame :title "Password Manager"
:on-close :exit))
(def frame-add (frame :title "Add Entry"))
Now there is a very basic way to show a frame, which is this one:
(show! (pack! frame-main))
But we will use a custom display function from here on. And we will modify the display function over and over again so it places all the elements where we want them to be.
Main Frame - Listbox
Defining the Listbox
It's time to add the main listbox that shows all the entries. It's important to keep in mind that it only shows the entry titles (for example the website name), but not the id or password.
We can get all the entry titles very easily like this:
(keys @entries) ; simplicity as usual...
And here is how we define the listbox:
(def lb-main (listbox :model (keys @entries)))
Note: lb-main stands for 'listbox-in-frame-main'.
. . .Premium Tutorial
Enjoyed this preview? Become a Premium member and access the full Clojure Password Manager Tutorial!All Tutorials. All Source Codes & Project Files. One time Payment.
Get Premium today!