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
9 changes: 5 additions & 4 deletions internal/cargo/cargo.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package cargo
import (
"context"
"fmt"
"net/url"
"strings"
"time"

Expand Down Expand Up @@ -102,7 +103,7 @@ type ownerInfo struct {
}

func (r *Registry) FetchPackage(ctx context.Context, name string) (*core.Package, error) {
url := fmt.Sprintf("%s/api/v1/crates/%s", r.baseURL, name)
url := fmt.Sprintf("%s/api/v1/crates/%s", r.baseURL, url.PathEscape(name))

var resp crateResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down Expand Up @@ -132,7 +133,7 @@ func (r *Registry) FetchPackage(ctx context.Context, name string) (*core.Package
}

func (r *Registry) FetchVersions(ctx context.Context, name string) ([]core.Version, error) {
url := fmt.Sprintf("%s/api/v1/crates/%s", r.baseURL, name)
url := fmt.Sprintf("%s/api/v1/crates/%s", r.baseURL, url.PathEscape(name))

var resp crateResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down Expand Up @@ -181,7 +182,7 @@ func (r *Registry) FetchVersions(ctx context.Context, name string) ([]core.Versi
}

func (r *Registry) FetchDependencies(ctx context.Context, name, version string) ([]core.Dependency, error) {
url := fmt.Sprintf("%s/api/v1/crates/%s/%s/dependencies", r.baseURL, name, version)
url := fmt.Sprintf("%s/api/v1/crates/%s/%s/dependencies", r.baseURL, url.PathEscape(name), url.PathEscape(version))

var resp dependenciesResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down Expand Up @@ -216,7 +217,7 @@ func mapScope(kind string) core.Scope {
}

func (r *Registry) FetchMaintainers(ctx context.Context, name string) ([]core.Maintainer, error) {
url := fmt.Sprintf("%s/api/v1/crates/%s/owner_user", r.baseURL, name)
url := fmt.Sprintf("%s/api/v1/crates/%s/owner_user", r.baseURL, url.PathEscape(name))

var resp ownersResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down
9 changes: 5 additions & 4 deletions internal/cocoapods/cocoapods.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package cocoapods
import (
"context"
"fmt"
"net/url"
"strings"
"time"

Expand Down Expand Up @@ -79,7 +80,7 @@ type ownerInfo struct {
}

func (r *Registry) FetchPackage(ctx context.Context, name string) (*core.Package, error) {
url := fmt.Sprintf("%s/api/v1/pods/%s", r.baseURL, name)
url := fmt.Sprintf("%s/api/v1/pods/%s", r.baseURL, url.PathEscape(name))

var resp podResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down Expand Up @@ -120,7 +121,7 @@ func (r *Registry) FetchPackage(ctx context.Context, name string) (*core.Package
}

func (r *Registry) FetchVersions(ctx context.Context, name string) ([]core.Version, error) {
url := fmt.Sprintf("%s/api/v1/pods/%s", r.baseURL, name)
url := fmt.Sprintf("%s/api/v1/pods/%s", r.baseURL, url.PathEscape(name))

var resp podResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand All @@ -143,7 +144,7 @@ func (r *Registry) FetchVersions(ctx context.Context, name string) ([]core.Versi
}

func (r *Registry) FetchDependencies(ctx context.Context, name, version string) ([]core.Dependency, error) {
url := fmt.Sprintf("%s/api/v1/pods/%s", r.baseURL, name)
url := fmt.Sprintf("%s/api/v1/pods/%s", r.baseURL, url.PathEscape(name))

var resp podResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down Expand Up @@ -195,7 +196,7 @@ func formatRequirement(req interface{}) string {
}

func (r *Registry) FetchMaintainers(ctx context.Context, name string) ([]core.Maintainer, error) {
url := fmt.Sprintf("%s/api/v1/pods/%s", r.baseURL, name)
url := fmt.Sprintf("%s/api/v1/pods/%s", r.baseURL, url.PathEscape(name))

var resp podResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down
5 changes: 3 additions & 2 deletions internal/deno/deno.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package deno
import (
"context"
"fmt"
"net/url"
"strings"
"time"

Expand Down Expand Up @@ -87,7 +88,7 @@ type directoryEntry struct {
}

func (r *Registry) FetchPackage(ctx context.Context, name string) (*core.Package, error) {
url := fmt.Sprintf("%s/v2/modules/%s", r.baseURL, name)
url := fmt.Sprintf("%s/v2/modules/%s", r.baseURL, url.PathEscape(name))

var resp moduleInfoResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down Expand Up @@ -115,7 +116,7 @@ func (r *Registry) FetchPackage(ctx context.Context, name string) (*core.Package
}

func (r *Registry) FetchVersions(ctx context.Context, name string) ([]core.Version, error) {
url := fmt.Sprintf("%s/v2/modules/%s", r.baseURL, name)
url := fmt.Sprintf("%s/v2/modules/%s", r.baseURL, url.PathEscape(name))

var resp moduleInfoResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down
7 changes: 4 additions & 3 deletions internal/pypi/pypi.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package pypi
import (
"context"
"fmt"
"net/url"
"regexp"
"strings"
"time"
Expand Down Expand Up @@ -86,7 +87,7 @@ type versionInfoResponse struct {
}

func (r *Registry) FetchPackage(ctx context.Context, name string) (*core.Package, error) {
url := fmt.Sprintf("%s/pypi/%s/json", r.baseURL, name)
url := fmt.Sprintf("%s/pypi/%s/json", r.baseURL, url.PathEscape(name))

var resp packageResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down Expand Up @@ -190,7 +191,7 @@ func normalizeName(name string) string {
}

func (r *Registry) FetchVersions(ctx context.Context, name string) ([]core.Version, error) {
url := fmt.Sprintf("%s/pypi/%s/json", r.baseURL, name)
url := fmt.Sprintf("%s/pypi/%s/json", r.baseURL, url.PathEscape(name))

var resp packageResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down Expand Up @@ -246,7 +247,7 @@ func (r *Registry) FetchVersions(ctx context.Context, name string) ([]core.Versi
var pep508NameRegex = regexp.MustCompile(`^([A-Za-z0-9][-A-Za-z0-9._]*[A-Za-z0-9]|[A-Za-z0-9])(\s*\[.*?\])?`)

func (r *Registry) FetchDependencies(ctx context.Context, name, version string) ([]core.Dependency, error) {
url := fmt.Sprintf("%s/pypi/%s/%s/json", r.baseURL, name, version)
url := fmt.Sprintf("%s/pypi/%s/%s/json", r.baseURL, url.PathEscape(name), url.PathEscape(version))

var resp versionInfoResponse
if err := r.client.GetJSON(ctx, url, &resp); err != nil {
Expand Down
24 changes: 24 additions & 0 deletions internal/pypi/pypi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,30 @@ func TestFetchPackage(t *testing.T) {
}
}

func TestFetchPackageEscapesName(t *testing.T) {
var gotPath, gotQuery string
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotPath = r.URL.Path
gotQuery = r.URL.RawQuery
w.WriteHeader(404)
}))
defer server.Close()

reg := New(server.URL, core.DefaultClient())
_, _ = reg.FetchPackage(context.Background(), "requests?evil=1#frag")

// Without escaping the ? starts a query string client-side and the
// server sees path /pypi/requests with query evil=1/json. With
// escaping the whole name is one path segment, the # doesn't
// truncate as a fragment, and /json survives at the end.
if gotQuery != "" {
t.Errorf("query string leaked: %q (path was %q)", gotQuery, gotPath)
}
if gotPath != "/pypi/requests?evil=1#frag/json" {
t.Errorf("path = %q, expected name kept intact with /json suffix", gotPath)
}
}

func TestFetchPackageWithLicenseExpression(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := packageResponse{
Expand Down