diff options
| -rw-r--r-- | README.org | 4 | ||||
| -rw-r--r-- | lisp/mastodon-auth.el | 47 | ||||
| -rw-r--r-- | test/mastodon-auth-tests.el | 53 | 
3 files changed, 89 insertions, 15 deletions
@@ -65,6 +65,10 @@ Set =mastodon-instance-url= in your =.emacs= or =customize=. Defaults to the [[h      (setq mastodon-instance-url "https://my.instance.url")  #+END_SRC +There is an option to have your user credentials (email address and password) saved to disk so you don't have to re-enter them on every restart. +The default is not to do this because if not properly configured it would save these unencrypted which is not a good default to have. +Customize the variable =mastodon-auth-source-file= if you want to enable this feature. +  *** Timelines  =M-x mastodon= diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 17f19e3..aa83fae 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -30,6 +30,7 @@  ;;; Code:  (require 'plstore) +(require 'auth-source)  (autoload 'mastodon-client "mastodon-client")  (autoload 'mastodon-http--api "mastodon-http") @@ -42,6 +43,15 @@    :prefix "mastodon-auth-"    :group 'mastodon) +(defcustom mastodon-auth-source-file "" +  "Filename to use to store user names and passwords. + +Leave empty to not permanently store any secrets. +Otherwise set to e.g. \"~/.authinfo.gpg\" to have encrypted storage, or +if you are happy with unencryped storage use e.g. \"~/authinfo\"." +  :group 'mastodon-auth +  :type 'string) +  (defvar mastodon-auth--token-alist nil    "Alist of User access tokens keyed by instance url.") @@ -50,6 +60,13 @@  (defun mastodon-auth--generate-token ()    "Make POST to generate auth token." +  (if (or (null mastodon-auth-source-file) +	  (string= "" mastodon-auth-source-file)) +      (mastodon-auth--generate-token-no-storing-credentials) +    (mastodon-auth--generate-token-and-store))) + +(defun mastodon-auth--generate-token-no-storing-credentials () +  "Make POST to generate auth token."    (mastodon-http--post     (concat mastodon-instance-url "/oauth/token")     `(("client_id" . ,(plist-get (mastodon-client) :client_id)) @@ -61,6 +78,36 @@     nil     :unauthenticated)) +(defun mastodon-auth--generate-token-and-store () +  "Make POST to generate auth token. + +Reads and/or stores secres in `MASTODON-AUTH-SOURCE-FILE'." +  (let* ((auth-sources (list mastodon-auth-source-file)) +	 (auth-source-creation-prompts +          '((user . "Enter email for %h: ") +            (secret . "Password: "))) +         (credentials-plist (nth 0 (auth-source-search +                                    :create t +                                    :host mastodon-instance-url +                                    :port 443 +                                    :require '(:user :secret))))) +    (prog1 +        (mastodon-http--post +         (concat mastodon-instance-url "/oauth/token") +         `(("client_id" . ,(plist-get (mastodon-client) :client_id)) +           ("client_secret" . ,(plist-get (mastodon-client) :client_secret)) +           ("grant_type" . "password") +           ("username" . ,(plist-get credentials-plist :user)) +           ("password" . ,(let ((secret (plist-get credentials-plist :secret))) +                            (if (functionp secret) +                                (funcall secret) +                              secret))) +           ("scope" . "read write follow")) +         nil +	 :unauthenticated) +      (when (functionp (plist-get credentials-plist :save-function)) +        (funcall (plist-get credentials-plist :save-function)))))) +  (defun mastodon-auth--get-token ()    "Make auth token request and return JSON response."    (with-current-buffer (mastodon-auth--generate-token) diff --git a/test/mastodon-auth-tests.el b/test/mastodon-auth-tests.el index 719a56c..5108f9a 100644 --- a/test/mastodon-auth-tests.el +++ b/test/mastodon-auth-tests.el @@ -1,22 +1,45 @@  (require 'el-mock) -(ert-deftest generate-token () +(ert-deftest generate-token--no-storing-credentials ()    "Should make `mastdon-http--post' request to generate auth token."    (with-mock -    (let ((mastodon-instance-url "https://instance.url")) -      (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) -      (mock (read-string "Email: ") => "foo@bar.com") -      (mock (read-passwd "Password: ") => "password") -      (mock (mastodon-http--post "https://instance.url/oauth/token" -                                 '(("client_id" . "id") -                                   ("client_secret" . "secret") -                                    ("grant_type" . "password") -                                    ("username" . "foo@bar.com") -                                    ("password" . "password") -                                    ("scope" . "read write follow")) -                                 nil -                                 :unauthenticated)) -      (mastodon-auth--generate-token)))) +   (let ((mastodon-auth-source-file "") +	 (mastodon-instance-url "https://instance.url")) +     (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) +     (mock (read-string "Email: ") => "foo@bar.com") +     (mock (read-passwd "Password: ") => "password") +     (mock (mastodon-http--post "https://instance.url/oauth/token" +                                '(("client_id" . "id") +                                  ("client_secret" . "secret") +                                  ("grant_type" . "password") +                                  ("username" . "foo@bar.com") +                                  ("password" . "password") +                                  ("scope" . "read write follow")) +                                nil +                                :unauthenticated)) +     (mastodon-auth--generate-token)))) + +(ert-deftest generate-token--storing-credentials () +  "Should make `mastdon-http--post' request to generate auth token." +  (with-mock +   (let ((mastodon-auth-source-file "~/.authinfo") +	 (mastodon-instance-url "https://instance.url")) +     (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) +     (mock (auth-source-search :create t +                               :host "https://instance.url" +                               :port 443 +                               :require '(:user :secret)) +           => '((:user "foo@bar.com" :secret (lambda () "password")))) +     (mock (mastodon-http--post "https://instance.url/oauth/token" +                                '(("client_id" . "id") +                                  ("client_secret" . "secret") +                                  ("grant_type" . "password") +                                  ("username" . "foo@bar.com") +                                  ("password" . "password") +                                  ("scope" . "read write follow")) +                                nil +				:unauthenticated)) +     (mastodon-auth--generate-token))))  (ert-deftest get-token ()    "Should generate token and return JSON response."  | 
