secrets.lisp 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. (in-package :cl-user)
  2. (defpackage chatikbot.secrets
  3. (:use :cl)
  4. (:export :*secret-ring*
  5. :*secret-pass-store*
  6. :*secret-pass-bin*
  7. :secret-get
  8. :secret-set
  9. :secret-del
  10. :secret-wipe
  11. :with-secret))
  12. (in-package :chatikbot.secrets)
  13. (defvar *secret-ring* nil "GPG keyring path")
  14. (defvar *secret-pass-store* nil "pass store dir")
  15. (defvar *secret-pass-bin* "pass" "pass util binary")
  16. (defun pass (cmd path &key input (output :string) error-output)
  17. (let ((input-stream (when input (make-string-input-stream input))))
  18. (unwind-protect
  19. (uiop:run-program
  20. (format nil "~@[GNUPGHOME=~A ~]~@[PASSWORD_STORE_DIR=~A ~]~A ~A~@[ ~{~A~^/~}~]"
  21. *secret-ring* *secret-pass-store* *secret-pass-bin*
  22. cmd path)
  23. :input input-stream :output output :error-output error-output)
  24. (when input-stream
  25. (close input-stream)))))
  26. (defun secret-get (path)
  27. (handler-case
  28. (let ((*read-eval* nil))
  29. (values (read-from-string (pass "show" path))))
  30. (error () (values))))
  31. (defun secret-set (path value)
  32. (pass "insert --force --multiline" path
  33. :input (prin1-to-string value) :output nil :error-output :string))
  34. (defun secret-del (path)
  35. (pass "rm --force" path))
  36. (defun secret-wipe (data)
  37. (cond
  38. ((stringp data) (fill data #\Space))
  39. ((vectorp data) (fill data 0))
  40. ((consp data)
  41. (secret-wipe (car data))
  42. (secret-wipe (cdr data)))))
  43. (defmacro with-secret ((vars path) &body body)
  44. (alexandria:with-gensyms (secret)
  45. `(let ((,secret (ignore-errors (secret-get ,path))))
  46. (unwind-protect
  47. ,(if (listp vars)
  48. `(destructuring-bind ,vars ,secret ,@body)
  49. `(let ((,vars ,secret)) ,@body))
  50. (secret-wipe ,secret)))))