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