pkgzip

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 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