Skip to content
Open
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
22 changes: 22 additions & 0 deletions reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import (
"errors"
"fmt"
"net"
"strings"

"github.com/opencontainers/go-digest"
Expand Down Expand Up @@ -167,14 +168,14 @@
// in which it can be referenced by
type Digested interface {
Reference
Digest() digest.Digest

Check failure on line 171 in reference.go

View workflow job for this annotation

GitHub Actions / build (stable, ubuntu-latest)

undefined: digest (typecheck)

Check failure on line 171 in reference.go

View workflow job for this annotation

GitHub Actions / build (stable, macos-latest)

undefined: digest (typecheck)
}

// Canonical reference is an object with a fully unique
// name including a name with domain and digest
type Canonical interface {
Named
Digest() digest.Digest

Check failure on line 178 in reference.go

View workflow job for this annotation

GitHub Actions / build (stable, ubuntu-latest)

undefined: digest (typecheck)

Check failure on line 178 in reference.go

View workflow job for this annotation

GitHub Actions / build (stable, macos-latest)

undefined: digest (typecheck)
}

// namedRepository is a reference to a repository with a name.
Expand Down Expand Up @@ -203,6 +204,21 @@
return path
}

// validateIPv6Host rejects a bracketed host that is not an IP address.
// The reference grammar uses an RFC 3986 IPv6address. The name regexp only
// checks that the brackets contain hex digits and colons, so "[:::]" and
// "[fd00123123123]" used to parse.
func validateIPv6Host(domain string) error {
if domain == "" || domain[0] != '[' {
return nil
}
end := strings.IndexByte(domain, ']')
if end <= 1 || net.ParseIP(domain[1:end]) == nil {
return ErrReferenceInvalidFormat
}
return nil
}

// splitDomain splits a named reference into a hostname and path string.
// If no valid hostname is found, the hostname is empty and the full value
// is returned as name
Expand Down Expand Up @@ -255,6 +271,9 @@
if len(repo.path) > RepositoryNameTotalLengthMax {
return nil, ErrNameTooLong
}
if err := validateIPv6Host(repo.domain); err != nil {
return nil, err
}

ref := reference{
namedRepository: repo,
Expand Down Expand Up @@ -302,6 +321,9 @@
if len(match[2]) > RepositoryNameTotalLengthMax {
return nil, ErrNameTooLong
}
if err := validateIPv6Host(match[1]); err != nil {
return nil, err
}

return repository{
domain: match[1],
Expand Down Expand Up @@ -402,7 +424,7 @@
type reference struct {
namedRepository
tag string
digest digest.Digest

Check failure on line 427 in reference.go

View workflow job for this annotation

GitHub Actions / build (stable, ubuntu-latest)

undefined: digest (typecheck)

Check failure on line 427 in reference.go

View workflow job for this annotation

GitHub Actions / build (stable, macos-latest)

undefined: digest (typecheck)
}

func (r reference) String() string {
Expand Down
12 changes: 12 additions & 0 deletions reference_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,18 @@ func TestReferenceParse(t *testing.T) {
input: "[fe80::1%@invalidzone]:5000/repo",
err: ErrReferenceInvalidFormat,
},
{
input: "[:::]:5000/repo",
err: ErrReferenceInvalidFormat,
},
{
input: "[:::::::]:5000/repo",
err: ErrReferenceInvalidFormat,
},
{
input: "[fd00123123123]:75050/repo",
err: ErrReferenceInvalidFormat,
},
{
input: "example.com/" + strings.Repeat("a", 255) + ":tag",
domain: "example.com",
Expand Down
Loading