Personal Password Generator

Table of Contents

A literate programming version for Emacs code to generate and store passwords.

Overlay Redaction

Love this idea for using a regular expression to redact (or at least, obscure) sensitive information before screen sharing.

(defun toggle-redact-buffer (regexp)
  "Redact buffer content matching regexp. A space redacts all."
  (interactive (list (read-regexp "Text to Redact (Regexp)" 'regexp-history-last)))
  (let* ((redacted)
         (matches (let ((results '()))
                    (when (string-empty-p regexp)
                      (setq regexp "[[:graph:]]")
                      (setq regexp-history-last regexp)
                      (add-to-history 'regexp-history regexp))
                    (save-excursion
                      (goto-char (point-min))
                      (while (re-search-forward regexp nil t)
                        (push (cons (match-beginning 0) (match-end 0)) results)))
                    (nreverse results))))
    (mapc (lambda (match)
            (dolist (overlay (overlays-in (car match) (cdr match)))
              (setq redacted t)
              (delete-overlay overlay))
            (unless redacted
              (overlay-put (make-overlay (car match) (cdr match))
                           'display (make-string (- (cdr match) (car match)) ?x))))
          matches)))

I’m not sure how often I will use this, so I’m not putting it on a keybinding, also so, I will also not put a name-spacing prefix on the function.

Password Generation

Let’s assume that I store a bunch of words in data files:

(defvar ha-passwords-data-files (list (expand-file-name "adjectives.txt"
                                                        (expand-file-name "data" hamacs-source-dir))
                                      (expand-file-name "colors.txt"
                                                        (expand-file-name "data" hamacs-source-dir))
                                      (expand-file-name "nouns.txt"
                                                        (expand-file-name "data" hamacs-source-dir)))
  "List of file name containing a data lines for our password generator. Order of these files matter.")

(defvar ha-passwords-data nil
  "Contains a list of lists of words that we can choose.")

You can see where I’m going with this, can’t you? Let’s read them into list variables.

(defun ha-passwords--read-data-file (filename)
  (with-temp-buffer
    (insert-file-contents filename)
    (split-string (buffer-string) "\n" t)))

Now we get three or so words from our list of lists:

(defun ha-passwords-words ()
  (unless ha-passwords-data
    (setq ha-passwords-data
          (--map (ha-passwords--read-data-file it) ha-passwords-data-files)))

  (--map (nth (random (length it)) it) ha-passwords-data))

Let’s make a password:

(defun ha-passwords-generate (&optional separator)
  (unless separator
    (setq separator "-"))

  (let* ((choices '("!" "@" "#" "$" "%" "^" "&" "*"))
         (choice (random (length choices)))
         (number (1+ choice)))
    (->> (ha-passwords-words)
         (s-join separator)
         (s-capitalize)
         (s-append (nth choice choices))
         (s-append (number-to-string number)))))
(defun generate-password (&optional separator)
  (interactive)
  (let ((passphrase (ha-passwords-generate separator)))
    (kill-new passphrase)
    (message "Random password: %s" passphrase)))

Keybindings

Got make it easy to call:

(ha-leader "a g" '("generate passwd" . generate-password))