diff --git a/internal/infra/storage/localfs.go b/internal/infra/storage/localfs.go index bde2411..a38e346 100644 --- a/internal/infra/storage/localfs.go +++ b/internal/infra/storage/localfs.go @@ -28,8 +28,13 @@ func NewLocalFS(base string) (*LocalFS, error) { return &LocalFS{base: filepath.Clean(base)}, nil } -// resolveSafe 把 key 限制在 base 之下,拒绝 ".." / 绝对路径。 +// resolveSafe 把 key 限制在 base 之下,拒绝 ".." / 绝对路径 / 空 key。 func (l *LocalFS) resolveSafe(key string) (string, error) { + // Reject empty / dot keys (would resolve to base itself and corrupt the layout) + if key == "" || key == "." { + return "", errors.New("storage: key must not be empty") + } + // Reject absolute paths if filepath.IsAbs(key) { return "", errors.New("storage: key must be relative") @@ -96,7 +101,11 @@ func (l *LocalFS) Get(ctx context.Context, storagePath string) (io.ReadCloser, e if err != nil { return nil, err } - return os.Open(full) + f, err := os.Open(full) + if err != nil { + return nil, err // 显式 nil interface,避免 typed-nil 包装 + } + return f, nil } func (l *LocalFS) Delete(ctx context.Context, storagePath string) error { diff --git a/internal/infra/storage/localfs_test.go b/internal/infra/storage/localfs_test.go index c35ae6c..986fe73 100644 --- a/internal/infra/storage/localfs_test.go +++ b/internal/infra/storage/localfs_test.go @@ -52,3 +52,22 @@ func TestLocalFS_DeleteNonexistentIsNoop(t *testing.T) { fs, _ := NewLocalFS(t.TempDir()) require.NoError(t, fs.Delete(context.Background(), "nope/nope.txt")) } + +func TestLocalFS_RejectEmptyKey(t *testing.T) { + fs, _ := NewLocalFS(t.TempDir()) + _, err := fs.Put(context.Background(), "", bytes.NewReader(nil), "text/plain") + require.Error(t, err) + _, err = fs.Put(context.Background(), ".", bytes.NewReader(nil), "text/plain") + require.Error(t, err) + _, err = fs.Get(context.Background(), "") + require.Error(t, err) + require.Error(t, fs.Delete(context.Background(), "")) +} + +func TestLocalFS_GetMissingFileReturnsNilCloser(t *testing.T) { + // 验证错误路径下不会返回 typed-nil io.ReadCloser + fs, _ := NewLocalFS(t.TempDir()) + r, err := fs.Get(context.Background(), "missing/file.txt") + require.Error(t, err) + require.Nil(t, r) +}