19 // transaction: either draft or debit cert
27 signed *document.Signed
29 debit *document.DebitCert
34 var serverkey *openpgp.Entity
35 var newchan chan *work
36 var delchan chan string
38 type worklist struct {
43 func pushwork(ws *worklist, w *work) {
53 func popwork(ws *worklist) *work {
65 func setserverkey(e *openpgp.Entity) (err error) {
68 // TODO: maybe Serialize should do this internally
69 for _, ident := range e.Identities {
70 err = ident.SelfSignature.SignUserId(rand.Reader, ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
75 for _, subkey := range e.Subkeys {
76 err = subkey.Sig.SignKey(rand.Reader, subkey.PublicKey, e.PrivateKey)
82 b := new(bytes.Buffer)
87 err = db.Set("key", key.Id(e), b.Bytes())
91 err = db.Set("", "serverkey", b.Bytes())
95 func GetKeys(fpr string) (es openpgp.EntityList, err error) {
96 b, err := db.Get("key", fpr)
100 es, err = openpgp.ReadKeyRing(bytes.NewBuffer(b))
102 // internal error: pubkey cannot be parsed
108 func AddKeys(d []byte) (err error) {
109 entities, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
113 // TODO: allow multiple key uploads at once?
114 if len(entities) > 100 {
115 err = fmt.Errorf("expected at most 100 keys; got %d", len(entities))
118 for _, e := range entities {
119 // TODO: various checks..
120 // TODO: collect errors instead of aborting addkeys
121 isIssuer, issuer, denom, err1 := key.Check(e)
127 es, err1 := GetKeys(issuer)
132 ok, _, den, err1 := key.Check(es[0])
138 if !ok || den != denom {
139 err = fmt.Errorf("Issuer key check failed")
143 b := new(bytes.Buffer)
149 err = db.Insert("key", fpr, b.Bytes())
153 err = db.Append("keysby/64", fpr[len(fpr)-16:], []byte(fpr))
157 err = db.Append("keysby/32", fpr[len(fpr)-8:], []byte(fpr))
165 // Get cert through the named store
166 func GetCert(name, id string) (d []byte, err error) {
167 certid, err := db.Get(name, id)
172 d, err = db.Get("cert", string(certid))
174 // internal error: cert is not available
180 func EvalDraft(d []byte) (c []byte, err error) {
181 iv, signed, err := document.Parse(d)
185 draft, ok := iv.(*document.Draft)
187 err = fmt.Errorf("EvalDraft: expected a draft document")
190 k, err := db.Get("key", draft.Drawer)
195 kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
197 // internal error: pubkey cannot be parsed
200 err = document.Verify(signed, kr)
204 // _, issuer, denom, err := key.Check(kr[0])
208 // TODO: do various format checks (AuthorizedBy check etc)
209 if draft.Amount <= 0 || draft.Amount >= IntLimit {
210 err = fmt.Errorf("draft amount is invalid: %d", draft.Amount)
213 k, err = db.Get("key", draft.Beneficiary)
217 kr, err = openpgp.ReadKeyRing(bytes.NewBuffer(k))
219 // internal error: pubkey cannot be parsed
222 return addDraft(d, signed, draft)
225 func EvalDebitCert(d []byte) (c []byte, err error) {
226 iv, signed, err := document.Parse(d)
230 cert, ok := iv.(*document.DebitCert)
232 err = fmt.Errorf("ParseDebitCert: expected a debit docuent")
236 kr := openpgp.EntityList{serverkey}
237 if key.Id(serverkey) != cert.AuthorizedBy {
240 k, err = db.Get("key", cert.AuthorizedBy)
244 kr, err = openpgp.ReadKeyRing(bytes.NewBuffer(k))
246 // internal error: pubkey cannot be parsed
250 // must clean up to make sure the hash is ok
251 err = document.Verify(signed, kr)
255 return addDebit(d, signed, cert)
258 func addDraft(d []byte, signed *document.Signed, draft *document.Draft) (c []byte, err error) {
260 w.docid = document.Id(signed)
261 w.account = fmt.Sprintf("%s.%s", draft.Drawer, draft.Issuer)
265 w.sync = make(chan int)
271 func addDebit(d []byte, signed *document.Signed, cert *document.DebitCert) (c []byte, err error) {
273 w.docid = document.Id(signed)
274 w.account = fmt.Sprintf("%s.%s", cert.Holder, cert.Issuer)
278 w.sync = make(chan int)
285 works := make(map[string]*worklist)
289 ws := works[w.account]
291 // TODO: unnecessary alloc
292 works[w.account] = new(worklist)
297 case account := <-delchan:
301 delete(works, account)
309 func handle(w *work) {
312 } else if w.draft != nil {
321 func handleDraft(w *work) {
322 nonce := fmt.Sprintf("%s.%s", w.account, w.draft.Nonce)
323 oldid, err := db.Get("draftby/key.issuer.nonce", nonce)
325 if string(oldid) != w.docid {
326 w.err = fmt.Errorf("draft nonce is not unique (see draft %s)", oldid)
328 w.out, w.err = GetCert("certby/draft", w.docid)
331 } else if _, ok := err.(store.NotFoundError); !ok {
336 err = db.Begin(w.docid)
341 err = db.Set("draft", w.docid, w.in)
346 err = db.Set("draftby/key.issuer.nonce", nonce, []byte(w.docid))
351 cert, err := newDebitCert(w)
353 // probably client error
357 c, signed, err := document.Format(cert, serverkey)
361 certid := document.Id(signed)
363 err = db.Set("cert", certid, c)
368 err = db.Set("certby/draft", w.docid, []byte(certid))
374 err = db.Set("certby/key.issuer.serial", fmt.Sprintf("%s.%09d", w.account, cert.Serial), []byte(certid))
379 err = db.Set("certby/key.issuer", w.account, []byte(certid))
384 // TODO: run journal cleanup in case of client errors
385 err = db.End(w.docid)
389 func handleDebit(w *work) {
390 c, err := GetCert("certby/debit", w.docid)
394 } else if _, ok := err.(store.NotFoundError); !ok {
399 err = db.Begin(w.docid)
404 err = db.Set("cert", w.docid, w.in)
409 // TODO: check pubkey etc
410 cert, err := newCreditCert(w)
415 c, signed, err := document.Format(cert, serverkey)
420 certid := document.Id(signed)
421 err = db.Set("cert", certid, c)
426 err = db.Set("certby/debit", w.docid, []byte(certid))
432 err = db.Set("certby/key.issuer.serial", fmt.Sprintf("%s.%09d", w.account, cert.Serial), []byte(certid))
437 err = db.Set("certby/key.issuer", w.account, []byte(certid))
446 func newDebitCert(w *work) (*document.DebitCert, error) {
447 cert := new(document.DebitCert)
448 cert.Holder = w.draft.Drawer
449 cert.Date = time.Now().Unix()
450 cert.Denomination = "epoint"
451 cert.Issuer = w.draft.Issuer
452 cert.AuthorizedBy = w.draft.AuthorizedBy
453 cert.Difference = -w.draft.Amount
455 cert.Beneficiary = w.draft.Beneficiary
457 oid, err := db.Get("certby/key.issuer", w.account)
458 oldcertid := string(oid)
460 // first cert: drawer is issuer
461 if w.draft.Drawer != w.draft.Issuer {
462 return nil, fmt.Errorf("drawer must be the issuer when drawing an empty account (%s != %s)", w.draft.Drawer, w.draft.Issuer)
465 cert.Balance = cert.Difference
466 cert.LastDebitSerial = 0
467 cert.LastCreditSerial = 0
469 d, err := db.Get("cert", oldcertid)
473 iv, _, err := document.Parse(d)
478 // TODO: this is a hack
479 oldcert, err := document.ToCert(iv)
484 // TODO: sanity checks? oldcert.Holder == draft.Drawer
485 cert.Serial = oldcert.Serial + 1
486 cert.Balance = oldcert.Balance + cert.Difference
487 if cert.Balance <= -IntLimit {
488 return nil, fmt.Errorf("balance limit exceeded: %d", cert.Balance)
490 if oldcert.Balance > 0 && cert.Balance < 0 {
491 return nil, fmt.Errorf("insufficient funds: %d", oldcert.Balance)
493 cert.LastDebitSerial = oldcert.LastDebitSerial
494 cert.LastCreditSerial = oldcert.LastCreditSerial
495 if _, ok := iv.(*document.DebitCert); ok {
496 cert.LastDebitSerial = oldcert.Serial
498 cert.LastCreditSerial = oldcert.Serial
500 cert.LastCert = &oldcertid
505 func newCreditCert(w *work) (*document.CreditCert, error) {
506 cert := new(document.CreditCert)
507 // TODO: get from old cert instead?
508 cert.Holder = w.debit.Beneficiary
509 cert.Date = time.Now().Unix()
510 // TODO: get these from the cert holder pubkey
511 cert.Denomination = "epoint"
512 cert.Issuer = w.debit.Issuer
513 cert.AuthorizedBy = w.debit.AuthorizedBy // TODO: draft vs dcert vs serverside decision
514 cert.Difference = -w.debit.Difference
515 cert.Draft = w.debit.Draft
516 cert.Drawer = w.debit.Holder
517 cert.DebitCert = w.docid
519 oid, err := db.Get("certby/key", w.debit.Beneficiary)
520 oldcertid := string(oid)
522 // this is the first cert
524 cert.Balance = cert.Difference
525 cert.LastDebitSerial = 0
526 cert.LastCreditSerial = 0
528 d, err := db.Get("cert", oldcertid)
533 iv, _, err := document.Parse(d)
538 // TODO: this is a hack
539 oldcert, err := document.ToCert(iv)
544 cert.Serial = oldcert.Serial + 1
545 cert.Balance = oldcert.Balance + cert.Difference
546 if cert.Balance >= IntLimit {
547 return nil, fmt.Errorf("balance limit exceeded: %d", cert.Balance)
549 cert.LastDebitSerial = oldcert.LastDebitSerial
550 cert.LastCreditSerial = oldcert.LastCreditSerial
551 if _, ok := iv.(*document.DebitCert); ok {
552 cert.LastDebitSerial = oldcert.Serial
554 cert.LastCreditSerial = oldcert.Serial
556 cert.LastCert = &oldcertid
561 func Init(rootdir string, sk *openpgp.Entity) (err error) {
562 db, err = store.Open(rootdir)
566 err = db.Ensure("key")
570 err = db.Ensure("cert")
574 err = db.Ensure("draft")
578 err = db.Ensure("certby/draft")
582 err = db.Ensure("certby/debit")
586 err = db.Ensure("certby/key.issuer")
590 err = db.Ensure("certby/key.issuer.serial")
594 err = db.Ensure("draftby/key.issuer.nonce")
598 err = db.Ensure("keysby/64")
602 err = db.Ensure("keysby/32")
606 err = setserverkey(sk)