From e4599334cf434f65cd49f92b604546acd39d4c39 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Tue, 26 Apr 2022 16:52:52 +0200 Subject: add url parsing for get-requests with input Pair-programmed with ln5. --- pkg/requests/requests.go | 86 ++++++++++++++++++----- pkg/requests/requests_test.go | 157 ++++++++++++++++++------------------------ pkg/types/endpoint.go | 6 +- 3 files changed, 138 insertions(+), 111 deletions(-) diff --git a/pkg/requests/requests.go b/pkg/requests/requests.go index 4321b2b..bb63de0 100644 --- a/pkg/requests/requests.go +++ b/pkg/requests/requests.go @@ -1,9 +1,13 @@ package requests import ( + "fmt" "io" + "strconv" + "strings" "git.sigsum.org/sigsum-go/pkg/ascii" + "git.sigsum.org/sigsum-go/pkg/hex" "git.sigsum.org/sigsum-go/pkg/types" ) @@ -16,18 +20,18 @@ type Leaf struct { } type Leaves struct { - StartSize uint64 `ascii:"start_size"` - EndSize uint64 `ascii:"end_size"` + StartSize uint64 + EndSize uint64 } type InclusionProof struct { - LeafHash types.Hash `ascii:"leaf_hash"` - TreeSize uint64 `ascii:"tree_size"` + TreeSize uint64 + LeafHash types.Hash } type ConsistencyProof struct { - NewSize uint64 `ascii:"new_size"` - OldSize uint64 `ascii:"old_size"` + OldSize uint64 + NewSize uint64 } type Cosignature struct { @@ -39,16 +43,19 @@ func (req *Leaf) ToASCII(w io.Writer) error { return ascii.StdEncoding.Serialize(w, req) } -func (req *Leaves) ToASCII(w io.Writer) error { - return ascii.StdEncoding.Serialize(w, req) +// ToURL encodes request parameters at the end of a slash-terminated URL +func (req *Leaves) ToURL(url string) string { + return url + fmt.Sprintf("%d/%d", req.StartSize, req.EndSize) } -func (req *InclusionProof) ToASCII(w io.Writer) error { - return ascii.StdEncoding.Serialize(w, req) +// ToURL encodes request parameters at the end of a slash-terminated URL +func (req *InclusionProof) ToURL(url string) string { + return url + fmt.Sprintf("%d/%s", req.TreeSize, hex.Serialize(req.LeafHash[:])) } -func (req *ConsistencyProof) ToASCII(w io.Writer) error { - return ascii.StdEncoding.Serialize(w, req) +// ToURL encodes request parameters at the end of a slash-terminated URL +func (req *ConsistencyProof) ToURL(url string) string { + return url + fmt.Sprintf("%d/%d", req.OldSize, req.NewSize) } func (req *Cosignature) ToASCII(w io.Writer) error { @@ -59,16 +66,59 @@ func (req *Leaf) FromASCII(r io.Reader) error { return ascii.StdEncoding.Deserialize(r, req) } -func (req *Leaves) FromASCII(r io.Reader) error { - return ascii.StdEncoding.Deserialize(r, req) +// FromURL parses request parameters from a URL that is not slash-terminated +func (req *Leaves) FromURL(url string) (err error) { + split := strings.Split(url, "/") + if len(split) < 2 { + return fmt.Errorf("not enough input") + } + startSize := split[len(split)-2] + if req.StartSize, err = strconv.ParseUint(startSize, 10, 64); err != nil { + return err + } + endSize := split[len(split)-1] + if req.EndSize, err = strconv.ParseUint(endSize, 10, 64); err != nil { + return err + } + return nil } -func (req *InclusionProof) FromASCII(r io.Reader) error { - return ascii.StdEncoding.Deserialize(r, req) +// FromURL parses request parameters from a URL that is not slash-terminated +func (req *InclusionProof) FromURL(url string) (err error) { + split := strings.Split(url, "/") + if len(split) < 2 { + return fmt.Errorf("not enough input") + } + treeSize := split[len(split)-2] + if req.TreeSize, err = strconv.ParseUint(treeSize, 10, 64); err != nil { + return err + } + b, err := hex.Deserialize(split[len(split)-1]) + if err != nil { + return err + } + if n := len(b); n != types.HashSize { + return fmt.Errorf("invalid hash size %d", n) + } + copy(req.LeafHash[:], b) + return nil } -func (req *ConsistencyProof) FromASCII(r io.Reader) error { - return ascii.StdEncoding.Deserialize(r, req) +// FromURL parses request parameters from a URL that is not slash-terminated +func (req *ConsistencyProof) FromURL(url string) (err error) { + split := strings.Split(url, "/") + if len(split) < 2 { + return fmt.Errorf("not enough input") + } + oldSize := split[len(split)-2] + if req.OldSize, err = strconv.ParseUint(oldSize, 10, 64); err != nil { + return err + } + newSize := split[len(split)-1] + if req.NewSize, err = strconv.ParseUint(newSize, 10, 64); err != nil { + return err + } + return nil } func (req *Cosignature) FromASCII(r io.Reader) error { diff --git a/pkg/requests/requests_test.go b/pkg/requests/requests_test.go index 691507a..ccbd8e9 100644 --- a/pkg/requests/requests_test.go +++ b/pkg/requests/requests_test.go @@ -21,36 +21,30 @@ func TestLeafToASCII(t *testing.T) { } } -func TestLeavesToASCII(t *testing.T) { - desc := "valid" - buf := bytes.NewBuffer(nil) - if err := validLeaves(t).ToASCII(buf); err != nil { - t.Fatalf("got error true but wanted false in test %q: %v", desc, err) - } - if got, want := string(buf.Bytes()), validLeavesASCII(t); got != want { - t.Errorf("got leaves request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc) +func TestLeavesToURL(t *testing.T) { + url := types.EndpointGetLeaves.Path("https://log.sigsum.com/sigsum/v0") + req := Leaves{1, 2} + want := url + "1/2" + if got := req.ToURL(url); got != want { + t.Errorf("got url %s but wanted %s", got, want) } } -func TestInclusionProofToASCII(t *testing.T) { - desc := "valid" - buf := bytes.NewBuffer(nil) - if err := validInclusionProof(t).ToASCII(buf); err != nil { - t.Fatalf("got error true but wanted false in test %q: %v", desc, err) - } - if got, want := string(buf.Bytes()), validInclusionProofASCII(t); got != want { - t.Errorf("got inclusion proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc) +func TestInclusionProofToURL(t *testing.T) { + url := types.EndpointGetInclusionProof.Path("https://log.sigsum.com/sigsum/v0") + req := InclusionProof{1, types.Hash{}} + want := url + "1/0000000000000000000000000000000000000000000000000000000000000000" + if got := req.ToURL(url); got != want { + t.Errorf("got url %s but wanted %s", got, want) } } -func TestConsistencyProofToASCII(t *testing.T) { - desc := "valid" - buf := bytes.NewBuffer(nil) - if err := validConsistencyProof(t).ToASCII(buf); err != nil { - t.Fatalf("got error true but wanted false in test %q: %v", desc, err) - } - if got, want := string(buf.Bytes()), validConsistencyProofASCII(t); got != want { - t.Errorf("got consistency proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc) +func TestConsistencyProofToURL(t *testing.T) { + url := types.EndpointGetConsistencyProof.Path("https://log.sigsum.com/sigsum/v0") + req := ConsistencyProof{1, 2} + want := url + "1/2" + if got := req.ToURL(url); got != want { + t.Errorf("got url %s but wanted %s", got, want) } } @@ -100,107 +94,90 @@ func TestLeafFromASCII(t *testing.T) { } } -func TestLeavesFromASCII(t *testing.T) { +func TestLeavesFromURL(t *testing.T) { for _, table := range []struct { - desc string - serialized io.Reader - wantErr bool - want *Leaves + desc string + input string + want Leaves + wantErr bool }{ - { - desc: "invalid: not a leaves request (unexpected key-value pair)", - serialized: bytes.NewBuffer( - append([]byte(validLeavesASCII(t)), - []byte("key=4")...), - ), - wantErr: true, - }, - { - desc: "valid", - serialized: bytes.NewBuffer([]byte(validLeavesASCII(t))), - want: validLeaves(t), - }, + {"invalid: not enough parameters", "some-url", Leaves{}, true}, + {"invalid: start size has a leading sign", "some-url/+1/2", Leaves{}, true}, + {"invalid: start size is empty", "some-url//2", Leaves{}, true}, + {"invalid: end size is empty", "some-url/1/", Leaves{}, true}, + {"valid", "some-url/1/2", Leaves{1, 2}, false}, } { var req Leaves - err := req.FromASCII(table.serialized) + err := req.FromURL(table.input) if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err) + t.Errorf("%s: got error %v but wanted %v: %v", table.desc, got, want, err) } if err != nil { continue } - if got, want := &req, table.want; !reflect.DeepEqual(got, want) { - t.Errorf("got leaves request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc) + + if got, want := req, table.want; !reflect.DeepEqual(got, want) { + t.Errorf("%s: got leaves request\n%v\nbut wanted\n%v", table.desc, got, want) } } } -func TestInclusionProofFromASCII(t *testing.T) { +func TestInclusionProofFromURL(t *testing.T) { + badHex := "F000000000000000000000000000000000000000000000000000000000000000" + shortHex := "00ff" + zeroHash := "0000000000000000000000000000000000000000000000000000000000000000" for _, table := range []struct { - desc string - serialized io.Reader - wantErr bool - want *InclusionProof + desc string + input string + want InclusionProof + wantErr bool }{ - { - desc: "invalid: not an inclusion proof request (unexpected key-value pair)", - serialized: bytes.NewBuffer(append( - []byte(validInclusionProofASCII(t)), - []byte("key=4")...), - ), - wantErr: true, - }, - { - desc: "valid", - serialized: bytes.NewBuffer([]byte(validInclusionProofASCII(t))), - want: validInclusionProof(t), - }, + {"invalid: not enough parameters", "some-url", InclusionProof{}, true}, + {"invalid: tree size has a leading sign", "some-url/+1/" + zeroHash, InclusionProof{}, true}, + {"invalid: tree size is empty", "some-url//" + zeroHash, InclusionProof{}, true}, + {"invalid: leaf hash is not lower-case hex", "some-url/1/" + badHex, InclusionProof{}, true}, + {"invalid: leaf hash is hex but too short", "some-url/1/" + shortHex, InclusionProof{}, true}, + {"valid", "some-url/1/" + zeroHash, InclusionProof{1, types.Hash{}}, false}, } { var req InclusionProof - err := req.FromASCII(table.serialized) + err := req.FromURL(table.input) if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err) + t.Errorf("%s: got error %v but wanted %v: %v", table.desc, got, want, err) } if err != nil { continue } - if got, want := &req, table.want; !reflect.DeepEqual(got, want) { - t.Errorf("got inclusion proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc) + + if got, want := req, table.want; !reflect.DeepEqual(got, want) { + t.Errorf("%s: got inclusion proof request\n%v\nbut wanted\n%v", table.desc, got, want) } } } -func TestConsistencyProofFromASCII(t *testing.T) { +func TestConsistencyProofFromURL(t *testing.T) { for _, table := range []struct { - desc string - serialized io.Reader - wantErr bool - want *ConsistencyProof + desc string + input string + want ConsistencyProof + wantErr bool }{ - { - desc: "invalid: not a consistency proof request (unexpected key-value pair)", - serialized: bytes.NewBuffer( - append([]byte(validConsistencyProofASCII(t)), - []byte("tree_size=4")...), - ), - wantErr: true, - }, - { - desc: "valid", - serialized: bytes.NewBuffer([]byte(validConsistencyProofASCII(t))), - want: validConsistencyProof(t), - }, + {"invalid: not enough parameters", "some-url", ConsistencyProof{}, true}, + {"invalid: old size has a leading sign", "some-url/+1/2", ConsistencyProof{}, true}, + {"invalid: old size is empty", "some-url//2", ConsistencyProof{}, true}, + {"invalid: new size is empty", "some-url/1/", ConsistencyProof{}, true}, + {"valid", "some-url/1/2", ConsistencyProof{1, 2}, false}, } { var req ConsistencyProof - err := req.FromASCII(table.serialized) + err := req.FromURL(table.input) if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.desc, err) + t.Errorf("%s: got error %v but wanted %v: %v", table.desc, got, want, err) } if err != nil { continue } - if got, want := &req, table.want; !reflect.DeepEqual(got, want) { - t.Errorf("got consistency proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc) + + if got, want := req, table.want; !reflect.DeepEqual(got, want) { + t.Errorf("%s: got consistency proof request\n%v\nbut wanted\n%v", table.desc, got, want) } } } diff --git a/pkg/types/endpoint.go b/pkg/types/endpoint.go index 0e4bab2..b93d2f6 100644 --- a/pkg/types/endpoint.go +++ b/pkg/types/endpoint.go @@ -10,9 +10,9 @@ const ( EndpointGetTreeHeadLatest = Endpoint("get-tree-head-latest") EndpointGetTreeHeadToSign = Endpoint("get-tree-head-to-sign") EndpointGetTreeHeadCosigned = Endpoint("get-tree-head-cosigned") - EndpointGetInclusionProof = Endpoint("get-inclusion-proof") - EndpointGetConsistencyProof = Endpoint("get-consistency-proof") - EndpointGetLeaves = Endpoint("get-leaves") + EndpointGetInclusionProof = Endpoint("get-inclusion-proof/") + EndpointGetConsistencyProof = Endpoint("get-consistency-proof/") + EndpointGetLeaves = Endpoint("get-leaves/") ) // Path joins a number of components to form a full endpoint path. For example, -- cgit v1.2.3 From 9dc0caf031f33f629f6c7e237a0c1539373431f1 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 28 Apr 2022 16:19:27 +0200 Subject: use a more appropriate URL for testing sigsum dot com is not a thing. --- pkg/requests/requests_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/requests/requests_test.go b/pkg/requests/requests_test.go index ccbd8e9..c8104ff 100644 --- a/pkg/requests/requests_test.go +++ b/pkg/requests/requests_test.go @@ -22,7 +22,7 @@ func TestLeafToASCII(t *testing.T) { } func TestLeavesToURL(t *testing.T) { - url := types.EndpointGetLeaves.Path("https://log.sigsum.com/sigsum/v0") + url := types.EndpointGetLeaves.Path("https://poc.sigsum.org/sigsum/v0") req := Leaves{1, 2} want := url + "1/2" if got := req.ToURL(url); got != want { @@ -31,7 +31,7 @@ func TestLeavesToURL(t *testing.T) { } func TestInclusionProofToURL(t *testing.T) { - url := types.EndpointGetInclusionProof.Path("https://log.sigsum.com/sigsum/v0") + url := types.EndpointGetInclusionProof.Path("https://poc.sigsum.org/sigsum/v0") req := InclusionProof{1, types.Hash{}} want := url + "1/0000000000000000000000000000000000000000000000000000000000000000" if got := req.ToURL(url); got != want { @@ -40,7 +40,7 @@ func TestInclusionProofToURL(t *testing.T) { } func TestConsistencyProofToURL(t *testing.T) { - url := types.EndpointGetConsistencyProof.Path("https://log.sigsum.com/sigsum/v0") + url := types.EndpointGetConsistencyProof.Path("https://poc.sigsum.org/sigsum/v0") req := ConsistencyProof{1, 2} want := url + "1/2" if got := req.ToURL(url); got != want { -- cgit v1.2.3