Skip to content

Commit

Permalink
fix: Ensure that all API endpoint URLs are constructed safely.
Browse files Browse the repository at this point in the history
  • Loading branch information
kpfleming committed Sep 6, 2024
1 parent 81f6471 commit 5705630
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 76 deletions.
3 changes: 2 additions & 1 deletion fastly/account_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ func (c *Client) GetAPIEvent(i *GetAPIEventInput) (*Event, error) {
return nil, ErrMissingEventID
}

path := fmt.Sprintf("/events/%s", i.EventID)
path := ToSafeURL("events", i.EventID)

resp, err := c.Get(path, nil)
if err != nil {
return nil, err
Expand Down
17 changes: 11 additions & 6 deletions fastly/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package fastly

import (
"fmt"
"net/url"
"strconv"
"time"
)

Expand Down Expand Up @@ -34,7 +34,8 @@ func (c *Client) ListACLs(i *ListACLsInput) ([]*ACL, error) {
return nil, ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/acl", i.ServiceID, i.ServiceVersion)
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "acl")

resp, err := c.Get(path, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -67,7 +68,8 @@ func (c *Client) CreateACL(i *CreateACLInput) (*ACL, error) {
return nil, ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/acl", i.ServiceID, i.ServiceVersion)
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "acl")

resp, err := c.PostForm(path, i, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -103,7 +105,8 @@ func (c *Client) DeleteACL(i *DeleteACLInput) error {
return ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/acl/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name))
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "acl", i.Name)

resp, err := c.Delete(path, nil)
if err != nil {
return err
Expand Down Expand Up @@ -142,7 +145,8 @@ func (c *Client) GetACL(i *GetACLInput) (*ACL, error) {
return nil, ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/acl/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name))
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "acl", i.Name)

resp, err := c.Get(path, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -180,7 +184,8 @@ func (c *Client) UpdateACL(i *UpdateACLInput) (*ACL, error) {
return nil, ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/acl/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name))
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "acl", i.Name)

