// 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"
"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
}
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
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
}
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())
}
}
// 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
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
}
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
}