Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions encoding/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package encoding

import (
stdencoding "encoding"
"encoding/base32"
"encoding/base64"
"encoding/hex"
Expand All @@ -11,6 +12,9 @@ import (
"github.com/pkg/errors"
)

// TextMarshaler alias for encoding.TextMarshaler.
type TextMarshaler = stdencoding.TextMarshaler

// Encoding is an encoding for bytes to and from a string
type Encoding string

Expand Down
57 changes: 33 additions & 24 deletions json/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
package json

import (
"bytes"
"encoding/json"
"regexp"
"strconv"
"strings"

"github.com/keys-pub/keys/encoding"

"github.com/pkg/errors"
)

Expand All @@ -21,55 +22,63 @@ type intEntry struct {
value int
}

// Value to string.
type Value interface {
Marshal() (string, error)
}

// NewString ...
func NewString(key string, value string) Value {
// String ...
func String(key string, value string) encoding.TextMarshaler {
return stringEntry{key: key, value: value}
}

// NewInt ...
func NewInt(key string, value int) Value {
// Int ...
func Int(key string, value int) encoding.TextMarshaler {
return intEntry{key: key, value: value}
}

var isAlphaNumericDot = regexp.MustCompile(`^[a-zA-Z0-9.]+$`).MatchString
var needsEscape = regexp.MustCompile(`^[\"]+$`).MatchString

func (e stringEntry) Marshal() (string, error) {
func (e stringEntry) MarshalText() ([]byte, error) {
if !isAlphaNumericDot(e.key) {
return "", errors.Errorf("invalid character in key")
return nil, errors.Errorf("invalid character in key")
}
if needsEscape(e.value) {
return "", errors.Errorf("invalid character in value")
return nil, errors.Errorf("invalid character in value")
}
if !encoding.IsASCII([]byte(e.value)) {
return "", errors.Errorf("invalid character in value")
return nil, errors.Errorf("invalid character in value")
}
return `"` + e.key + `":"` + e.value + `"`, nil
return []byte(`"` + e.key + `":"` + e.value + `"`), nil
}

func (e intEntry) Marshal() (string, error) {
func (e intEntry) MarshalText() ([]byte, error) {
if !isAlphaNumericDot(e.key) {
return "", errors.Errorf("invalid character in key")
return nil, errors.Errorf("invalid character in key")
}
return `"` + e.key + `":` + strconv.Itoa(e.value), nil

b := []byte{}
b = append(b, '"')
b = append(b, []byte(e.key)...)
b = append(b, '"', ':')
b = append(b, []byte(strconv.Itoa(e.value))...)

return b, nil
}

// Marshal values.
func Marshal(es []Value) ([]byte, error) {
out := make([]string, 0, len(es))
for _, e := range es {
s, err := e.Marshal()
func Marshal(vals ...encoding.TextMarshaler) ([]byte, error) {
out := make([][]byte, 0, len(vals))
for _, val := range vals {
b, err := val.MarshalText()
if err != nil {
return nil, err
}
out = append(out, s)
out = append(out, b)
}
return []byte("{" + strings.Join(out, ",") + "}"), nil

b := []byte{}
b = append(b, '{')
b = append(b, bytes.Join(out, []byte{','})...)
b = append(b, '}')

return b, nil
}

// Unmarshal bytes.
Expand Down
20 changes: 10 additions & 10 deletions json/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ import (
)

func TestMarshal(t *testing.T) {
b, err := json.Marshal([]json.Value{
json.NewString("key1", "val1"),
json.NewInt("key2", 2),
})
b, err := json.Marshal(
json.String("key1", "val1"),
json.Int("key2", 2),
)
require.NoError(t, err)
require.Equal(t, `{"key1":"val1","key2":2}`, string(b))

_, err = json.Marshal([]json.Value{
json.NewString(`"`, ""),
})
_, err = json.Marshal(
json.String(`"`, ""),
)
require.EqualError(t, err, "invalid character in key")
_, err = json.Marshal([]json.Value{
json.NewString("key1", `"`),
})
_, err = json.Marshal(
json.String("key1", `"`),
)
require.EqualError(t, err, "invalid character in value")
}
20 changes: 10 additions & 10 deletions statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,30 +210,30 @@ func statementBytesToSign(st *Statement) ([]byte, error) {
}

func statementBytes(st *Statement, sig []byte) ([]byte, error) {
mes := []json.Value{
json.NewString(".sig", encoding.MustEncode(sig, encoding.Base64)),
mes := []encoding.TextMarshaler{
json.String(".sig", encoding.MustEncode(sig, encoding.Base64)),
}
if len(st.Data) != 0 {
mes = append(mes, json.NewString("data", encoding.MustEncode(st.Data, encoding.Base64)))
mes = append(mes, json.String("data", encoding.MustEncode(st.Data, encoding.Base64)))
}
mes = append(mes, json.NewString("kid", st.KID.String()))
mes = append(mes, json.String("kid", st.KID.String()))
if len(st.Prev) != 0 {
mes = append(mes, json.NewString("prev", encoding.MustEncode(st.Prev, encoding.Base64)))
mes = append(mes, json.String("prev", encoding.MustEncode(st.Prev, encoding.Base64)))
}
if st.Revoke != 0 {
mes = append(mes, json.NewInt("revoke", st.Revoke))
mes = append(mes, json.Int("revoke", st.Revoke))
}
if st.Seq != 0 {
mes = append(mes, json.NewInt("seq", st.Seq))
mes = append(mes, json.Int("seq", st.Seq))
}
if !st.Timestamp.IsZero() {
mes = append(mes, json.NewInt("ts", int(tsutil.Millis(st.Timestamp))))
mes = append(mes, json.Int("ts", int(tsutil.Millis(st.Timestamp))))
}
if st.Type != "" {
mes = append(mes, json.NewString("type", st.Type))
mes = append(mes, json.String("type", st.Type))
}

return json.Marshal(mes)
return json.Marshal(mes...)
}

// unmarshalJSON returns a Statement from JSON bytes.
Expand Down
14 changes: 7 additions & 7 deletions user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,19 @@ func (u User) MarshalJSON() ([]byte, error) {

// Bytes is a serialized User.
func (u User) Bytes() ([]byte, error) {
mes := []json.Value{}
mes := []encoding.TextMarshaler{}

mes = append(mes, json.NewString("k", u.KID.String()))
mes = append(mes, json.NewString("n", u.Name))
mes = append(mes, json.String("k", u.KID.String()))
mes = append(mes, json.String("n", u.Name))

if u.Seq != 0 {
mes = append(mes, json.NewInt("sq", u.Seq))
mes = append(mes, json.Int("sq", u.Seq))
}
mes = append(mes, json.NewString("sr", u.Service))
mes = append(mes, json.String("sr", u.Service))
if u.URL != "" {
mes = append(mes, json.NewString("u", u.URL))
mes = append(mes, json.String("u", u.URL))
}
return json.Marshal(mes)
return json.Marshal(mes...)
}

// Status is the status of the user statement.
Expand Down