utils

package
v0.33.5 Latest Latest
Warning

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

Go to latest
Published: Nov 4, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

uploadpath.go 上传相对路径的统一生成收口。

随机码/令牌生成已上收至 github.com/oekit/kitx/uidgen(2026-10-05 起); 上传相对路径 uploads/YYYY/MM/DD/ 的拼接逻辑保留在此。

Index

Constants

This section is empty.

Variables

View Source
var DefaultTextShareMaxBytes int64 = 222 * 1024

DefaultTextShareMaxBytes 文本分享默认上限(对齐上游 222KB)。

View Source
var ErrFileTooLarge = errors.New("file size exceeds limit")

ErrFileTooLarge 文件超过允许大小

View Source
var ErrFileTypeNotAllowed error = &fileTypeError{}
View Source
var ErrPasswordRequired = errors.New("password required")

ErrPasswordRequired 开启密码保护但未提供密码(调用方映射为 400)。

View Source
var ErrTextTooLarge = errors.New("text share exceeds size limit")

ErrTextTooLarge 文本分享超过大小上限

Functions

func AllExpireStyles added in v0.27.1

func AllExpireStyles() []string

AllExpireStyles 返回全部合法过期样式(**有序**,便于前端渲染与对账)。

2026-10-22:这是「过期样式合法集合」的**唯一真相源**。此前 setup_service.go / app/mcp/tools.go / bootstrap/handlers_public.go 各有一份独立白名单,**三份都漏了 "count"**(按取件次数过期)⇒ 管理员勾了会被静默丢弃、前端根本选不到、MCP 判非法——同一能力四种行为。 新增/调整样式只改这一处。

func CalculateExpireCount

func CalculateExpireCount(expireStyle string, expireValue int) int

CalculateExpireCount 计算过期次数(-1 表示无限制)

func CalculateExpireTime

func CalculateExpireTime(expireValue int, expireStyle string) *time.Time

CalculateExpireTime 计算过期时间。 全局上限钳制:upload.max_save_seconds_cap > 0 且时长超过上限时钳到上限 (此前该配置定义了但无任何调用方,形同虚设)。

func CheckExpireStyleAllowed

func CheckExpireStyleAllowed(style string) error

CheckExpireStyleAllowed 过期样式白名单校验(对标上游"管理员裁剪过期样式")。 upload.allowed_expire_styles 为空 = 全部允许;否则样式必须在列表内。 空样式 = 未指定(历史语义,下游 CalculateExpireTime 会默认 day),放行。

func CheckPassword

func CheckPassword(hash, pw string) bool

CheckPassword 校验密码。 空 hash 一律拒绝:启用密码保护的分享若哈希缺失(配置错误/历史脏数据), 不允许任何密码(包括空密码)通过——防止"空哈希绕过"。

func CheckPickupCountCap added in v0.33.1

func CheckPickupCountCap(n int) error

CheckPickupCountCap 「单分享可取件次数上限」校验(transfer.max_count,0 = 不限)。

n = 分享允许的取件次数(expire_style=count 的 expire_value,或已换算的 ExpiredCount;<=0 表示不按次数过期/无限 ⇒ 不校验)。 超限**显式拒绝**——不静默钳制:用户要 50 次、静默改成上限值是撒谎。

func CheckUploadContent

func CheckUploadContent(filename string, head []byte) error

CheckUploadContent 组合校验:扩展名准入(白/黑名单)+ 魔数。

  • IsAllowedExtension(白名单未命中 / 黑名单命中)→ 拒绝
  • 魔数命中(开关 upload.enable_magic_check 开、head 非空、扩展名不在 skip 列表)→ 拒绝 防"jpg.exe 改名 cat.jpg"

head 可为 nil(调用方拿不到内容头时只做扩展名检查)。

func CheckUploadSize

func CheckUploadSize(fileSize, maxSize int64) error

CheckUploadSize 校验文件大小是否超限。 maxSize <= 0 表示不限制。

func CheckWholeFileSize

func CheckWholeFileSize(fileSize int64) error

CheckWholeFileSize 整文件大小上限校验(upload.max_file_size,0=不限)。 分片/presign 直传等"整文件"通道用本函数;与单请求体上限 GetMaxUploadSize 区分。

func DefaultBlockedExtensions

func DefaultBlockedExtensions() []string

DefaultBlockedExtensions 返回内置默认黑名单扩展名(返回副本,调用方可追加)

func EffectiveTransferDefaults added in v0.33.1

func EffectiveTransferDefaults() (maxPickupCount int, expireDefaultDays int)

