The GNU Emacs Package rcd-password.el
helps you generate new
passwords, save them into an appendable only file and find last
passwords. We recommend to keep the password file on the encrypted
partition /home
, and note that this program will not encrypt your
password file. You can even grep through it on a command line to find
specific passwords.
Simply save the below embedded code, then install it with:
{M-x package-install-file RET rcd-password.el RET}
The embedded code follows:
;;; rcd-password.el --- RCD password management -*- lexical-binding: t; -*-
;; Copyright (C) 2016-2021 Jean Louis
;; Author: Jean Louis <bugs@gnu.support>
;; Version: 1.1
;; Package-Requires: (rcd-utilities)
;; Keywords: files
;; URL: https://gnu.support/gnu-emacs/packages/rcd-password-el.html
;; This file is not part of GNU Emacs.
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This is the RCD password manager for GNU Emacs.
;;
;; RCD is acronym for Reach, Connect, Deliver, my personal
;; principle and formula for Wealth.
;;
;; The recommended use is that you have /home partition
;; encrypted, and that passwords are held in ~/.passwords
;; file. By setting the variable `rcd-password-file' you may
;; change the location of your password file.
;;
;; 1. First create the password file, for example in shell:
;; $ touch .passwords
;;
;; 2. Strong recommendation is that you use the command:
;; $ sudo chattr +a ~/.passwords
;;
;; as that way you are making the file appendable only,
;; neither you or software without root rights will not
;; be able to remove it. You can only append to it.
;;
;; You should make the file readable and writeable by its
;; owner only by using the command:
;; $ chmod 600 .passwords
;;
;; The file need not be hidden, or appendable only, that
;; is my personal way of doing it.
;;
;; 3. To load the package use `(require 'rcd-password)' in
;; your init file or other method of loading it.
;;
;; 4. Use the command {M-x rcd-password-new} or its alias
;; {M-x password-new} to generate new password. It will
;; be appeneded to your specified password file, line by
;; line. Password will be killed or copied into memory so
;; that you may easier yank or paste it at some other
;; place.
;;
;; 5. Use the command (M-x rcd-password-find) or its aliases
;; {M-x find-password} or {M-x password-find} to find
;; desired passwords. In the *passwords* buffer you may
;; click `q' to close the buffer.
;;; Change Log:
;;; Code:
(eval-when-compile
(require 'subr-x))
(require 'rcd-utilities)
;; TODO change these to defcustom
(defvar rcd-password-length 20)
(defvar rcd-password-digits 2)
(defvar rcd-password-specials 2)
(defvar rcd-password-alpha "ABCDEFGHIJKLMNOPQRSTUVWHYZ")
(defvar rcd-password-special-characters "!@#$%^&*()-=+_[]{}|")
(defvar rcd-password-file "~/.passwords")
(defvar rcd-url-password-prefix "987")
(defvar rcd-url-password-suffix "321")
(defvar rcd-password-query-history nil)
(defun rcd-random-md5-string ()
(md5 (concat (emacs-uptime) (format-time-string "%N %6N %3N"))))
(defun rcd-password-generate-1 (string)
"Return capitalized or downcased single symbol from a string"
(random (rcd-random-md5-string))
(let* ((max (length string))
(rnd (random max))
(single (substring string rnd (+ rnd 1))))
single))
(defun rcd-password-generate-alpha-1 ()
"Returns random downcased or upcased character"
(let* ((single (rcd-password-generate-1 rcd-password-alpha))
(down-up (random 2)))
(if (= down-up 1) (upcase single) (downcase single))))
(defun rcd-password-generate-number-1 ()
"Returns single random digit"
(let* ((number "0123456789")
(single (rcd-password-generate-1 number)))
single))
(defun rcd-password-generate-special-1 ()
"Returns single special character"
(let* ((single (rcd-password-generate-1 rcd-password-special-characters)))
single))
(defun rcd-password-insert-char (char password)
"Inserts CHAR into PASSWORD at random place"
(let ((rnd (random (length password))))
(store-substring password rnd char)))
(defun rcd-password-spit (&optional length)
"Returns password using alphabet of specified LENGTH"
(let ((length (or length rcd-password-length))
(counter 0))
(with-output-to-string
(while (< counter length)
(princ (rcd-password-generate-alpha-1))
(setq counter (1+ counter))))))
(defun rcd-password-insert-digits (password &optional how-many)
"Inserts HOW-MANY digits into PASSWORD, it does not guarantee
it will not insert digits on the same index"
(let ((how-many (or how-many rcd-password-digits))
(counter 0))
(while (< counter how-many)
(setq password (rcd-password-insert-char (rcd-password-generate-number-1) password))
(setq counter (1+ counter)))
password))
(defun rcd-password-insert-special (password &optional how-many)
"Inserts HOW-MANY special characters into PASSWORD string"
(let ((how-many (or how-many rcd-password-specials))
(counter 0))
(while (< counter how-many)
(setq password (rcd-password-insert-char (rcd-password-generate-special-1) password))
(setq counter (1+ counter)))
password))
(defun rcd-password (&optional length)
"Returns random password with optional LENGTH, containing both
the alphabet, some digits and special characters. It does not
guarantee to return specific number of digits or specific special
characters, it relies on probabilities and settings"
(rcd-password-insert-special (rcd-password-insert-digits (rcd-password-spit length))))
(defun rcd-password-insert ()
(interactive)
"Inserts random password in buffer"
(let ((password (rcd-password)))
(insert password)))
;;;###autoload
(defun rcd-find-password (query)
"Finds a password in file as set under variable RCD-PASSWORD-FILE"
(interactive
(list
(read-from-minibuffer "Find password: " nil nil nil 'rcd-password-query-history)))
(let* ((default-directory (file-name-directory rcd-password-file))
(query (if (string-match " " query) (split-string query) (list query)))
(list (with-temp-buffer
(insert-file-contents-literally rcd-password-file)
(split-string (buffer-string) "\n" t)))
(nlist (list-has-elements query list))
(nnlist '())
(nlist (dolist (item nlist (reverse nnlist))
(push (string-join (split-string (string-trim item) ":") " ") nnlist))))
(when (buffer-live-p "*passwords*")
(kill-buffer "*passwords*"))
(pop-buffer-highlight-elements query nlist "*passwords*" t)))
;;;###autoload
(defun rcd-password-new (&optional hostname service username email)
(interactive "sHostname: \nsService: \nsUsername: \nsEmail: ")
(let ((default-directory "~/"))
(if (or (not (string-blank-p username)) (not (string-blank-p email)))
(let* ((password (read-from-minibuffer "Password: " (rcd-password 20)))
(line (concat (string-join (list hostname service username email password) "::") "\n")))
(kill-new password)
(if (and (or (not (string-blank-p username)) (not (string-blank-p email))) (not (string-blank-p password)))
(append-to-file line nil rcd-password-file)
(message "Either password or email or username is missing")))
(message "Either username or email line is missing"))))
(defalias 'find-password 'rcd-find-password)
(defalias 'password-find 'rcd-find-password)
(defalias 'new-password 'rcd-password-new)
(defalias 'password-new 'rcd-password-new)
(defalias 'lozinka 'rcd-password-new)
(provide 'rcd-password)
;;; rcd-password.el ends here
or you may download the file from: https://gnu.support/files/emacs/packages/rcd-utilities.el
and then install it with the Emacs command:
{M-x package-install-file RET rcd-password.el RET}
The file rcd-password.el
requires our set of Emacs Lisp utilities within rcd-utilities.el
package that you may find here below: