summaryrefslogtreecommitdiff
path: root/modules/auth-config.el
blob: c3000f7f8adca24c584a79bc0430cfedc1e3eb26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
;; auth-config.el --- Configuration for Authentication Utilities -*- lexical-binding: t; coding: utf-8; -*-
;; author Craig Jennings <c@cjennings.net>

;;; Commentary:
;;
;; Configuration for Emacs authentication and GPG integration:

;; • auth-source
;;   – Forces use of your default authinfo file
;;   – Disable external GPG agent in favor of Emacs’s own prompt
;;   – Enable auth-source debug messages

;; • Easy PG Assistant (epa)
;;   – Force using the ‘gpg2’ executable for encryption/decryption operations

;;; Code:

(eval-when-compile (require 'user-constants)) ;; defines authinfo-file location

;; -------------------------------- Auth Sources -------------------------------
;; auth sources settings

(use-package auth-source
  :ensure nil                           ;; built in
  :demand t                             ;; load this package immediately
  :config
  ;; USE gpg-agent for passphrase caching (400-day cache from gpg-agent.conf)
  ;; (setenv "GPG_AGENT_INFO" nil)      ;; DISABLED: was preventing gpg-agent cache
  (setq auth-sources `(,authinfo-file))  ;; use authinfo.gpg (see user-constants.el)
  (setq auth-source-debug t)             ;; echo debug info to Messages
  (setq auth-source-cache-expiry 86400)) ;; cache decrypted credentials for 24 hours

;; ----------------------------- Easy PG Assistant -----------------------------
;; Key management, cryptographic operations on regions and files, dired
;; integration, and automatic encryption/decryption of *.gpg files.

(use-package epa
  :ensure nil ;; built-in
  :demand t
  :config
  (epa-file-enable)
  ;; (setq epa-pinentry-mode 'loopback)  ;; emacs request passwords in minibuffer
  (setq epg-gpg-program "gpg2")  ;; force use gpg2 (not gpg v.1)

  ;; Update gpg-agent with current DISPLAY environment
  ;; This ensures pinentry can open GUI windows when Emacs starts
  (call-process "gpg-connect-agent" nil nil nil "updatestartuptty" "/bye"))

;; ---------------------------------- Plstore ----------------------------------
;; Encrypted storage used by oauth2-auto for Google Calendar tokens.
;; CRITICAL: Enable passphrase caching to prevent password prompts every 10 min.

(use-package plstore
  :ensure nil ;; built-in
  :demand t
  :config
  ;; Cache passphrase indefinitely (relies on gpg-agent for actual caching)
  (setq plstore-cache-passphrase-for-symmetric-encryption t)
  ;; Allow gpg-agent to cache the passphrase (400 days per gpg-agent.conf)
  (setq plstore-encrypt-to nil)) ;; Use symmetric encryption, not key-based

;; ------------------------ Authentication Reset Utility -----------------------

(defun cj/reset-auth-cache (&optional include-gpg-agent)
  "Reset authentication caches when wrong password was entered.

By default, only clears Emacs-side caches (auth-source, EPA file
handler) and leaves gpg-agent's long-term cache intact.  This preserves
your 400-day cache for GPG and SSH passphrases.

With prefix argument INCLUDE-GPG-AGENT (\\[universal-argument]), also
clears gpg-agent's password cache.  Use this when gpg-agent itself has
cached an incorrect password.

Clears:
1. auth-source cache (Emacs-level credential cache)
2. EPA file handler cache (encrypted file cache)
3. gpg-agent cache (only if INCLUDE-GPG-AGENT is non-nil)

Use this when you see errors like:
  - \"Bad session key\"
  - \"Decryption failed\"
  - GPG repeatedly using wrong cached password"
  (interactive "P")
  (message "Resetting authentication caches...")

  ;; Clear auth-source cache (Emacs credential cache)
  (auth-source-forget-all-cached)

  ;; Clear EPA file handler cache
  (when (fboundp 'epa-file-clear-cache)
    (epa-file-clear-cache))

  ;; Only clear gpg-agent cache if explicitly requested
  (if include-gpg-agent
      (let ((result (shell-command "echo RELOADAGENT | gpg-connect-agent")))
        (if (zerop result)
            (message "✓ Emacs and gpg-agent caches cleared. Next access will prompt for password.")
          (message "⚠ Warning: Failed to clear gpg-agent cache")))
    (message "✓ Emacs caches cleared. GPG/SSH passphrases preserved for session.")))

(defun cj/kill-gpg-agent ()
  "Force kill gpg-agent (it will restart automatically on next use).

This is a more aggressive reset than `cj/reset-auth-cache'.  Use this
when gpg-agent is stuck or behaving incorrectly.

The gpg-agent will automatically restart on the next GPG operation."
  (interactive)
  (let ((result (shell-command "gpgconf --kill gpg-agent")))
    (if (zerop result)
        (message "✓ gpg-agent killed. It will restart automatically on next use.")
      (message "⚠ Warning: Failed to kill gpg-agent"))))

;; Keybindings
(with-eval-after-load 'keybindings
  (keymap-set cj/custom-keymap "A" #'cj/reset-auth-cache))

(with-eval-after-load 'which-key
  (which-key-add-key-based-replacements
    "C-; A" "reset auth cache"))

(provide 'auth-config)
;;; auth-config.el ends here.