diff options
| author | Vineet Kumar <git@vineetk.net> | 2026-05-22 16:45:27 -0400 |
|---|---|---|
| committer | Vineet Kumar <git@vineetk.net> | 2026-05-22 16:47:40 -0400 |
| commit | 6cbb431459e9a0db73264c4144937a136fdb5b83 (patch) | |
| tree | 215f8cd38160a0005a03890e39a3af815bdcfaac | |
| parent | f3e21ba9cdaec50f2a99f8d33e68204c694c7ac7 (diff) | |
add random password/username generation
| -rw-r--r-- | kasi.el | 55 |
1 files changed, 44 insertions, 11 deletions
| @@ -44,35 +44,68 @@ | |||
| 44 | 44 | ||
| 45 | (defvar kasi-version "1.0") | 45 | (defvar kasi-version "1.0") |
| 46 | 46 | ||
| 47 | (defun kasi-filename-short (file) | 47 | (defun kasi--filename-short (file) |
| 48 | "Returns shortened name of filename." | 48 | "Returns shortened name of filename." |
| 49 | (file-name-sans-extension | 49 | (file-name-sans-extension |
| 50 | (file-relative-name file kasi-dir))) | 50 | (file-relative-name file kasi-dir))) |
| 51 | 51 | ||
| 52 | (defun kasi-filename () | 52 | (defun kasi--filename () |
| 53 | "Returns full filename of the secret file." | 53 | "Returns full filename of the secret file." |
| 54 | (let* ((filenames (file-expand-wildcards (format "%s/*/*" kasi-dir))) | 54 | (let* ((filenames (file-expand-wildcards (format "%s/*/*" kasi-dir))) |
| 55 | (options (mapcar (lambda (f) | 55 | (options (mapcar (lambda (f) |
| 56 | (kasi-filename-short f)) | 56 | (kasi--filename-short f)) |
| 57 | filenames)) | 57 | filenames)) |
| 58 | (selected (completing-read "File: " options)) | 58 | (selected (completing-read "File: " options)) |
| 59 | (file (elt filenames (seq-position options selected)))) | 59 | (file (elt filenames (seq-position options selected)))) |
| 60 | file)) | 60 | file)) |
| 61 | 61 | ||
| 62 | (defun kasi-get (file elem) | 62 | (defun kasi--get (file elem) |
| 63 | "Returns element from secret file." | 63 | "Returns element from secret file." |
| 64 | (car (with-temp-buffer | 64 | (car (with-temp-buffer |
| 65 | (insert-file-contents file) | 65 | (insert-file-contents file) |
| 66 | (alist-get elem (read (current-buffer)))))) | 66 | (alist-get elem (read (current-buffer)))))) |
| 67 | 67 | ||
| 68 | (defun kasi-totp (file) | 68 | (defun kasi--totp (file) |
| 69 | "Returns current TOTP code from secret file." | 69 | "Returns current TOTP code from secret file." |
| 70 | (let* ((totp-secret (kasi-get file 'totp)) | 70 | (let* ((totp-secret (kasi--get file 'totp)) |
| 71 | (totp-code (totp (base32-hex-decode totp-secret)))) | 71 | (totp-code (totp (base32-hex-decode totp-secret)))) |
| 72 | (kill-new totp-code) | 72 | (kill-new totp-code) |
| 73 | (message (format "TOTP %s for %s copied to kill ring" | 73 | (message (format "TOTP %s for %s copied to kill ring" |
| 74 | totp-code | 74 | totp-code |
| 75 | (kasi-filename-short file))))) | 75 | (kasi--filename-short file))))) |
| 76 | |||
| 77 | (defun kasi--random-string (length charset) | ||
| 78 | "Generate a random string of LENGTH using characters from CHARSET. | ||
| 79 | Uses /dev/urandom for cryptographic security." | ||
| 80 | ;; I have not seen any other built-in way to get cryptographically | ||
| 81 | ;; random outputs in Emacs. | ||
| 82 | (let* ((bytes (with-temp-buffer | ||
| 83 | (call-process "dd" nil (current-buffer) nil | ||
| 84 | "if=/dev/urandom" "bs=1" (format "count=%d" (* length 4))) | ||
| 85 | (buffer-string))) | ||
| 86 | (charset-len (length charset)) | ||
| 87 | (result "")) | ||
| 88 | (dotimes (i length) | ||
| 89 | (setq result (concat result | ||
| 90 | (char-to-string | ||
| 91 | (aref charset | ||
| 92 | (% (aref bytes i) | ||
| 93 | charset-len)))))) | ||
| 94 | result)) | ||
| 95 | |||
| 96 | ;;;###autoload | ||
| 97 | (defun kasi-generate-password (&optional length) | ||
| 98 | "Generate a random password of LENGTH (default 32)." | ||
| 99 | (interactive "P") | ||
| 100 | (let ((charset "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~")) | ||
| 101 | (message (kasi--random-string (or length 32) charset)))) | ||
| 102 | |||
| 103 | ;;;###autoload | ||
| 104 | (defun kasi-generate-username (&optional length) | ||
| 105 | "Generate a random username of LENGTH (default 12)." | ||
| 106 | (interactive "P") | ||
| 107 | (let ((charset "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")) | ||
| 108 | (message (kasi--random-string (or length 12) charset)))) | ||
| 76 | 109 | ||
| 77 | ;;;###autoload | 110 | ;;;###autoload |
| 78 | (defun kasi (command file) | 111 | (defun kasi (command file) |
| @@ -83,15 +116,15 @@ | |||
| 83 | username | 116 | username |
| 84 | 117 | ||
| 85 | totp))) | 118 | totp))) |
| 86 | (kasi-filename))) | 119 | (kasi--filename))) |
| 87 | (pcase command | 120 | (pcase command |
| 88 | ('edit (find-file-other-window file)) | 121 | ('edit (find-file-other-window file)) |
| 89 | ('totp (kasi-totp file)) | 122 | ('totp (kasi--totp file)) |
| 90 | ((or 'password 'username 'email) | 123 | ((or 'password 'username 'email) |
| 91 | (progn | 124 | (progn |
| 92 | (kill-new (kasi-get file command)) | 125 | (kill-new (kasi--get file command)) |
| 93 | (message (format "Copied %s for %s to kill ring." | 126 | (message (format "Copied %s for %s to kill ring." |
| 94 | command | 127 | command |
| 95 | (kasi-filename-short file))))))) | 128 | (kasi--filename-short file))))))) |
| 96 | 129 | ||
| 97 | (provide 'kasi) | 130 | (provide 'kasi) |
