diff options
| author | Thanos Apollo <public@thanosapollo.org> | 2026-04-30 02:25:51 +0300 |
|---|---|---|
| committer | Thanos Apollo <public@thanosapollo.org> | 2026-04-30 02:29:41 +0300 |
| commit | 7e0d21406e7f4c9ad312b7fc38f6ba4cb0806ba3 (patch) | |
| tree | d38e836f693501acfc300f463a4a2dd30d177f99 | |
| parent | abcb66e6e26781b1a4280837c5bbe5b57463ee13 (diff) | |
token: Automate token creation.
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | README.org | 16 | ||||
| -rw-r--r-- | lisp/forgejo-token.el | 91 | ||||
| -rw-r--r-- | lisp/forgejo.el | 14 |
4 files changed, 106 insertions, 17 deletions
@@ -18,7 +18,7 @@ SRCS = lisp/forgejo.el lisp/forgejo-api.el lisp/forgejo-db.el \ lisp/forgejo-buffer.el lisp/forgejo-tl.el lisp/forgejo-view.el \ lisp/forgejo-repo.el lisp/forgejo-issue.el lisp/forgejo-pull.el \ lisp/forgejo-vc.el lisp/forgejo-review.el lisp/forgejo-settings.el \ - lisp/forgejo-alert.el lisp/forgejo-watch.el + lisp/forgejo-token.el lisp/forgejo-alert.el lisp/forgejo-watch.el TESTS = tests/forgejo-test-load.el tests/forgejo-test-api.el \ tests/forgejo-test-db.el tests/forgejo-test-host.el \ @@ -18,7 +18,7 @@ Emacs front-end for [[https://forgejo.org][Forgejo]] instances (Codeberg, self-h =emacs-forgejo= is available via [[https://elpa.gnu.org/packages/forgejo.html][GNU ELPA]]. #+begin_src emacs-lisp - (use-package forgejo-vc + (use-package forgejo :ensure t :custom (forgejo-hosts '(("https://codeberg.org"))) @@ -30,18 +30,8 @@ Emacs front-end for [[https://forgejo.org][Forgejo]] instances (Codeberg, self-h (forgejo-watch-filter-default "read:no")) #+end_src -Store your token in =~/.authinfo.gpg=: - -#+begin_example -machine codeberg.org login YOUR_USERNAME password YOUR_TOKEN -#+end_example - -Or provide tokens inline: - -#+begin_src emacs-lisp - (setq forgejo-hosts '(("https://codeberg.org" "your-token") - ("https://git.myorg.com" "other-token"))) -#+end_src +Visit a codeberg/forgejo repo and call =M-x forgejo-vc=. It will +automatically handle the token creation. * Usage diff --git a/lisp/forgejo-token.el b/lisp/forgejo-token.el new file mode 100644 index 0000000..146eb6c --- /dev/null +++ b/lisp/forgejo-token.el @@ -0,0 +1,91 @@ +;;; forgejo-token.el --- Token creation for Forgejo -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 Free Software Foundation, Inc. + +;; Author: Thanos Apollo <public@thanosapollo.org> + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Create Forgejo API tokens via Basic Auth and save them to +;; auth-source. + +;;; Code: + +(require 'auth-source) +(require 'url) +(require 'forgejo) +(require 'forgejo-api) + +(defun forgejo-token--request (host-url username password) + "Create an API token on HOST-URL for USERNAME with PASSWORD. +Returns the token string on success, signals an error otherwise." + (let* ((url (forgejo-api--url host-url + (format "users/%s/tokens" username))) + (url-request-method "POST") + (url-request-extra-headers + `(("Authorization" + . ,(concat "Basic " + (base64-encode-string + (format "%s:%s" username password) t))) + ("Content-Type" . "application/json"))) + (url-request-data + (encode-coding-string + (json-encode '((name . "emacs-forgejo") (scopes . ("all")))) + 'utf-8)) + (buf (url-retrieve-synchronously url t))) + (unwind-protect + (let ((status (forgejo-api--response-status buf)) + (data (forgejo-api--parse-response buf))) + (unless (and status (< status 300)) + (user-error "Token creation failed (HTTP %s): %s" + (or status "?") + (or (alist-get 'message data) ""))) + (alist-get 'sha1 data)) + (kill-buffer buf)))) + +(defun forgejo-token--save (host username token) + "Save TOKEN for USERNAME@HOST to auth-source. +Falls back to copying TOKEN to the kill ring." + (let* ((auth-source-creation-defaults `((secret . ,token))) + (auth-source-creation-prompts '((secret . "Token: "))) + (entry (car (auth-source-search + :host host :user username + :require '(:secret) + :create t))) + (save-fn (plist-get entry :save-function))) + (if (functionp save-fn) + (progn + (funcall save-fn) + (auth-source-forget+ :host host) + (message "Token saved to auth-source for %s@%s." username host)) + (kill-new token) + (message "No writable auth-source; token copied to kill ring.")))) + +(defun forgejo-create-token (&optional host-url) + "Create a Forgejo API token and save it to auth-source. +HOST-URL is the instance URL; prompted when nil. +Returns the token string." + (interactive) + (let* ((host-url (or host-url (forgejo--host-from-hosts-list))) + (host (url-host (url-generic-parse-url host-url))) + (username (read-string (format "Username on %s: " host))) + (password (read-passwd (format "Password for %s@%s: " username host))) + (token (forgejo-token--request host-url username password))) + (forgejo-token--save host username token) + token)) + +(provide 'forgejo-token) +;;; forgejo-token.el ends here diff --git a/lisp/forgejo.el b/lisp/forgejo.el index 28a0caf..f30aa15 100644 --- a/lisp/forgejo.el +++ b/lisp/forgejo.el @@ -283,17 +283,25 @@ Falls back to \"https://HOSTNAME\" if not found." (user-error "Host %s not configured in `forgejo-hosts'" (url-host (url-generic-parse-url host-url))))) +(declare-function forgejo-create-token "forgejo-token.el" (&optional host-url)) + (defun forgejo-token (host-url) "Return the API token for HOST-URL. Resolution order: inline token from `forgejo-hosts', auth-source, -`forgejo-token' variable." +`forgejo-token' variable. When no token is found, offers to +create one via `forgejo-create-token'." (forgejo--validate-host host-url) (or (forgejo--hosts-token host-url) (and forgejo-token-use-auth-source (forgejo--auth-source-token host-url)) forgejo-token - (user-error "No token for host %s; add to `forgejo-hosts' or auth-source" - (url-host (url-generic-parse-url host-url))))) + (if (y-or-n-p (format "No token for %s. Create one now?" + (url-host (url-generic-parse-url host-url)))) + (or (forgejo-create-token host-url) + (user-error "Token creation failed for %s" + (url-host (url-generic-parse-url host-url)))) + (user-error "No token for host %s" + (url-host (url-generic-parse-url host-url)))))) ;;; Top-level menu |
