Files
sing-box/experimental/boxdd/insecure_mode_windows.go
T
2026-07-16 00:38:31 +08:00

211 lines
5.1 KiB
Go

//go:build windows
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/experimental/locale"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/filemanager"
)
func registerSecurityPolicy(ctx context.Context, daemon *Daemon) {
service.MustRegister[adapter.SecurityPolicy](ctx, &daemonSecurityPolicy{daemon})
service.MustRegister[filemanager.Manager](ctx, &restrictedFileManager{daemon})
}
func insecureModeAvailable() bool {
return true
}
func loadSecuritySettings(directory string) (securitySettings, error) {
content, err := os.ReadFile(filepath.Join(directory, securitySettingsFileName))
if err != nil {
return securitySettings{}, err
}
settings, err := json.UnmarshalExtended[securitySettings](content)
if err != nil {
return securitySettings{}, err
}
return settings, nil
}
func (d *Daemon) insecureModeEnabled() bool {
settings, err := loadSecuritySettings(workingDirectory)
if err != nil {
return false
}
return settings.InsecureModeEnabled
}
func insecureFeatureError(feature string) error {
return E.New(fmt.Sprintf(locale.Current().InsecureFeatureMessage, feature))
}
type daemonSecurityPolicy struct {
daemon *Daemon
}
func (p *daemonSecurityPolicy) CheckFeature(feature string) error {
if p.daemon.insecureModeEnabled() {
return nil
}
return insecureFeatureError(feature)
}
type restrictedFileManager struct {
daemon *Daemon
}
func (m *restrictedFileManager) BasePath(name string) string {
if filepath.IsAbs(name) {
return name
}
currentDirectory, err := os.Getwd()
if err != nil {
return name
}
return filepath.Join(currentDirectory, name)
}
func (m *restrictedFileManager) TempPath() string {
currentDirectory, err := os.Getwd()
if err != nil {
return "."
}
return currentDirectory
}
func (m *restrictedFileManager) checkPath(name string) (string, error) {
path, err := filepath.Abs(m.BasePath(name))
if err != nil {
return "", err
}
if m.daemon.insecureModeEnabled() {
return path, nil
}
currentDirectory, err := os.Getwd()
if err != nil {
return "", err
}
normalizedRoot := strings.ToLower(filepath.Clean(currentDirectory))
normalizedPath := strings.ToLower(filepath.Clean(path))
if normalizedPath != normalizedRoot && !strings.HasPrefix(normalizedPath, normalizedRoot+string(filepath.Separator)) {
return "", E.New(fmt.Sprintf(locale.Current().ExternalPathFeature, path))
}
existingPath := path
for {
_, err = os.Lstat(existingPath)
if err == nil {
break
}
if !os.IsNotExist(err) {
return "", err
}
parentPath := filepath.Dir(existingPath)
if parentPath == existingPath {
return "", err
}
existingPath = parentPath
}
resolvedRoot, err := filepath.EvalSymlinks(currentDirectory)
if err != nil {
return "", err
}
resolvedExistingPath, err := filepath.EvalSymlinks(existingPath)
if err != nil {
return "", err
}
remainingPath, err := filepath.Rel(existingPath, path)
if err != nil {
return "", err
}
resolvedPath := filepath.Join(resolvedExistingPath, remainingPath)
normalizedResolvedRoot := strings.ToLower(filepath.Clean(resolvedRoot))
normalizedResolvedPath := strings.ToLower(filepath.Clean(resolvedPath))
if normalizedResolvedPath != normalizedResolvedRoot && !strings.HasPrefix(normalizedResolvedPath, normalizedResolvedRoot+string(filepath.Separator)) {
return "", E.New(fmt.Sprintf(locale.Current().ExternalPathFeature, path))
}
return path, nil
}
func (m *restrictedFileManager) OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
path, err := m.checkPath(name)
if err != nil {
return nil, err
}
return os.OpenFile(path, flag, perm)
}
func (m *restrictedFileManager) Create(name string) (*os.File, error) {
path, err := m.checkPath(name)
if err != nil {
return nil, err
}
return os.Create(path)
}
func (m *restrictedFileManager) CreateTemp(pattern string) (*os.File, error) {
currentDirectory, err := os.Getwd()
if err != nil {
return nil, err
}
return os.CreateTemp(currentDirectory, pattern)
}
func (m *restrictedFileManager) Chown(path string) error {
return nil
}
func (m *restrictedFileManager) Mkdir(path string, perm os.FileMode) error {
checkedPath, err := m.checkPath(path)
if err != nil {
return err
}
return os.Mkdir(checkedPath, perm)
}
func (m *restrictedFileManager) MkdirAll(path string, perm os.FileMode) error {
checkedPath, err := m.checkPath(path)
if err != nil {
return err
}
return os.MkdirAll(checkedPath, perm)
}
func (m *restrictedFileManager) Remove(path string) error {
checkedPath, err := m.checkPath(path)
if err != nil {
return err
}
return os.Remove(checkedPath)
}
func (m *restrictedFileManager) RemoveAll(path string) error {
checkedPath, err := m.checkPath(path)
if err != nil {
return err
}
return os.RemoveAll(checkedPath)
}
func (m *restrictedFileManager) Rename(oldPath string, newPath string) error {
checkedOldPath, err := m.checkPath(oldPath)
if err != nil {
return err
}
checkedNewPath, err := m.checkPath(newPath)
if err != nil {
return err
}
return os.Rename(checkedOldPath, checkedNewPath)
}