add NotFoundError to store
[epoint] / epoint-server.go
1 package main
2
3 import (
4         "crypto/openpgp"
5         "epoint/logic"
6         "fmt"
7         "log"
8         "net/http"
9         "os"
10 )
11
12 const (
13         addr    = ":8080"
14         rootdir = "docroot"
15         seckey  = "./key.sec"
16 )
17
18 var serverkey *openpgp.Entity
19
20 // todo: http header limit: 64K, body limit: 64K
21
22 // Dummy initialization of serverkey
23 func initkey() (err error) {
24         f, err := os.Open(seckey)
25         if err != nil {
26                 return
27         }
28         keys, err := openpgp.ReadKeyRing(f)
29         if err != nil {
30                 f.Close()
31                 return
32         }
33         err = f.Close()
34         if err != nil {
35                 return
36         }
37         serverkey = keys[0]
38         err = os.MkdirAll(rootdir, 0755)
39         if err != nil {
40                 return
41         }
42         f, err = os.Create(rootdir + "/serverkey")
43         if err != nil {
44                 return
45         }
46         err = serverkey.Serialize(f)
47         if err != nil {
48                 return
49         }
50         // TODO: make sure pubkey is replicated and available
51         err = f.Sync()
52         if err != nil {
53                 return
54         }
55         err = f.Close()
56         return
57 }
58
59 func httpError(w http.ResponseWriter, code int, msg string) {
60         log.Printf("error: %d %s", code, msg)
61         http.Error(w, fmt.Sprintf("%d %s\n\n%s\n", code, http.StatusText(code), msg), code)
62 }
63
64 func httpReq(r *http.Request) string {
65         err := r.ParseForm()
66         form := ""
67         if err != nil {
68                 form = err.Error()
69         } else {
70                 a := []string{}
71                 for k := range r.Form {
72                         a = append(a, k)
73                 }
74                 form = fmt.Sprintf("%v", a)
75         }
76         return fmt.Sprintf("%s %s params:%s", r.Method, r.URL.Raw, form)
77 }
78
79 func defaultHandler(w http.ResponseWriter, r *http.Request) {
80         log.Printf("%s %s", r.RemoteAddr, httpReq(r))
81         fmt.Fprintf(w, "not implemented: %s %s\n", r.Method, r.URL.Raw)
82 }
83
84 func submitHandler(w http.ResponseWriter, r *http.Request) {
85         log.Printf("%s %s", r.RemoteAddr, httpReq(r))
86         draft := r.FormValue("draft")
87         debit := r.FormValue("debit")
88         key := r.FormValue("key")
89         switch {
90         case draft != "":
91                 cert, err := logic.EvalDraft([]byte(draft), serverkey)
92                 if err != nil {
93                         msg := fmt.Sprintf("eval draft failed: %s", err)
94                         httpError(w, 404, msg)
95                 } else {
96                         w.Write(cert)
97                 }
98         case debit != "":
99                 cert, err := logic.EvalDebitCert([]byte(debit), serverkey)
100                 if err != nil {
101                         msg := fmt.Sprintf("eval debit failed: %s", err)
102                         httpError(w, 404, msg)
103                 } else {
104                         w.Write(cert)
105                 }
106         case key != "":
107                 err := logic.AddKeys([]byte(key))
108                 if err != nil {
109                         msg := fmt.Sprintf("add keys failed: %s", err)
110                         httpError(w, 404, msg)
111                 } else {
112                         w.Write([]byte("ok\nTODO: create cert 1 here?"))
113                 }
114         default:
115                 msg := fmt.Sprintf("expected key, draft or debit param, got: %s", httpReq(r))
116                 httpError(w, 404, msg)
117         }
118 }
119
120 func main() {
121         err := initkey()
122         if err != nil {
123                 log.Fatal(err)
124         }
125         err = logic.Init(rootdir)
126         if err != nil {
127                 log.Fatal(err)
128         }
129         err = logic.StoreSk(serverkey)
130         if err != nil {
131                 log.Fatal(err)
132         }
133
134         // TODO: url from key
135         f, err := os.Create(rootdir + "/form.html")
136         if err != nil {
137                 log.Fatal(err)
138         }
139         _, _ = fmt.Fprintf(f, `<html><head><title>epoint-server submit form</title></head><body>
140 <h2>epoint-server submit form</h2>
141 <h3>web form</h3>
142 <p>submit one document at once
143 <form method="post" action="http://localhost%s/submit">
144 <p>key:<br><textarea name="key" rows="5" cols="80"></textarea>
145 <p>draft:<br><textarea name="draft" rows="5" cols="80"></textarea>
146 <p>debit:<br><textarea name="debit" rows="5" cols="80"></textarea>
147 <p><input type="submit">
148 </form>
149 <h3>command line</h3>
150 <pre>
151 curl --data-urlencode name@path/to/file.txt host/submit
152 </pre>
153 where 'name' is 'key', 'draft' or 'debit'.
154 </body></html>
155 `, addr)
156         _ = f.Close()
157
158         // queries
159         http.Handle("/", http.FileServer(http.Dir(rootdir)))
160
161         // actions
162         // withdraw, draw, deposit, process, clear
163         http.HandleFunc("/submit", submitHandler)
164
165         log.Printf("start service on %s, server key id: %X\n", addr, serverkey.PrimaryKey.Fingerprint)
166         log.Fatal(http.ListenAndServe(addr, nil))
167 }