20 // TODO: store documents, query document by id, easy submit
24 const usage = `usage: ./epoint-client [i|h|d|q|s|v|c] [args..] < [seed|document]
25 server is http://localhost:8080 by default
27 i - make issuer key, use seed for generation, args: denomination
28 h - make holder key, use seed for generation, args: issuer
29 d - make draft, use seed for signing key, args: targetid value
30 q - query document, args: k|d|c id [server]
31 s - submit a (key|draft|cert) document, args: k|d|c [server]
32 v - verify a document (prints body of the document if ok)
33 c - connect to server and get server key, args: [server]
36 func rnd(n int) (r []byte, err error) {
38 _, err = io.ReadFull(rand.Reader, r)
42 func k(r []byte, cmd, arg string) (err error) {
46 e, err = key.Issuer(r, arg)
48 s, err1 := db.Get("key", arg)
53 ie, err1 := key.Parse(s)
58 isIssuer, _, denom, err1 := key.Check(ie)
64 err = fmt.Errorf("Not an issuer key: %s", arg)
67 e, err = key.Holder(r, arg, denom)
72 log.Printf("generated key %s", key.Id(e))
73 d, err := db.Get("key", key.Id(e))
75 // TODO: issuer, denom check (remove keys from store if they are not sent to server?)
76 log.Printf("key %s was found in store", key.Id(e))
78 out := new(bytes.Buffer)
79 w, err1 := armor.Encode(out, openpgp.PublicKeyType, nil)
84 // TODO: maybe Serialize should do this internally
85 for _, ident := range e.Identities {
86 err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
91 for _, subkey := range e.Subkeys {
92 err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey)
105 _, err = out.Write([]byte{'\n'})
110 err = db.Insert("key", key.Id(e), d)
115 _, err = os.Stdout.Write(d)
119 func d(r []byte, target, value string) (err error) {
120 v, err := strconv.ParseInt(value, 10, 64)
124 e, err := key.Holder(r, "", "")
128 log.Printf("drawer: %s", key.Id(e))
129 if key.Id(e) == target {
130 err = fmt.Errorf("Drawer and beneficiary are the same")
133 b, err := db.Get("key", key.Id(e))
137 e1, err := key.Parse(b)
141 _, issuer, denom, err := key.Check(e1)
145 // TODO: store server id as well?
146 b, err = db.Get("", "serverkey")
150 sk, err := key.Parse(b)
154 // TODO: check beneficiary (check value?)
155 draft := new(document.Draft)
156 draft.Drawer = key.Id(e)
157 draft.Beneficiary = target
159 draft.Denomination = denom
160 draft.Issuer = issuer
161 draft.AuthorizedBy = key.Id(sk)
162 nonce, err := rnd(10)
166 draft.Nonce = fmt.Sprintf("%X", nonce)
167 s, c, err := document.Format(draft, e)
171 log.Printf("draft id: %s", document.Id(c))
172 _, err = os.Stdout.Write(s)
176 func q(cmd, id, server string) (err error) {
177 log.Printf("document id: %s, server: %s", id, server)
178 m := map[string]string{
185 err = fmt.Errorf("unknown query command: %s", cmd)
188 d, err := db.Get(k, id)
190 if _, ok := err.(store.NotFoundError); !ok {
194 _, err = os.Stdout.Write(d)
195 log.Printf("found %s in local store", id)
198 resp, err := http.Get(server+"/"+k+"/"+id)
202 d, err = readall(resp.Body)
206 err = resp.Body.Close()
210 _, err = os.Stdout.Write(d)
211 if resp.StatusCode != 200 {
212 err = fmt.Errorf("request failed: %s", resp.Status)
218 log.Printf("got %s from the server", id)
221 e, err1 := key.Parse(d)
227 err = fmt.Errorf("id mismatch, expected %s, got %s", id, key.Id(e))
230 err = db.Set("key", id, d)
232 i, s, err1 := document.Parse(d)
237 if id != document.Id(s) {
238 err = fmt.Errorf("id mismatch, expected %s, got %s", id, document.Id(s))
241 draft := i.(*document.Draft)
242 b, err1 := db.Get("key", draft.Drawer)
247 e, err1 := key.Parse(b)
252 err = document.Verify(s, openpgp.EntityList{e})
256 err = db.Set("draft", id, d)
258 i, s, err1 := document.Parse(d)
263 if id != document.Id(s) {
264 err = fmt.Errorf("id mismatch, expected %s, got %s", id, document.Id(s))
267 cert, err1 := document.ToCert(i)
272 // TODO: check serverkey
273 b, err1 := db.Get("key", cert.AuthorizedBy)
278 e, err1 := key.Parse(b)
283 err = document.Verify(s, openpgp.EntityList{e})
287 err = db.Set("cert", id, d)
292 func s(d []byte, cmd, server string) (err error) {
293 m := map[string]string{
300 err = fmt.Errorf("unknown submit command: %s", cmd)
306 e, err1 := key.Parse(d)
312 err = db.Set("key", id, d)
314 _, s, err1 := document.Parse(d)
320 err = db.Set("draft", id, d)
322 _, s, err1 := document.Parse(d)
328 err = db.Set("cert", id, d)
333 log.Printf("document id: %s, server: %s", id, server)
334 resp, err := http.PostForm(server+"/submit", url.Values{k: {string(d)}})
338 if resp.StatusCode != 200 {
339 log.Printf("request failed: %s", resp.Status)
341 // TODO: store result
342 b, err := readall(resp.Body)
343 defer resp.Body.Close()
347 _, err = os.Stdout.Write(b)
351 cert, s, err := document.Parse(b)
355 d, err = db.Get("", "serverkey")
359 e, err := key.Parse(d)
363 err = document.Verify(s, openpgp.EntityList{e})
367 log.Printf("response type: %T, response id: %s", cert, document.Id(s))
368 err = db.Set("cert", document.Id(s), b)
372 func v(d []byte) (err error) {
373 // handle armored pubkey
374 if bytes.Index(d, []byte(openpgp.PublicKeyType)) >= 0 {
375 es, err1 := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
380 for _, e := range es {
381 isIssuer, issuer, denom, err1 := key.Check(e)
390 fmt.Println("Issuer key")
392 fmt.Println("Holder key")
394 fmt.Printf("Issuer: %s\nDenomination: %s\nId: %s\n", issuer, denom, key.Id(e))
398 _, s, err := document.Parse(d)
402 _, err = os.Stdout.Write(s.Body)
406 func c(server string) (err error) {
407 resp, err := http.Get(server + "/serverkey")
411 if resp.StatusCode != 200 {
412 log.Printf("request failed: %s\n", resp.Status)
414 b, err := readall(resp.Body)
418 err = resp.Body.Close()
422 e, err := key.Parse(b)
426 log.Printf("got server key %s", key.Id(e))
427 err = db.Set("key", key.Id(e), b)
431 err = db.Set("", "serverkey", b)
435 // TODO: commmon code with server
436 func initstore(dir string) (db *store.Conn, err error) {
437 log.Printf("using root dir %s", dir)
438 db, err = store.Open(dir)
442 err = db.Ensure("key")
446 err = db.Ensure("cert")
450 err = db.Ensure("draft")
454 err = db.Ensure("certby/draft")
458 err = db.Ensure("certby/debit")
462 err = db.Ensure("certby/key")
466 err = db.Ensure("certby/key.serial")
473 func storedir() string {
474 dir := os.Getenv("HOME")
476 dir = "/var/cache/epoint"
478 dir += "/.epoint-client"
483 func readall(r io.Reader) ([]byte, error) {
484 b := make([]byte, 10000)
485 n, err := io.ReadFull(r, b)
486 if err != io.ErrUnexpectedEOF {
488 err = fmt.Errorf("too much input")
496 b, err := readall(os.Stdin)
504 if len(os.Args) < 2 {
509 db, err = initstore(storedir())
510 server := "http://localhost:8080"
513 if len(os.Args) != 3 {
516 err = k(read(), os.Args[1], os.Args[2])
518 if len(os.Args) != 4 {
521 err = d(read(), os.Args[2], os.Args[3])
525 if len(os.Args) == 5 {
529 } else if len(os.Args) == 4 {
535 err = q(cmd, id, server)
538 if len(os.Args) == 4 {
541 } else if len(os.Args) == 3 {
546 err = s(read(), cmd, server)
548 if len(os.Args) != 2 {
553 if len(os.Args) == 3 {
555 } else if len(os.Args) != 2 {