insert key into store only if it does not exist
[epoint] / cmd / epoint-client / epoint-client.go
1 package main
2
3 import (
4         "bytes"
5         "crypto/openpgp"
6         "crypto/openpgp/armor"
7         "crypto/rand"
8         "epoint/document"
9         "epoint/key"
10         "fmt"
11         "io"
12         "log"
13         "net/http"
14         "net/url"
15         "os"
16         "strconv"
17 )
18
19 const usage = `usage: ./epoint-client [k|d|s|v] [args..] < [seed|document]
20 server is http://localhost:8080 by default
21
22 k - make key, use seed for generation, args: [issuer] denomination
23 d - make draft, use seed as signing key, args: targetid value
24 s - submit a document, args: k[ey]|d[raft]|c[ert] [server]
25 v - verify a document (prints body of the document if ok)
26 `
27
28 func rnd(n int) (r []byte, err error) {
29         r = make([]byte, n)
30         _, err = io.ReadFull(rand.Reader, r)
31         return
32 }
33
34 func k(r []byte, issuer, denom string) (err error) {
35         var e *openpgp.Entity
36
37         if issuer == "" {
38                 e, err = key.Issuer(r, denom)
39         } else {
40                 e, err = key.Holder(r, issuer, denom)
41         }
42         if err != nil {
43                 return
44         }
45         w, err := armor.Encode(os.Stdout, openpgp.PublicKeyType, nil)
46         if err != nil {
47                 return
48         }
49         // TODO: maybe Serialize should do this internally
50         for _, ident := range e.Identities {
51                 err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
52                 if err != nil {
53                         return
54                 }
55         }
56         for _, subkey := range e.Subkeys {
57                 err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey)
58                 if err != nil {
59                         return
60                 }
61         }
62
63         err = e.Serialize(w)
64         if err != nil {
65                 return
66         }
67         err = w.Close()
68         if err != nil {
69                 return
70         }
71         _, err = os.Stdout.Write([]byte{'\n'})
72         return
73 }
74
75 func d(r []byte, target, value string) (err error) {
76         v, err := strconv.Atoi64(value)
77         if err != nil {
78                 return
79         }
80         e, err := key.Holder(r, "", "")
81         if err != nil {
82                 return
83         }
84         draft := new(document.Draft)
85         draft.Drawer = key.Id(e)
86         draft.Beneficiary = target
87         draft.Amount = v
88         draft.Denomination = "" // TODO
89         draft.Issuer = ""       // TODO
90         draft.AuthorizedBy = "" // TODO
91         nonce, err := rnd(10)
92         if err != nil {
93                 return
94         }
95         draft.Nonce = fmt.Sprintf("%X", nonce)
96         s, _, err := document.Format(draft, e)
97         if err != nil {
98                 return
99         }
100         _, err = os.Stdout.Write(s)
101         return
102 }
103
104 func s(d []byte, cmd, server string) (err error) {
105         m := map[string]string{
106                 "k": "key",
107                 "d": "draft",
108                 "c": "debit",
109         }
110         k, ok := m[cmd]
111         if !ok {
112                 err = fmt.Errorf("unknown submit command: %s", cmd)
113                 return
114         }
115         resp, err := http.PostForm(server, url.Values{k: {string(d)}})
116         if err != nil {
117                 return
118         }
119         if resp.StatusCode != 200 {
120                 log.Printf("request failed: %s\n", resp.Status)
121         }
122         _, err = io.Copy(os.Stdout, resp.Body)
123         if err != nil {
124                 return
125         }
126         err = resp.Body.Close()
127         return
128 }
129
130 func v(d []byte) (err error) {
131         // handle armored pubkey
132         if bytes.Index(d, []byte(openpgp.PublicKeyType)) >= 0 {
133                 es, err1 := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
134                 if err1 != nil {
135                         err = err1
136                         return
137                 }
138                 for _, e := range es {
139                         isIssuer, issuer, denom, err1 := key.Check(e)
140                         if err1 != nil {
141                                 if err != nil {
142                                         log.Println(err)
143                                 }
144                                 err = err1
145                                 continue
146                         }
147                         if isIssuer {
148                                 fmt.Println("Issuer key")
149                         } else {
150                                 fmt.Println("Holder key")
151                         }
152                         fmt.Printf("Issuer: %s\nDenomination: %s\nId: %s\n", issuer, denom, key.Id(e))
153                 }
154                 return
155         }
156         _, s, err := document.Parse(d)
157         if err != nil {
158                 return
159         }
160         _, err = os.Stdout.Write(s.Body)
161         return
162 }
163
164 func read() []byte {
165         b := make([]byte, 10000)
166         n, err := io.ReadFull(os.Stdin, b)
167         if err != io.ErrUnexpectedEOF {
168                 if err == nil {
169                         log.Fatal("too much input")
170                 }
171                 log.Fatal(err)
172         }
173         return b[:n]
174 }
175
176 func main() {
177         if len(os.Args) < 2 {
178                 log.Fatal(usage)
179         }
180
181         var err error
182         switch os.Args[1] {
183         case "k":
184                 issuer := ""
185                 denom := ""
186                 if len(os.Args) == 4 {
187                         issuer = os.Args[2]
188                         denom = os.Args[3]
189                 } else if len(os.Args) == 3 {
190                         denom = os.Args[2]
191                 } else {
192                         log.Fatal(usage)
193                 }
194                 err = k(read(), issuer, denom)
195         case "d":
196                 if len(os.Args) != 4 {
197                         log.Fatal(usage)
198                 }
199                 err = d(read(), os.Args[2], os.Args[3])
200         case "s":
201                 server := "http://localhost:8080"
202                 cmd := ""
203                 if len(os.Args) == 4 {
204                         cmd = os.Args[2]
205                         server = os.Args[3]
206                 } else if len(os.Args) == 3 {
207                         cmd = os.Args[2]
208                 } else {
209                         log.Fatal(usage)
210                 }
211                 err = s(read(), cmd, server+"/submit")
212         case "v":
213                 if len(os.Args) != 2 {
214                         log.Fatal(usage)
215                 }
216                 err = v(read())
217         }
218         if err != nil {
219                 log.Fatal(err)
220         }
221 }