| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- // Copyright 2023 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package goproxy
-
- import (
- "archive/zip"
- "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 = "module " + p.Name
-
- return p, nil
- }
|