internal/httpd/account.go
130 lines · 3568 bytes
1package httpd
2
3import (
4 "encoding/json"
5 "net/http"
6 "net/url"
7 "strings"
8
9 "gitbay.org/gitbay/internal/store"
10)
11
12// accountKey is one SSH key as the settings page shows it: enough to
13// recognise which key this is without printing the whole blob.
14type accountKey struct {
15 Fingerprint string
16 Algo string
17 Scope string
18}
19
20type accountPGP struct {
21 Fingerprint string
22 UIDs []string
23 Expired bool
24 Revoked bool
25}
26
27// accountForm renders the account's own settings: keys, addresses, and the
28// commands for everything that stays on SSH.
29func (s *Server) accountForm(w http.ResponseWriter, r *http.Request, u store.User) {
30 var keys []accountKey
31 if list, err := s.st.ListSSHKeys(u.ID); err == nil {
32 for _, k := range list {
33 keys = append(keys, accountKey{Fingerprint: k.Fingerprint, Algo: k.Algo, Scope: k.Scope})
34 }
35 }
36 var pgp []accountPGP
37 if list, err := s.st.ListPGPKeys(u.ID); err == nil {
38 for _, k := range list {
39 var uids []string
40 json.Unmarshal([]byte(k.UIDsJSON), &uids)
41 pgp = append(pgp, accountPGP{
42 Fingerprint: k.Fingerprint, UIDs: uids,
43 Expired: k.ExpiresAt != nil, Revoked: k.RevokedAt != nil,
44 })
45 }
46 }
47 emails, _ := s.st.ListEmails(u.ID)
48
49 s.render(w, "account.html", struct {
50 basePage
51 Tab string // marks the rail's Settings row as current
52 Keys []accountKey
53 PGP []accountPGP
54 Emails []store.Email
55 Host string
56 Notice string
57 Message string
58 }{s.baseFor(u), "account", keys, pgp, emails, s.cfg.SiteHost(),
59 r.URL.Query().Get("e"), r.URL.Query().Get("m")})
60}
61
62// accountSubmit routes the account forms to their commands. Everything
63// here is a public key or an address — no secret is accepted over the web.
64func (s *Server) accountSubmit(w http.ResponseWriter, r *http.Request, u store.User) {
65 back := func(msg, note string) {
66 q := ""
67 switch {
68 case msg != "":
69 q = "?e=" + url.QueryEscape(msg)
70 case note != "":
71 q = "?m=" + url.QueryEscape(note)
72 }
73 http.Redirect(w, r, "/settings"+q, http.StatusSeeOther)
74 }
75
76 switch r.FormValue("field") {
77 case "key-add":
78 body := strings.TrimSpace(r.FormValue("key"))
79 if body == "" {
80 back("paste a public key in authorized_keys format", "")
81 return
82 }
83 argv := []string{"keys", "add"}
84 if scope := r.FormValue("scope"); scope == "git" {
85 argv = append(argv, "--scope", "git")
86 }
87 if msg, ok := s.runControlStdin(u, argv, body+"\n"); !ok {
88 back(msg, "")
89 return
90 }
91 back("", "key registered")
92 case "key-remove":
93 if _, msg, ok := s.runControl(u, []string{"keys", "remove", r.FormValue("fingerprint")}); !ok {
94 back(msg, "")
95 return
96 }
97 back("", "key removed")
98 case "pgp-add":
99 body := strings.TrimSpace(r.FormValue("key"))
100 if body == "" {
101 back("paste an armored OpenPGP public key", "")
102 return
103 }
104 if msg, ok := s.runControlStdin(u, []string{"pgp", "add"}, body+"\n"); !ok {
105 back(msg, "")
106 return
107 }
108 back("", "PGP key registered")
109 case "pgp-remove":
110 if _, msg, ok := s.runControl(u, []string{"pgp", "remove", r.FormValue("fingerprint")}); !ok {
111 back(msg, "")
112 return
113 }
114 back("", "PGP key removed")
115 case "email-add":
116 if _, msg, ok := s.runControl(u, []string{"email", "add", strings.TrimSpace(r.FormValue("address"))}); !ok {
117 back(msg, "")
118 return
119 }
120 back("", "check that inbox for a verification code")
121 case "email-verify":
122 if _, msg, ok := s.runControl(u, []string{"email", "verify", strings.TrimSpace(r.FormValue("code"))}); !ok {
123 back(msg, "")
124 return
125 }
126 back("", "address verified")
127 default:
128 back("unknown form", "")
129 }
130}