EffectiveTransferDefaults 生效的分享传输默认值(conf.transfer 段)。

· maxPickupCount:单分享可取件次数上限(0 = 不限,transfer.max_count)
· expireDefaultDays:创建分享**完全未指定**过期时的站点默认天数(transfer.expire_default)

conf 未装载(单测/极早期)回退内置默认 100/7(与 bootstrap setDefaults / 管理台 app/config.defaultConfig 的展示默认同款)。⚠️ MaxCount 的 0 是**显式 不限**(viper 缺省已在装载时补 100),不得再拿 0 当"未配置"回退。

func GetAllowedExtensions

func GetAllowedExtensions() []string

GetAllowedExtensions 扩展名白名单(小写)。空 = 未启用白名单。

func GetBlockedExtensions

func GetBlockedExtensions() []string

GetBlockedExtensions 生效的黑名单扩展名:upload.blocked_extensions 非空时用配置, 否则回退内置默认。黑名单永远参与校验(白名单命中也不能豁免)。

func GetEnableMagicCheck

func GetEnableMagicCheck() bool

GetEnableMagicCheck 魔数校验开关(upload.enable_magic_check)。 配置未初始化(测试/启动早期)按开处理,保持历史安全行为。

func GetMagicCheckSkipExts added in v0.33.3

func GetMagicCheckSkipExts() []string

GetMagicCheckSkipExts 魔数检查豁免扩展名追加项(upload.magic_check_skip_extensions)。 只做**追加**:内置事实性豁免(magic.go 的 magicCheckSkipExts)恒生效, 配置供站点补充特有扩展名;移除需求应走扩展名黑名单(blocked_extensions 永远优先)。

func GetMaxFileSize

func GetMaxFileSize() int64

GetMaxFileSize 整文件大小上限(分片/预签名/匿名登记通道)。 upload.max_file_size,0 = 不限(分片通道的存在意义即突破单请求限制)。

func GetMaxSaveSecondsCap

func GetMaxSaveSecondsCap() int64

GetMaxSaveSecondsCap 全局过期时间上限(秒),upload.max_save_seconds_cap,0 = 不限。

func GetMaxUploadSize

func GetMaxUploadSize() int64

GetMaxUploadSize 从全局配置获取上传大小上限。 配置未初始化(测试/启动早期)返回 0 表示不限,避免 nil 解引用。

func GetTextShareMaxBytes

func GetTextShareMaxBytes() int64

GetTextShareMaxBytes 文本分享大小上限(字节)。未配置时用默认 222KB。

func HashBytes

func HashBytes(data []byte) string

HashBytes 计算字节切片 SHA-256(小内容场景,如分片数据)。

func HashFile

func HashFile(path string) (string, error)

HashFile 计算本地文件 SHA-256(分片合并完成后由 handler 调用,写入 file_codes.file_hash)。

func HashPassword

func HashPassword(pw string) (string, error)

HashPassword 用 bcrypt(cost=10) 哈希密码。 空密码返回空字符串(表示"无密码"),不哈希。

func HashReader

func HashReader(r io.Reader) (string, error)

HashReader 流式计算 reader 的 SHA-256,返回十六进制字符串。 用于大文件(分片合并后 / 上传落盘后)不占额外内存的完整性指纹。

func IsAllowedExtension

func IsAllowedExtension(filename string) bool

IsAllowedExtension 扩展名准入判定(大小写不敏感),组合白/黑名单:

  • 白名单非空:扩展名必须命中白名单,否则拒绝(无扩展名视同未命中)
  • 黑名单(可配置,空则用内置默认)永远生效,命中即拒绝——白名单命中也不能豁免

魔数检查不在此函数内,由 CheckUploadContent 编排。

func IsBlockedExtension

func IsBlockedExtension(filename string, blacklist []string) bool

IsBlockedExtension 判断文件扩展名是否在黑名单(大小写不敏感)。 无扩展名返回 false。

func IsValidExpireStyle

func IsValidExpireStyle(style string) bool

IsValidExpireStyle 样式是否合法(在已知样式表内)

func MatchBlockedMagic

func MatchBlockedMagic(head []byte) (string, bool)

MatchBlockedMagic 检查内容头部是否命中可执行文件魔数。 head 为文件(或首个分片)的前若干字节。

func NewFileTooLargeError added in v0.30.5

func NewFileTooLargeError(limit int64) error

NewFileTooLargeError 构造整文件超限错误(带业务码 + 动态文案)。

func NewUploadRelPath

func NewUploadRelPath(originalName string) (uuidName, rel string)

