19 func AddKeys(d []byte) (err error) {
20 entities, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(d))
24 // TODO: allow multiple key uploads at once?
25 if len(entities) > 100 {
26 err = fmt.Errorf("expected at most 100 keys; got %d", len(entities))
29 for _, e := range entities {
30 // TODO: various checks..
31 b := new(bytes.Buffer)
36 fpr := fmt.Sprintf("%040X", e.PrimaryKey.Fingerprint)
37 err = db.Set("key", fpr, b.Bytes())
41 err = db.Append("keysby/64", fpr[len(fpr)-16:], []byte(fpr))
45 err = db.Append("keysby/32", fpr[len(fpr)-8:], []byte(fpr))
53 func CertByDraft(draftid string) (d []byte, err error) {
54 certid, err := db.Get("certby/draft", draftid)
56 // TODO: we have the draft but the cert is not ready
59 d, err = db.Get("cert", string(certid))
61 // shouldn't happen, cert is not available
67 func CertByDebitCert(debitid string) (d []byte, err error) {
68 creditid, err := db.Get("certby/debit", debitid)
70 // TODO: we have the debit cert but the credit cert is not ready
73 d, err = db.Get("cert", string(creditid))
75 // shouldn't happen, cert is not available
81 // parse clear signed draft and verify it
82 func ParseDraft(d []byte) (draft *document.Draft, draftid string, err error) {
83 iv, signed, err := document.Parse(d)
87 draft, ok := iv.(*document.Draft)
89 err = fmt.Errorf("ParseDraft: expected a draft docuent")
92 draftid = document.Id(signed)
94 k, err := db.Get("key", draft.Drawer)
98 kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
100 // internal error: pubkey cannot be parsed
103 cleaned, err = document.Verify(signed, kr)
107 // TODO: verify issuer
108 _, err = db.Get("key", draft.Beneficiary)
113 // TODO: do various format checks (AuthorizedBy check etc)
114 if draft.Amount <= 0 || draft.Amount >= IntLimit {
115 err = fmt.Errorf("draft amount is invalid: %d", draft.Amount)
121 func ParseDebitCert(d []byte) (cert *document.DebitCert, certid string, err error) {
122 iv, signed, err := document.Parse(d)
126 cert, ok := iv.(*document.DebitCert)
128 err = fmt.Errorf("ParseDebitCert: expected a debit docuent")
132 // TODO: keep our key at hand
133 k, err := db.Get("key", cert.AuthorizedBy)
137 kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
139 // internal error: pubkey cannot be parsed
142 // must clean up to make sure the hash is ok
143 cleaned, err = document.Verify(signed, kr)
148 certid = document.Id(signed)
152 func NewDebitCert(draftid string, draft *document.Draft) (*document.DebitCert, error) {
153 cert := new(document.DebitCert)
154 cert.Holder = draft.Drawer
155 cert.Date = time.Seconds()
156 cert.Denomination = "epoint"
157 cert.Issuer = draft.Issuer
158 cert.AuthorizedBy = draft.AuthorizedBy
159 cert.Difference = -draft.Amount
161 cert.Beneficiary = draft.Beneficiary
163 oid, err := db.Get("certby/key", draft.Drawer)
164 oldcertid := string(oid)
166 // first cert: drawer is issuer
167 if draft.Drawer != draft.Issuer {
168 return nil, fmt.Errorf("drawer must be the issuer when drawing an empty account")
171 cert.Balance = cert.Difference
172 cert.LastDebitSerial = 0
173 cert.LastCreditSerial = 0
175 d, err := db.Get("cert", oldcertid)
179 iv, _, err := document.Parse(d)
184 // TODO: this is a hack
185 oldcert, err := document.ToCert(iv)
186 // TODO: sanity checks? oldcert.Holder == draft.Drawer
187 cert.Serial = oldcert.Serial + 1
188 cert.Balance = oldcert.Balance + cert.Difference
189 if cert.Balance <= -IntLimit {
190 return nil, fmt.Errorf("balance limit exceeded: %d", cert.Balance)
192 if oldcert.Balance > 0 && cert.Balance < 0 {
193 return nil, fmt.Errorf("insufficient funds: %d", oldcert.Balance)
195 cert.LastDebitSerial = oldcert.LastDebitSerial
196 cert.LastCreditSerial = oldcert.LastCreditSerial
198 cert.LastDebitSerial = oldcert.Serial
200 cert.LastCreditSerial = oldcert.Serial
202 cert.LastCert = &oldcertid
207 func NewCreditCert(draftid string, draft *document.Draft, dcertid string, dcert *document.DebitCert) (*document.CreditCert, error) {
208 cert := new(document.CreditCert)
209 // TODO: get from old cert instead?
210 cert.Holder = dcert.Beneficiary
211 cert.Date = time.Seconds()
212 // TODO: get these from the cert holder pubkey
213 cert.Denomination = "epoint"
214 cert.Issuer = draft.Issuer
215 cert.AuthorizedBy = dcert.AuthorizedBy // TODO: draft vs dcert vs serverside decision
216 cert.Difference = -dcert.Difference
218 cert.Drawer = dcert.Holder
219 cert.DebitCert = dcertid
221 oid, err := db.Get("certby/key", dcert.Beneficiary)
222 oldcertid := string(oid)
224 // this is the first cert
226 cert.Balance = cert.Difference
227 cert.LastDebitSerial = 0
228 cert.LastCreditSerial = 0
230 d, err := db.Get("cert", oldcertid)
235 iv, _, err := document.Parse(d)
240 // TODO: this is a hack
241 oldcert, err := document.ToCert(iv)
246 cert.Serial = oldcert.Serial + 1
247 cert.Balance = oldcert.Balance + cert.Difference
248 if cert.Balance >= IntLimit {
249 return nil, fmt.Errorf("balance limit exceeded: %d", cert.Balance)
251 cert.LastDebitSerial = oldcert.LastDebitSerial
252 cert.LastCreditSerial = oldcert.LastCreditSerial
254 cert.LastDebitSerial = oldcert.Serial
256 cert.LastCreditSerial = oldcert.Serial
258 cert.LastCert = &oldcertid
263 func EvalDraft(d []byte, sk *openpgp.Entity) (r []byte, err error) {
264 draft, draftid, err := ParseDraft(d)
268 _, err = db.Get("draft", draftid)
271 return CertByDraft(draftid)
273 // if draft is ok we save it
274 err = db.Set("draft", draftid, d)
279 // TODO: db.Insert: fails if key exists
280 _, err = db.Get("draftby/nonce", draft.Nonce)
282 err = fmt.Errorf("draft nonce is not unique")
285 err = db.Set("draftby/nonce", draft.Nonce, d)
292 cert, err := NewDebitCert(draftid, draft)
296 r, signed, err := document.Format(cert, sk)
297 certid := document.Id(signed)
298 err = db.Set("cert", certid, r)
303 err = db.Set("certby/draft", draftid, []byte(certid))
308 err = db.Set("certby/key", cert.Holder, []byte(certid))
314 err = db.Set("certby/key.serial", fmt.Sprintf("%s.%09d", cert.Holder, cert.Serial), []byte(certid))
322 func EvalDebitCert(d []byte, sk *openpgp.Entity) (r []byte, err error) {
323 dcert, dcertid, err := ParseDebitCert(d)
327 r, err = CertByDebitCert(dcertid)
332 // TODO: we only need the draft to know the issuer (+beneficiary)
333 // it should be in the pubkey
334 d, err = db.Get("draft", dcert.Draft)
339 iv, _, err := document.Parse(d)
344 draft, ok := iv.(*document.Draft)
347 err = fmt.Errorf("EvalDebitCert: expected draft from internal db")
352 // TODO: check pubkey etc
353 cert, err := NewCreditCert(dcert.Draft, draft, dcertid, dcert)
358 r, signed, err := document.Format(cert, sk)
363 certid := document.Id(signed)
364 err = db.Set("cert", certid, r)
369 err = db.Set("certby/debit", dcertid, []byte(certid))
374 err = db.Set("certby/key", cert.Holder, []byte(certid))
380 err = db.Set("certby/key.serial", fmt.Sprintf("%s.%09d", cert.Holder, cert.Serial), []byte(certid))
388 func Init(rootdir string) (err error) {
389 db, err = store.Open(rootdir)
393 err = db.Ensure("key")
397 err = db.Ensure("cert")
401 err = db.Ensure("draft")
405 err = db.Ensure("certby/draft")
409 err = db.Ensure("certby/debit")
413 err = db.Ensure("certby/key")
417 err = db.Ensure("certby/key.serial")
421 err = db.Ensure("draftby/nonce")
425 err = db.Ensure("keysby/64")
429 err = db.Ensure("keysby/32")