anonymous

package
v0.33.4 Latest Latest
Warning

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

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

Documentation

Overview

Package anonymous 实现匿名取件 service(仿 vastsa/PigeonBox UX)。

核心流程:

  1. 上传方:上传文件后,调用 GenerateCode 获取 6 位取件码(建立 pickup_code → share_code 映射)
  2. 取件方:输入 6 位码 + 可选密码,按码取文件
  3. 系统:校验(DB 为准)→ 扣减次数(DB 原子)→ 返回下载信息

设计要点(DB 为唯一真相源):

  • 6 位取件码落 file_codes.pickup_code 列(真相源,唯一索引防撞码); Redis 仅存 pickup_code → share_code 映射 + 展示信息作为加速缓存 (TTL=分享过期;永久分享不写 KV,经 DB 回退路径解析,重启不失联)
  • 过期时间、剩余次数、密码哈希全部以 file_codes 表为准
  • 取件码字符表去掉易混淆字符 0/O/1/I/L

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrCodeNotFound  = errors.New("pickup code not found")
	ErrCodeExpired   = errors.New("pickup code expired")
	ErrCodeExhausted = errors.New("pickup code exhausted")
	ErrPasswordWrong = errors.New("password wrong")
	ErrNotReady      = errors.New("share upload incomplete") // 登记占位未回填物理文件
)

错误哨兵

Functions

This section is empty.

Types

type AnonymousShareParams

type AnonymousShareParams struct {
	FilePath       string
	FileName       string
	FileSize       int64
	ExpireAt       *time.Time // 必填,决定 DB 过期时间 + Redis TTL
	MaxPickupCount int        // -1=无限, 0=默认无限, >0=限制
	Password       string     // 空=无密码
}

AnonymousShareParams 匿名分享端到端参数

type BlockedError

type BlockedError = pkgerrors.ShareBlocked

BlockedError 分享处于管控拒绝态(治理状态机)。 handler 侧 errors.As 后按 ErrCode 透传(20012 blocked / 20013 pending_review)。 实现收口 pkg/errors.ShareBlocked——历史上 share.ShareBlockedError 持有一份 逐字相同的拷贝(本域还用字面量而非常量,已漂移),2026-10-10 合并; 别名保持域内构造点与 handler 用法不变。

type CodeMeta

type CodeMeta struct {
	ShareCode   string // 真实 file_code
	FileName    string
	FileSize    int64
	RequireAuth bool // 仅展示"是否需要密码"
	// ExpireAt 分享过期时间(Unix 秒;0=未设/长期)。Retrieve 成功回填,
	// 供取件结果页展示(此前 handler 恒发 0,页面"过期时间 -")。
	ExpireAt int64
	// RemainingCount 本次取件后剩余可取次数:-1=不限次,>0=剩余。
	// 与 model.FileCode.ExpiredCount 语义一致(0=耗尽不会出现在成功响应里)。
	RemainingCount int
	// IsText 文本分享标记(Retrieve 时按 DB 回填,不进 KV meta 串)。
	// 文本分享取件后前端跳详情页展示(结果页无文本渲染形态),handler 据此回传 share_code。
	IsText bool
	// WrappedKey 口令型 E2E 信封密钥(Retrieve 时按 DB 回填,不进 KV meta 串)。
	// 取件结果页据此提示「需要口令解密」并走 unwrap 流程(core#30)。
	WrappedKey string
}

CodeMeta 取件码展示信息(仅存于 Redis,真实状态查 DB)

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service 匿名取件 service。 Redis 仅存映射 + 展示信息;过期/次数/密码等真实状态全部以 file_codes 表为准。

func NewService

func NewService(rdb *redis.Client, gormDB *gorm.DB) *Service

NewService 创建 service(repo 构造注入,去全局化终态)。 rdb nil 归一化:typed-nil 接口会骗过"Redis 可用"守卫(!= nil 判真)。 rdb 为 nil(redis.host 未配置)时进入单机内存模式:映射/展示信息存进程内 TTL KV,匿名取件全功能可用(单进程语义等价;重启丢失、不跨副本共享)。

func (*Service) BindFilePath added in v0.14.5

func (s *Service) BindFilePath(ctx context.Context, shareCode, filePath string, size int64, note string) error