NewUploadRelPath 上传相对路径 uploads/YYYY/MM/DD/<uuid><ext>。 单次取时钟构造日期段(避免跨秒边界日期漂移);返回 (唯一文件名, 相对路径)。

func ResolveSharePassword

func ResolveSharePassword(requireAuth bool, password string) (string, error)

ResolveSharePassword 分享密码守卫的统一收口: requireAuth=false 返回空哈希;requireAuth=true 时密码为空返回 ErrPasswordRequired,否则返回 bcrypt 哈希(哈希失败返回底层错误)。

func SanitizeFileName

func SanitizeFileName(name string) string

SanitizeFileName 消毒用户提供的原始文件名(展示/存储用):

  • 剥离目录成分(/ \ ..),防止路径穿越
  • 丢弃控制字符,Windows 保留字符 : * ? " < > | 换下划线
  • 去首尾空白与结尾的点(Windows 目录项陷阱)
  • 空名/纯符号名回退为 "file"
  • 超长按字节截断且保留扩展名

返回值仅用于"展示/存储原始名",磁盘文件名仍由 UUID 生成,双保险。

实现委托 oekit/pkg/pathx.SanitizeFileName(口径见该包文档);本仓只额外 钉死长度上限(120 字节)——磁盘侧按字节卡,多字节文件名不会落盘 ENAMETOOLONG。

func TextPreview added in v0.32.11

func TextPreview(text string) string

TextPreview 取文本的一行预览(换行/竖线归一为空格,截断到 32 字符 + 省略号)。

用途:**文本分享的展示名**——文本分享没有文件名,取件页展示的就是这段预览 (原先靠 Redis「展示信息快照」携带,2026-10-25 删除该快照后改为从 DB 的 text 字段现算 ⇒ 两处共用本函数,保证「铸造时算的」与「取件时算的」一致)。

func UploadObjectRelPath

func UploadObjectRelPath(fileName string) string

UploadObjectRelPath 上传对象的统一相对路径布局:

uploads/YYYY/MM/DD/<uuid><ext>

直传分享落盘与分片合并共用本函数——磁盘名一律 UUID,原始文件名只用于 扩展名推导与展示(消费方存 Text/FileName 字段),路径基变更只改这里。

func ValidateUsername

func ValidateUsername(name string) error

ValidateUsername 用户名字符集白名单(2026-10-05 审计 P3): 2-32 位,仅字母/数字/下划线/连字符/点。username 进锁定键、限流键、 审计日志与存储路径拼接,收紧字符集防控制字符/超长/同形字符注入。 已有老用户不受影响(仅约束新建)。

Types

type ExpireParams

type ExpireParams struct {
	ExpireValue int
	ExpireStyle string
	RequireAuth bool
}

ExpireParams 过期参数

func ParseExpireParams

func ParseExpireParams(expireValueStr, expireStyle, requireAuthStr string) (*ExpireParams, error)

ParseExpireParams 解析过期参数

type FileTooLargeError added in v0.30.5

type FileTooLargeError struct{ Limit int64 }

FileTooLargeError 文件超过整文件大小上限(upload.max_file_size)。

带业务码(ErrCode)⇒ handler 的 resp.NewTypedError 透传 CodeTooLarge (HTTP 413)并保留动态文案「文件过大: 最大允许 N 字节」;前端已把 10010 列入动态文案白名单,直接显示后端原文。

2026-10-23 背景:此前各处用 fmt.Errorf("文件过大: ...") 包装 ⇒ 退化成普通 error,业务码丢失——presign init 落 30008「预签名生成失败」,把后端清晰的 文案抹掉(前端按错误码映射覆盖);chunk init 更糟,落 500「服务器内部错误」。

func (*FileTooLargeError) ErrCode added in v0.30.5

func (e *FileTooLargeError) ErrCode() int

ErrCode 实现 app 侧 typed error 约定(见 pkg/gate.GateError)。

func (*FileTooLargeError) Error added in v0.30.5

func (e *FileTooLargeError) Error() string

type MagicMismatchError

type MagicMismatchError struct {
	Signature string
}

MagicMismatchError 扩展名与内容魔数不符

func (*MagicMismatchError) ErrCode added in v0.33.3

func (e *MagicMismatchError) ErrCode() int

ErrCode 实现 app 侧 typed error 约定 ⇒ wire 上落 30011(HTTP 415)。 2026-11-03 实录:presign Complete 的 default 分支曾把它塌成 10008 「内部错误」——用户被误杀后只看到「内部错误」,无从判断是内容问题。

func (*MagicMismatchError) Error

func (e *MagicMismatchError) Error() string

Jump to

Keyboard shortcuts

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