Files
Local-Cursor/internal/skills/safety.go
FuDie0915 188225fae6 Ð޸´ȫÏîĿÉó²éÎÊÌⲢ·¢²¼ v1.1.9
¸ÄÓñ¾»ú¶ÀÁ¢ CA£¬»ָ´ CLI TLS УÑ飬±£»¤ƾ¾ÝÓëÅäÖò¢·¢±£´档
Ð޸´ Cursor Êý¾ݡ¢»Ự·¾¶¡¢´úÀíÉúÃüÖÜÆڡ¢ģÐÍÇëÇóÓë Skills Îļþ²Ù×÷¡£
Ϊ¶ÀÁ¢ Tab ·þÎñÔö¼ӿͻ§¶˼øȨ£¬Éý¼¶ÒÀÀµÓ빤¾ßÁ´£¬ÍêÉƷ¢²¼ԪÐÅϢͬ²½¡£

Ñé֤£ºÁ½¸ö Go ģ¿éµIJâÊÔ/vet¡¢¹ؼüģ¿é race¡¢ǰ¶˲âÊÔ/Éú²ú¹¹½¨/Éó¼ơ¢
Go ¿ɴï©¶´ɨÃèÓë macOS/Linux ¿ÉÐÐģ¿齻²æ±àÒë¾ùͨ¹ý¡£
Windows ¸ôÀëÆô¶¯ͨ¹ý£»δÍê³ɵĵã»÷ðÑ̺ÍԭÉúƽ̨Ñé֤¼ûÉó²鱨¸档
2026-11-10 09:59:34 +08:00

114 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package skills
import (
"bytes"
"crypto/sha256"
"fmt"
"io/fs"
"os"
"path"
"path/filepath"
"strings"
"sync"
"cursor/internal/appdata"
"cursor/internal/securefile"
)
var operationMu sync.Mutex
func checkManagedPaths(project, name string) error {
paths := []string{filepath.Join(project, ".cursor"), skillsDir(project), skillTargetDir(project, name), projectCommandsDir(project)}
for _, file := range commandFileNames(name) {
paths = append(paths, filepath.Join(projectCommandsDir(project), file))
}
for _, entry := range paths {
info, err := os.Lstat(entry)
if os.IsNotExist(err) {
continue
}
if err != nil {
return err
}
if info.Mode()&os.ModeSymlink != 0 {
return fmt.Errorf("安全保护:拒绝通过符号链接修改 %s", entry)
}
}
target := skillTargetDir(project, name)
if _, err := os.Stat(target); os.IsNotExist(err) {
return nil
}
return filepath.WalkDir(target, func(p string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.Type()&os.ModeSymlink != 0 {
return fmt.Errorf("安全保护:skill 内含符号链接 %s", p)
}
return nil
})
}
func backupBeforeReplace(target string, next []byte) error {
previous, err := os.ReadFile(target)
if os.IsNotExist(err) {
return nil
}
if err != nil {
return err
}
if bytes.Equal(previous, next) {
return nil
}
id := fmt.Sprintf("%x", sha256.Sum256([]byte(target)))
dir := filepath.Join(appdata.DataRootPath(), "skill-backups", id[:16])
if err = securefile.PrivateDir(dir); err != nil {
return err
}
file, err := os.CreateTemp(dir, filepath.Base(target)+"-*.bak")
if err != nil {
return err
}
name := file.Name()
if err = file.Close(); err != nil {
return err
}
return securefile.Write(name, previous)
}
func ensureNoCustomSkillFiles(project, name string) error {
allowed := map[string]bool{}
err := fs.WalkDir(builtinFS, path.Join(builtinRoot, name), func(p string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() {
rel := strings.TrimPrefix(p, path.Join(builtinRoot, name)+"/")
allowed[rel] = true
}
return nil
})
if err != nil {
return err
}
for _, file := range retiredSkillFiles[name] {
allowed[file] = true
}
target := skillTargetDir(project, name)
if _, err = os.Stat(target); os.IsNotExist(err) {
return nil
}
return filepath.WalkDir(target, func(p string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() {
rel, _ := filepath.Rel(target, p)
if !allowed[filepath.ToSlash(rel)] {
return fmt.Errorf("skill 含自建文件 %s,已保留;请先备份后手动移除", strings.TrimPrefix(p, target))
}
}
return nil
})
}