Blob


1 package mailmux
3 import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "log"
8 "net/http"
9 )
11 type Server struct {
12 aliases AliasStore
13 users UserStore
14 }
16 // rerror replies to the HTTP request with a JSON-encoded Rerror message
17 // with its Error field set to errormsg.
18 // Just like http.Error, callers should ensure no further writes are done to w.
19 func rerror(w http.ResponseWriter, errormsg string, status int) {
20 w.WriteHeader(status)
21 rmsg := &Mcall{Type: Rerror, Error: errormsg}
22 if err := json.NewEncoder(w).Encode(rmsg); err != nil {
23 http.Error(w, err.Error(), http.StatusInternalServerError)
24 return
25 }
26 }
28 func NewWebServer(aliases AliasStore, users UserStore) http.Handler {
29 mux := http.NewServeMux()
30 srv := Server{aliases, users}
31 mux.HandleFunc("/register", srv.registerHandler)
32 mux.HandleFunc("/alias", srv.aliasHandler)
33 return mux
34 }
36 func (srv *Server) registerHandler(w http.ResponseWriter, req *http.Request) {
37 if req.Method != http.MethodPost {
38 rerror(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
39 return
40 }
42 defer req.Body.Close()
43 tmsg, err := ParseMcall(req.Body)
44 if err != nil {
45 rerror(w, err.Error(), http.StatusBadRequest)
46 return
47 }
48 if tmsg.Type != Tregister {
49 s := fmt.Sprintf("mcall type %d is not Tregister", tmsg.Type)
50 rerror(w, s, http.StatusBadRequest)
51 return
52 }
54 _, err = srv.users.Lookup(tmsg.Username)
55 if err == nil {
56 rerror(w, "user already exists", http.StatusBadRequest)
57 return
58 } else if !errors.Is(err, ErrUnknownUser) {
59 rerror(w, err.Error(), http.StatusInternalServerError)
60 return
61 }
63 if err := srv.users.Change(tmsg.Username, Password(tmsg.Password)); err != nil {
64 rerror(w, err.Error(), http.StatusInternalServerError)
65 return
66 }
67 rmsg := &Mcall{
68 Type: Rregister,
69 Username: tmsg.Username,
70 }
71 b, err := json.Marshal(rmsg)
72 if err != nil {
73 rerror(w, err.Error(), http.StatusInternalServerError)
74 return
75 }
76 w.Write(b)
77 }
79 func (srv *Server) aliasHandler(w http.ResponseWriter, req *http.Request) {
80 tmsg, err := ParseMcall(req.Body)
81 if err != nil {
82 rerror(w, err.Error(), http.StatusBadRequest)
83 return
84 }
86 err = srv.users.Authenticate(tmsg.Username, Password(tmsg.Password))
87 if err != nil {
88 rerror(w, "unauthorised", http.StatusUnauthorized)
89 log.Println(err)
90 return
91 }
93 var rmsg *Mcall
94 switch tmsg.Type {
95 case Tnew:
96 rmsg = srv.newAlias(tmsg)
97 case Tlist:
98 rmsg = srv.listAliasHandler(tmsg)
99 default:
100 rerror(w, "not implemented yet", http.StatusNotImplemented)
101 return
103 if rmsg.Type == Rerror {
104 w.WriteHeader(http.StatusInternalServerError)
106 if err := json.NewEncoder(w).Encode(rmsg); err != nil {
107 rerror(w, err.Error(), http.StatusInternalServerError)
111 func (srv *Server) newAlias(tmsg *Mcall) *Mcall {
112 alias, err := srv.aliases.Create(tmsg.Username)
113 if err != nil {
114 return &Mcall{Type: Rerror, Error: err.Error()}
116 return &Mcall{Type: Rnew, Username: tmsg.Username, Aliases: []Alias{alias}}
119 func (srv *Server) listAliasHandler(tmsg *Mcall) *Mcall {
120 a, err := srv.aliases.Aliases(tmsg.Username)
121 if err != nil {
122 return &Mcall{Type: Rerror, Error: err.Error()}
124 return &Mcall{Type: Rlist, Username: tmsg.Username, Aliases: a}