package main import ( "crypto/openpgp" "crypto/openpgp/armor" "crypto/rand" "epoint/document" "epoint/key" "fmt" "io" "log" "net/http" "net/url" "os" "strconv" ) const usage = `usage: ./epoint-client [k|d|s|v] [args..] < [seed|document] server is http://localhost:8080 by default k - make key, use seed for generation, args: [issuer] denomination d - make draft, use seed as signing key, args: targetid value s - submit a document, args: k[ey]|d[raft]|c[ert] [server] v - verify a document (prints body of the document if ok) ` func rnd(n int) (r []byte, err error) { r = make([]byte, n) _, err = io.ReadFull(rand.Reader, r) return } func k(r []byte, issuer, denom string) (err error) { var e *openpgp.Entity if issuer == "" { e, err = key.Issuer(r, denom) } else { e, err = key.Holder(r, issuer, denom) } if err != nil { return } w, err := armor.Encode(os.Stdout, openpgp.PublicKeyType, nil) if err != nil { return } // TODO: maybe Serialize should do this internally for _, ident := range e.Identities { err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey) if err != nil { return } } for _, subkey := range e.Subkeys { err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey) if err != nil { return } } err = e.Serialize(w) if err != nil { return } err = w.Close() if err != nil { return } _, err = os.Stdout.Write([]byte{'\n'}) return } func d(r []byte, target, value string) (err error) { v, err := strconv.Atoi64(value) if err != nil { return } e, err := key.Holder(r, "", "") if err != nil { return } draft := new(document.Draft) draft.Drawer = key.Id(e) draft.Beneficiary = target draft.Amount = v draft.Denomination = "" // TODO draft.Issuer = "" // TODO draft.AuthorizedBy = "" // TODO nonce, err := rnd(10) if err != nil { return } draft.Nonce = fmt.Sprintf("%X", nonce) s, _, err := document.Format(draft, e) if err != nil { return } _, err = os.Stdout.Write(s) return } func s(d []byte, cmd, server string) (err error) { m := map[string]string{ "k": "key", "d": "draft", "c": "debit", } k, ok := m[cmd] if !ok { err = fmt.Errorf("unknown submit command: %s", cmd) return } resp, err := http.PostForm(server, url.Values{k: {string(d)}}) if err != nil { return } fmt.Printf("%v", resp) return } func v(d []byte) (err error) { _, s, err := document.Parse(d) if err != nil { return } _, err = os.Stdout.Write(s.Body) return } func read() []byte { b := make([]byte, 10000) n, err := io.ReadFull(os.Stdin, b) if err != io.ErrUnexpectedEOF { if err == nil { log.Fatal("too much input") } log.Fatal(err) } return b[:n] } func main() { if len(os.Args) < 2 { log.Fatal(usage) } var err error switch os.Args[1] { case "k": issuer := "" denom := "" if len(os.Args) == 4 { issuer = os.Args[2] denom = os.Args[3] } else if len(os.Args) == 3 { denom = os.Args[2] } else { log.Fatal(usage) } err = k(read(), issuer, denom) case "d": if len(os.Args) != 4 { log.Fatal(usage) } err = d(read(), os.Args[2], os.Args[3]) case "s": server := "http://localhost:8080" cmd := "" if len(os.Args) == 4 { cmd = os.Args[2] server = os.Args[3] } else if len(os.Args) == 3 { cmd = os.Args[2] } else { log.Fatal(usage) } err = s(read(), cmd, server+"/submit") case "v": if len(os.Args) != 2 { log.Fatal(usage) } err = v(read()) } if err != nil { log.Fatal(err) } }