20 // TODO: store documents, query document by id, 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 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 s - submit a (key|draft|cert) document, args: k|d|c [server]
31 v - verify a document (prints body of the document if ok)
32 c - connect to server and get server key, args: [server]
35 func rnd(n int) (r []byte, err error) {
37 _, err = io.ReadFull(rand.Reader, r)
41 func k(r []byte, cmd, arg string) (err error) {
45 e, err = key.Issuer(r, arg)
47 s, err1 := db.Get("key", arg)
52 ie, err1 := key.Parse(s)
57 isIssuer, _, denom, err1 := key.Check(ie)
63 err = fmt.Errorf("Not an issuer key: %s", arg)
66 e, err = key.Holder(r, arg, denom)
71 log.Printf("generated key %s", key.Id(e))
72 d, err := db.Get("key", key.Id(e))
74 // TODO: issuer, denom check (remove keys from store if they are not sent to server?)
75 log.Printf("key %s was found in store", key.Id(e))
77 out := new(bytes.Buffer)
78 w, err1 := armor.Encode(out, openpgp.PublicKeyType, nil)
83 // TODO: maybe Serialize should do this internally
84 for _, ident := range e.Identities {
85 err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
90 for _, subkey := range e.Subkeys {
91 err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey)
104 _, err = out.Write([]byte{'\n'})
109 err = db.Insert("key", key.Id(e), d)
114 _, err = os.Stdout.Write(d)
118 func d(r []byte, target, value string) (err error) {
119 v, err := strconv.Atoi64(value)
123 e, err := key.Holder(r, "", "")
127 log.Printf("drawer: %s", key.Id(e))
128 if key.Id(e) == target {
129 err = fmt.Errorf("Drawer and beneficiary are the same")
132 b, err := db.Get("key", key.Id(e))
136 e1, err := key.Parse(b)
140 _, issuer, denom, err := key.Check(e1)
144 // TODO: store server id as well?
145 b, err = db.Get("", "serverkey")
149 sk, err := key.Parse(b)
153 // TODO: check beneficiary (check value?)
154 draft := new(document.Draft)
155 draft.Drawer = key.Id(e)
156 draft.Beneficiary = target
158 draft.Denomination = denom
159 draft.Issuer = issuer
160 draft.AuthorizedBy = key.Id(sk)
161 nonce, err := rnd(10)
165 draft.Nonce = fmt.Sprintf("%X", nonce)
166 s, c, err := document.Format(draft, e)
170 log.Printf("draft id: %s", document.Id(c))
171 _, err = os.Stdout.Write(s)
175 func s(d []byte, cmd, server string) (err error) {
176 m := map[string]string{
183 err = fmt.Errorf("unknown submit command: %s", cmd)
189 e, err1 := key.Parse(d)
195 err = db.Set("key", id, d)
197 _, s, err1 := document.Parse(d)
203 err = db.Set("draft", id, d)
205 _, s, err1 := document.Parse(d)
211 err = db.Set("cert", id, d)
216 log.Printf("document id: %s, server: %s", id, server)
217 resp, err := http.PostForm(server+"/submit", url.Values{k: {string(d)}})
221 if resp.StatusCode != 200 {
222 log.Printf("request failed: %s", resp.Status)
224 // TODO: store result
225 b, err := readall(resp.Body)
226 defer resp.Body.Close()
230 _, err = os.Stdout.Write(b)
234 cert, s, err := document.Parse(b)
238 d, err = db.Get("", "serverkey")
242 e, err := key.Parse(d)
246 err = document.Verify(s, openpgp.EntityList{e})
250 log.Printf("response type: %T, response id: %s", cert, document.Id(s))
251 err = db.Set("cert", document.Id(s), b)
255 func v(d []byte) (err error) {
256 // handle armored pubkey
257 if bytes.Index(d, []byte(openpgp.PublicKeyType)) >= 0 {
258 es, err1 := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
263 for _, e := range es {
264 isIssuer, issuer, denom, err1 := key.Check(e)
273 fmt.Println("Issuer key")
275 fmt.Println("Holder key")
277 fmt.Printf("Issuer: %s\nDenomination: %s\nId: %s\n", issuer, denom, key.Id(e))
281 _, s, err := document.Parse(d)
285 _, err = os.Stdout.Write(s.Body)
289 func c(server string) (err error) {
290 resp, err := http.Get(server + "/serverkey")
294 if resp.StatusCode != 200 {
295 log.Printf("request failed: %s\n", resp.Status)
297 b, err := readall(resp.Body)
301 err = resp.Body.Close()
305 e, err := key.Parse(b)
309 log.Printf("got server key %s", key.Id(e))
310 err = db.Set("key", key.Id(e), b)
314 err = db.Set("", "serverkey", b)
318 // TODO: commmon code with server
319 func initstore(dir string) (db *store.Conn, err error) {
320 log.Printf("using root dir %s", dir)
321 db, err = store.Open(dir)
325 err = db.Ensure("key")
329 err = db.Ensure("cert")
333 err = db.Ensure("draft")
337 err = db.Ensure("certby/draft")
341 err = db.Ensure("certby/debit")
345 err = db.Ensure("certby/key")
349 err = db.Ensure("certby/key.serial")
356 func storedir() string {
357 dir := os.Getenv("HOME")
359 dir = "/var/cache/epoint"
361 dir += "/.epoint-client"
366 func readall(r io.Reader) ([]byte, error) {
367 b := make([]byte, 10000)
368 n, err := io.ReadFull(r, b)
369 if err != io.ErrUnexpectedEOF {
371 err = fmt.Errorf("too much input")
379 b, err := readall(os.Stdin)
387 if len(os.Args) < 2 {
392 db, err = initstore(storedir())
393 server := "http://localhost:8080"
396 if len(os.Args) != 3 {
399 err = k(read(), os.Args[1], os.Args[2])
401 if len(os.Args) != 4 {
404 err = d(read(), os.Args[2], os.Args[3])
407 if len(os.Args) == 4 {
410 } else if len(os.Args) == 3 {
415 err = s(read(), cmd, server)
417 if len(os.Args) != 2 {
422 if len(os.Args) == 3 {
424 } else if len(os.Args) != 2 {