Skip to content

Commit

Permalink
feat: client side change id validation (#404)
Browse files Browse the repository at this point in the history
Add client-side validation for change ID used in URLs.

Closes #318.
  • Loading branch information
IronCore864 authored Apr 9, 2024
1 parent 996c12a commit 3c7d436
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
19 changes: 19 additions & 0 deletions client/changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"encoding/json"
"fmt"
"net/url"
"regexp"
"time"
)

Expand Down Expand Up @@ -86,8 +87,18 @@ type changeAndData struct {
Data map[string]*json.RawMessage `json:"data"`
}

// This is used to ensure we send a well-formed change ID in the URL path.
// It's a little more permissive than the currently-valid change IDs (which
// are always integers), but it will allow older clients to talk to newer
// servers which might start allowing letters too (for example).
var changeIDRegexp = regexp.MustCompile(`^[a-z0-9]+$`)

// Change fetches information about a Change given its ID.
func (client *Client) Change(id string) (*Change, error) {
if !changeIDRegexp.MatchString(id) {
return nil, fmt.Errorf("invalid change ID %q", id)
}

var chgd changeAndData
_, err := client.doSync("GET", "/v1/changes/"+id, nil, nil, nil, &chgd)
if err != nil {
Expand All @@ -100,6 +111,10 @@ func (client *Client) Change(id string) (*Change, error) {

// Abort attempts to abort a change that is not yet ready.
func (client *Client) Abort(id string) (*Change, error) {
if !changeIDRegexp.MatchString(id) {
return nil, fmt.Errorf("invalid change ID %q", id)
}

var postData struct {
Action string `json:"action"`
}
Expand Down Expand Up @@ -183,6 +198,10 @@ type WaitChangeOptions struct {
// succeeds, the returned Change.Err string will be non-empty if the change
// itself had an error.
func (client *Client) WaitChange(id string, opts *WaitChangeOptions) (*Change, error) {
if !changeIDRegexp.MatchString(id) {
return nil, fmt.Errorf("invalid change ID %q", id)
}

var chgd changeAndData

query := url.Values{}
Expand Down
15 changes: 15 additions & 0 deletions client/changes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,18 @@ func (cs *clientSuite) TestClientAbort(c *check.C) {

c.Assert(string(body), check.Equals, "{\"action\":\"abort\"}\n")
}

func (cs *clientSuite) TestChangeInvalidID(c *check.C) {
_, err := cs.cli.Change("select * from users;")
c.Assert(err, check.ErrorMatches, "invalid change ID.*")
}

func (cs *clientSuite) TestAbortInvalidID(c *check.C) {
_, err := cs.cli.Abort("<foo>")
c.Assert(err, check.ErrorMatches, "invalid change ID.*")
}

func (cs *clientSuite) TestWaitChangeInvalidID(c *check.C) {
_, err := cs.cli.WaitChange("$bar", nil)
c.Assert(err, check.ErrorMatches, "invalid change ID.*")
}

0 comments on commit 3c7d436

Please sign in to comment.