20 // TODO: store documents, query store (keys), easy submit
24 const usage = `usage: ./epoint-client [k|d|s|v|c] [args..] < [seed|document]
25 server is http://localhost:8080 by default
27 k - make key, use seed for generation, args: [issuer] denomination
28 d - make draft, use seed for signing key, args: targetid value
29 s - submit a (key|draft|cert) document, args: k|d|c [server]
30 v - verify a document (prints body of the document if ok)
31 c - connect to server and get server key, args: [server]
34 func rnd(n int) (r []byte, err error) {
36 _, err = io.ReadFull(rand.Reader, r)
40 func k(r []byte, issuer, denom string) (err error) {
44 e, err = key.Issuer(r, denom)
46 e, err = key.Holder(r, issuer, denom)
51 log.Printf("generated key %s", key.Id(e))
52 d, err := db.Get("key", key.Id(e))
54 // TODO: issuer, denom check (remove keys from store if they are not sent to server?)
55 log.Printf("key %s was found in store", key.Id(e))
57 out := new(bytes.Buffer)
58 w, err1 := armor.Encode(out, openpgp.PublicKeyType, nil)
63 // TODO: maybe Serialize should do this internally
64 for _, ident := range e.Identities {
65 err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
70 for _, subkey := range e.Subkeys {
71 err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey)
84 _, err = out.Write([]byte{'\n'})
89 err = db.Insert("key", key.Id(e), d)
94 _, err = os.Stdout.Write(d)
98 func d(r []byte, target, value string) (err error) {
99 v, err := strconv.Atoi64(value)
103 e, err := key.Holder(r, "", "")
107 log.Printf("drawer: %s", key.Id(e))
108 if key.Id(e) == target {
109 err = fmt.Errorf("Drawer and beneficiary are the same")
112 b, err := db.Get("key", key.Id(e))
116 e1, err := key.Parse(b)
120 _, issuer, denom, err := key.Check(e1)
124 // TODO: store server id as well?
125 b, err = db.Get("", "serverkey")
129 sk, err := key.Parse(b)
133 // TODO: check beneficiary (check value?)
134 draft := new(document.Draft)
135 draft.Drawer = key.Id(e)
136 draft.Beneficiary = target
138 draft.Denomination = denom
139 draft.Issuer = issuer
140 draft.AuthorizedBy = key.Id(sk)
141 nonce, err := rnd(10)
145 draft.Nonce = fmt.Sprintf("%X", nonce)
146 s, _, err := document.Format(draft, e)
150 _, err = os.Stdout.Write(s)
154 func s(d []byte, cmd, server string) (err error) {
155 m := map[string]string{
162 err = fmt.Errorf("unknown submit command: %s", cmd)
165 resp, err := http.PostForm(server+"/submit", url.Values{k: {string(d)}})
169 if resp.StatusCode != 200 {
170 log.Printf("request failed: %s\n", resp.Status)
172 // TODO: store result
173 _, err = io.Copy(os.Stdout, resp.Body)
177 err = resp.Body.Close()
181 func v(d []byte) (err error) {
182 // handle armored pubkey
183 if bytes.Index(d, []byte(openpgp.PublicKeyType)) >= 0 {
184 es, err1 := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
189 for _, e := range es {
190 isIssuer, issuer, denom, err1 := key.Check(e)
199 fmt.Println("Issuer key")
201 fmt.Println("Holder key")
203 fmt.Printf("Issuer: %s\nDenomination: %s\nId: %s\n", issuer, denom, key.Id(e))
207 _, s, err := document.Parse(d)
211 _, err = os.Stdout.Write(s.Body)
215 func c(server string) (err error) {
216 resp, err := http.Get(server + "/serverkey")
220 if resp.StatusCode != 200 {
221 log.Printf("request failed: %s\n", resp.Status)
223 b, err := readall(resp.Body)
227 err = resp.Body.Close()
231 e, err := key.Parse(b)
235 log.Printf("got server key %s", key.Id(e))
236 err = db.Set("", "serverkey", b)
240 // TODO: commmon code with server
241 func initstore(dir string) (db *store.Conn, err error) {
242 log.Printf("using root dir %s", dir)
243 db, err = store.Open(dir)
247 err = db.Ensure("key")
251 err = db.Ensure("cert")
255 err = db.Ensure("draft")
259 err = db.Ensure("certby/draft")
263 err = db.Ensure("certby/debit")
267 err = db.Ensure("certby/key")
271 err = db.Ensure("certby/key.serial")
278 func storedir() string {
279 dir := os.Getenv("HOME")
281 dir = "/var/cache/epoint"
283 dir += "/.epoint-client"
288 func readall(r io.Reader) ([]byte, error) {
289 b := make([]byte, 10000)
290 n, err := io.ReadFull(r, b)
291 if err != io.ErrUnexpectedEOF {
293 err = fmt.Errorf("too much input")
301 b, err := readall(os.Stdin)
309 if len(os.Args) < 2 {
314 db, err = initstore(storedir())
315 server := "http://localhost:8080"
320 if len(os.Args) == 4 {
323 } else if len(os.Args) == 3 {
328 err = k(read(), issuer, denom)
330 if len(os.Args) != 4 {
333 err = d(read(), os.Args[2], os.Args[3])
336 if len(os.Args) == 4 {
339 } else if len(os.Args) == 3 {
344 err = s(read(), cmd, server)
346 if len(os.Args) != 2 {
351 if len(os.Args) == 3 {
353 } else if len(os.Args) != 2 {