Skip to content

Commit

Permalink
Validate base URLs (#1264)
Browse files Browse the repository at this point in the history
* Validate base URLs

* Fix lint error

* allow 127.0.0.1 for tests

* cleanup
  • Loading branch information
vcheung-stripe authored Oct 18, 2024
1 parent 2206d0a commit 94c1bee
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 9 deletions.
4 changes: 4 additions & 0 deletions pkg/cmd/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ func newFixturesCmd(cfg *config.Config) *FixturesCmd {
func (fc *FixturesCmd) runFixturesCmd(cmd *cobra.Command, args []string) error {
version.CheckLatestVersion()

if err := stripe.ValidateAPIBaseURL(fc.apiBaseURL); err != nil {
return err
}

apiKey, err := fc.Cfg.Profile.GetAPIKey(false)
if err != nil {
return err
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/listen.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ Stripe account.`,
// Normally, this function would be listed alphabetically with the others declared in this file,
// but since it's acting as the core functionality for the cmd above, I'm keeping it close.
func (lc *listenCmd) runListenCmd(cmd *cobra.Command, args []string) error {
if err := stripe.ValidateAPIBaseURL(lc.apiBaseURL); err != nil {
return err
}

if !lc.printJSON && !lc.onlyPrintSecret && !lc.skipUpdate {
version.CheckLatestVersion()
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ func newLoginCmd() *loginCmd {
}

func (lc *loginCmd) runLoginCmd(cmd *cobra.Command, args []string) error {
if err := stripe.ValidateDashboardBaseURL(lc.dashboardBaseURL); err != nil {
return err
}

if lc.interactive {
return login.InteractiveLogin(cmd.Context(), &Config)
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/logs/tail.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ func withSIGTERMCancel(ctx context.Context, onCancel func()) context.Context {
}

func (tailCmd *TailCmd) runTailCmd(cmd *cobra.Command, args []string) error {
if err := stripe.ValidateAPIBaseURL(tailCmd.apiBaseURL); err != nil {
return err
}

err := tailCmd.validateArgs()
if err != nil {
return err
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/plugin/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ func (ic *InstallCmd) installPluginByName(cmd *cobra.Command, arg string) error
}

func (ic *InstallCmd) runInstallCmd(cmd *cobra.Command, args []string) error {
if err := stripe.ValidateAPIBaseURL(ic.apiBaseURL); err != nil {
return err
}

var err error
color := ansi.Color(os.Stdout)

Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/plugin/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func NewUpgradeCmd(config *config.Config) *UpgradeCmd {
}

func (uc *UpgradeCmd) runUpgradeCmd(cmd *cobra.Command, args []string) error {
if err := stripe.ValidateAPIBaseURL(uc.apiBaseURL); err != nil {
return err
}

ctx := withSIGTERMCancel(cmd.Context(), func() {
log.WithFields(log.Fields{
"prefix": "cmd.upgradeCmd.runUpgradeCmd",
Expand Down
5 changes: 5 additions & 0 deletions pkg/cmd/resource/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/stripe/stripe-cli/pkg/ansi"
"github.com/stripe/stripe-cli/pkg/config"
"github.com/stripe/stripe-cli/pkg/requests"
"github.com/stripe/stripe-cli/pkg/stripe"
"github.com/stripe/stripe-cli/pkg/validators"
)

Expand Down Expand Up @@ -40,6 +41,10 @@ type OperationCmd struct {
}

func (oc *OperationCmd) runOperationCmd(cmd *cobra.Command, args []string) error {
if err := stripe.ValidateAPIBaseURL(oc.APIBaseURL); err != nil {
return err
}

apiKey, err := oc.Profile.GetAPIKey(oc.Livemode)
if err != nil {
return err
Expand Down
4 changes: 4 additions & 0 deletions pkg/cmd/trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ needed to create the triggered event as well as the corresponding API objects.
func (tc *triggerCmd) runTriggerCmd(cmd *cobra.Command, args []string) error {
version.CheckLatestVersion()

if err := stripe.ValidateAPIBaseURL(tc.apiBaseURL); err != nil {
return err
}

if len(args) == 0 {
cmd.Help()

Expand Down
4 changes: 4 additions & 0 deletions pkg/requests/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ var confirmationCommands = map[string]bool{http.MethodDelete: true}

// RunRequestsCmd is the interface exposed for the CLI to run network requests through
func (rb *Base) RunRequestsCmd(cmd *cobra.Command, args []string) error {
if err := stripe.ValidateAPIBaseURL(rb.APIBaseURL); err != nil {
return err
}

if len(args) > 1 {
return fmt.Errorf("this command only supports one argument. Run with the --help flag to see usage and examples")
}
Expand Down
9 changes: 0 additions & 9 deletions pkg/stripe/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@ import (
"github.com/stripe/stripe-cli/pkg/useragent"
)

// DefaultAPIBaseURL is the default base URL for API requests
const DefaultAPIBaseURL = "https://api.stripe.com"

// DefaultFilesAPIBaseURL is the default base URL for Files API requsts
const DefaultFilesAPIBaseURL = "https://files.stripe.com"

// DefaultDashboardBaseURL is the default base URL for dashboard requests
const DefaultDashboardBaseURL = "https://dashboard.stripe.com"

// APIVersion is API version used in CLI
const APIVersion = "2019-03-14"

Expand Down
64 changes: 64 additions & 0 deletions pkg/stripe/url.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package stripe

import (
"errors"
"regexp"
)

const (
// DefaultAPIBaseURL is the default base URL for API requests
DefaultAPIBaseURL = "https://api.stripe.com"
qaAPIBaseURL = "https://qa-api.stripe.com"
devAPIBaseURLRegexp = `http(s)?:\/\/[A-Za-z0-9\-]+api-mydev.dev.stripe.me`

// DefaultFilesAPIBaseURL is the default base URL for Files API requsts
DefaultFilesAPIBaseURL = "https://files.stripe.com"

// DefaultDashboardBaseURL is the default base URL for dashboard requests
DefaultDashboardBaseURL = "https://dashboard.stripe.com"
qaDashboardBaseURL = "https://qa-dashboard.stripe.com"
devDashboardBaseURLRegexp = `http(s)?:\/\/[A-Za-z0-9\-]+manage-mydev\.dev\.stripe\.me`

// localhostURLRegexp is used in tests
localhostURLRegexp = `http:\/\/127\.0\.0\.1(:[0-9]+)?`
)

var (
errInvalidAPIBaseURL = errors.New("invalid API base URL")
errInvalidDashboardBaseURL = errors.New("invalid dashboard base URL")
)

func isValid(url string, exactStrings []string, regexpStrings []string) bool {
for _, s := range exactStrings {
if url == s {
return true
}
}
for _, r := range regexpStrings {
matched, err := regexp.Match(r, []byte(url))
if err == nil && matched {
return true
}
}
return false
}

// ValidateAPIBaseURL returns an error if apiBaseURL isn't allowed
func ValidateAPIBaseURL(apiBaseURL string) error {
exactStrings := []string{DefaultAPIBaseURL, qaAPIBaseURL}
regexpStrings := []string{devAPIBaseURLRegexp, localhostURLRegexp}
if isValid(apiBaseURL, exactStrings, regexpStrings) {
return nil
}
return errInvalidAPIBaseURL
}

// ValidateDashboardBaseURL returns an error if dashboardBaseURL isn't allowed
func ValidateDashboardBaseURL(dashboardBaseURL string) error {
exactStrings := []string{DefaultDashboardBaseURL, qaDashboardBaseURL}
regexpStrings := []string{devDashboardBaseURLRegexp, localhostURLRegexp}
if isValid(dashboardBaseURL, exactStrings, regexpStrings) {
return nil
}
return errInvalidDashboardBaseURL
}
35 changes: 35 additions & 0 deletions pkg/stripe/url_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package stripe

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestValidateAPIBaseURLWorks(t *testing.T) {
assert.Nil(t, ValidateAPIBaseURL("https://api.stripe.com"))
assert.Nil(t, ValidateAPIBaseURL("https://qa-api.stripe.com"))
assert.Nil(t, ValidateAPIBaseURL("http://foo-api-mydev.dev.stripe.me"))
assert.Nil(t, ValidateAPIBaseURL("https://foo-lv5r9y--api-mydev.dev.stripe.me/"))
assert.Nil(t, ValidateAPIBaseURL("http://127.0.0.1"))
assert.Nil(t, ValidateAPIBaseURL("http://127.0.0.1:1337"))

assert.ErrorIs(t, ValidateAPIBaseURL("https://example.com"), errInvalidAPIBaseURL)
assert.ErrorIs(t, ValidateAPIBaseURL("https://unknowndomain"), errInvalidAPIBaseURL)
assert.ErrorIs(t, ValidateAPIBaseURL("localhost"), errInvalidAPIBaseURL)
assert.ErrorIs(t, ValidateAPIBaseURL("anything_else"), errInvalidAPIBaseURL)
}

func TestValidateDashboardBaseURLWorks(t *testing.T) {
assert.Nil(t, ValidateDashboardBaseURL("https://dashboard.stripe.com"))
assert.Nil(t, ValidateDashboardBaseURL("https://qa-dashboard.stripe.com"))
assert.Nil(t, ValidateDashboardBaseURL("http://foo-manage-mydev.dev.stripe.me"))
assert.Nil(t, ValidateDashboardBaseURL("https://foo-lv5r9y--manage-mydev.dev.stripe.me/"))
assert.Nil(t, ValidateDashboardBaseURL("http://127.0.0.1"))
assert.Nil(t, ValidateDashboardBaseURL("http://127.0.0.1:1337"))

assert.ErrorIs(t, ValidateDashboardBaseURL("https://example.com"), errInvalidDashboardBaseURL)
assert.ErrorIs(t, ValidateDashboardBaseURL("https://unknowndomain"), errInvalidDashboardBaseURL)
assert.ErrorIs(t, ValidateDashboardBaseURL("localhost"), errInvalidDashboardBaseURL)
assert.ErrorIs(t, ValidateDashboardBaseURL("anything_else"), errInvalidDashboardBaseURL)
}

0 comments on commit 94c1bee

Please sign in to comment.