0271155f406f85438856993a59ec12c7ff5ea6d9
[epoint] / pkg / server / server.go
1 package server
2
3 // main transfer logic
4
5 import (
6         "bytes"
7         "crypto/openpgp"
8         "epoint/document"
9         "epoint/key"
10         "epoint/store"
11         "fmt"
12         "log"
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 *work
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         err = key.SelfSign(e)
68         if err != nil {
69                 return
70         }
71         d, err := key.Format(e)
72         if err != nil {
73                 return
74         }
75         err = db.Set("key", key.Id(e), d)
76         if err != nil {
77                 return
78         }
79         err = db.Set("", "serverkey", d)
80         return
81 }
82
83 func GetKeys(fpr string) (es openpgp.EntityList, err error) {
84         b, err := db.Get("key", fpr)
85         if err != nil {
86                 return
87         }
88         es, err = openpgp.ReadKeyRing(bytes.NewBuffer(b))
89         if err != nil {
90                 // internal error: pubkey cannot be parsed
91                 return
92         }
93         return
94 }
95
96 func AddKeys(d []byte) (err error) {
97         entities, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
98         if err != nil {
99                 return
100         }
101         // TODO: allow multiple key uploads at once?
102         if len(entities) > 100 {
103                 err = fmt.Errorf("expected at most 100 keys; got %d", len(entities))
104                 return
105         }
106         for _, e := range entities {
107                 // TODO: various checks..
108                 // TODO: collect errors instead of aborting addkeys
109                 isIssuer, issuer, denom, err1 := key.Check(e)
110                 err = err1
111                 if err != nil {
112                         return
113                 }
114                 if !isIssuer {
115                         es, err1 := GetKeys(issuer)
116                         err = err1
117                         if err != nil {
118                                 return
119                         }
120                         ok, _, den, err1 := key.Check(es[0])
121                         err = err1
122                         if err != nil {
123                                 // internal error
124                                 return
125                         }
126                         if !ok || den != denom {
127                                 err = fmt.Errorf("Issuer key check failed")
128                                 return
129                         }
130                 }
131                 b := new(bytes.Buffer)
132                 err = e.Serialize(b)
133                 if err != nil {
134                         return
135                 }
136                 fpr := key.Id(e)
137                 err = db.Insert("key", fpr, b.Bytes())
138                 if err != nil {
139                         return
140                 }
141                 err = db.Append("keysby/64", fpr[len(fpr)-16:], []byte(fpr))
142                 if err != nil {
143                         return
144                 }
145                 err = db.Append("keysby/32", fpr[len(fpr)-8:], []byte(fpr))
146                 if err != nil {
147                         return
148                 }
149         }
150         return
151 }
152
153 // Get cert through the named store
154 func GetCert(name, id string) (d []byte, err error) {
155         certid, err := db.Get(name, id)
156         if err != nil {
157                 // ok if notfound
158                 return
159         }
160         d, err = db.Get("cert", string(certid))
161         if err != nil {
162                 // internal error: cert is not available
163                 return
164         }
165         return
166 }
167
168 func EvalDraft(d []byte) (c []byte, err error) {
169         iv, signed, err := document.Parse(d)
170         if err != nil {
171                 return
172         }
173         draft, ok := iv.(*document.Draft)
174         if !ok {
175                 err = fmt.Errorf("EvalDraft: expected a draft document")
176                 return
177         }
178         k, err := db.Get("key", draft.Drawer)
179         if err != nil {
180                 return
181         }
182         // TODO: key.Parse
183         kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
184         if err != nil {
185                 // internal error: pubkey cannot be parsed
186                 return
187         }
188         err = document.Verify(signed, kr)
189         if err != nil {
190                 return
191         }
192         //      _, issuer, denom, err := key.Check(kr[0])
193         //      if err != nil {
194         //              return
195         //      }
196         // TODO: do various format checks (AuthorizedBy check etc)
197         if draft.Amount <= 0 || draft.Amount >= IntLimit {
198                 err = fmt.Errorf("draft amount is invalid: %d", draft.Amount)
199                 return
200         }
201         k, err = db.Get("key", draft.Beneficiary)
202         if err != nil {
203                 return
204         }
205         kr, err = openpgp.ReadKeyRing(bytes.NewBuffer(k))
206         if err != nil {
207                 // internal error: pubkey cannot be parsed
208                 return
209         }
210         return addDraft(d, signed, draft)
211 }
212
213 func EvalDebitCert(d []byte) (c []byte, err error) {
214         iv, signed, err := document.Parse(d)
215         if err != nil {
216                 return
217         }
218         cert, ok := iv.(*document.DebitCert)
219         if !ok {
220                 err = fmt.Errorf("ParseDebitCert: expected a debit docuent")
221                 return
222         }
223
224         kr := openpgp.EntityList{serverkey}
225         if key.Id(serverkey) != cert.AuthorizedBy {
226                 // TODO: ...
227                 k := []byte(nil)
228                 k, err = db.Get("key", cert.AuthorizedBy)
229                 if err != nil {
230                         return
231                 }
232                 kr, err = openpgp.ReadKeyRing(bytes.NewBuffer(k))
233                 if err != nil {
234                         // internal error: pubkey cannot be parsed
235                         return
236                 }
237         }
238         // must clean up to make sure the hash is ok
239         err = document.Verify(signed, kr)
240         if err != nil {
241                 return
242         }
243         return addDebit(d, signed, cert)
244 }
245
246 func addDraft(d []byte, signed *document.Signed, draft *document.Draft) (c []byte, err error) {
247         w := new(work)
248         w.docid = document.Id(signed)
249         w.account = fmt.Sprintf("%s.%s", draft.Drawer, draft.Issuer)
250         w.in = d
251         w.signed = signed
252         w.draft = draft
253         w.sync = make(chan int)
254         log.Printf("add draft work: %s", w.account)
255         newchan <- w
256         <-w.sync
257         return w.out, w.err
258 }
259
260 func addDebit(d []byte, signed *document.Signed, cert *document.DebitCert) (c []byte, err error) {
261         w := new(work)
262         w.docid = document.Id(signed)
263         w.account = fmt.Sprintf("%s.%s", cert.Beneficiary, cert.Issuer)
264         w.in = d
265         w.signed = signed
266         w.debit = cert
267         w.sync = make(chan int)
268         log.Printf("add debit work: %s", w.account)
269         newchan <- w
270         <-w.sync
271         return w.out, w.err
272 }
273
274 func dispatch() {
275         log.Printf("start dispatch")
276         works := make(map[string]*worklist)
277         for {
278                 select {
279                 case w := <-newchan:
280                         log.Printf("queue work: %s", w.account)
281                         ws := works[w.account]
282                         if ws == nil {
283                                 // TODO: unnecessary alloc
284                                 works[w.account] = new(worklist)
285                                 go handle(w)
286                         } else {
287                                 pushwork(ws, w)
288                         }
289                 case w := <-delchan:
290                         log.Printf("unqueue work: %s", w.account)
291                         ws := works[w.account]
292                         wnext := popwork(ws)
293                         if wnext == nil {
294                                 delete(works, w.account)
295                         } else {
296                                 go handle(wnext)
297                         }
298                 }
299         }
300 }
301
302 func handle(w *work) {
303         log.Printf("start work: %s", w.account)
304         if w.debit != nil {
305                 w.out, w.err = handleDebit(w)
306         } else if w.draft != nil {
307                 w.out, w.err = handleDraft(w)
308         } else {
309                 panic("unreachable")
310         }
311         log.Printf("finish work: %s outlen: %d, errtype: %T", w.account, len(w.out), w.err)
312         delchan <- w
313         w.sync <- 0
314 }
315
316 func handleDraft(w *work) (c []byte, err error) {
317         nonce := fmt.Sprintf("%s.%s", w.account, w.draft.Nonce)
318         oldid, err := db.Get("draftby/key.issuer.nonce", nonce)
319         if err == nil {
320                 if string(oldid) != w.docid {
321                         err = fmt.Errorf("draft nonce is not unique (see draft %s)", oldid)
322                 } else {
323                         c, err = GetCert("certby/draft", w.docid)
324                 }
325                 return
326         } else if _, ok := err.(store.NotFoundError); !ok {
327                 return
328         }
329
330         err = db.Begin(w.docid)
331         if err != nil {
332                 return
333         }
334         err = db.Set("draft", w.docid, w.in)
335         if err != nil {
336                 return
337         }
338         err = db.Set("draftby/key.issuer.nonce", nonce, []byte(w.docid))
339         if err != nil {
340                 return
341         }
342         cert, err := newDebitCert(w)
343         if err != nil {
344                 // probably client error
345                 db.End(w.docid)
346                 return
347         }
348         c, signed, err := document.Format(cert, serverkey)
349         if err != nil {
350                 return
351         }
352         certid := document.Id(signed)
353         err = db.Set("cert", certid, c)
354         if err != nil {
355                 // internal error
356                 return
357         }
358         err = db.Set("certby/draft", w.docid, []byte(certid))
359         if err != nil {
360                 // internal error
361                 return
362         }
363         // TODO: append?
364         err = db.Set("certby/key.issuer.serial", fmt.Sprintf("%s.%09d", w.account, cert.Serial), []byte(certid))
365         if err != nil {
366                 // internal error
367                 return
368         }
369         err = db.Set("certby/key.issuer", w.account, []byte(certid))
370         if err != nil {
371                 // internal error
372                 return
373         }
374         // TODO: run journal cleanup in case of client errors
375         err = db.End(w.docid)
376         return
377 }
378
379 func handleDebit(w *work) (c []byte, err error) {
380         c, err = GetCert("certby/debit", w.docid)
381         if err == nil {
382                 return
383         } else if _, ok := err.(store.NotFoundError); !ok {
384                 // internal error
385                 return
386         }
387         err = db.Begin(w.docid)
388         if err != nil {
389                 return
390         }
391         err = db.Set("cert", w.docid, w.in)
392         if err != nil {
393                 return
394         }
395         // TODO: check pubkey etc
396         cert, err := newCreditCert(w)
397         if err != nil {
398                 // internal error
399                 return
400         }
401         c, signed, err := document.Format(cert, serverkey)
402         if err != nil {
403                 // internal error
404                 return
405         }
406         certid := document.Id(signed)
407         err = db.Set("cert", certid, c)
408         if err != nil {
409                 // internal error
410                 return
411         }
412         err = db.Set("certby/debit", w.docid, []byte(certid))
413         if err != nil {
414                 // internal error
415                 return
416         }
417         // TODO: append?
418         err = db.Set("certby/key.issuer.serial", fmt.Sprintf("%s.%09d", w.account, cert.Serial), []byte(certid))
419         if err != nil {
420                 // internal error
421                 return
422         }
423         err = db.Set("certby/key.issuer", w.account, []byte(certid))
424         if err != nil {
425                 // internal error
426                 return
427         }
428         db.End(w.docid)
429         return
430 }
431
432 func newDebitCert(w *work) (*document.DebitCert, error) {
433         cert := new(document.DebitCert)
434         cert.Holder = w.draft.Drawer
435         cert.Date = time.Now().Unix()
436         cert.Denomination = "epoint"
437         cert.Issuer = w.draft.Issuer
438         cert.AuthorizedBy = w.draft.AuthorizedBy
439         cert.Difference = -w.draft.Amount
440         cert.Draft = w.docid
441         cert.Beneficiary = w.draft.Beneficiary
442
443         oid, err := db.Get("certby/key.issuer", w.account)
444         oldcertid := string(oid)
445         if err != nil {
446                 // first cert: drawer is issuer
447                 if w.draft.Drawer != w.draft.Issuer {
448                         return nil, fmt.Errorf("drawer must be the issuer when drawing an empty account (%s != %s)", w.draft.Drawer, w.draft.Issuer)
449                 }
450                 cert.Serial = 1
451                 cert.Balance = cert.Difference
452                 cert.LastDebitSerial = 0
453                 cert.LastCreditSerial = 0
454         } else {
455                 d, err := db.Get("cert", oldcertid)
456                 if err != nil {
457                         return nil, err
458                 }
459                 iv, _, err := document.Parse(d)
460                 if err != nil {
461                         // internal error
462                         return nil, err
463                 }
464                 // TODO: this is a hack
465                 oldcert, err := document.ToCert(iv)
466                 if err != nil {
467                         // internal error
468                         return nil, err
469                 }
470                 // TODO: sanity checks? oldcert.Holder == draft.Drawer
471                 cert.Serial = oldcert.Serial + 1
472                 cert.Balance = oldcert.Balance + cert.Difference
473                 if cert.Balance <= -IntLimit {
474                         return nil, fmt.Errorf("balance limit exceeded: %d", cert.Balance)
475                 }
476                 if oldcert.Balance > 0 && cert.Balance < 0 {
477                         return nil, fmt.Errorf("insufficient funds: %d", oldcert.Balance)
478                 }
479                 cert.LastDebitSerial = oldcert.LastDebitSerial
480                 cert.LastCreditSerial = oldcert.LastCreditSerial
481                 if _, ok := iv.(*document.DebitCert); ok {
482                         cert.LastDebitSerial = oldcert.Serial
483                 } else {
484                         cert.LastCreditSerial = oldcert.Serial
485                 }
486                 cert.LastCert = &oldcertid
487         }
488         return cert, nil
489 }
490
491 func newCreditCert(w *work) (*document.CreditCert, error) {
492         cert := new(document.CreditCert)
493         // TODO: get from old cert instead?
494         cert.Holder = w.debit.Beneficiary
495         cert.Date = time.Now().Unix()
496         // TODO: get these from the cert holder pubkey
497         cert.Denomination = "epoint"
498         cert.Issuer = w.debit.Issuer
499         cert.AuthorizedBy = w.debit.AuthorizedBy // TODO: draft vs dcert vs serverside decision
500         cert.Difference = -w.debit.Difference
501         cert.Draft = w.debit.Draft
502         cert.Drawer = w.debit.Holder
503         cert.DebitCert = w.docid
504
505         oid, err := db.Get("certby/key.issuer", w.account)
506         oldcertid := string(oid)
507         if err != nil {
508                 if _, ok := err.(store.NotFoundError); !ok {
509                         // internal error
510                         return nil, err
511                 }
512                 // this is the first cert
513                 cert.Serial = 1
514                 cert.Balance = cert.Difference
515                 cert.LastDebitSerial = 0
516                 cert.LastCreditSerial = 0
517         } else {
518                 d, err := db.Get("cert", oldcertid)
519                 if err != nil {
520                         // internal error
521                         return nil, err
522                 }
523                 iv, _, err := document.Parse(d)
524                 if err != nil {
525                         // internal error
526                         return nil, err
527                 }
528                 // TODO: this is a hack
529                 oldcert, err := document.ToCert(iv)
530                 if err != nil {
531                         // internal error
532                         return nil, err
533                 }
534                 cert.Serial = oldcert.Serial + 1
535                 cert.Balance = oldcert.Balance + cert.Difference
536                 if cert.Balance >= IntLimit {
537                         return nil, fmt.Errorf("balance limit exceeded: %d", cert.Balance)
538                 }
539                 cert.LastDebitSerial = oldcert.LastDebitSerial
540                 cert.LastCreditSerial = oldcert.LastCreditSerial
541                 if _, ok := iv.(*document.DebitCert); ok {
542                         cert.LastDebitSerial = oldcert.Serial
543                 } else {
544                         cert.LastCreditSerial = oldcert.Serial
545                 }
546                 cert.LastCert = &oldcertid
547         }
548         return cert, nil
549 }
550
551 func Init(rootdir string, sk *openpgp.Entity) (err error) {
552         db, err = store.Open(rootdir)
553         if err != nil {
554                 return
555         }
556         err = db.Ensure("key")
557         if err != nil {
558                 return
559         }
560         err = db.Ensure("cert")
561         if err != nil {
562                 return
563         }
564         err = db.Ensure("draft")
565         if err != nil {
566                 return
567         }
568         err = db.Ensure("certby/draft")
569         if err != nil {
570                 return
571         }
572         err = db.Ensure("certby/debit")
573         if err != nil {
574                 return
575         }
576         err = db.Ensure("certby/key.issuer")
577         if err != nil {
578                 return
579         }
580         err = db.Ensure("certby/key.issuer.serial")
581         if err != nil {
582                 return
583         }
584         err = db.Ensure("draftby/key.issuer.nonce")
585         if err != nil {
586                 return
587         }
588         err = db.Ensure("keysby/64")
589         if err != nil {
590                 return
591         }
592         err = db.Ensure("keysby/32")
593         if err != nil {
594                 return
595         }
596         err = setserverkey(sk)
597         if err != nil {
598                 return
599         }
600         newchan = make(chan *work)
601         delchan = make(chan *work)
602         go dispatch()
603         return
604 }