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)
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}
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)
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))
36 71bdede3 2022-04-21 o type aliasesHandler struct {
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)
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)
54 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(aliases)
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)
62 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(alias)
64 71bdede3 2022-04-21 o jerror(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)
68 71bdede3 2022-04-21 o type aliasHandler struct {
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)
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)
85 71bdede3 2022-04-21 o var alias Alias
87 71bdede3 2022-04-21 o for _, a := range aliases {
88 71bdede3 2022-04-21 o if a.Recipient == recipient {
94 71bdede3 2022-04-21 o jerror(w, "no such alias", http.StatusNotFound)
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)
104 71bdede3 2022-04-21 o w.WriteHeader(http.StatusNoContent)
106 71bdede3 2022-04-21 o case http.MethodGet:
107 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(alias)
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)
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)
122 71bdede3 2022-04-21 o alias.Expiry = time.Unix(int64(i), 0)
124 71bdede3 2022-04-21 o alias.Note = req.PostForm.Get(param)
126 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("invalid alias parameter %s", param), http.StatusBadRequest)
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)
134 71bdede3 2022-04-21 o json.NewEncoder(w).Encode(alias)
137 71bdede3 2022-04-21 o jerror(w, "not implemented yet", http.StatusMethodNotAllowed)
141 71bdede3 2022-04-21 o type authHandler struct {
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)
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)
157 71bdede3 2022-04-21 o next.ServeHTTP(w, req)
159 71bdede3 2022-04-21 o return http.HandlerFunc(fn)
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)
169 71bdede3 2022-04-21 o if err := req.ParseForm(); err != nil {
170 71bdede3 2022-04-21 o jerror(w, err.Error(), http.StatusBadRequest)
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)
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)
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)
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)
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
198 71bdede3 2022-04-21 o jerror(w, fmt.Sprintf("change %s: %v", username, err), code)