dsakey proof of concept (needs cleanup)
[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
130         // TODO: url from key
131         f, err := os.Create(rootdir + "/form.html")
132         if err != nil {
133                 log.Fatal(err)
134         }
135         _, _ = fmt.Fprintf(f, `<html><head><title>epoint-server submit form</title></head><body>
136 <h2>epoint-server submit form</h2>
137 <h3>web form</h3>
138 <p>submit one document at once
139 <form method="post" action="http://localhost%s/submit">
140 <p>key:<br><textarea name="key" rows="5" cols="80"></textarea>
141 <p>draft:<br><textarea name="draft" rows="5" cols="80"></textarea>
142 <p>debit:<br><textarea name="debit" rows="5" cols="80"></textarea>
143 <p><input type="submit">
144 </form>
145 <h3>command line</h3>
146 <pre>
147 curl --data-urlencode name@path/to/file.txt host/submit
148 </pre>
149 where 'name' is 'key', 'draft' or 'debit'.
150 </body></html>
151 `, addr)
152         _ = f.Close()
153
154         // queries
155         http.Handle("/", http.FileServer(http.Dir(rootdir)))
156
157         // actions
158         // withdraw, draw, deposit, process, clear
159         http.HandleFunc("/submit", submitHandler)
160
161         log.Printf("start service on %s, server key id: %X\n", addr, serverkey.PrimaryKey.Fingerprint)
162         log.Fatal(http.ListenAndServe(addr, nil))
163 }