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