Compare commits
No commits in common. "main" and "v1.5.0" have entirely different histories.
@ -1,8 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v1.5.2 (2026-06-08)
|
|
||||||
- **JS 对齐**: 将所有注册到 `jsmod` 的导出方法名统一为 PascalCase(如 `Read`, `Write`, `GetFileInfo`),消除 JS 环境下的调用摩擦。
|
|
||||||
|
|
||||||
## [1.3.3] - 2026-05-30
|
## [1.3.3] - 2026-05-30
|
||||||
- **新增**: 注册到 `jsmod`,将所有文件操作方法(Read/Write/Archive 等)注册为高危方法(unsafeList),确保安全沙箱隔离。
|
- **新增**: 注册到 `jsmod`,将所有文件操作方法(Read/Write/Archive 等)注册为高危方法(unsafeList),确保安全沙箱隔离。
|
||||||
|
|
||||||
|
|||||||
15
file.go
15
file.go
@ -123,17 +123,6 @@ func Write(filename string, content string) error {
|
|||||||
return WriteBytes(filename, []byte(content))
|
return WriteBytes(filename, []byte(content))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Append(filename string, content []byte) error {
|
|
||||||
EnsureParentDir(filename)
|
|
||||||
f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
_, err = f.Write(content)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func Copy(from, to string) error {
|
func Copy(from, to string) error {
|
||||||
fromStat, err := os.Stat(from)
|
fromStat, err := os.Stat(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -308,9 +297,9 @@ func VerifyPathForSafeMode(ctx context.Context, path string) (string, error) {
|
|||||||
return RealPath(path), nil
|
return RealPath(path), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 获取白名单
|
// 1. 获取白名单 (约定从 ctx 获取 "AllowedDirs")
|
||||||
var allowedDirs []string
|
var allowedDirs []string
|
||||||
cast.Convert(&allowedDirs, jsmod.Get(ctx, "AllowedDirs"))
|
cast.Convert(&allowedDirs, ctx.Value("AllowedDirs"))
|
||||||
if len(allowedDirs) == 0 {
|
if len(allowedDirs) == 0 {
|
||||||
return "", fmt.Errorf("file: access denied, AllowedDirs not found in context")
|
return "", fmt.Errorf("file: access denied, AllowedDirs not found in context")
|
||||||
}
|
}
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -14,7 +14,7 @@ require (
|
|||||||
apigo.cc/go/rand v1.5.0 // indirect
|
apigo.cc/go/rand v1.5.0 // indirect
|
||||||
github.com/kr/pretty v0.3.0 // indirect
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
golang.org/x/crypto v0.52.0 // indirect
|
golang.org/x/crypto v0.51.0 // indirect
|
||||||
golang.org/x/sys v0.45.0 // indirect
|
golang.org/x/sys v0.44.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
6
go.sum
6
go.sum
@ -20,8 +20,10 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
|
||||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
|
||||||
|
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
||||||
|
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
|||||||
40
js_export.go
40
js_export.go
@ -9,42 +9,42 @@ import (
|
|||||||
func init() {
|
func init() {
|
||||||
jsmod.Register("file", map[string]any{
|
jsmod.Register("file", map[string]any{
|
||||||
// 读操作 (映射到私有包装器)
|
// 读操作 (映射到私有包装器)
|
||||||
"Exists": func(ctx context.Context, path string) bool {
|
"exists": func(ctx context.Context, path string) bool {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return Exists(p)
|
return Exists(p)
|
||||||
},
|
},
|
||||||
"Read": func(ctx context.Context, path string) (string, error) {
|
"read": func(ctx context.Context, path string) (string, error) {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return Read(p)
|
return Read(p)
|
||||||
},
|
},
|
||||||
"ReadBytes": func(ctx context.Context, path string) ([]byte, error) {
|
"readBytes": func(ctx context.Context, path string) ([]byte, error) {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ReadBytes(p)
|
return ReadBytes(p)
|
||||||
},
|
},
|
||||||
"ReadLines": func(ctx context.Context, path string) ([]string, error) {
|
"readLines": func(ctx context.Context, path string) ([]string, error) {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ReadLines(p)
|
return ReadLines(p)
|
||||||
},
|
},
|
||||||
"ReadDir": func(ctx context.Context, path string) ([]FileInfo, error) {
|
"readDir": func(ctx context.Context, path string) ([]FileInfo, error) {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ReadDir(p)
|
return ReadDir(p)
|
||||||
},
|
},
|
||||||
"GetFileInfo": func(ctx context.Context, path string) *FileInfo {
|
"getFileInfo": func(ctx context.Context, path string) *FileInfo {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@ -53,35 +53,35 @@ func init() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 写操作
|
// 写操作
|
||||||
"Write": func(ctx context.Context, path string, content string) error {
|
"write": func(ctx context.Context, path string, content string) error {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return Write(p, content)
|
return Write(p, content)
|
||||||
},
|
},
|
||||||
"WriteBytes": func(ctx context.Context, path string, content []byte) error {
|
"writeBytes": func(ctx context.Context, path string, content []byte) error {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return WriteBytes(p, content)
|
return WriteBytes(p, content)
|
||||||
},
|
},
|
||||||
"Remove": func(ctx context.Context, path string) error {
|
"remove": func(ctx context.Context, path string) error {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return Remove(p)
|
return Remove(p)
|
||||||
},
|
},
|
||||||
"Mkdir": func(ctx context.Context, path string) error {
|
"mkdir": func(ctx context.Context, path string) error {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return Mkdir(p)
|
return Mkdir(p)
|
||||||
},
|
},
|
||||||
"Copy": func(ctx context.Context, from, to string) error {
|
"copy": func(ctx context.Context, from, to string) error {
|
||||||
pFrom, err := VerifyPathForSafeMode(ctx, from)
|
pFrom, err := VerifyPathForSafeMode(ctx, from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -92,7 +92,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
return Copy(pFrom, pTo)
|
return Copy(pFrom, pTo)
|
||||||
},
|
},
|
||||||
"Move": func(ctx context.Context, from, to string) error {
|
"move": func(ctx context.Context, from, to string) error {
|
||||||
pFrom, err := VerifyPathForSafeMode(ctx, from)
|
pFrom, err := VerifyPathForSafeMode(ctx, from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -103,7 +103,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
return Move(pFrom, pTo)
|
return Move(pFrom, pTo)
|
||||||
},
|
},
|
||||||
"Replace": func(ctx context.Context, path, old, new string) error {
|
"replace": func(ctx context.Context, path, old, new string) error {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -112,21 +112,21 @@ func init() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 序列化
|
// 序列化
|
||||||
"UnmarshalFile": func(ctx context.Context, path string, to any) error {
|
"unmarshalFile": func(ctx context.Context, path string, to any) error {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return UnmarshalFile(p, to)
|
return UnmarshalFile(p, to)
|
||||||
},
|
},
|
||||||
"MarshalFile": func(ctx context.Context, path string, data any) error {
|
"marshalFile": func(ctx context.Context, path string, data any) error {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return MarshalFile(p, data)
|
return MarshalFile(p, data)
|
||||||
},
|
},
|
||||||
"MarshalFilePretty": func(ctx context.Context, path string, data any) error {
|
"marshalFilePretty": func(ctx context.Context, path string, data any) error {
|
||||||
p, err := VerifyPathForSafeMode(ctx, path)
|
p, err := VerifyPathForSafeMode(ctx, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -135,7 +135,7 @@ func init() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 归档
|
// 归档
|
||||||
"Archive": func(ctx context.Context, src, dest string) error {
|
"archive": func(ctx context.Context, src, dest string) error {
|
||||||
pSrc, err := VerifyPathForSafeMode(ctx, src)
|
pSrc, err := VerifyPathForSafeMode(ctx, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -146,7 +146,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
return Archive(pSrc, pDest)
|
return Archive(pSrc, pDest)
|
||||||
},
|
},
|
||||||
"Extract": func(ctx context.Context, src, dest string, strip bool) error {
|
"extract": func(ctx context.Context, src, dest string, strip bool) error {
|
||||||
pSrc, err := VerifyPathForSafeMode(ctx, src)
|
pSrc, err := VerifyPathForSafeMode(ctx, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -159,7 +159,7 @@ func init() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 压缩工具 (无路径,不校验)
|
// 压缩工具 (无路径,不校验)
|
||||||
"Compress": Compress,
|
"compress": Compress,
|
||||||
"Decompress": Decompress,
|
"decompress": Decompress,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -186,7 +186,7 @@ func LoadFileToB64(filename string) *MemFileB64 {
|
|||||||
ModTime: info.ModTime(),
|
ModTime: info.ModTime(),
|
||||||
IsDir: false,
|
IsDir: false,
|
||||||
Size: info.Size(),
|
Size: info.Size(),
|
||||||
DataB64: []byte(encoding.Base64(data)),
|
DataB64: encoding.Base64(data),
|
||||||
Compressed: compressed,
|
Compressed: compressed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user