mirror of https://github.com/go-gitea/gitea.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
1.8 KiB
94 lines
1.8 KiB
// Copyright 2023 The Gitea Authors. All rights reserved. |
|
// SPDX-License-Identifier: MIT |
|
|
|
package goproxy |
|
|
|
import ( |
|
"archive/zip" |
|
"fmt" |
|
"io" |
|
"path" |
|
"strings" |
|
|
|
"code.gitea.io/gitea/modules/util" |
|
) |
|
|
|
const ( |
|
PropertyGoMod = "go.mod" |
|
|
|
maxGoModFileSize = 16 * 1024 * 1024 // https://go.dev/ref/mod#zip-path-size-constraints |
|
) |
|
|
|
var ( |
|
ErrInvalidStructure = util.NewInvalidArgumentErrorf("package has invalid structure") |
|
ErrGoModFileTooLarge = util.NewInvalidArgumentErrorf("go.mod file is too large") |
|
) |
|
|
|
type Package struct { |
|
Name string |
|
Version string |
|
GoMod string |
|
} |
|
|
|
// ParsePackage parses the Go package file |
|
// https://go.dev/ref/mod#zip-files |
|
func ParsePackage(r io.ReaderAt, size int64) (*Package, error) { |
|
archive, err := zip.NewReader(r, size) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
var p *Package |
|
|
|
for _, file := range archive.File { |
|
nameAndVersion := path.Dir(file.Name) |
|
|
|
parts := strings.SplitN(nameAndVersion, "@", 2) |
|
if len(parts) != 2 { |
|
continue |
|
} |
|
|
|
versionParts := strings.SplitN(parts[1], "/", 2) |
|
|
|
if p == nil { |
|
p = &Package{ |
|
Name: strings.TrimSuffix(nameAndVersion, "@"+parts[1]), |
|
Version: versionParts[0], |
|
} |
|
} |
|
|
|
if len(versionParts) > 1 { |
|
// files are expected in the "root" folder |
|
continue |
|
} |
|
|
|
if path.Base(file.Name) == "go.mod" { |
|
if file.UncompressedSize64 > maxGoModFileSize { |
|
return nil, ErrGoModFileTooLarge |
|
} |
|
|
|
f, err := archive.Open(file.Name) |
|
if err != nil { |
|
return nil, err |
|
} |
|
defer f.Close() |
|
|
|
bytes, err := io.ReadAll(&io.LimitedReader{R: f, N: maxGoModFileSize}) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
p.GoMod = string(bytes) |
|
|
|
return p, nil |
|
} |
|
} |
|
|
|
if p == nil { |
|
return nil, ErrInvalidStructure |
|
} |
|
|
|
p.GoMod = fmt.Sprintf("module %s", p.Name) |
|
|
|
return p, nil |
|
}
|
|
|