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
4 changes: 4 additions & 0 deletions internal/handler/download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,10 @@ func TestMavenHandler_NonArtifactPathsProxied(t *testing.T) {
"/com/google/protobuf/protoc/3.21.0/",
"/com/google/protobuf/protoc/",
"/archetype-catalog.xml",
// Checksums of files that aren't artifacts, too short to parse.
"/archetype-catalog.xml.sha1",
"/archetype-catalog.xml.md5",
"/.index/nexus-maven-repository-index.gz.sha1",
}
for _, path := range paths {
w := httptest.NewRecorder()
Expand Down
32 changes: 24 additions & 8 deletions internal/handler/maven.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,12 @@ func (h *MavenHandler) handleDownload(w http.ResponseWriter, r *http.Request, so
// e.g., com/google/guava/guava/32.1.3-jre/guava-32.1.3-jre.jar
group, artifact, version, filename := h.parsePath(urlPath)
if artifact == "" {
if strings.Count(urlPath, "/") >= minMavenParts-1 {
// A dot or colon in a group directory, or a colon in the
// artifact, which the Maven layout never has. Proxied, the
// file would skip the denylist, scan and cooldown.
// Too few segments to hold a coordinate, or a dot or colon in a
// group directory, or a colon in the artifact, which the Maven
// layout never has. Proxied, an artifact would skip the denylist,
// scan and cooldown. A checksum of another file, such as
// archetype-catalog.xml.sha1, is proxied like that file.
if h.isArtifactFile(h.checksummedFile(path.Base(urlPath))) || h.isCoordinateFile(urlPath) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
http.NotFound(w, r)
return
}
Expand Down Expand Up @@ -384,12 +386,26 @@ func (h *MavenHandler) isVersionListingFile(filename string) bool {
// an artifact. They are as immutable as the artifact, so they are cached
// with it rather than refetched on every request.
func (h *MavenHandler) isChecksumFile(filename string) bool {
for _, ext := range []string{".sha1", ".sha256", ".sha512", ".md5", ".asc"} {
if strings.HasSuffix(filename, ext) {
return true
return h.checksummedFile(filename) != filename
}

// checksummedFile is the file a checksum or signature file is for
// (bar-1.0.jar for bar-1.0.jar.sha1 and bar-1.0.jar.asc.sha1), or filename
// itself if it is neither.
func (h *MavenHandler) checksummedFile(filename string) string {
for {
trimmed := filename
for _, ext := range []string{".sha1", ".sha256", ".sha512", ".md5", ".asc"} {
if name, ok := strings.CutSuffix(trimmed, ext); ok {
trimmed = name
break
}
}
if trimmed == filename {
return filename
}
filename = trimmed
}
return false
}

// mavenForwardHeaders lets clients resume artifacts proxied without caching.
Expand Down
11 changes: 7 additions & 4 deletions internal/handler/maven_repositories_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,18 @@ func TestMavenRepositoryRepointedServesTheNewUpstream(t *testing.T) {
}
}

// TestMavenDottedGroupDirectoryNotCachedAsGroup checks that a file whose
// group directories contain dots or colons, which the Maven layout never
// has, is not served: it would either share the cache entry of the group
// the dots spell or be proxied past the denylist, scan and cooldown.
// TestMavenDottedGroupDirectoryNotCachedAsGroup checks that a file outside
// the Maven layout is not served: a group directory with a dot or a colon,
// which the layout never has and which would share the cache entry of the
// group the dots spell, and a path too short to hold a coordinate. Proxied,
// they would skip the denylist, scan and cooldown.
func TestMavenDottedGroupDirectoryNotCachedAsGroup(t *testing.T) {
const standard = "/org/foo/bar/1.0/bar-1.0.jar"
odd := []string{
"/org.foo/bar/1.0/bar-1.0.jar", "/org.foo/bar/1.0/bar-1.0-linux.exe",
"/org/foo:x/bar/1.0/bar-1.0.jar", "/org/foo/b:ar/1.0/b:ar-1.0.jar",
"/bar/1.0/bar-1.0.jar", "/bar-1.0.jar", "/bar/1.0/bar-1.0.jar.sha1", "/bar-1.0.pom.asc",
"/bar/1.0/bar-1.0.jar.asc.sha1",
}
central, requests := mavenRepoUpstream(t, "central", append([]string{standard}, odd...)...)
portal, _ := mavenRepoUpstream(t, "portal")
Expand Down
Loading