resp, err := c.PutForm(path, i, nil)
if err != nil {
return nil, err
Expand Down
13 changes: 6 additions & 7 deletions fastly/acl_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ type ACLEntry struct {
UpdatedAt *time.Time `mapstructure:"updated_at"`
}

const aclEntriesPath = "/service/%s/acl/%s/entries"

// GetACLEntriesInput is the input parameter to GetACLEntries function.
type GetACLEntriesInput struct {
// ACLID is an alphanumeric string identifying a ACL (required).
Expand Down Expand Up @@ -52,7 +50,7 @@ func (c *Client) GetACLEntries(i *GetACLEntriesInput) *ListPaginator[ACLEntry] {
if i.PerPage != nil {
input.PerPage = *i.PerPage
}
path := fmt.Sprintf(aclEntriesPath, i.ServiceID, i.ACLID)
path := ToSafeURL("service", i.ServiceID, "acl", i.ACLID, "entries")
return NewPaginator[ACLEntry](c, input, path)
}

Expand Down Expand Up @@ -115,7 +113,7 @@ func (c *Client) GetACLEntry(i *GetACLEntryInput) (*ACLEntry, error) {
return nil, ErrMissingServiceID
}

path := fmt.Sprintf("/service/%s/acl/%s/entry/%s", i.ServiceID, i.ACLID, i.EntryID)
path := ToSafeURL("service", i.ServiceID, "acl", i.ACLID, "entry", i.EntryID)

resp, err := c.Get(path, nil)
if err != nil {
Expand Down Expand Up @@ -194,7 +192,7 @@ func (c *Client) DeleteACLEntry(i *DeleteACLEntryInput) error {
return ErrMissingServiceID
}

path := fmt.Sprintf("/service/%s/acl/%s/entry/%s", i.ServiceID, i.ACLID, i.EntryID)
path := ToSafeURL("service", i.ServiceID, "acl", i.ACLID, "entry", i.EntryID)

resp, err := c.Delete(path, nil)
if err != nil {
Expand Down Expand Up @@ -244,7 +242,7 @@ func (c *Client) UpdateACLEntry(i *UpdateACLEntryInput) (*ACLEntry, error) {
return nil, ErrMissingServiceID
}

path := fmt.Sprintf("/service/%s/acl/%s/entry/%s", i.ServiceID, i.ACLID, i.EntryID)
path := ToSafeURL("service", i.ServiceID, "acl", i.ACLID, "entry", i.EntryID)

resp, err := c.RequestForm("PATCH", path, i, nil)
if err != nil {
Expand Down Expand Up @@ -299,7 +297,8 @@ func (c *Client) BatchModifyACLEntries(i *BatchModifyACLEntriesInput) error {
return ErrMaxExceededEntries
}

path := fmt.Sprintf(aclEntriesPath, i.ServiceID, i.ACLID)
path := ToSafeURL("service", i.ServiceID, "acl", i.ACLID, "entries")

resp, err := c.PatchJSON(path, i, nil)
if err != nil {
return err
Expand Down
10 changes: 6 additions & 4 deletions fastly/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package fastly

import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
Expand Down Expand Up @@ -151,7 +150,8 @@ func (c *Client) GetAlertDefinition(i *GetAlertDefinitionInput) (*AlertDefinitio
return nil, ErrMissingID
}

path := fmt.Sprintf("/alerts/definitions/%s", *i.ID)
path := ToSafeURL("alerts", "definitions", *i.ID)

resp, err := c.Get(path, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -190,7 +190,8 @@ func (c *Client) UpdateAlertDefinition(i *UpdateAlertDefinitionInput) (*AlertDef
return nil, ErrMissingID
}

path := fmt.Sprintf("/alerts/definitions/%s", *i.ID)
path := ToSafeURL("alerts", "definitions", *i.ID)

resp, err := c.PutJSON(path, i, nil)
if err != nil {
return nil, err
Expand All @@ -216,7 +217,8 @@ func (c *Client) DeleteAlertDefinition(i *DeleteAlertDefinitionInput) error {
return ErrMissingID
}

path := fmt.Sprintf("/alerts/definitions/%s", *i.ID)
path := ToSafeURL("alerts", "definitions", *i.ID)

resp, err := c.Delete(path, nil)
if err != nil {
return err
Expand Down
17 changes: 11 additions & 6 deletions fastly/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package fastly

import (
"fmt"
"net/url"
"strconv"
"time"
)

Expand Down Expand Up @@ -64,7 +64,8 @@ func (c *Client) ListBackends(i *ListBackendsInput) ([]*Backend, error) {
return nil, ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/backend", i.ServiceID, i.ServiceVersion)
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "backend")

resp, err := c.Get(path, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -157,7 +158,8 @@ func (c *Client) CreateBackend(i *CreateBackendInput) (*Backend, error) {
return nil, ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/backend", i.ServiceID, i.ServiceVersion)
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "backend")

resp, err := c.PostForm(path, i, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -193,7 +195,8 @@ func (c *Client) GetBackend(i *GetBackendInput) (*Backend, error) {
return nil, ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/backend/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name))
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "backend", i.Name)

resp, err := c.Get(path, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -291,7 +294,8 @@ func (c *Client) UpdateBackend(i *UpdateBackendInput) (*Backend, error) {
return nil, ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/backend/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name))
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "backend", i.Name)

resp, err := c.PutForm(path, i, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -327,7 +331,8 @@ func (c *Client) DeleteBackend(i *DeleteBackendInput) error {
return ErrMissingServiceVersion
}

path := fmt.Sprintf("/service/%s/version/%d/backend/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name))
path := ToSafeURL("service", i.ServiceID, "version", strconv.Itoa(i.ServiceVersion), "backend", i.Name)

resp, err := c.Delete(path, nil)
if err != nil {
return err
Expand Down
4 changes: 3 additions & 1 deletion fastly/billing.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fastly

import (
"fmt"
"strconv"
"time"
)

Expand Down Expand Up @@ -68,7 +69,8 @@ func (c *Client) GetBilling(i *GetBillingInput) (*Billing, error) {
return nil, ErrMissingMonth
}

path := fmt.Sprintf("/billing/year/%d/month/%02d", i.Year, i.Month)
path := ToSafeURL("billing", "year", strconv.Itoa(int(i.Year)), "month", fmt.Sprintf("%02d", i.Month))

resp, err := c.Get(path, nil)
if err != nil {
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions fastly/compute_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package fastly
import (
"bytes"
"errors"
"fmt"
"io"
"strconv"
"time"
)

Expand Down Expand Up @@ -107,7 +107,7 @@ func MakePackagePath(serviceID string, serviceVersion int) (string, error) {
if serviceVersion == 0 {
return "", ErrMissingServiceVersion
}
return fmt.Sprintf("/service/%s/version/%d/package", serviceID, serviceVersion), nil
return ToSafeURL("service", serviceID, "version", strconv.Itoa(serviceVersion), "package"), nil
}

// PopulatePackage encapsulates the decoding of returned package data.
Expand Down
16 changes: 10 additions & 6 deletions fastly/config_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package fastly

import (
"encoding/json"
"fmt"
"sort"
"time"
)
Expand Down Expand Up @@ -68,7 +67,8 @@ func (c *Client) DeleteConfigStore(i *DeleteConfigStoreInput) error {
return ErrMissingStoreID
}

path := fmt.Sprintf("/resources/stores/config/%s", i.StoreID)
path := ToSafeURL("resources", "stores", "config", i.StoreID)

resp, err := c.Delete(path, &RequestOptions{
Headers: map[string]string{
"Accept": "application/json",
Expand Down Expand Up @@ -97,7 +97,8 @@ func (c *Client) GetConfigStore(i *GetConfigStoreInput) (*ConfigStore, error) {
return nil, ErrMissingStoreID
}

path := fmt.Sprintf("/resources/stores/config/%s", i.StoreID)
path := ToSafeURL("resources", "stores", "config", i.StoreID)

resp, err := c.Get(path, &RequestOptions{
Headers: map[string]string{
"Accept": "application/json",
Expand Down Expand Up @@ -129,7 +130,8 @@ func (c *Client) GetConfigStoreMetadata(i *GetConfigStoreMetadataInput) (*Config
return nil, ErrMissingStoreID
}

path := fmt.Sprintf("/resources/stores/config/%s/info", i.StoreID)
path := ToSafeURL("resources", "stores", "config", i.StoreID, "info")

resp, err := c.Get(path, &RequestOptions{
Headers: map[string]string{
"Accept": "application/json",
Expand Down Expand Up @@ -200,7 +202,8 @@ func (c *Client) ListConfigStoreServices(i *ListConfigStoreServicesInput) ([]*Se
return nil, ErrMissingStoreID
}

path := fmt.Sprintf("/resources/stores/config/%s/services", i.StoreID)
path := ToSafeURL("resources", "stores", "config", i.StoreID, "services")

resp, err := c.Get(path, &RequestOptions{
Headers: map[string]string{
"Accept": "application/json",
Expand Down Expand Up @@ -235,7 +238,8 @@ func (c *Client) UpdateConfigStore(i *UpdateConfigStoreInput) (*ConfigStore, err
return nil, ErrMissingStoreID
}

path := fmt.Sprintf("/resources/stores/config/%s", i.StoreID)
path := ToSafeURL("resources", "stores", "config", i.StoreID)

resp, err := c.PutForm(path, i, &RequestOptions{
Headers: map[string]string{
// PutForm adds the appropriate Content-Type header.
Expand Down
19 changes: 11 additions & 8 deletions fastly/config_store_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package fastly

import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"sort"
"time"
)
Expand Down Expand Up @@ -38,7 +36,8 @@ func (c *Client) CreateConfigStoreItem(i *CreateConfigStoreItemInput) (*ConfigSt
return nil, ErrMissingStoreID
}

path := fmt.Sprintf("/resources/stores/config/%s/item", i.StoreID)
path := ToSafeURL("resources", "stores", "config", i.StoreID, "item")

resp, err := c.PostForm(path, i, &RequestOptions{
Headers: map[string]string{
// PostForm adds the appropriate Content-Type header.
Expand Down Expand Up @@ -76,7 +75,8 @@ func (c *Client) DeleteConfigStoreItem(i *DeleteConfigStoreItemInput) error {
return ErrMissingKey
}

path := fmt.Sprintf("/resources/stores/config/%s/item/%s", i.StoreID, url.PathEscape(i.Key))
path := ToSafeURL("resources", "stores", "config", i.StoreID, "item", i.Key)

resp, err := c.Delete(path, &RequestOptions{
Headers: map[string]string{
"Accept": "application/json",
Expand Down Expand Up @@ -110,7 +110,8 @@ func (c *Client) GetConfigStoreItem(i *GetConfigStoreItemInput) (*ConfigStoreIte
return nil, ErrMissingKey
}

path := fmt.Sprintf("/resources/stores/config/%s/item/%s", i.StoreID, url.PathEscape(i.Key))
path := ToSafeURL("resources", "stores", "config", i.StoreID, "item", i.Key)

resp, err := c.Get(path, &RequestOptions{
Headers: map[string]string{
"Accept": "application/json",
Expand Down Expand Up @@ -142,7 +143,8 @@ func (c *Client) ListConfigStoreItems(i *ListConfigStoreItemsInput) ([]*ConfigSt
return nil, ErrMissingStoreID
}

path := fmt.Sprintf("/resources/stores/config/%s/items", i.StoreID)
path := ToSafeURL("resources", "stores", "config", i.StoreID, "items")

resp, err := c.Get(path, nil)
if err != nil {
return nil, err
Expand Down Expand Up @@ -181,7 +183,7 @@ func (c *Client) UpdateConfigStoreItem(i *UpdateConfigStoreItemInput) (*ConfigSt
return nil, ErrMissingKey
}

path := fmt.Sprintf("/resources/stores/config/%s/item/%s", i.StoreID, url.PathEscape(i.Key))
path := ToSafeURL("resources", "stores", "config", i.StoreID, "item", i.Key)

var httpMethod string
if i.Upsert {
Expand Down Expand Up @@ -240,7 +242,8 @@ func (c *Client) BatchModifyConfigStoreItems(i *BatchModifyConfigStoreItemsInput
return ErrMaxExceededItems
}

path := fmt.Sprintf("/resources/stores/config/%s/items", i.StoreID)
path := ToSafeURL("resources", "stores", "config", i.StoreID, "items")

resp, err := c.PatchJSON(path, i, nil)
if err != nil {
return err
Expand Down
Loading

0 comments on commit 5705630

Please sign in to comment.