BindFilePath 把直传完成的对象回填到占位分享(匿名取件码直传通道的最后一公里)。 以实际落盘对象为准更新 file_path 与 size;完成标记由调用方(presign Complete)保证。 note 非空时一并写入(先出码会话随 init 携带的文件备注)。

⚠️ 2026-10-26 审计修复:**原始文件名曾被永久丢弃**。 占位记录把 generate 时的**原始名**寄存在 `uuid_file_name`(因为占位期 file_path 为空 ⇒ 不能写 text:text 非空会让 IsTextShare() 把「待上传的 文件分享」误判成**文本分享**);而绑定时又把 uuid_file_name 清空 ⇒ 原始名彻底消失 ⇒ 展示名退化成存储名(up_<uuid>.pdf)——取件页/管理台/ 用户列表/MCP/传输日志**全部**显示 UUID。 ⇒ 绑定时把原始名**转写进 text**(此时 file_path 已非空 ⇒ 不再误判文本分享), `uuid_file_name` 回归本义(存储名 = 路径末段),一列只担一种语义。

func (*Service) Cancel

func (s *Service) Cancel(ctx context.Context, code string) error

Cancel 作废取件码(KV 映射与 DB pickup_code 列同步清除,真相源一致)

func (*Service) CreateAnonymousShare

func (s *Service) CreateAnonymousShare(ctx context.Context, p AnonymousShareParams) (string, error)

CreateAnonymousShare 端到端:建 file_codes 记录 + 生成取件码。 供 gen handler 调用,避免 handler 直接操作 DAO;密码在此 bcrypt 哈希后存 DB。 返回 6 位取件码。

func (*Service) GenerateCode

func (s *Service) GenerateCode(ctx context.Context, meta CodeMeta, expireAt time.Time) (string, error)

GenerateCode 生成 6 位取件码:落库 file_codes.pickup_code(真相源,唯一索引 防跨分享撞码),有 TTL 时另写 KV 映射加速解析。expireAt 零值=永久分享(不写 KV,取件走 DB 回退);过期时间应与 DB 记录对齐,已过期则拒绝铸造。

func (*Service) MintForShare added in v0.14.5

func (s *Service) MintForShare(ctx context.Context, shareCode, fileName string, fileSize int64, requireAuth bool, expireAt *time.Time) (string, error)

MintForShare 为既有分享铸造 6 位取件码(2026-10-08 起文本/文件/永久分享同权, "只保留 6 位码"呈现;E2E 密文分享由调用方跳过——密钥只随链接,凭码取不到明文)。 真相源落 DB pickup_code 列;有 TTL 时另写 KV 映射加速解析:

  • expireAt nil(永久分享)→ 零值传入 GenerateCode:不写 KV(无 TTL 可言), 取件经 lookupShareCode 的 pickup_code 列回退路径解析,重启不失联
  • KV 写失败返回错误但调用方应视为非致命(出码主流程不阻断)

func (*Service) Peek

func (s *Service) Peek(ctx context.Context, code string) (*CodeMeta, *model.FileCode, error)

Peek 按取件码查询分享信息(不扣次数、不校验密码),仅供展示。 返回展示信息 CodeMeta + DB 记录(含剩余次数、过期时间等)。

func (*Service) ResolvePlaceholder added in v0.14.5

func (s *Service) ResolvePlaceholder(ctx context.Context, pickupCode string) (string, error)

ResolvePlaceholder 校验取件码对应一个"待回填"的占位分享(/anonymous/generate 创建、FilePath 为空),返回其 8 位分享码。供 presign 直传绑定通道在 Init 时 预检、Complete 时定位回填目标。 非占位(已完成上传)/不存在/已过期 → 显式错误,防把对象绑到任意分享上。

func (*Service) Retrieve

func (s *Service) Retrieve(ctx context.Context, code, password, clientIP string) (*CodeMeta, error)

Retrieve 按取件码取件(校验 + 扣减次数,DB 为准)。 返回展示信息 CodeMeta。每次成功调用扣减一次剩余次数。 clientIP 为可信代理解析后的取件方 IP(handler 注入,防爆破锁定键维度)。

Jump to

Keyboard shortcuts

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