Blame


1 71bdede3 2022-04-21 o package mailmux
2 71bdede3 2022-04-21 o
3 71bdede3 2022-04-21 o import (
4 71bdede3 2022-04-21 o "encoding/json"
5 71bdede3 2022-04-21 o "errors"
6 71bdede3 2022-04-21 o "fmt"
7 71bdede3 2022-04-21 o "net/http"
8 71bdede3 2022-04-21 o "path"
9 71bdede3 2022-04-21 o "strconv"
10 71bdede3 2022-04-21 o "strings"
11 71bdede3 2022-04-21 o "time"
12 71bdede3 2022-04-21 o )
13 71bdede3 2022-04-21 o
14 71bdede3 2022-04-21 o func jerror(w http.ResponseWriter, msg string, status int) {
15 71bdede3 2022-04-21 o w.WriteHeader(status)
16 71bdede3 2022-04-21 o m := map[string]string{"error": msg}
17 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(m)
18 71bdede3 2022-04-21 o }
19 71bdede3 2022-04-21 o
20 71bdede3 2022-04-21 o func NewWebServer(aliases AliasStore, users UserStore) http.Handler {
21 71bdede3 2022-04-21 o mux := http.NewServeMux()
22 71bdede3 2022-04-21 o aliaseshandler := &aliasesHandler{aliases}
23 71bdede3 2022-04-21 o aliashandler := &aliasHandler{aliases}
24 acca18c6 2022-04-23 o
25 71bdede3 2022-04-21 o authhandler := &authHandler{users}
26 acca18c6 2022-04-23 o // 8KB is definitely large enough for any reasonable registration
27 acca18c6 2022-04-23 o // request and response.
28 acca18c6 2022-04-23 o limitedAuthHandler := http.MaxBytesHandler(authhandler, 8*1024)
29 acca18c6 2022-04-23 o
30 acca18c6 2022-04-23 o mux.Handle("/register", limitedAuthHandler)
31 acca18c6 2022-04-23 o mux.Handle("/aliases", authhandler.basicAuth(aliaseshandler))
32 acca18c6 2022-04-23 o mux.Handle("/aliases/", authhandler.basicAuth(aliashandler))
33 71bdede3 2022-04-21 o return mux
34 71bdede3 2022-04-21 o }
35 71bdede3 2022-04-21 o
36 71bdede3 2022-04-21 o type aliasesHandler struct {
37 71bdede3 2022-04-21 o AliasStore
38 71bdede3 2022-04-21 o }
39 71bdede3 2022-04-21 o
40 71bdede3 2022-04-21 o func (h *aliasesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
41 71bdede3 2022-04-21 o username, _, ok := req.BasicAuth()
42 71bdede3 2022-04-21 o if !ok || len(username) == 0 {
43 71bdede3 2022-04-21 o jerror(w, "empty username", http.StatusForbidden)
44 71bdede3 2022-04-21 o return
45 71bdede3 2022-04-21 o }
46 71bdede3 2022-04-21 o
47 71bdede3 2022-04-21 o switch req.Method {
48 71bdede3 2022-04-21 o case http.MethodGet:
49 71bdede3 2022-04-21 o aliases, err := h.Aliases(username)
50 71bdede3 2022-04-21 o if err != nil {
51 71bdede3 2022-04-21 o jerror(w, err.Error(), http.StatusInternalServerError)
52 71bdede3 2022-04-21 o return
53 71bdede3 2022-04-21 o }
54 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(aliases)
55 71bdede3 2022-04-21 o
56 71bdede3 2022-04-21 o case http.MethodPost:
57 71bdede3 2022-04-21 o alias, err := h.Create(username)
58 71bdede3 2022-04-21 o if err != nil {
59 71bdede3 2022-04-21 o jerror(w, err.Error(), http.StatusInternalServerError)
60 71bdede3 2022-04-21 o return
61 71bdede3 2022-04-21 o }
62 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(alias)
63 71bdede3 2022-04-21 o default:
64 71bdede3 2022-04-21 o jerror(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)
65 71bdede3 2022-04-21 o }
66 71bdede3 2022-04-21 o }
67 71bdede3 2022-04-21 o
68 71bdede3 2022-04-21 o type aliasHandler struct {
69 71bdede3 2022-04-21 o AliasStore
70 71bdede3 2022-04-21 o }
71 71bdede3 2022-04-21 o
72 71bdede3 2022-04-21 o func (h *aliasHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
73 71bdede3 2022-04-21 o username, _, ok := req.BasicAuth()
74 71bdede3 2022-04-21 o if !ok || len(username) == 0 {
75 71bdede3 2022-04-21 o jerror(w, "empty username", http.StatusForbidden)
76 71bdede3 2022-04-21 o return
77 71bdede3 2022-04-21 o }
78 71bdede3 2022-04-21 o
79 71bdede3 2022-04-21 o recipient := path.Base(req.URL.Path)
80 71bdede3 2022-04-21 o aliases, err := h.Aliases(username)
81 71bdede3 2022-04-21 o if err != nil {
82 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("aliases for %s: %v", recipient, err), http.StatusInternalServerError)
83 71bdede3 2022-04-21 o return
84 71bdede3 2022-04-21 o }
85 71bdede3 2022-04-21 o var alias Alias
86 71bdede3 2022-04-21 o var found bool
87 71bdede3 2022-04-21 o for _, a := range aliases {
88 71bdede3 2022-04-21 o if a.Recipient == recipient {
89 71bdede3 2022-04-21 o alias = a
90 71bdede3 2022-04-21 o found = true
91 71bdede3 2022-04-21 o }
92 71bdede3 2022-04-21 o }
93 71bdede3 2022-04-21 o if !found {
94 71bdede3 2022-04-21 o jerror(w, "no such alias", http.StatusNotFound)
95 71bdede3 2022-04-21 o return
96 71bdede3 2022-04-21 o }
97 71bdede3 2022-04-21 o
98 71bdede3 2022-04-21 o switch req.Method {
99 71bdede3 2022-04-21 o case http.MethodDelete:
100 71bdede3 2022-04-21 o if err := h.Delete(recipient); err != nil {
101 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("delete %s: %v", recipient, err), http.StatusInternalServerError)
102 71bdede3 2022-04-21 o return
103 71bdede3 2022-04-21 o }
104 71bdede3 2022-04-21 o w.WriteHeader(http.StatusNoContent)
105 71bdede3 2022-04-21 o
106 71bdede3 2022-04-21 o case http.MethodGet:
107 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(alias)
108 71bdede3 2022-04-21 o
109 71bdede3 2022-04-21 o case http.MethodPost:
110 71bdede3 2022-04-21 o if err := req.ParseForm(); err != nil {
111 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("parse form: %v", err), http.StatusBadRequest)
112 71bdede3 2022-04-21 o return
113 71bdede3 2022-04-21 o }
114 71bdede3 2022-04-21 o for param := range req.PostForm {
115 71bdede3 2022-04-21 o switch param {
116 71bdede3 2022-04-21 o case "expiry":
117 71bdede3 2022-04-21 o i, err := strconv.Atoi(req.PostForm.Get(param))
118 71bdede3 2022-04-21 o if err != nil {
119 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("parse expiry: %v", err), http.StatusBadRequest)
120 71bdede3 2022-04-21 o return
121 71bdede3 2022-04-21 o }
122 71bdede3 2022-04-21 o alias.Expiry = time.Unix(int64(i), 0)
123 71bdede3 2022-04-21 o case "note":
124 71bdede3 2022-04-21 o alias.Note = req.PostForm.Get(param)
125 71bdede3 2022-04-21 o default:
126 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("invalid alias parameter %s", param), http.StatusBadRequest)
127 71bdede3 2022-04-21 o return
128 71bdede3 2022-04-21 o }
129 71bdede3 2022-04-21 o }
130 71bdede3 2022-04-21 o if err := h.Put(alias); err != nil {
131 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("update alias %s: %v", alias.Recipient, err), http.StatusInternalServerError)
132 71bdede3 2022-04-21 o return
133 71bdede3 2022-04-21 o }
134 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(alias)
135 71bdede3 2022-04-21 o
136 71bdede3 2022-04-21 o default:
137 71bdede3 2022-04-21 o jerror(w, "not implemented yet", http.StatusMethodNotAllowed)
138 71bdede3 2022-04-21 o }
139 71bdede3 2022-04-21 o }
140 71bdede3 2022-04-21 o
141 71bdede3 2022-04-21 o type authHandler struct {
142 71bdede3 2022-04-21 o UserStore
143 71bdede3 2022-04-21 o }
144 71bdede3 2022-04-21 o
145 71bdede3 2022-04-21 o func (h *authHandler) basicAuth(next http.Handler) http.Handler {
146 71bdede3 2022-04-21 o fn := func(w http.ResponseWriter, req *http.Request) {
147 71bdede3 2022-04-21 o username, password, ok := req.BasicAuth()
148 71bdede3 2022-04-21 o if !ok || len(username) == 0 || len(password) == 0 {
149 71bdede3 2022-04-21 o jerror(w, "unauthorised", http.StatusUnauthorized)
150 71bdede3 2022-04-21 o return
151 71bdede3 2022-04-21 o }
152 71bdede3 2022-04-21 o err := h.Authenticate(username, Password(password))
153 71bdede3 2022-04-21 o if err != nil {
154 71bdede3 2022-04-21 o jerror(w, "unauthorised", http.StatusUnauthorized)
155 71bdede3 2022-04-21 o return
156 71bdede3 2022-04-21 o }
157 71bdede3 2022-04-21 o next.ServeHTTP(w, req)
158 71bdede3 2022-04-21 o }
159 71bdede3 2022-04-21 o return http.HandlerFunc(fn)
160 71bdede3 2022-04-21 o }
161 71bdede3 2022-04-21 o
162 71bdede3 2022-04-21 o func (h *authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
163 71bdede3 2022-04-21 o if req.Method != http.MethodPost {
164 71bdede3 2022-04-21 o code := http.StatusMethodNotAllowed
165 71bdede3 2022-04-21 o http.Error(w, http.StatusText(code), code)
166 71bdede3 2022-04-21 o return
167 71bdede3 2022-04-21 o }
168 71bdede3 2022-04-21 o
169 71bdede3 2022-04-21 o if err := req.ParseForm(); err != nil {
170 71bdede3 2022-04-21 o jerror(w, err.Error(), http.StatusBadRequest)
171 71bdede3 2022-04-21 o return
172 71bdede3 2022-04-21 o }
173 71bdede3 2022-04-21 o username := req.PostForm.Get("username")
174 71bdede3 2022-04-21 o if username == "" {
175 71bdede3 2022-04-21 o jerror(w, "empty username", http.StatusBadRequest)
176 71bdede3 2022-04-21 o return
177 71bdede3 2022-04-21 o }
178 71bdede3 2022-04-21 o password := req.PostForm.Get("password")
179 71bdede3 2022-04-21 o if password == "" {
180 71bdede3 2022-04-21 o jerror(w, "empty password", http.StatusBadRequest)
181 71bdede3 2022-04-21 o return
182 71bdede3 2022-04-21 o }
183 71bdede3 2022-04-21 o
184 71bdede3 2022-04-21 o _, err := h.Lookup(username)
185 71bdede3 2022-04-21 o if err == nil {
186 71bdede3 2022-04-21 o jerror(w, "user already exists", http.StatusBadRequest)
187 71bdede3 2022-04-21 o return
188 71bdede3 2022-04-21 o } else if !errors.Is(err, ErrUnknownUser) {
189 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("lookup %s: %v", username, err), http.StatusInternalServerError)
190 71bdede3 2022-04-21 o return
191 71bdede3 2022-04-21 o }
192 71bdede3 2022-04-21 o
193 71bdede3 2022-04-21 o if err := h.Change(username, Password(password)); err != nil {
194 71bdede3 2022-04-21 o code := http.StatusInternalServerError
195 71bdede3 2022-04-21 o if strings.Contains(err.Error(), "invalid username") {
196 71bdede3 2022-04-21 o code = http.StatusBadRequest
197 71bdede3 2022-04-21 o }
198 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("change %s: %v", username, err), code)
199 71bdede3 2022-04-21 o }
200 71bdede3 2022-04-21 o }