~bigbes/sr-ht-dolt

ref: cd0b0c0fb427bff6060c3f785d67784b999610f3 sr-ht-dolt/web/handlers_keys.go -rw-r--r-- 3.4 KiB
cd0b0c0f — Eugene Blikh web: rename a database from its settings page 3 days ago
                                                                                
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
package web

import (
	"errors"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"sourcecraft.dev/bigbes/sr-ht-ecore/chrome"
	"sourcecraft.dev/bigbes/sr-ht-ecore/pages"

	"sourcecraft.dev/bigbes/sr-ht-dolt/db"
)

// keysView is the dolt-key management page model.
type keysView struct {
	chrome.Page
	Keys   []*db.DoltKey
	Error  string
	Notice string
}

func (a *app) renderKeys(w http.ResponseWriter, r *http.Request, ac *authContext, status int, errMsg, notice string) {
	keys, err := a.cfg.Repos.ListKeysByUser(r.Context(), ac.UserID)
	if err != nil {
		http.Error(w, "failed to list keys", http.StatusInternalServerError)
		return
	}
	view := keysView{
		Page:   a.page(r, "Dolt keys — "+serviceName),
		Keys:   keys,
		Error:  errMsg,
		Notice: notice,
	}
	a.render(w, status, "keys", view)
}

// handleKeys renders the dolt-key page: the user's registered keys and the
// add-key form. The page reads a `#<pubkey-base32>` URL fragment (which
// `dolt login` appends) into the form via a few lines of inline JS, but works
// without JS too — the user can paste the key the CLI printed. Login required.
func (a *app) handleKeys(w http.ResponseWriter, r *http.Request) {
	ac := a.requireLogin(w, r)
	if ac == nil {
		return
	}
	a.renderKeys(w, r, ac, http.StatusOK, "", "")
}

// handleKeysPost adds or deletes a dolt key. A form carrying `delete_id` removes
// that key; otherwise `pubkey` (the base32 string dolt emits) is decoded,
// validated and registered. Login is required; the same-origin check is the
// router's (csrf.Require) and has already run.
func (a *app) handleKeysPost(w http.ResponseWriter, r *http.Request) {
	ac := a.requireLogin(w, r)
	if ac == nil {
		return
	}
	form, err := pages.FormValues(w, r, 0)
	if err != nil {
		a.renderKeys(w, r, ac, http.StatusBadRequest, "Malformed form submission.", "")
		return
	}

	if idStr := form.Get("delete_id"); idStr != "" {
		a.keysDelete(w, r, ac, idStr)
		return
	}
	a.keysAdd(w, r, ac, form)
}

// keysAdd decodes and registers a dolt public key for the caller.
func (a *app) keysAdd(w http.ResponseWriter, r *http.Request, ac *authContext, form url.Values) {
	pubStr := strings.TrimSpace(form.Get("pubkey"))
	comment := strings.TrimSpace(form.Get("comment"))

	pubkey, kid, err := decodeDoltPubKey(pubStr)
	if err != nil {
		a.renderKeys(w, r, ac, http.StatusBadRequest, "Invalid public key: "+err.Error(), "")
		return
	}

	if _, err := a.cfg.Repos.InsertKey(r.Context(), ac.UserID, kid, pubkey, comment); err != nil {
		if errors.Is(err, db.ErrKeyExists) {
			a.renderKeys(w, r, ac, http.StatusConflict, "That key is already registered.", "")
			return
		}
		http.Error(w, "failed to register key", http.StatusInternalServerError)
		return
	}
	a.renderKeys(w, r, ac, http.StatusOK, "", "Key added. You can now use `dolt clone`/`push` without --user.")
}

// keysDelete removes one of the caller's keys, scoped by user id so a user can
// only delete their own keys.
func (a *app) keysDelete(w http.ResponseWriter, r *http.Request, ac *authContext, idStr string) {
	id, err := strconv.Atoi(idStr)
	if err != nil {
		a.renderKeys(w, r, ac, http.StatusBadRequest, "Invalid key id.", "")
		return
	}
	if err := a.cfg.Repos.DeleteKey(r.Context(), id, ac.UserID); err != nil {
		if errors.Is(err, db.ErrNotFound) {
			a.renderKeys(w, r, ac, http.StatusNotFound, "No such key.", "")
			return
		}
		http.Error(w, "failed to delete key", http.StatusInternalServerError)
		return
	}
	a.renderKeys(w, r, ac, http.StatusOK, "", "Key deleted.")
}