Help us shape the future of Go! Take the 2026 Go Developer Survey

pkgzip

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 26, 2026 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package pkgzip 安全地把 zip 包解压到磁盘,供主题与插件共用一个实现。

为什么不各写一份:这里的每一条约束都对应一种真实的攻击或事故—— 路径穿越、zip 炸弹、符号链接指向 /etc/passwd、把 .wasm 塞进主题包。 两份实现意味着每次补一个洞要补两遍,而漏掉的那一份不会有任何症状, 直到有人拿它做事。

本包只负责「安全解压」这一件事。包长什么样、清单怎么解析、 什么时候提交到最终目录,都由调用方决定——那些是策略,不同包类型本就不同。

本包**不定义错误哨兵**:错误的措辞随包类型而变(「主题包不合法」与「插件包不合法」 该说清楚是哪一个),由调用方用它自己的哨兵包装这里返回的错误。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllowedExtensionList

func AllowedExtensionList(allowed map[string]bool) []string

AllowedExtensionList 把扩展名白名单摊成有序列表,供接口文档展示。

func DetectPrefix

func DetectPrefix(zr *zip.Reader, manifestName string) (string, error)

DetectPrefix 判断包内是否有统一的顶层目录,返回需要剥掉的前缀。

从 GitHub 下载的 zip 会多套一层 `<repo>-<branch>/`,而手工打的包通常没有。 两种都得支持,否则一半作者会卡在「为什么提示缺少清单文件」上。

func Extract

func Extract(zr *zip.Reader, dest, prefix string, opts Options) error

Extract 把 zip 内容安全地解压到 dest,逐项施加限额与白名单。

Types

type Limits

type Limits struct {
	// MaxFiles 是包内文件数上限。
	MaxFiles int
	// MaxEntries 是「文件 + 落盘目录」的总条目数上限。
	//
	// 单看文件数不够:目录条目不占字节、也不计入文件数,一个只含几万个空目录的
	// 几十 KB 压缩包能绕过 MaxFiles/MaxTotalSize,耗尽 inode 与磁盘元数据。
	// 非正数时退回 MaxFiles,保持旧调用方的行为不变。
	MaxEntries int
	// MaxFileSize 是单个文件解压后的字节上限。
	MaxFileSize int64
	// MaxTotalSize 是整包解压后的字节上限。
	MaxTotalSize int64
	// MaxPathDepth 是包内路径的层级上限。
	MaxPathDepth int
}

Limits 是解压限额。包来自第三方上传,必须防 zip 炸弹。

type Options

type Options struct {
	Limits Limits
	// AllowedExtensions 是允许出现的文件扩展名(小写,含点)。
	//
	// 白名单而非黑名单:两类包都只该包含声明式资产,没有理由出现可执行文件。
	// 放行一个不该放行的后缀,等于给站点留下一个可上传的后门。
	AllowedExtensions map[string]bool
	// DirPerm 与 FilePerm 是新建目录与文件的权限。
	DirPerm  os.FileMode
	FilePerm os.FileMode
}

Options 是一次解压的参数。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL