internal/httpd/account.go
129 lines · 3496 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 Keys []accountKey
52 PGP []accountPGP
53 Emails []store.Email
54 Host string
55 Notice string
56 Message string
57 }{s.baseFor(u), keys, pgp, emails, s.cfg.SiteHost(),
58 r.URL.Query().Get("e"), r.URL.Query().Get("m")})
59}
60
61// accountSubmit routes the account forms to their commands. Everything
62// here is a public key or an address — no secret is accepted over the web.
63func (s *Server) accountSubmit(w http.ResponseWriter, r *http.Request, u store.User) {
64 back := func(msg, note string) {
65 q := ""
66 switch {
67 case msg != "":
68 q = "?e=" + url.QueryEscape(msg)
69 case note != "":
70 q = "?m=" + url.QueryEscape(note)
71 }
72 http.Redirect(w, r, "/settings"+q, http.StatusSeeOther)
73 }
74
75 switch r.FormValue("field") {
76 case "key-add":
77 body := strings.TrimSpace(r.FormValue("key"))
78 if body == "" {
79 back("paste a public key in authorized_keys format", "")
80 return
81 }
82 argv := []string{"keys", "add"}
83 if scope := r.FormValue("scope"); scope == "git" {
84 argv = append(argv, "--scope", "git")
85 }
86 if msg, ok := s.runControlStdin(u, argv, body+"\n"); !ok {
87 back(msg, "")
88 return
89 }
90 back("", "key registered")
91 case "key-remove":
92 if _, msg, ok := s.runControl(u, []string{"keys", "remove", r.FormValue("fingerprint")}); !ok {
93 back(msg, "")
94 return
95 }
96 back("", "key removed")
97 case "pgp-add":
98 body := strings.TrimSpace(r.FormValue("key"))
99 if body == "" {
100 back("paste an armored OpenPGP public key", "")
101 return
102 }
103 if msg, ok := s.runControlStdin(u, []string{"pgp", "add"}, body+"\n"); !ok {
104 back(msg, "")
105 return
106 }
107 back("", "PGP key registered")
108 case "pgp-remove":
109 if _, msg, ok := s.runControl(u, []string{"pgp", "remove", r.FormValue("fingerprint")}); !ok {
110 back(msg, "")
111 return
112 }
113 back("", "PGP key removed")
114 case "email-add":
115 if _, msg, ok := s.runControl(u, []string{"email", "add", strings.TrimSpace(r.FormValue("address"))}); !ok {
116 back(msg, "")
117 return
118 }
119 back("", "check that inbox for a verification code")
120 case "email-verify":
121 if _, msg, ok := s.runControl(u, []string{"email", "verify", strings.TrimSpace(r.FormValue("code"))}); !ok {
122 back(msg, "")
123 return
124 }
125 back("", "address verified")
126 default:
127 back("unknown form", "")
128 }
129}