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