update code to latest go
[epoint] / pkg / server / server.go
1 package server
2
3 // main transfer logic
4
5 import (
6         "bytes"
7         "crypto/openpgp"
8         "crypto/rand"
9         "epoint/document"
10         "epoint/key"
11         "epoint/store"
12         "fmt"
13         "time"
14 )
15
16 // TODO: do in docs?
17 const IntLimit = 1e15
18
19 // transaction: either draft or debit cert
20 type work struct {
21         next    *work
22         docid   string
23         account string
24         in      []byte
25         out     []byte
26         err     error
27         signed  *document.Signed
28         draft   *document.Draft
29         debit   *document.DebitCert
30         sync    chan int
31 }
32
33 var db *store.Conn
34 var serverkey *openpgp.Entity
35 var newchan chan *work
36 var delchan chan string
37
38 type worklist struct {
39         head *work
40         tail *work
41 }
42
43 func pushwork(ws *worklist, w *work) {
44         if ws.tail == nil {
45                 ws.head = w
46                 ws.tail = w
47         } else {
48                 ws.tail.next = w
49                 ws.tail = w
50         }
51 }
52
53 func popwork(ws *worklist) *work {
54         w := ws.head
55         if w == nil {
56                 return nil
57         }
58         ws.head = w.next
59         if ws.head == nil {
60                 ws.tail = nil
61         }
62         return w
63 }
64
65 func setserverkey(e *openpgp.Entity) (err error) {
66         serverkey = e
67
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)
71                 if err != nil {
72                         return
73                 }
74         }
75         for _, subkey := range e.Subkeys {
76                 err = subkey.Sig.SignKey(rand.Reader, subkey.PublicKey, e.PrivateKey)
77                 if err != nil {
78                         return
79                 }
80         }
81
82         b := new(bytes.Buffer)
83         err = e.Serialize(b)
84         if err != nil {
85                 return
86         }
87         err = db.Set("key", key.Id(e), b.Bytes())
88         if err != nil {
89                 return
90         }
91         err = db.Set("", "serverkey", b.Bytes())
92         return
93 }
94
95 func GetKeys(fpr string) (es openpgp.EntityList, err error) {
96         b, err := db.Get("key", fpr)
97         if err != nil {
98                 return
99         }
100         es, err = openpgp.ReadKeyRing(bytes.NewBuffer(b))
101         if err != nil {
102                 // internal error: pubkey cannot be parsed
103                 return
104         }
105         return
106 }
107
108 func AddKeys(d []byte) (err error) {
109         entities, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
110         if err != nil {
111                 return
112         }
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))
116                 return
117         }
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)
122                 err = err1
123                 if err != nil {
124                         return
125                 }
126                 if !isIssuer {
127                         es, err1 := GetKeys(issuer)
128                         err = err1
129                         if err != nil {
130                                 return
131                         }
132                         ok, _, den, err1 := key.Check(es[0])
133                         err = err1
134                         if err != nil {
135                                 // internal error
136                                 return
137                         }
138                         if !ok || den != denom {
139                                 err = fmt.Errorf("Issuer key check failed")
140                                 return
141                         }
142                 }
143                 b := new(bytes.Buffer)
144                 err = e.Serialize(b)
145                 if err != nil {
146                         return
147                 }
148                 fpr := key.Id(e)
149                 err = db.Insert("key", fpr, b.Bytes())
150                 if err != nil {
151                         return
152                 }
153                 err = db.Append("keysby/64", fpr[len(fpr)-16:], []byte(fpr))
154                 if err != nil {
155                         return
156                 }
157                 err = db.Append("keysby/32", fpr[len(fpr)-8:], []byte(fpr))
158                 if err != nil {
159                         return
160                 }
161         }
162         return
163 }
164
165 // Get cert through the named store
166 func GetCert(name, id string) (d []byte, err error) {
167         certid, err := db.Get(name, id)
168         if err != nil {
169                 // ok if notfound
170                 return
171         }
172         d, err = db.Get("cert", string(certid))
173         if err != nil {
174                 // internal error: cert is not available
175                 return
176         }
177         return
178 }
179
180 func EvalDraft(d []byte) (c []byte, err error) {
181         iv, signed, err := document.Parse(d)
182         if err != nil {
183                 return
184         }
185         draft, ok := iv.(*document.Draft)
186         if !ok {
187                 err = fmt.Errorf("EvalDraft: expected a draft document")
188                 return
189         }
190         k, err := db.Get("key", draft.Drawer)
191         if err != nil {
192                 return
193         }
194         // TODO: key.Parse
195         kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
196         if err != nil {
197                 // internal error: pubkey cannot be parsed
198                 return
199         }
200         err = document.Verify(signed, kr)
201         if err != nil {
202                 return
203         }
204         //      _, issuer, denom, err := key.Check(kr[0])
205         //      if err != nil {
206         //              return
207         //      }
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)
211                 return
212         }
213         k, err = db.Get("key", draft.Beneficiary)
214         if err != nil {
215                 return
216         }
217         kr, err = openpgp.ReadKeyRing(bytes.NewBuffer(k))
218         if err != nil {
219                 // internal error: pubkey cannot be parsed
220                 return
221         }
222         return addDraft(d, signed, draft)
223 }
224
225 func EvalDebitCert(d []byte) (c []byte, err error) {
226         iv, signed, err := document.Parse(d)
227         if err != nil {
228                 return
229         }
230         cert, ok := iv.(*document.DebitCert)
231         if !ok {
232                 err = fmt.Errorf("ParseDebitCert: expected a debit docuent")
233                 return
234         }
235
236         kr := openpgp.EntityList{serverkey}
237         if key.Id(serverkey) != cert.AuthorizedBy {
238                 // TODO: ...
239                 k := []byte(nil)
240                 k, err = db.Get("key", cert.AuthorizedBy)
241                 if err != nil {
242                         return
243                 }
244                 kr, err = openpgp.ReadKeyRing(bytes.NewBuffer(k))
245                 if err != nil {
246                         // internal error: pubkey cannot be parsed
247                         return
248                 }
249         }
250         // must clean up to make sure the hash is ok
251         err = document.Verify(signed, kr)
252         if err != nil {
253                 return
254         }
255         return addDebit(d, signed, cert)
256 }
257
258 func addDraft(d []byte, signed *document.Signed, draft *document.Draft) (c []byte, err error) {
259         w := new(work)
260         w.docid = document.Id(signed)
261         w.account = fmt.Sprintf("%s.%s", draft.Drawer, draft.Issuer)
262         w.in = d
263         w.signed = signed
264         w.draft = draft
265         w.sync = make(chan int)
266         newchan <- w
267         <-w.sync
268         return w.out, w.err
269 }
270
271 func addDebit(d []byte, signed *document.Signed, cert *document.DebitCert) (c []byte, err error) {
272         w := new(work)
273         w.docid = document.Id(signed)
274         w.account = fmt.Sprintf("%s.%s", cert.Holder, cert.Issuer)
275         w.in = d
276         w.signed = signed
277         w.debit = cert
278         w.sync = make(chan int)
279         newchan <- w
280         <-w.sync
281         return w.out, w.err
282 }
283
284 func dispatch() {
285         works := make(map[string]*worklist)
286         for {
287                 select {
288                 case w := <-newchan:
289                         ws := works[w.account]
290                         if ws == nil {
291                                 // TODO: unnecessary alloc
292                                 works[w.account] = new(worklist)
293                                 go handle(w)
294                         } else {
295                                 pushwork(ws, w)
296                         }
297                 case account := <-delchan:
298                         ws := works[account]
299                         w := popwork(ws)
300                         if w == nil {
301                                 delete(works, account)
302                         } else {
303                                 go handle(w)
304                         }
305                 }
306         }
307 }
308
309 func handle(w *work) {
310         if w.debit != nil {
311                 handleDebit(w)
312         } else if w.draft != nil {
313                 handleDraft(w)
314         } else {
315                 panic("unreachable")
316         }
317         delchan <- w.account
318         w.sync <- 0
319 }
320
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)
324         if err == nil {
325                 if string(oldid) != w.docid {
326                         w.err = fmt.Errorf("draft nonce is not unique (see draft %s)", oldid)
327                 } else {
328                         w.out, w.err = GetCert("certby/draft", w.docid)
329                 }
330                 return
331         } else if _, ok := err.(store.NotFoundError); !ok {
332                 w.err = err
333                 return
334         }
335
336         err = db.Begin(w.docid)
337         if err != nil {
338                 w.err = err
339                 return
340         }
341         err = db.Set("draft", w.docid, w.in)
342         if err != nil {
343                 w.err = err
344                 return
345         }
346         err = db.Set("draftby/key.issuer.nonce", nonce, []byte(w.docid))
347         if err != nil {
348                 w.err = err
349                 return
350         }
351         cert, err := newDebitCert(w)
352         if err != nil {
353                 // probably client error
354                 db.End(w.docid)
355                 return
356         }
357         c, signed, err := document.Format(cert, serverkey)
358         if err != nil {
359                 return
360         }
361         certid := document.Id(signed)
362         w.out = c
363         err = db.Set("cert", certid, c)
364         if err != nil {
365                 // internal error
366                 return
367         }
368         err = db.Set("certby/draft", w.docid, []byte(certid))
369         if err != nil {
370                 // internal error
371                 return
372         }
373         // TODO: append?
374         err = db.Set("certby/key.issuer.serial", fmt.Sprintf("%s.%09d", w.account, cert.Serial), []byte(certid))
375         if err != nil {
376                 // internal error
377                 return
378         }
379         err = db.Set("certby/key.issuer", w.account, []byte(certid))
380         if err != nil {
381                 // internal error
382                 return
383         }
384         // TODO: run journal cleanup in case of client errors
385         err = db.End(w.docid)
386         return
387 }
388
389 func handleDebit(w *work) {
390         c, err := GetCert("certby/debit", w.docid)
391         if err == nil {
392                 w.out = c
393                 return
394         } else if _, ok := err.(store.NotFoundError); !ok {
395                 // internal error
396                 w.err = err
397                 return
398         }
399         err = db.Begin(w.docid)
400         if err != nil {
401                 w.err = err
402                 return
403         }
404         err = db.Set("cert", w.docid, w.in)
405         if err != nil {
406                 w.err = err
407                 return
408         }
409         // TODO: check pubkey etc
410         cert, err := newCreditCert(w)
411         if err != nil {
412                 // internal error
413                 return
414         }
415         c, signed, err := document.Format(cert, serverkey)
416         if err != nil {
417                 // internal error
418                 return
419         }
420         certid := document.Id(signed)
421         err = db.Set("cert", certid, c)
422         if err != nil {
423                 // internal error
424                 return
425         }
426         err = db.Set("certby/debit", w.docid, []byte(certid))
427         if err != nil {
428                 // internal error
429                 return
430         }
431         // TODO: append?
432         err = db.Set("certby/key.issuer.serial", fmt.Sprintf("%s.%09d", w.account, cert.Serial), []byte(certid))
433         if err != nil {
434                 // internal error
435                 return
436         }
437         err = db.Set("certby/key.issuer", w.account, []byte(certid))
438         if err != nil {
439                 // internal error
440                 return
441         }
442         db.End(w.docid)
443         return
444 }
445
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
454         cert.Draft = w.docid
455         cert.Beneficiary = w.draft.Beneficiary
456
457         oid, err := db.Get("certby/key.issuer", w.account)
458         oldcertid := string(oid)
459         if err != nil {
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)
463                 }
464                 cert.Serial = 1
465                 cert.Balance = cert.Difference
466                 cert.LastDebitSerial = 0
467                 cert.LastCreditSerial = 0
468         } else {
469                 d, err := db.Get("cert", oldcertid)
470                 if err != nil {
471                         return nil, err
472                 }
473                 iv, _, err := document.Parse(d)
474                 if err != nil {
475                         // internal error
476                         return nil, err
477                 }
478                 // TODO: this is a hack
479                 oldcert, err := document.ToCert(iv)
480                 if err != nil {
481                         // internal error
482                         return nil, err
483                 }
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)
489                 }
490                 if oldcert.Balance > 0 && cert.Balance < 0 {
491                         return nil, fmt.Errorf("insufficient funds: %d", oldcert.Balance)
492                 }
493                 cert.LastDebitSerial = oldcert.LastDebitSerial
494                 cert.LastCreditSerial = oldcert.LastCreditSerial
495                 if _, ok := iv.(*document.DebitCert); ok {
496                         cert.LastDebitSerial = oldcert.Serial
497                 } else {
498                         cert.LastCreditSerial = oldcert.Serial
499                 }
500                 cert.LastCert = &oldcertid
501         }
502         return cert, nil
503 }
504
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
518
519         oid, err := db.Get("certby/key", w.debit.Beneficiary)
520         oldcertid := string(oid)
521         if err != nil {
522                 // this is the first cert
523                 cert.Serial = 1
524                 cert.Balance = cert.Difference
525                 cert.LastDebitSerial = 0
526                 cert.LastCreditSerial = 0
527         } else {
528                 d, err := db.Get("cert", oldcertid)
529                 if err != nil {
530                         // internal error
531                         return nil, err
532                 }
533                 iv, _, err := document.Parse(d)
534                 if err != nil {
535                         // internal error
536                         return nil, err
537                 }
538                 // TODO: this is a hack
539                 oldcert, err := document.ToCert(iv)
540                 if err != nil {
541                         // internal error
542                         return nil, err
543                 }
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)
548                 }
549                 cert.LastDebitSerial = oldcert.LastDebitSerial
550                 cert.LastCreditSerial = oldcert.LastCreditSerial
551                 if _, ok := iv.(*document.DebitCert); ok {
552                         cert.LastDebitSerial = oldcert.Serial
553                 } else {
554                         cert.LastCreditSerial = oldcert.Serial
555                 }
556                 cert.LastCert = &oldcertid
557         }
558         return cert, nil
559 }
560
561 func Init(rootdir string, sk *openpgp.Entity) (err error) {
562         db, err = store.Open(rootdir)
563         if err != nil {
564                 return
565         }
566         err = db.Ensure("key")
567         if err != nil {
568                 return
569         }
570         err = db.Ensure("cert")
571         if err != nil {
572                 return
573         }
574         err = db.Ensure("draft")
575         if err != nil {
576                 return
577         }
578         err = db.Ensure("certby/draft")
579         if err != nil {
580                 return
581         }
582         err = db.Ensure("certby/debit")
583         if err != nil {
584                 return
585         }
586         err = db.Ensure("certby/key.issuer")
587         if err != nil {
588                 return
589         }
590         err = db.Ensure("certby/key.issuer.serial")
591         if err != nil {
592                 return
593         }
594         err = db.Ensure("draftby/key.issuer.nonce")
595         if err != nil {
596                 return
597         }
598         err = db.Ensure("keysby/64")
599         if err != nil {
600                 return
601         }
602         err = db.Ensure("keysby/32")
603         if err != nil {
604                 return
605         }
606         err = setserverkey(sk)
607         if err != nil {
608                 return
609         }
610         go dispatch()
611         return
612 }