X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=document%2Fdocument.go;h=1e26d28cf59669dc32435e9f08520680d08da983;hb=11dabddd0bb1fce854b001a70694cb9b6be4ff26;hp=e2a08599c0316cf18a9e8388f2479d278b971888;hpb=90b0c664371e5c26560412ae004e0c5e01a77bca;p=epoint diff --git a/document/document.go b/document/document.go index e2a0859..1e26d28 100644 --- a/document/document.go +++ b/document/document.go @@ -31,6 +31,9 @@ package document // TODO: trailing space handling in ParseFields // 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 (require only draftid.nonce to be uniq) +// TODO: denom, issuer from key (key representation: armor?) import ( "bytes" @@ -103,7 +106,7 @@ var fieldtype = map[string]string{ "Last-Credit-Serial": "int", "Last-Debit-Serial": "int", "Maturity-Date": "date", - "Nonce": "text", + "Nonce": "id", "Notes": "text", "References": "ids", "Serial": "int", @@ -126,9 +129,9 @@ type Draft struct { 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 } @@ -139,6 +142,27 @@ type Notice struct { References []string // may be empty (startup notice) } +type Cert struct { + IsDebit bool + Holder string + Serial int64 + Balance int64 + Denomination string + Issuer string + Date int64 + Difference int64 + Draft string + Beneficiary *string // only in debit cert + Drawer *string // only in credit cert + DebitCert *string // only in credit cert + AuthorizedBy string + Notes *string // optional + LastDebitSerial int64 // 0 if none + LastCreditSerial int64 // 0 if none + LastCert *string // nil if serial == 1 + References []string +} + type DebitCert struct { Holder string Serial int64 @@ -153,7 +177,7 @@ type DebitCert struct { Notes *string // optional LastDebitSerial int64 // 0 if none LastCreditSerial int64 // 0 if none - LastCert *string // ? if serial == 1 + LastCert *string // nil if serial == 1 References []string } @@ -187,10 +211,66 @@ type BounceCert struct { References []string } -// sha1 sum of the (cleaned) document as uppercase hex string -func Id(d []byte) string { +func ToCert(v interface{}) (cert *Cert, err error) { + cert = new(Cert) + switch x := v.(type) { + case *DebitCert: + cert.IsDebit = true + cert.Beneficiary = &x.Beneficiary + + cert.Holder = x.Holder + cert.Serial = x.Serial + cert.Balance = x.Balance + cert.Denomination = x.Denomination + cert.Issuer = x.Issuer + cert.Date = x.Date + cert.Difference = x.Difference + cert.Draft = x.Draft + cert.AuthorizedBy = x.AuthorizedBy + cert.Notes = x.Notes + cert.LastDebitSerial = x.LastDebitSerial + cert.LastCreditSerial = x.LastCreditSerial + cert.LastCert = x.LastCert + cert.References = x.References + + case *CreditCert: + cert.IsDebit = false + cert.Drawer = &x.Drawer + cert.DebitCert = &x.DebitCert + + cert.Holder = x.Holder + cert.Serial = x.Serial + cert.Balance = x.Balance + cert.Denomination = x.Denomination + cert.Issuer = x.Issuer + cert.Date = x.Date + cert.Difference = x.Difference + cert.Draft = x.Draft + cert.AuthorizedBy = x.AuthorizedBy + cert.Notes = x.Notes + cert.LastDebitSerial = x.LastDebitSerial + cert.LastCreditSerial = x.LastCreditSerial + cert.LastCert = x.LastCert + cert.References = x.References + default: + err = fmt.Errorf("ToCert: only debit or credit document can be converted to cert") + } + return +} + +func cleanBody(s []byte) []byte { + nl := []byte{'\n'} + a := bytes.Split(s, nl) + for i := range a { + a[i] = bytes.TrimRight(a[i], " \t") + } + return bytes.Join(a, nl) +} + +// sha1 sum of the (cleaned) document body as uppercase hex string +func Id(c *Signed) string { h := sha1.New() - h.Write(d) + h.Write(c.Body) return fmt.Sprintf("%040X", h.Sum()) } @@ -209,7 +289,7 @@ func Parse(s []byte) (iv interface{}, c *Signed, err error) { } // format and sign an epoint document -func Format(iv interface{}, key *openpgp.Entity) (s []byte, err error) { +func Format(iv interface{}, key *openpgp.Entity) (s []byte, c *Signed, err error) { doc, err := FormatStruct(iv) if err != nil { return @@ -218,31 +298,21 @@ func Format(iv interface{}, key *openpgp.Entity) (s []byte, err error) { if err != nil { return } - c, err := Sign(body, key) + c, err = Sign(body, key) if err != nil { return } - return FormatSigned(c) + s, err = FormatSigned(c) + return } // verify an epoint document, return the cleaned version as well -func Verify(c *Signed, key openpgp.KeyRing) (cleaned []byte, err error) { - err = CleanSigned(c) - if err != nil { - return - } - err = VerifyCleaned(c, key) - if err != nil { - return - } - return FormatSigned(c) -} - -// verify signature of body with given key -func VerifyCleaned(c *Signed, key openpgp.KeyRing) (err error) { +func Verify(c *Signed, key openpgp.KeyRing) (err error) { msg := bytes.NewBuffer(c.Body) sig := bytes.NewBuffer(c.Signature) - _, err = openpgp.CheckArmoredDetachedSignature(key, msg, sig) + // TODO: verify signature + _, _ = msg, sig + // _, err = openpgp.CheckArmoredDetachedSignature(key, msg, sig) return } @@ -250,9 +320,14 @@ func VerifyCleaned(c *Signed, key openpgp.KeyRing) (err error) { func Sign(body []byte, key *openpgp.Entity) (c *Signed, err error) { c = new(Signed) c.Hash = "SHA256" - c.Body = body + c.Body = cleanBody(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 }