From 20db4e11f54e324af9e7e6c8f96a75589445629b Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Thu, 13 Jan 2022 16:03:11 +0530 Subject: mastodon.el: introduce new defcustom `mastodon-active-user' Use `mastodon-active-user' and `mastodon-instance-url' to determine which mastodon account the user wants to be active for the current session of Emacs. See the documentation string of this variable for details on how to use it. This new variable becomes necessary to prevent conflict when a user has two accounts on the same instance, that is same value of `mastodon-instance-url'. --- lisp/mastodon.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon.el b/lisp/mastodon.el index f65a86d..c7fcccf 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -95,6 +95,19 @@ (defcustom mastodon-instance-url "https://mastodon.social" "Base URL for the Masto instance from which you toot." +(defcustom mastodon-active-user "user" + "Username of the active user. + +For example, if your mastodon username is +\"example_user@social.instance.org\", and you want this account +to be active, the value of this variable should be +\"example_user\". + +Also for completeness, the value of `mastodon-instance-url' +should be \"https://social.instance.org\". + +After setting these variables you should restart Emacs for these +changes to take effect." :group 'mastodon :type 'string) -- cgit v1.2.3 From 2349750b607388a1a665c5e68b5708d9563ecaff Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Thu, 13 Jan 2022 16:22:10 +0530 Subject: mastodon.el: update `mastodon-instance-url' docstring Update the docstring for the defcustom `mastodon-instance-url' to clarify what it's value should be to reflect the changes introduced in the previous commit. --- lisp/mastodon.el | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'lisp') diff --git a/lisp/mastodon.el b/lisp/mastodon.el index c7fcccf..2758f9d 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -94,7 +94,21 @@ :group 'external) (defcustom mastodon-instance-url "https://mastodon.social" - "Base URL for the Masto instance from which you toot." + "Base URL for the Mastodon instance you want to be active. + +For example, if your mastodon username is +\"example_user@social.instance.org\", and you want this account +to be active, the value of this variable should be +\"https://social.instance.org\". + +Also for completeness, the value of `mastodon-active-user' should +be \"example_user\". + +After setting these variables you should restart Emacs for these +changes to take effect." + :group 'mastodon + :type 'string) + (defcustom mastodon-active-user "user" "Username of the active user. -- cgit v1.2.3 From 89add914c9e10979c271cdbb5f4af076ecbe41db Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Tue, 28 Dec 2021 14:46:46 +0530 Subject: add helper function `mastodon-http-append-query-string' Add helper function `mastodon-http-append-query-string' which create URLs with query strings appended to its end. (see doc string for details.) --- lisp/mastodon-http.el | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index f988e39..8e96b39 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -32,6 +32,7 @@ (require 'json) (require 'request) ; for attachments upload +(require 'url) (defvar mastodon-instance-url) (defvar mastodon-toot--media-attachment-ids) @@ -156,6 +157,13 @@ Pass response buffer to CALLBACK function." (with-temp-buffer (mastodon-http--url-retrieve-synchronously url)))) +(defun mastodon-http-append-query-string (url params) + "Append PARAMS to URL as query strings and return it. + +PARAMS should be an alist as required `url-build-query-string'." + (let ((query-string (url-build-query-string params))) + (concat url "?" query-string))) + ;; search functions: (defun mastodon-http--process-json-search () "Process JSON returned by a search query to the server." -- cgit v1.2.3 From 03365c8fbaac2c71e6bbfed731ae88d551175c2c Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Tue, 28 Dec 2021 14:58:44 +0530 Subject: abstract Mastodon API request info Mastodon API requires some info that needs to be passed during app registration and user authentication. Those info were hard coded into various functions. Introduce three variables (defvars): 1. mastodon-client-scopes 2. mastodon-client-website 3. mastodon-client-redirect-uri use them to abstract those info. Also refactor `mastodon-client--register' function in terms of these variables. --- lisp/mastodon-client.el | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'lisp') diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index b27d434..9fb45f7 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -46,14 +46,23 @@ (defvar mastodon-client--client-details-alist nil "An alist of Client id and secrets keyed by the instance url.") +(defvar mastodon-client-scopes "read write follow" + "Scopes to pass to oauth during registration.") + +(defvar mastodon-client-website "https://codeberg.org/martianh/mastodon.el" + "Website of mastodon.el.") + +(defvar mastodon-client-redirect-uri "urn:ietf:wg:oauth:2.0:oob" + "Redirect_uri as required by oauth.") + (defun mastodon-client--register () "POST client to Mastodon." (mastodon-http--post (mastodon-http--api "apps") - '(("client_name" . "mastodon.el") - ("redirect_uris" . "urn:ietf:wg:oauth:2.0:oob") - ("scopes" . "read write follow") - ("website" . "https://github.com/jdenen/mastodon.el")) + `(("client_name" . "mastodon.el") + ("redirect_uris" . ,mastodon-client-redirect-uri) + ("scopes" . ,mastodon-client-scopes) + ("website" . ,mastodon-client-website)) nil :unauthenticated)) -- cgit v1.2.3 From 9ca02d048fdb70c1edec189ddf87265dfb4c80b2 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Thu, 13 Jan 2022 20:07:42 +0530 Subject: re-implement user auth and token generation mechanism Refactor `mastodon-auth--generate-token' to work with new user authentication and token generation mechanism. This enables mastodon.el to work with 2FA and also not to handle password directly. In this implementation mastodon-auth--generate-token gets authorization code from the user and sends post request to mastodon server. Ask for authorization code from the user using two helper functions: * mastodon-auth--ask-authorization-code: Explain to the user what the user needs to do to get the authorization code. Store this explanation message in variable `mastodon-auth--explanation'. * mastodon-auth--get-browser-login-url: Return a appropriate query string appended to url to the caller, which is needed by the user to access the authorization code. --- lisp/mastodon-auth.el | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 74d4404..8a058f3 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -61,17 +61,32 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." (defvar mastodon-auth--acct-alist nil "Alist of account accts (name@domain) keyed by instance url.") -(defun mastodon-auth--generate-token () - "Make POST to generate auth token. +(defun mastodon-auth--get-browser-login-url () + "Return properly formed browser login url." + (mastodon-http-append-query-string + (concat mastodon-instance-url "/oauth/authorize/") + `(("response_type" "code") + ("redirect_uri" ,mastodon-client-redirect-uri) + ("scope" ,mastodon-client-scopes) + ("client_id" ,(plist-get (mastodon-client) :client_id))))) + +(defvar mastodon-auth--explanation + (format + (concat "A URL has been copied to your clipboard.\n" + "Open this URL in a javascript capable browser.\n" + "Login to your account (%s) and authorize \"mastodon.el\".\n" + "Paste Authorization Code here: ") + (mastodon-client-form-user-from-vars))) + +(defun mastodon-auth--ask-authorization-code () + "Ask authorization code and return it." + (let ((url (mastodon-auth--get-browser-login-url)) + authorization-code) + (kill-new url) + (setq authorization-code (read-string mastodon-auth--explanation)) + authorization-code)) -If no auth-sources file, runs -`mastodon-auth--generate-token-no-storing-credentials'. If -auth-sources file exists, runs -`mastodon-auth--generate-token-and-store'." - (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 () (defun mastodon-auth--generate-token-no-storing-credentials () "Make POST to generate auth token, without using auth-sources file." @@ -115,6 +130,17 @@ Reads and/or stores secrets in `MASTODON-AUTH-SOURCE-FILE'." :unauthenticated) (when (functionp (plist-get credentials-plist :save-function)) (funcall (plist-get credentials-plist :save-function)))))) + "Generate access_token for the user. Return response buffer." + (let ((authorization-code (mastodon-auth--ask-authorization-code))) + (mastodon-http--post + (concat mastodon-instance-url "/oauth/token") + `(("grant_type" . "authorization_code") + ("client_secret" . ,(plist-get (mastodon-client) :client_secret)) + ("client_id" . ,(plist-get (mastodon-client) :client_id)) + ("code" . ,authorization-code) + ("redirect_uri" . ,mastodon-client-redirect-uri)) + nil + :unauthenticated))) (defun mastodon-auth--get-token () "Make a request to generate an auth token and return JSON response." -- cgit v1.2.3 From e18a2d541fca4c5f08f35d1de72d3a3ee9cfe011 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Thu, 13 Jan 2022 20:22:48 +0530 Subject: remove functions no longer needed Remove `mastodon-auth--generate-token-no-storing-credentials' and 'mastodon-auth--generate-token-and-store' as these two are no longer needed. --- lisp/mastodon-auth.el | 43 ------------------------------------------- 1 file changed, 43 deletions(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 8a058f3..55db0c0 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -87,49 +87,6 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." authorization-code)) (defun mastodon-auth--generate-token () - -(defun mastodon-auth--generate-token-no-storing-credentials () - "Make POST to generate auth token, without using auth-sources file." - (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" . ,(read-string "Email: " user-mail-address)) - ("password" . ,(read-passwd "Password: ")) - ("scope" . "read write follow")) - nil - :unauthenticated)) - -(defun mastodon-auth--generate-token-and-store () - "Make POST to generate auth token. - -Reads and/or stores secrets 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)))))) "Generate access_token for the user. Return response buffer." (let ((authorization-code (mastodon-auth--ask-authorization-code))) (mastodon-http--post -- cgit v1.2.3 From 2d5717faf83d59d11a4f89ce96eb326a39a5ee56 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Tue, 28 Dec 2021 18:40:53 +0530 Subject: refactor *-access-token and *-handle-token-response Refactor `mastodon-auth--access-token' and `mastodon-auth--handle-token-response' to work with the new authentication mechanism. --- lisp/mastodon-auth.el | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 55db0c0..71f790a 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -111,16 +111,26 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." (json-read-from-string json-string)))) (defun mastodon-auth--access-token () - "Return exiting or generate new access token. - -If an access token for `mastodon-instance-url' is in -`mastodon-auth--token-alist', return it. - -Otherwise, generate a token and pass it to -`mastodon-auth--handle-token-reponse'." - (if-let ((token (cdr (assoc mastodon-instance-url mastodon-auth--token-alist)))) - token - (mastodon-auth--handle-token-response (mastodon-auth--get-token)))) + "Return the access token to use with `mastodon-instance-url'. + +Generate/save token if none known yet." + (cond (mastodon-auth--token-alist + ;; user variables are known and + ;; initialised already. + (alist-get mastodon-instance-url mastodon-auth--token-alist + nil nil 'equal)) + ((plist-get (mastodon-client-active-user) :access_token) + ;; user variables needs to initialised by reading from + ;; plstore. + (push (cons mastodon-instance-url + (plist-get (mastodon-client-active-user) :access_token)) + mastodon-auth--token-alist) + (alist-get mastodon-instance-url mastodon-auth--token-alist + nil nil 'equal)) + (t + ;; user access-token needs to fetched from the server and + ;; stored and variables initialised. + (mastodon-auth--handle-token-response (mastodon-auth--get-token))))) (defun mastodon-auth--handle-token-response (response) "Add token RESPONSE to `mastodon-auth--token-alist'. @@ -131,6 +141,8 @@ Handle any errors from the server." (pcase response ((and (let token (plist-get response :access_token)) (guard token)) + (mastodon-client-make-user-active + (mastodon-client-store-access-token token)) (cdar (push (cons mastodon-instance-url token) mastodon-auth--token-alist))) -- cgit v1.2.3 From cd03ff5319dc60b4aa4f6d42f57b737e002cd923 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Mon, 17 Jan 2022 19:31:55 +0530 Subject: abstract plstore implementation details of getting value Introduce a new function `mastodon-client--remove-key-from-plstore' which removes "key" part from a plstore item. Refactor `mastodon-client--read' to use `mastodon-client--remove-key-from-plstore'. --- lisp/mastodon-client.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lisp') diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 9fb45f7..04a26ce 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -97,11 +97,17 @@ Make `mastodon-client--fetch' call to determine client values." (plstore-close plstore) client)) +(defun mastodon-client--remove-key-from-plstore (plstore) + "Remove KEY from PLSTORE." + (cdr plstore)) + +;; Actually it returns a plist with client-details if such details are +;; already stored in mastodon.plstore (defun mastodon-client--read () "Retrieve client_id and client_secret from `mastodon-client--token-file'." (let* ((plstore (plstore-open (mastodon-client--token-file))) (mastodon (plstore-get plstore (concat "mastodon-" mastodon-instance-url)))) - (cdr mastodon))) + (mastodon-client--remove-key-from-plstore mastodon))) (defun mastodon-client () "Return variable client secrets to use for `mastodon-instance-url'. -- cgit v1.2.3 From 8e36abecbb8fa0df1aba30b1100130e5e382b92b Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Mon, 17 Jan 2022 19:40:59 +0530 Subject: introduce a general plstore reading function Introduce a general version of `mastodon-client--read'[1] with the name `mastodon-client--general-read'[2] as [1] is too specific. [2] can be called with with a plstore "key" to retrieve the item keyed by that KEY. --- lisp/mastodon-client.el | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 04a26ce..7a857a2 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -109,6 +109,13 @@ Make `mastodon-client--fetch' call to determine client values." (mastodon (plstore-get plstore (concat "mastodon-" mastodon-instance-url)))) (mastodon-client--remove-key-from-plstore mastodon))) +(defun mastodon-client--general-read (key) + "Retrieve the plstore item keyed by KEY. +Return plist without the KEY." + (let* ((plstore (plstore-open (mastodon-client--token-file))) + (plstore-item (plstore-get plstore key))) + (mastodon-client--remove-key-from-plstore plstore-item))) + (defun mastodon-client () "Return variable client secrets to use for `mastodon-instance-url'. -- cgit v1.2.3 From a80bd14c4c22bf5aeda7b37e6f0631a9f4912384 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Mon, 17 Jan 2022 19:55:33 +0530 Subject: get account ID from user variables specified in the init file Get user account ID from the mastodon variables specified in the init file by introducing the function `mastodon-client-form-user-from-vars'. Return user account ID in the form "user@instance.com" when the values of `mastodon-active-user' and `mastodon-instance-url' are "user" and "https://instance.com" respectively. --- lisp/mastodon-client.el | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 7a857a2..f7d06a5 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -116,6 +116,15 @@ Return plist without the KEY." (plstore-item (plstore-get plstore key))) (mastodon-client--remove-key-from-plstore plstore-item))) +(defun mastodon-client-form-user-from-vars () + "Create a username from user variable. Return that username. + +Username in the form user@instance.com is formed from the +variables `mastodon-instance-url' and `mastodon-active-user'." + (concat mastodon-active-user + "@" + (url-host (url-generic-parse-url mastodon-instance-url)))) + (defun mastodon-client () "Return variable client secrets to use for `mastodon-instance-url'. -- cgit v1.2.3 From ebb4bfcee21020cec5cae08955cf2a8c57d3532c Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Mon, 17 Jan 2022 20:03:01 +0530 Subject: store access token in plstore of the current user Store access token in the plstore of the current user. To do that introduce the function `mastodon-client-store-access-token' of one argument TOKEN. Also define a helper function `mastodon-client--make-user-details-plist' which creates a plist with current users details and returns it. --- lisp/mastodon-client.el | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index f7d06a5..1c3b2e1 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -116,6 +116,28 @@ Return plist without the KEY." (plstore-item (plstore-get plstore key))) (mastodon-client--remove-key-from-plstore plstore-item))) +(defun mastodon-client--make-user-details-plist () + "Make a plist with current user details. Return it." + `(:username ,(mastodon-client-form-user-from-vars) + :instance ,mastodon-instance-url + :client_id ,(plist-get (mastodon-client) :client_id) + :client_secret ,(plist-get (mastodon-client) :client_secret))) + +(defun mastodon-client-store-access-token (token) + "Save TOKEN as :access_token in plstore of the current user. +Return the plist after the operation." + (let* ((user-details (mastodon-client--make-user-details-plist)) + (plstore (plstore-open (mastodon-client--token-file))) + (username (plist-get user-details :username)) + (plstore-value (setq user-details + (plist-put user-details :access_token token))) + (print-length nil) + (print-level nil)) + (plstore-put plstore (concat "user-" username) plstore-value nil) + (plstore-save plstore) + (plstore-close plstore) + plstore-value)) + (defun mastodon-client-form-user-from-vars () "Create a username from user variable. Return that username. -- cgit v1.2.3 From 6305a5b809fc9185626c2cbcdf43ba4416efeb11 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Mon, 17 Jan 2022 20:15:28 +0530 Subject: functions for making/checking active users Define functions for like: * mastodon-client-make-user-active: Take one argument USER-DETAILS and make it the user details of the active user. * mastodon-client--make-current-user-active: Make the user details specified in the init file the current user. * mastodon-client--current-user-active-p: Return user-details if the current user is active, otherwise return nil. --- lisp/mastodon-client.el | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 1c3b2e1..d622e52 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -138,6 +138,15 @@ Return the plist after the operation." (plstore-close plstore) plstore-value)) +(defun mastodon-client-make-user-active (user-details) + "USER-DETAILS is a plist consisting of user details." + (let ((plstore (plstore-open (mastodon-client--token-file))) + (print-length nil) + (print-level nil)) + (plstore-put plstore "active-user" user-details nil) + (plstore-save plstore) + (plstore-close plstore))) + (defun mastodon-client-form-user-from-vars () "Create a username from user variable. Return that username. @@ -147,6 +156,24 @@ variables `mastodon-instance-url' and `mastodon-active-user'." "@" (url-host (url-generic-parse-url mastodon-instance-url)))) +(defun mastodon-client--make-current-user-active () + "Make the user specified by user variables active user. +Return the details (plist)." + (let ((username (mastodon-client-form-user-from-vars)) + user-plist) + (when (setq user-plist + (mastodon-client--general-read (concat "user-" username))) + (mastodon-client-make-user-active user-plist)) + user-plist)) + +(defun mastodon-client--current-user-active-p () + "Return user-details if the current user is active. +Otherwise return nil." + (let ((username (mastodon-client-form-user-from-vars)) + (user-details (mastodon-client--general-read "active-user"))) + (when (and user-details + (equal (plist-get user-details :username) username)) + user-details))) (defun mastodon-client () "Return variable client secrets to use for `mastodon-instance-url'. -- cgit v1.2.3 From 639f89eb714efea5062bdbf21995033f57ea5207 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Mon, 17 Jan 2022 20:23:22 +0530 Subject: make a public interface for accessing user details Introduce the function `mastodon-client-active-user' for public use which returns the details of the currently active users. It performs similar function as that of the function `mastodon-client'. --- lisp/mastodon-client.el | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index d622e52..e0ae34c 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -46,6 +46,9 @@ (defvar mastodon-client--client-details-alist nil "An alist of Client id and secrets keyed by the instance url.") +(defvar mastodon-client--active-user-details-plist nil + "A plist of active user details.") + (defvar mastodon-client-scopes "read write follow" "Scopes to pass to oauth during registration.") @@ -174,6 +177,20 @@ Otherwise return nil." (when (and user-details (equal (plist-get user-details :username) username)) user-details))) + +(defun mastodon-client-active-user () + "Return the details of the currently active user. + +Details is a plist." + (let ((active-user-details mastodon-client--active-user-details-plist)) + (unless active-user-details + (setq active-user-details + (or (mastodon-client--current-user-active-p) + (mastodon-client--make-current-user-active))) + (setq mastodon-client--active-user-details-plist + active-user-details)) + active-user-details)) + (defun mastodon-client () "Return variable client secrets to use for `mastodon-instance-url'. -- cgit v1.2.3 From 257209846e30e9ad7ac410e7dc7c72ecddb0b6ad Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Tue, 28 Dec 2021 18:51:39 +0530 Subject: define autoloads and defvars to silence the byte compiler --- lisp/mastodon-auth.el | 7 +++++++ lisp/mastodon-client.el | 2 ++ 2 files changed, 9 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 71f790a..72c0333 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -39,7 +39,14 @@ (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") +(autoload 'mastodon-http-append-query-string "mastodon-http") +(autoload 'mastodon-client-store-access-token "mastodon-client") +(autoload 'mastodon-client-active-user "mastodon-client") +(autoload 'mastodon-client-make-user-active "mastodon-client") +(autoload 'mastodon-client-form-user-from-vars "mastodon-client") (defvar mastodon-instance-url) +(defvar mastodon-client-scopes) +(defvar mastodon-client-redirect-uri) (defgroup mastodon-auth nil "Authenticate with Mastodon." diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index e0ae34c..13e0150 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -32,8 +32,10 @@ (require 'plstore) (require 'json) +(require 'url) (defvar mastodon-instance-url) +(defvar mastodon-active-user) (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") -- cgit v1.2.3 From f037340225fecb16ed7bb92c26a56e0a96c8aee6 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Tue, 28 Dec 2021 19:29:40 +0530 Subject: update copyright holder info Update Copyright holder info for files that have undergone non trivial changes. --- lisp/mastodon-auth.el | 1 + lisp/mastodon-client.el | 1 + lisp/mastodon.el | 1 + 3 files changed, 3 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 72c0333..c09dfdf 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -1,6 +1,7 @@ ;;; mastodon-auth.el --- Auth functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2021 Abhiseck Paira ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt ;; Version: 0.10.0 diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index 13e0150..c577fec 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -1,6 +1,7 @@ ;;; mastodon-client.el --- Client functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2021 Abhiseck Paira ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt ;; Version: 0.10.0 diff --git a/lisp/mastodon.el b/lisp/mastodon.el index 2758f9d..d22c842 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -1,6 +1,7 @@ ;;; mastodon.el --- Client for Mastodon -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen +;; Copyright (C) 2021 Abhiseck Paira ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt ;; Version: 0.10.0 -- cgit v1.2.3 From 0af5b491d14d521c03ebc48d82608afd65166e90 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Wed, 23 Feb 2022 14:24:37 +0530 Subject: change '-' to '--' in between function and namespace names mastodon.el currently follows the convention where all function names should have two dashes (not one dash) in between function and namespace names. Update all function names to follow this convention. See issue #205 and pull request #255 --- lisp/mastodon-auth.el | 20 ++++++++++---------- lisp/mastodon-client.el | 16 ++++++++-------- lisp/mastodon-http.el | 2 +- test/mastodon-auth-tests.el | 4 ++-- test/mastodon-client-tests.el | 16 ++++++++-------- 5 files changed, 29 insertions(+), 29 deletions(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index c09dfdf..2540598 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -40,11 +40,11 @@ (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") -(autoload 'mastodon-http-append-query-string "mastodon-http") -(autoload 'mastodon-client-store-access-token "mastodon-client") -(autoload 'mastodon-client-active-user "mastodon-client") -(autoload 'mastodon-client-make-user-active "mastodon-client") -(autoload 'mastodon-client-form-user-from-vars "mastodon-client") +(autoload 'mastodon-http--append-query-string "mastodon-http") +(autoload 'mastodon-client--store-access-token "mastodon-client") +(autoload 'mastodon-client--active-user "mastodon-client") +(autoload 'mastodon-client--make-user-active "mastodon-client") +(autoload 'mastodon-client--form-user-from-vars "mastodon-client") (defvar mastodon-instance-url) (defvar mastodon-client-scopes) (defvar mastodon-client-redirect-uri) @@ -71,7 +71,7 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." (defun mastodon-auth--get-browser-login-url () "Return properly formed browser login url." - (mastodon-http-append-query-string + (mastodon-http--append-query-string (concat mastodon-instance-url "/oauth/authorize/") `(("response_type" "code") ("redirect_uri" ,mastodon-client-redirect-uri) @@ -127,11 +127,11 @@ Generate/save token if none known yet." ;; initialised already. (alist-get mastodon-instance-url mastodon-auth--token-alist nil nil 'equal)) - ((plist-get (mastodon-client-active-user) :access_token) + ((plist-get (mastodon-client--active-user) :access_token) ;; user variables needs to initialised by reading from ;; plstore. (push (cons mastodon-instance-url - (plist-get (mastodon-client-active-user) :access_token)) + (plist-get (mastodon-client--active-user) :access_token)) mastodon-auth--token-alist) (alist-get mastodon-instance-url mastodon-auth--token-alist nil nil 'equal)) @@ -149,8 +149,8 @@ Handle any errors from the server." (pcase response ((and (let token (plist-get response :access_token)) (guard token)) - (mastodon-client-make-user-active - (mastodon-client-store-access-token token)) + (mastodon-client--make-user-active + (mastodon-client--store-access-token token)) (cdar (push (cons mastodon-instance-url token) mastodon-auth--token-alist))) diff --git a/lisp/mastodon-client.el b/lisp/mastodon-client.el index c577fec..80338b1 100644 --- a/lisp/mastodon-client.el +++ b/lisp/mastodon-client.el @@ -124,12 +124,12 @@ Return plist without the KEY." (defun mastodon-client--make-user-details-plist () "Make a plist with current user details. Return it." - `(:username ,(mastodon-client-form-user-from-vars) + `(:username ,(mastodon-client--form-user-from-vars) :instance ,mastodon-instance-url :client_id ,(plist-get (mastodon-client) :client_id) :client_secret ,(plist-get (mastodon-client) :client_secret))) -(defun mastodon-client-store-access-token (token) +(defun mastodon-client--store-access-token (token) "Save TOKEN as :access_token in plstore of the current user. Return the plist after the operation." (let* ((user-details (mastodon-client--make-user-details-plist)) @@ -144,7 +144,7 @@ Return the plist after the operation." (plstore-close plstore) plstore-value)) -(defun mastodon-client-make-user-active (user-details) +(defun mastodon-client--make-user-active (user-details) "USER-DETAILS is a plist consisting of user details." (let ((plstore (plstore-open (mastodon-client--token-file))) (print-length nil) @@ -153,7 +153,7 @@ Return the plist after the operation." (plstore-save plstore) (plstore-close plstore))) -(defun mastodon-client-form-user-from-vars () +(defun mastodon-client--form-user-from-vars () "Create a username from user variable. Return that username. Username in the form user@instance.com is formed from the @@ -165,23 +165,23 @@ variables `mastodon-instance-url' and `mastodon-active-user'." (defun mastodon-client--make-current-user-active () "Make the user specified by user variables active user. Return the details (plist)." - (let ((username (mastodon-client-form-user-from-vars)) + (let ((username (mastodon-client--form-user-from-vars)) user-plist) (when (setq user-plist (mastodon-client--general-read (concat "user-" username))) - (mastodon-client-make-user-active user-plist)) + (mastodon-client--make-user-active user-plist)) user-plist)) (defun mastodon-client--current-user-active-p () "Return user-details if the current user is active. Otherwise return nil." - (let ((username (mastodon-client-form-user-from-vars)) + (let ((username (mastodon-client--form-user-from-vars)) (user-details (mastodon-client--general-read "active-user"))) (when (and user-details (equal (plist-get user-details :username) username)) user-details))) -(defun mastodon-client-active-user () +(defun mastodon-client--active-user () "Return the details of the currently active user. Details is a plist." diff --git a/lisp/mastodon-http.el b/lisp/mastodon-http.el index 8e96b39..05c9d2e 100644 --- a/lisp/mastodon-http.el +++ b/lisp/mastodon-http.el @@ -157,7 +157,7 @@ Pass response buffer to CALLBACK function." (with-temp-buffer (mastodon-http--url-retrieve-synchronously url)))) -(defun mastodon-http-append-query-string (url params) +(defun mastodon-http--append-query-string (url params) "Append PARAMS to URL as query strings and return it. PARAMS should be an alist as required `url-build-query-string'." diff --git a/test/mastodon-auth-tests.el b/test/mastodon-auth-tests.el index 3ff745f..3bf65b2 100644 --- a/test/mastodon-auth-tests.el +++ b/test/mastodon-auth-tests.el @@ -56,8 +56,8 @@ (mastodon-auth--token-alist nil)) (with-mock (mock (mastodon-auth--get-token) => '(:access_token "foobaz")) - (mock (mastodon-client-store-access-token "foobaz")) - (stub mastodon-client-make-user-active) + (mock (mastodon-client--store-access-token "foobaz")) + (stub mastodon-client--make-user-active) (should (string= (mastodon-auth--access-token) "foobaz")) diff --git a/test/mastodon-client-tests.el b/test/mastodon-client-tests.el index c2ec50c..b302ed6 100644 --- a/test/mastodon-client-tests.el +++ b/test/mastodon-client-tests.el @@ -122,11 +122,11 @@ (should (equal mastodon-client--client-details-alist '(("http://mastodon.example" :client_id "foo" :client_secret "baz"))))))) -(ert-deftest mastodon-client-form-user-from-vars () +(ert-deftest mastodon-client--form-user-from-vars () (let ((mastodon-active-user "test9000") (mastodon-instance-url "https://mastodon.example")) (should - (equal (mastodon-client-form-user-from-vars) + (equal (mastodon-client--form-user-from-vars) "test9000@mastodon.example")))) (ert-deftest mastodon-client--current-user-active-p () @@ -142,7 +142,7 @@ (mock (mastodon-client--general-read "active-user") => '(:username "user@other.example" :client_id "id1")) (should (null (mastodon-client--current-user-active-p)))))) -(ert-deftest mastodon-client-store-access-token () +(ert-deftest mastodon-client--store-access-token () (let ((mastodon-instance-url "https://mastodon.example") (mastodon-active-user "test8000") (user-details @@ -150,14 +150,14 @@ :instance "https://mastodon.example" :client_id "id" :client_secret "secret" :access_token "token"))) - ;; test if mastodon-client-store-access-token /returns/ right + ;; test if mastodon-client--store-access-token /returns/ right ;; value (with-mock (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) (mock (mastodon-client--token-file) => "stubfile.plstore") - (should (equal (mastodon-client-store-access-token "token") + (should (equal (mastodon-client--store-access-token "token") user-details))) - ;; test if mastodon-client-store-access-token /stores/ right value + ;; test if mastodon-client--store-access-token /stores/ right value (with-mock (mock (mastodon-client--token-file) => "stubfile.plstore") (should (equal (mastodon-client--general-read @@ -165,10 +165,10 @@ user-details))) (delete-file "stubfile.plstore"))) -(ert-deftest mastodon-client-make-user-active () +(ert-deftest mastodon-client--make-user-active () (let ((user-details '(:username "test@mastodon.example"))) (with-mock (mock (mastodon-client--token-file) => "stubfile.plstore") - (mastodon-client-make-user-active user-details) + (mastodon-client--make-user-active user-details) (should (equal (mastodon-client--general-read "active-user") user-details))))) -- cgit v1.2.3 From 7ec5aea30e8ada9475e1199a084d468f0031002d Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Fri, 25 Feb 2022 18:59:56 +0530 Subject: auth: change name to mastodon-auth--request-authorization-code Change the name of the function `mastodon-auth--ask-authorization-code' to `mastodon-auth--request-authorization-code'. Suggested-by: Marty Hiatt --- lisp/mastodon-auth.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 2540598..416e714 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -86,7 +86,7 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." "Paste Authorization Code here: ") (mastodon-client-form-user-from-vars))) -(defun mastodon-auth--ask-authorization-code () +(defun mastodon-auth--request-authorization-code () "Ask authorization code and return it." (let ((url (mastodon-auth--get-browser-login-url)) authorization-code) @@ -96,7 +96,7 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." (defun mastodon-auth--generate-token () "Generate access_token for the user. Return response buffer." - (let ((authorization-code (mastodon-auth--ask-authorization-code))) + (let ((authorization-code (mastodon-auth--request-authorization-code))) (mastodon-http--post (concat mastodon-instance-url "/oauth/token") `(("grant_type" . "authorization_code") -- cgit v1.2.3 From 7a0d85b3f7c170ae930ea7ff5be948a6183ca513 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Fri, 25 Feb 2022 19:16:07 +0530 Subject: auth: present auth code request in a nicer way Instead of using the minibuffer prompt to present the explanation what the user needs to do to get authorization code, use Emacs buffer and Window. The minibuffer prompt should have 2-3 words. This increases the readability of the explanation. Of course delete explanation buffer and restore the window configuration as it was after reading from minibuffer. --- lisp/mastodon-auth.el | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 416e714..ebbe86c 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -85,13 +85,44 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." "Login to your account (%s) and authorize \"mastodon.el\".\n" "Paste Authorization Code here: ") (mastodon-client-form-user-from-vars))) +(defun mastodon-auth--show-notice (notice buffer-name &optional ask) + "Display NOTICE to user. +NOTICE is displayed in vertical split occupying 50% of total +width. The buffer name of the buffer being displayed in the +window is BUFFER-NAME. + +When optional argument ASK is given which should be a string, use +ASK as the minibuffer prompt. Return whatever user types in +response to the prompt. + +When ASK is absent return nil." + (let ((buffer (get-buffer-create buffer-name)) + (inhibit-read-only t) + ask-value window) + (set-buffer buffer) + (erase-buffer) + (insert notice) + (fill-region (point-min) (point-max)) + (read-only-mode) + (setq window (select-window + (split-window (frame-root-window) nil 'left) + t)) + (switch-to-buffer buffer t) + (when ask + (setq ask-value (read-string ask)) + (kill-buffer buffer) + (delete-window window)) + ask-value)) (defun mastodon-auth--request-authorization-code () "Ask authorization code and return it." (let ((url (mastodon-auth--get-browser-login-url)) authorization-code) (kill-new url) - (setq authorization-code (read-string mastodon-auth--explanation)) + (setq authorization-code + (mastodon-auth--show-notice mastodon-auth--explanation + "*mastodon-notice*" + "Authorization Code: ")) authorization-code)) (defun mastodon-auth--generate-token () -- cgit v1.2.3 From 1e4ab751683d497243f719c70cccb0450c9cb451 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Fri, 25 Feb 2022 19:36:43 +0530 Subject: auth: make the wording in mastodon-auth--explanation clearer --- lisp/mastodon-auth.el | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index ebbe86c..491d6ae 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -80,11 +80,17 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." (defvar mastodon-auth--explanation (format - (concat "A URL has been copied to your clipboard.\n" - "Open this URL in a javascript capable browser.\n" - "Login to your account (%s) and authorize \"mastodon.el\".\n" - "Paste Authorization Code here: ") - (mastodon-client-form-user-from-vars))) + " +1. A URL has been copied to your clipboard. Open this URL in a +javascript capable browser and your browser will take you to your +Mastodon instance's login page. + +2. Login to your account (%s) and authorize \"mastodon.el\". + +3. After authorization you will be presented an authorization +code. Copy this code and paste it in the minibuffer prompt." + (mastodon-client--form-user-from-vars))) + (defun mastodon-auth--show-notice (notice buffer-name &optional ask) "Display NOTICE to user. NOTICE is displayed in vertical split occupying 50% of total -- cgit v1.2.3 From 6ac09ec8bc5f3011e59602b030d45ce3f3860e25 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Fri, 25 Feb 2022 19:43:08 +0530 Subject: auth: make old mastodon.el users aware Most old users of the mastodon.el wouldn't know about the introduction of new variable `mastodon-active-user'[1]. Our goal is to make them aware. Set the default value of [1] to nil. This way we can know that the user hasn't set [1] properly because user is unaware of it. In the definition of `mastodon-auth--access-token', check [1]'s value and if it's null, explain to the user about the new situation. Finally signal the error "Variables not set properly". We have considered the possibility of automating the process but since the new login mechanism depends on setting [1] *in the init file*, the only way to automate it would be to write to user's init file which we consider to be very rude and shouldn't be done by this package. --- lisp/mastodon-auth.el | 8 ++++++++ lisp/mastodon.el | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index 491d6ae..bad9e08 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -48,6 +48,7 @@ (defvar mastodon-instance-url) (defvar mastodon-client-scopes) (defvar mastodon-client-redirect-uri) +(defvar mastodon-active-user) (defgroup mastodon-auth nil "Authenticate with Mastodon." @@ -172,6 +173,13 @@ Generate/save token if none known yet." mastodon-auth--token-alist) (alist-get mastodon-instance-url mastodon-auth--token-alist nil nil 'equal)) + ((null mastodon-active-user) + ;; user not aware of 2FA related changes and has not set the + ;; `mastodon-active-user' properly. Make user aware and error + ;; out. + (mastodon-auth--show-notice mastodon-auth--user-unaware + "*mastodon-notice*") + (error "Variables not set properly")) (t ;; user access-token needs to fetched from the server and ;; stored and variables initialised. diff --git a/lisp/mastodon.el b/lisp/mastodon.el index d22c842..6daa755 100644 --- a/lisp/mastodon.el +++ b/lisp/mastodon.el @@ -110,7 +110,7 @@ changes to take effect." :group 'mastodon :type 'string) -(defcustom mastodon-active-user "user" +(defcustom mastodon-active-user nil "Username of the active user. For example, if your mastodon username is -- cgit v1.2.3 From fbb34e106b7164a9c1d47cf31d9803827540e228 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Fri, 25 Feb 2022 20:15:48 +0530 Subject: auth: define variable mastodon-auth--user-unaware Hold the explanation string in the variable `mastodon-auth--user-unaware'. This explanation is provided to old mastodon.el users who are not aware of the 2FA related changes. --- lisp/mastodon-auth.el | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index bad9e08..ba7bebe 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -70,6 +70,21 @@ if you are happy with unencryped storage use e.g. \"~/authinfo\"." (defvar mastodon-auth--acct-alist nil "Alist of account accts (name@domain) keyed by instance url.") +(defvar mastodon-auth--user-unaware + " ** MASTODON.EL - NOTICE ** + +It appears that you are not aware of the recent developments in +mastodon.el. In short we now require that you also set the +variable `mastodon-active-user' in your init file in addition to +`mastodon-instance-url'. + +Please see its documentation to understand what value it accepts +by running M-x describe-variable on it or visiting our web page: +https://codeberg.org/martianh/mastodon.el + +We apologize for the inconvenience. +") + (defun mastodon-auth--get-browser-login-url () "Return properly formed browser login url." (mastodon-http--append-query-string -- cgit v1.2.3 From 56fa25df379623e79261b535cd724db3ed979d44 Mon Sep 17 00:00:00 2001 From: Abhiseck Paira Date: Fri, 25 Feb 2022 21:11:30 +0530 Subject: auth: make mastodon-auth-source-file a defvar The variable `mastodon-auth-source-file' serves no purpose so change it from a defcustom to a defvar. Also update its docstring to document it. --- lisp/mastodon-auth.el | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'lisp') diff --git a/lisp/mastodon-auth.el b/lisp/mastodon-auth.el index ba7bebe..f50f5ed 100644 --- a/lisp/mastodon-auth.el +++ b/lisp/mastodon-auth.el @@ -55,14 +55,10 @@ :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-source-file nil + "This variable is obsolete. +This variable currently serves no purpose and will be removed in +the future.") (defvar mastodon-auth--token-alist nil "Alist of User access tokens keyed by instance url.") -- cgit v1.2.3