summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README.org16
-rw-r--r--lisp/forgejo-token.el91
-rw-r--r--lisp/forgejo.el14
4 files changed, 106 insertions, 17 deletions
diff --git a/Makefile b/Makefile
index a0ef608..d32eb93 100644
--- a/Makefile
+++ b/Makefile
@@ -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 \
diff --git a/README.org b/README.org
index f046405..ef9bceb 100644
--- a/README.org
+++ b/README.org
@@ -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