// TODO: fields of notice (last notice, serial, failure notice,..)
// TODO: limits and cert type specific input validation
// TODO: fix Cert mess
+// TODO: nonce is id, id is even number of hex digits
+// TODO: denom, issuer from key (key representation: armor?)
import (
"bytes"
"Last-Credit-Serial": "int",
"Last-Debit-Serial": "int",
"Maturity-Date": "date",
- "Nonce": "text",
+ "Nonce": "id",
"Notes": "text",
"References": "ids",
"Serial": "int",
Denomination string
Issuer string
AuthorizedBy string
- MaturityDate *int64 // optional
- ExpiryDate *int64 // optional
- Nonce *string // optional
+ MaturityDate *int64 // optional
+ ExpiryDate *int64 // optional
+ Nonce string
Notes *string // optional
}
func Verify(c *Signed, key openpgp.KeyRing) (err error) {
msg := bytes.NewBuffer(c.Body)
sig := bytes.NewBuffer(c.Signature)
-// TODO: verify signature
- _,_ = msg,sig
-// _, err = openpgp.CheckArmoredDetachedSignature(key, msg, sig)
+ // TODO: verify signature
+ _, _ = msg, sig
+ // _, err = openpgp.CheckArmoredDetachedSignature(key, msg, sig)
return
}
c.Body = body
w := new(bytes.Buffer)
err = openpgp.ArmoredDetachSignText(w, key, bytes.NewBuffer(c.Body))
+ if err != nil {
+ return
+ }
+ // close armored document with a \n
+ _, _ = w.Write([]byte{'\n'})
c.Signature = w.Bytes()
return
}
)
const (
- port = ":8080"
- rootdir = "teststore"
+ addr = ":8080"
+ rootdir = "docroot"
seckey = "./key.sec"
)
// todo: http header limit: 64K, body limit: 64K
-// getPubkey(db, fpr) (pk, err)
-// putPubkey(db, fpr, pk) (err)
-// getDraft(db, id) (draft, err)
-// putDraft(db, id, draft) (err)
-
-// getCert(db, id) (cert, err)
-// putCert(db, id, cert) (err)
-// getCertBySerial(db, fpr, sn) (cert, err)
-// getCertByFpr(db, fpr) (cert, err)
-
-// todo: update cert (inc serial..)
-
// Dummy initialization of serverkey
func initkey() (err error) {
f, err := os.Open(seckey)
return
}
+func httpError(w http.ResponseWriter, code int, msg string) {
+ log.Printf("error: %d %s", code, msg)
+ http.Error(w, fmt.Sprintf("%d %s\n\n%s\n", code, http.StatusText(code), msg), code)
+}
+
+func httpReq(r *http.Request) string {
+ err := r.ParseForm()
+ form := ""
+ if err != nil {
+ form = err.Error()
+ } else {
+ a := []string{}
+ for k := range r.Form {
+ a = append(a, k)
+ }
+ form = fmt.Sprintf("%v", a)
+ }
+ return fmt.Sprintf("%s %s params:%s", r.Method, r.URL.Raw, form)
+}
+
func defaultHandler(w http.ResponseWriter, r *http.Request) {
- log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL.Raw)
+ log.Printf("%s %s", r.RemoteAddr, httpReq(r))
fmt.Fprintf(w, "not implemented: %s %s\n", r.Method, r.URL.Raw)
}
func submitHandler(w http.ResponseWriter, r *http.Request) {
- log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL.Raw)
+ log.Printf("%s %s", r.RemoteAddr, httpReq(r))
draft := r.FormValue("draft")
debit := r.FormValue("debit")
- if len(draft) > 0 {
+ key := r.FormValue("key")
+ switch {
+ case draft != "":
cert, err := logic.EvalDraft([]byte(draft), serverkey)
if err != nil {
- log.Printf("eval draft fail: %s", err)
- fmt.Fprintf(w, "eval draft fail: %s\n", err)
+ msg := fmt.Sprintf("eval draft failed: %s", err)
+ httpError(w, 404, msg)
} else {
w.Write(cert)
}
- } else if len(debit) > 0 {
+ case debit != "":
cert, err := logic.EvalDebitCert([]byte(debit), serverkey)
if err != nil {
- log.Printf("eval debit fail: %s", err)
- fmt.Fprintf(w, "eval debit fail: %s\n", err)
+ msg := fmt.Sprintf("eval debit failed: %s", err)
+ httpError(w, 404, msg)
} else {
w.Write(cert)
}
- } else {
- fmt.Fprintf(w, "expected draft or debit param, got: %s %s\n", r.Method, r.URL.Raw)
+ case key != "":
+ err := logic.AddKeys([]byte(key))
+ if err != nil {
+ msg := fmt.Sprintf("add keys failed: %s", err)
+ httpError(w, 404, msg)
+ } else {
+ w.Write([]byte("ok\nTODO: create cert 1 here?"))
+ }
+ default:
+ msg := fmt.Sprintf("expected key, draft or debit param, got: %s", httpReq(r))
+ httpError(w, 404, msg)
}
}
if err != nil {
log.Fatal(err)
}
- err = logic.Init()
+ err = logic.Init(rootdir)
if err != nil {
log.Fatal(err)
}
- http.HandleFunc("/", defaultHandler)
+ // TODO: url from key
+ f, err := os.Create(rootdir + "/form.html")
+ if err != nil {
+ log.Fatal(err)
+ }
+ _, _ = fmt.Fprintf(f, `<html><head><title>epoint-server submit form</title></head><body>
+<h2>epoint-server submit form</h2>
+<h3>web form</h3>
+<p>submit one document at once
+<form method="post" action="http://localhost%s/submit">
+<p>key:<br><textarea name="key" rows="5" cols="80"></textarea>
+<p>draft:<br><textarea name="draft" rows="5" cols="80"></textarea>
+<p>debit:<br><textarea name="debit" rows="5" cols="80"></textarea>
+<p><input type="submit">
+</form>
+<h3>command line</h3>
+<pre>
+curl --data-urlencode name@path/to/file.txt host/submit
+</pre>
+where 'name' is 'key', 'draft' or 'debit'.
+</body></html>
+`, addr)
+ _ = f.Close()
// queries
- http.HandleFunc("/serverkey", func(w http.ResponseWriter, r *http.Request) {
- http.ServeFile(w, r, rootdir+"/serverkey")
- })
-// http.HandleFunc("/status", defaultHandler)
-// http.HandleFunc("/pubkey", defaultHandler)
-// http.HandleFunc("/daft", defaultHandler)
-// http.HandleFunc("/cert", defaultHandler)
+ http.Handle("/", http.FileServer(http.Dir(rootdir)))
// actions
// withdraw, draw, deposit, process, clear
http.HandleFunc("/submit", submitHandler)
- log.Printf("start service, server id: %X\n", serverkey.PrimaryKey.Fingerprint)
- log.Fatal(http.ListenAndServe(port, nil))
+ log.Printf("start service on %s, server key id: %X\n", addr, serverkey.PrimaryKey.Fingerprint)
+ log.Fatal(http.ListenAndServe(addr, nil))
}
if err != nil {
return
}
- err = db.Append("fprlist/64", fpr[len(fpr)-16:], []byte(fpr))
+ err = db.Append("keysby/64", fpr[len(fpr)-16:], []byte(fpr))
if err != nil {
return
}
- err = db.Append("fprlist/32", fpr[len(fpr)-8:], []byte(fpr))
+ err = db.Append("keysby/32", fpr[len(fpr)-8:], []byte(fpr))
if err != nil {
return
}
}
func CertByDraft(draftid string) (d []byte, err error) {
- certid, err := db.Get("certid/debit", draftid)
+ certid, err := db.Get("certby/draft", draftid)
if err != nil {
// TODO: we have the draft but the cert is not ready
return
}
func CertByDebitCert(debitid string) (d []byte, err error) {
- creditid, err := db.Get("certid/credit", debitid)
+ creditid, err := db.Get("certby/debit", debitid)
if err != nil {
// TODO: we have the debit cert but the credit cert is not ready
return
return
}
draftid = document.Id(signed)
-/*
- k, err := db.Get("key", draft.Drawer)
- if err != nil {
- return
- }
- kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
- if err != nil {
- // internal error: pubkey cannot be parsed
- return
- }
- cleaned, err = document.Verify(signed, kr)
- if err != nil {
- return
- }
- // TODO: verify issuer
- _, err = db.Get("key", draft.Beneficiary)
- if err != nil {
- return
- }
-*/
+ /*
+ k, err := db.Get("key", draft.Drawer)
+ if err != nil {
+ return
+ }
+ kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
+ if err != nil {
+ // internal error: pubkey cannot be parsed
+ return
+ }
+ cleaned, err = document.Verify(signed, kr)
+ if err != nil {
+ return
+ }
+ // TODO: verify issuer
+ _, err = db.Get("key", draft.Beneficiary)
+ if err != nil {
+ return
+ }
+ */
// TODO: do various format checks (AuthorizedBy check etc)
if draft.Amount <= 0 || draft.Amount >= IntLimit {
err = fmt.Errorf("draft amount is invalid: %d", draft.Amount)
err = fmt.Errorf("ParseDebitCert: expected a debit docuent")
return
}
-/*
- // TODO: keep our key at hand
- k, err := db.Get("key", cert.AuthorizedBy)
- if err != nil {
- return
- }
- kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
- if err != nil {
- // internal error: pubkey cannot be parsed
- return
- }
- // must clean up to make sure the hash is ok
- cleaned, err = document.Verify(signed, kr)
- if err != nil {
- return
- }
-*/
+ /*
+ // TODO: keep our key at hand
+ k, err := db.Get("key", cert.AuthorizedBy)
+ if err != nil {
+ return
+ }
+ kr, err := openpgp.ReadKeyRing(bytes.NewBuffer(k))
+ if err != nil {
+ // internal error: pubkey cannot be parsed
+ return
+ }
+ // must clean up to make sure the hash is ok
+ cleaned, err = document.Verify(signed, kr)
+ if err != nil {
+ return
+ }
+ */
certid = document.Id(signed)
return
}
cert.Draft = draftid
cert.Beneficiary = draft.Beneficiary
- oid, err := db.Get("certid/last", draft.Drawer)
+ oid, err := db.Get("certby/key", draft.Drawer)
oldcertid := string(oid)
if err != nil {
// first cert: drawer is issuer
cert.Drawer = dcert.Holder
cert.DebitCert = dcertid
- oid, err := db.Get("certid/last", dcert.Beneficiary)
+ oid, err := db.Get("certby/key", dcert.Beneficiary)
oldcertid := string(oid)
if err != nil {
// this is the first cert
return cert, nil
}
-// TODO: draft ref
func EvalDraft(d []byte, sk *openpgp.Entity) (r []byte, err error) {
draft, draftid, err := ParseDraft(d)
if err != nil {
// internal error
return
}
+ // TODO: db.Insert: fails if key exists
+ _, err = db.Get("draftby/nonce", draft.Nonce)
+ if err == nil {
+ err = fmt.Errorf("draft nonce is not unique")
+ return
+ }
+ err = db.Set("draftby/nonce", draft.Nonce, d)
+ if err != nil {
+ // internal error
+ return
+ }
// debit cert
cert, err := NewDebitCert(draftid, draft)
// internal error
return
}
- err = db.Set("certid/debit", draftid, []byte(certid))
+ err = db.Set("certby/draft", draftid, []byte(certid))
if err != nil {
// internal error
return
}
- err = db.Set("certid/last", cert.Holder, []byte(certid))
+ err = db.Set("certby/key", cert.Holder, []byte(certid))
if err != nil {
// internal error
return
}
// TODO: append?
- err = db.Set("certid/all", fmt.Sprintf("%s.%09d", cert.Holder, cert.Serial), []byte(certid))
+ err = db.Set("certby/key.serial", fmt.Sprintf("%s.%09d", cert.Holder, cert.Serial), []byte(certid))
if err != nil {
// internal error
return
// internal error
return
}
- err = db.Set("certid/credit", dcertid, []byte(certid))
+ err = db.Set("certby/debit", dcertid, []byte(certid))
if err != nil {
// internal error
return
}
- err = db.Set("certid/last", cert.Holder, []byte(certid))
+ err = db.Set("certby/key", cert.Holder, []byte(certid))
if err != nil {
// internal error
return
}
// TODO: append?
- err = db.Set("certid/all", fmt.Sprintf("%s.%09d", cert.Holder, cert.Serial), []byte(certid))
+ err = db.Set("certby/key.serial", fmt.Sprintf("%s.%09d", cert.Holder, cert.Serial), []byte(certid))
if err != nil {
// internal error
return
return
}
-func Init() (err error) {
- db, err = store.Open("teststore")
+func Init(rootdir string) (err error) {
+ db, err = store.Open(rootdir)
if err != nil {
return
}
if err != nil {
return
}
- err = db.Ensure("certid/credit")
+ err = db.Ensure("certby/draft")
+ if err != nil {
+ return
+ }
+ err = db.Ensure("certby/debit")
if err != nil {
return
}
- err = db.Ensure("certid/debit")
+ err = db.Ensure("certby/key")
if err != nil {
return
}
- err = db.Ensure("certid/last")
+ err = db.Ensure("certby/key.serial")
if err != nil {
return
}
- err = db.Ensure("certid/all")
+ err = db.Ensure("draftby/nonce")
if err != nil {
return
}
- err = db.Ensure("fprlist/64")
+ err = db.Ensure("keysby/64")
if err != nil {
return
}
- err = db.Ensure("fprlist/32")
+ err = db.Ensure("keysby/32")
if err != nil {
return
}