mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-28 10:40:14 +00:00
boxdd: Add insecure mode
This commit is contained in:
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -48,6 +49,18 @@ var commandServiceUninstall = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var commandServiceSetInsecureMode = &cobra.Command{
|
||||
Use: "set-insecure-mode <enabled>",
|
||||
Short: "Set whether configurations may use privileges unrelated to networking",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(command *cobra.Command, args []string) {
|
||||
err := serviceSetInsecureMode(args[0])
|
||||
if err != nil {
|
||||
log.Fatal(E.Cause(err, "set insecure mode"))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func addPlatformServiceCommands() {
|
||||
commandServiceInstall.Flags().BoolVar(
|
||||
&commandServiceFlagAllowUnsafeInstallation,
|
||||
@@ -57,6 +70,57 @@ func addPlatformServiceCommands() {
|
||||
)
|
||||
commandService.AddCommand(commandServiceInstall)
|
||||
commandService.AddCommand(commandServiceUninstall)
|
||||
commandService.AddCommand(commandServiceSetInsecureMode)
|
||||
}
|
||||
|
||||
func serviceSetInsecureMode(value string) error {
|
||||
enabled, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return E.Cause(err, "parse value")
|
||||
}
|
||||
if !windows.GetCurrentProcessToken().IsElevated() {
|
||||
return E.New("setting insecure mode requires an elevated process")
|
||||
}
|
||||
directory, err := installedServiceWorkingDirectory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serviceUserID, err := windowsServiceSID()
|
||||
if err != nil {
|
||||
return E.Cause(err, "create daemon service SID")
|
||||
}
|
||||
err = validateProtectedWindowsWorkingDirectory(directory, serviceUserID)
|
||||
if err != nil {
|
||||
return E.Cause(err, "validate working directory")
|
||||
}
|
||||
return saveSecuritySettings(directory, securitySettings{InsecureModeEnabled: enabled})
|
||||
}
|
||||
|
||||
func installedServiceWorkingDirectory() (string, error) {
|
||||
manager, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return "", E.Cause(err, "connect to service manager")
|
||||
}
|
||||
defer manager.Disconnect()
|
||||
service, err := manager.OpenService(serviceName)
|
||||
if err != nil {
|
||||
return "", E.Cause(err, "open service")
|
||||
}
|
||||
defer service.Close()
|
||||
config, err := service.Config()
|
||||
if err != nil {
|
||||
return "", E.Cause(err, "query service config")
|
||||
}
|
||||
arguments, err := windows.DecomposeCommandLine(config.BinaryPathName)
|
||||
if err != nil {
|
||||
return "", E.Cause(err, "parse service command line")
|
||||
}
|
||||
for index, argument := range arguments {
|
||||
if argument == "--working-directory" && index+1 < len(arguments) {
|
||||
return arguments[index+1], nil
|
||||
}
|
||||
}
|
||||
return "", E.New("missing working directory in the service configuration")
|
||||
}
|
||||
|
||||
func serviceInstall() error {
|
||||
|
||||
@@ -63,8 +63,8 @@ func runWorker() error {
|
||||
}
|
||||
defer listener.Close()
|
||||
server := grpc.NewServer(
|
||||
grpc.ChainUnaryInterceptor(daemon.UnaryErrorInterceptor),
|
||||
grpc.ChainStreamInterceptor(daemon.StreamErrorInterceptor),
|
||||
grpc.ChainUnaryInterceptor(unaryLocaleInterceptor),
|
||||
grpc.ChainStreamInterceptor(streamLocaleInterceptor),
|
||||
)
|
||||
RegisterApplicationServiceServer(server, &applicationService{
|
||||
startedService: daemon.NewStartedService(daemon.ServiceOptions{Context: include.Context(context.Background())}),
|
||||
|
||||
@@ -196,18 +196,69 @@ func (s *desktopService) TakeOverService(ctx context.Context, empty *emptypb.Emp
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *desktopService) GetSecuritySettings(ctx context.Context, empty *emptypb.Empty) (*SecuritySettings, error) {
|
||||
_, err := peerIdentityFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !insecureModeAvailable() {
|
||||
return &SecuritySettings{}, nil
|
||||
}
|
||||
return &SecuritySettings{
|
||||
Available: true,
|
||||
InsecureModeEnabled: s.daemon.insecureModeEnabled(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *desktopService) SetInsecureModeEnabled(ctx context.Context, request *SetInsecureModeEnabledRequest) (*emptypb.Empty, error) {
|
||||
_, err := peerIdentityFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !insecureModeAvailable() {
|
||||
return nil, status.Error(codes.FailedPrecondition, "insecure mode is not available on this platform")
|
||||
}
|
||||
if request.Enabled {
|
||||
return nil, status.Error(codes.PermissionDenied, "enabling insecure mode requires an elevated service command")
|
||||
}
|
||||
s.daemon.lifecycleAccess.Lock()
|
||||
defer s.daemon.lifecycleAccess.Unlock()
|
||||
if s.daemon.closed {
|
||||
return nil, os.ErrClosed
|
||||
}
|
||||
wasEnabled := s.daemon.insecureModeEnabled()
|
||||
err = saveSecuritySettings(workingDirectory, securitySettings{InsecureModeEnabled: false})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if wasEnabled && s.daemon.startedService.Instance() != nil {
|
||||
var ownerUserID string
|
||||
ownerUserID, err = loadOwner()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = s.daemon.stopServiceLocked(ownerUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (d *Daemon) cleanFailedStartLocked(ownerUserID string, options startOptions, startError error) error {
|
||||
var platformError error
|
||||
if d.platform != nil {
|
||||
platformError = d.platform.ResetPlatformOptions()
|
||||
}
|
||||
closeError := d.startedService.CloseService()
|
||||
if d.startedService.Instance() != nil {
|
||||
_ = d.startedService.CloseService()
|
||||
}
|
||||
directory := userWorkingDirectory(ownerUserID)
|
||||
crashReportError := tagUnownedReports(filepath.Join(directory, crashReportsDirectoryName), ownerUserID)
|
||||
oomReportError := tagUnownedReports(filepath.Join(directory, oomReportsDirectoryName), ownerUserID)
|
||||
options.WasRunning = false
|
||||
snapshotError := saveStartOptions(ownerUserID, options)
|
||||
return E.Errors(startError, platformError, closeError, crashReportError, oomReportError, snapshotError)
|
||||
return E.Errors(startError, platformError, crashReportError, oomReportError, snapshotError)
|
||||
}
|
||||
|
||||
func (s *desktopService) GetWorkingDirectory(ctx context.Context, empty *emptypb.Empty) (*WorkingDirectoryInfo, error) {
|
||||
|
||||
@@ -1424,6 +1424,102 @@ func (x *OOMReportFile) GetIsProfile() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type SecuritySettings struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Available bool `protobuf:"varint,1,opt,name=available,proto3" json:"available,omitempty"`
|
||||
InsecureModeEnabled bool `protobuf:"varint,2,opt,name=insecure_mode_enabled,json=insecureModeEnabled,proto3" json:"insecure_mode_enabled,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SecuritySettings) Reset() {
|
||||
*x = SecuritySettings{}
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[23]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SecuritySettings) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SecuritySettings) ProtoMessage() {}
|
||||
|
||||
func (x *SecuritySettings) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[23]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SecuritySettings.ProtoReflect.Descriptor instead.
|
||||
func (*SecuritySettings) Descriptor() ([]byte, []int) {
|
||||
return file_experimental_boxdd_desktop_service_proto_rawDescGZIP(), []int{23}
|
||||
}
|
||||
|
||||
func (x *SecuritySettings) GetAvailable() bool {
|
||||
if x != nil {
|
||||
return x.Available
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *SecuritySettings) GetInsecureModeEnabled() bool {
|
||||
if x != nil {
|
||||
return x.InsecureModeEnabled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type SetInsecureModeEnabledRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SetInsecureModeEnabledRequest) Reset() {
|
||||
*x = SetInsecureModeEnabledRequest{}
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[24]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SetInsecureModeEnabledRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SetInsecureModeEnabledRequest) ProtoMessage() {}
|
||||
|
||||
func (x *SetInsecureModeEnabledRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[24]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SetInsecureModeEnabledRequest.ProtoReflect.Descriptor instead.
|
||||
func (*SetInsecureModeEnabledRequest) Descriptor() ([]byte, []int) {
|
||||
return file_experimental_boxdd_desktop_service_proto_rawDescGZIP(), []int{24}
|
||||
}
|
||||
|
||||
func (x *SetInsecureModeEnabledRequest) GetEnabled() bool {
|
||||
if x != nil {
|
||||
return x.Enabled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type InstallUpdateRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
InstallerPath string `protobuf:"bytes,1,opt,name=installer_path,json=installerPath,proto3" json:"installer_path,omitempty"`
|
||||
@@ -1433,7 +1529,7 @@ type InstallUpdateRequest struct {
|
||||
|
||||
func (x *InstallUpdateRequest) Reset() {
|
||||
*x = InstallUpdateRequest{}
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[23]
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[25]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1445,7 +1541,7 @@ func (x *InstallUpdateRequest) String() string {
|
||||
func (*InstallUpdateRequest) ProtoMessage() {}
|
||||
|
||||
func (x *InstallUpdateRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[23]
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[25]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1458,7 +1554,7 @@ func (x *InstallUpdateRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use InstallUpdateRequest.ProtoReflect.Descriptor instead.
|
||||
func (*InstallUpdateRequest) Descriptor() ([]byte, []int) {
|
||||
return file_experimental_boxdd_desktop_service_proto_rawDescGZIP(), []int{23}
|
||||
return file_experimental_boxdd_desktop_service_proto_rawDescGZIP(), []int{25}
|
||||
}
|
||||
|
||||
func (x *InstallUpdateRequest) GetInstallerPath() string {
|
||||
@@ -1477,7 +1573,7 @@ type InstallUpdateResponse struct {
|
||||
|
||||
func (x *InstallUpdateResponse) Reset() {
|
||||
*x = InstallUpdateResponse{}
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[24]
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[26]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1489,7 +1585,7 @@ func (x *InstallUpdateResponse) String() string {
|
||||
func (*InstallUpdateResponse) ProtoMessage() {}
|
||||
|
||||
func (x *InstallUpdateResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[24]
|
||||
mi := &file_experimental_boxdd_desktop_service_proto_msgTypes[26]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1502,7 +1598,7 @@ func (x *InstallUpdateResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use InstallUpdateResponse.ProtoReflect.Descriptor instead.
|
||||
func (*InstallUpdateResponse) Descriptor() ([]byte, []int) {
|
||||
return file_experimental_boxdd_desktop_service_proto_rawDescGZIP(), []int{24}
|
||||
return file_experimental_boxdd_desktop_service_proto_rawDescGZIP(), []int{26}
|
||||
}
|
||||
|
||||
func (x *InstallUpdateResponse) GetResult() InstallUpdateResult {
|
||||
@@ -1606,7 +1702,12 @@ const file_experimental_boxdd_desktop_service_proto_rawDesc = "" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" +
|
||||
"\acontent\x18\x02 \x01(\fR\acontent\x12\x1d\n" +
|
||||
"\n" +
|
||||
"is_profile\x18\x03 \x01(\bR\tisProfile\"=\n" +
|
||||
"is_profile\x18\x03 \x01(\bR\tisProfile\"d\n" +
|
||||
"\x10SecuritySettings\x12\x1c\n" +
|
||||
"\tavailable\x18\x01 \x01(\bR\tavailable\x122\n" +
|
||||
"\x15insecure_mode_enabled\x18\x02 \x01(\bR\x13insecureModeEnabled\"9\n" +
|
||||
"\x1dSetInsecureModeEnabledRequest\x12\x18\n" +
|
||||
"\aenabled\x18\x01 \x01(\bR\aenabled\"=\n" +
|
||||
"\x14InstallUpdateRequest\x12%\n" +
|
||||
"\x0einstaller_path\x18\x01 \x01(\tR\rinstallerPath\"M\n" +
|
||||
"\x15InstallUpdateResponse\x124\n" +
|
||||
@@ -1620,7 +1721,7 @@ const file_experimental_boxdd_desktop_service_proto_rawDesc = "" +
|
||||
"!INSTALL_UPDATE_RESULT_UNSPECIFIED\x10\x00\x12!\n" +
|
||||
"\x1dINSTALL_UPDATE_RESULT_STARTED\x10\x01\x12)\n" +
|
||||
"%INSTALL_UPDATE_RESULT_SIGNER_MISMATCH\x10\x02\x12#\n" +
|
||||
"\x1fINSTALL_UPDATE_RESULT_NOT_NEWER\x10\x032\x9c\v\n" +
|
||||
"\x1fINSTALL_UPDATE_RESULT_NOT_NEWER\x10\x032\xc4\f\n" +
|
||||
"\x0eDesktopService\x12>\n" +
|
||||
"\rGetDaemonInfo\x12\x16.google.protobuf.Empty\x1a\x13.desktop.DaemonInfo\"\x00\x12@\n" +
|
||||
"\fClaimService\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12C\n" +
|
||||
@@ -1640,7 +1741,9 @@ const file_experimental_boxdd_desktop_service_proto_rawDesc = "" +
|
||||
"\x0fExportOOMReport\x12\x1f.desktop.OOMReportExportRequest\x1a\x1b.desktop.CrashReportArchive\"\x00\x12F\n" +
|
||||
"\x0fDeleteOOMReport\x12\x19.desktop.OOMReportRequest\x1a\x16.google.protobuf.Empty\"\x00\x12G\n" +
|
||||
"\x13DeleteAllOOMReports\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\"\x00\x12P\n" +
|
||||
"\rInstallUpdate\x12\x1d.desktop.InstallUpdateRequest\x1a\x1e.desktop.InstallUpdateResponse\"\x002\xbd\x04\n" +
|
||||
"\rInstallUpdate\x12\x1d.desktop.InstallUpdateRequest\x1a\x1e.desktop.InstallUpdateResponse\"\x00\x12J\n" +
|
||||
"\x13GetSecuritySettings\x12\x16.google.protobuf.Empty\x1a\x19.desktop.SecuritySettings\"\x00\x12Z\n" +
|
||||
"\x16SetInsecureModeEnabled\x12&.desktop.SetInsecureModeEnabledRequest\x1a\x16.google.protobuf.Empty\"\x002\xbd\x04\n" +
|
||||
"\x12ApplicationService\x12?\n" +
|
||||
"\vCheckConfig\x12\x16.desktop.ConfigContent\x1a\x16.google.protobuf.Empty\"\x00\x12@\n" +
|
||||
"\fFormatConfig\x12\x16.desktop.ConfigContent\x1a\x16.desktop.ConfigContent\"\x00\x12@\n" +
|
||||
@@ -1664,7 +1767,7 @@ func file_experimental_boxdd_desktop_service_proto_rawDescGZIP() []byte {
|
||||
|
||||
var (
|
||||
file_experimental_boxdd_desktop_service_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||
file_experimental_boxdd_desktop_service_proto_msgTypes = make([]protoimpl.MessageInfo, 25)
|
||||
file_experimental_boxdd_desktop_service_proto_msgTypes = make([]protoimpl.MessageInfo, 27)
|
||||
file_experimental_boxdd_desktop_service_proto_goTypes = []any{
|
||||
(DaemonOwnership)(0), // 0: desktop.DaemonOwnership
|
||||
(InstallUpdateResult)(0), // 1: desktop.InstallUpdateResult
|
||||
@@ -1692,11 +1795,13 @@ var (
|
||||
(*OOMReportExportRequest)(nil), // 23: desktop.OOMReportExportRequest
|
||||
(*OOMReportContent)(nil), // 24: desktop.OOMReportContent
|
||||
(*OOMReportFile)(nil), // 25: desktop.OOMReportFile
|
||||
(*InstallUpdateRequest)(nil), // 26: desktop.InstallUpdateRequest
|
||||
(*InstallUpdateResponse)(nil), // 27: desktop.InstallUpdateResponse
|
||||
(*emptypb.Empty)(nil), // 28: google.protobuf.Empty
|
||||
(*daemon.NetworkQualityTestProgress)(nil), // 29: daemon.NetworkQualityTestProgress
|
||||
(*daemon.STUNTestProgress)(nil), // 30: daemon.STUNTestProgress
|
||||
(*SecuritySettings)(nil), // 26: desktop.SecuritySettings
|
||||
(*SetInsecureModeEnabledRequest)(nil), // 27: desktop.SetInsecureModeEnabledRequest
|
||||
(*InstallUpdateRequest)(nil), // 28: desktop.InstallUpdateRequest
|
||||
(*InstallUpdateResponse)(nil), // 29: desktop.InstallUpdateResponse
|
||||
(*emptypb.Empty)(nil), // 30: google.protobuf.Empty
|
||||
(*daemon.NetworkQualityTestProgress)(nil), // 31: daemon.NetworkQualityTestProgress
|
||||
(*daemon.STUNTestProgress)(nil), // 32: daemon.STUNTestProgress
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1709,60 +1814,64 @@ var file_experimental_boxdd_desktop_service_proto_depIdxs = []int32{
|
||||
21, // 5: desktop.OOMReportList.reports:type_name -> desktop.OOMReportEntry
|
||||
25, // 6: desktop.OOMReportContent.files:type_name -> desktop.OOMReportFile
|
||||
1, // 7: desktop.InstallUpdateResponse.result:type_name -> desktop.InstallUpdateResult
|
||||
28, // 8: desktop.DesktopService.GetDaemonInfo:input_type -> google.protobuf.Empty
|
||||
28, // 9: desktop.DesktopService.ClaimService:input_type -> google.protobuf.Empty
|
||||
28, // 10: desktop.DesktopService.TakeOverService:input_type -> google.protobuf.Empty
|
||||
30, // 8: desktop.DesktopService.GetDaemonInfo:input_type -> google.protobuf.Empty
|
||||
30, // 9: desktop.DesktopService.ClaimService:input_type -> google.protobuf.Empty
|
||||
30, // 10: desktop.DesktopService.TakeOverService:input_type -> google.protobuf.Empty
|
||||
7, // 11: desktop.DesktopService.StartService:input_type -> desktop.StartServiceRequest
|
||||
28, // 12: desktop.DesktopService.GetWorkingDirectory:input_type -> google.protobuf.Empty
|
||||
28, // 13: desktop.DesktopService.DestroyWorkingDirectory:input_type -> google.protobuf.Empty
|
||||
28, // 14: desktop.DesktopService.ListCrashReports:input_type -> google.protobuf.Empty
|
||||
30, // 12: desktop.DesktopService.GetWorkingDirectory:input_type -> google.protobuf.Empty
|
||||
30, // 13: desktop.DesktopService.DestroyWorkingDirectory:input_type -> google.protobuf.Empty
|
||||
30, // 14: desktop.DesktopService.ListCrashReports:input_type -> google.protobuf.Empty
|
||||
15, // 15: desktop.DesktopService.ReadCrashReport:input_type -> desktop.CrashReportRequest
|
||||
15, // 16: desktop.DesktopService.MarkCrashReportRead:input_type -> desktop.CrashReportRequest
|
||||
16, // 17: desktop.DesktopService.ExportCrashReport:input_type -> desktop.CrashReportExportRequest
|
||||
15, // 18: desktop.DesktopService.DeleteCrashReport:input_type -> desktop.CrashReportRequest
|
||||
28, // 19: desktop.DesktopService.DeleteAllCrashReports:input_type -> google.protobuf.Empty
|
||||
28, // 20: desktop.DesktopService.ListOOMReports:input_type -> google.protobuf.Empty
|
||||
30, // 19: desktop.DesktopService.DeleteAllCrashReports:input_type -> google.protobuf.Empty
|
||||
30, // 20: desktop.DesktopService.ListOOMReports:input_type -> google.protobuf.Empty
|
||||
22, // 21: desktop.DesktopService.ReadOOMReport:input_type -> desktop.OOMReportRequest
|
||||
22, // 22: desktop.DesktopService.MarkOOMReportRead:input_type -> desktop.OOMReportRequest
|
||||
23, // 23: desktop.DesktopService.ExportOOMReport:input_type -> desktop.OOMReportExportRequest
|
||||
22, // 24: desktop.DesktopService.DeleteOOMReport:input_type -> desktop.OOMReportRequest
|
||||
28, // 25: desktop.DesktopService.DeleteAllOOMReports:input_type -> google.protobuf.Empty
|
||||
26, // 26: desktop.DesktopService.InstallUpdate:input_type -> desktop.InstallUpdateRequest
|
||||
9, // 27: desktop.ApplicationService.CheckConfig:input_type -> desktop.ConfigContent
|
||||
9, // 28: desktop.ApplicationService.FormatConfig:input_type -> desktop.ConfigContent
|
||||
10, // 29: desktop.ApplicationService.EncodeProfile:input_type -> desktop.ProfileContent
|
||||
11, // 30: desktop.ApplicationService.DecodeProfile:input_type -> desktop.ProfileData
|
||||
3, // 31: desktop.ApplicationService.ArchiveReport:input_type -> desktop.ArchiveReportRequest
|
||||
4, // 32: desktop.ApplicationService.StartStandaloneNetworkQualityTest:input_type -> desktop.StandaloneNetworkQualityTestRequest
|
||||
5, // 33: desktop.ApplicationService.StartStandaloneSTUNTest:input_type -> desktop.StandaloneSTUNTestRequest
|
||||
6, // 34: desktop.DesktopService.GetDaemonInfo:output_type -> desktop.DaemonInfo
|
||||
28, // 35: desktop.DesktopService.ClaimService:output_type -> google.protobuf.Empty
|
||||
28, // 36: desktop.DesktopService.TakeOverService:output_type -> google.protobuf.Empty
|
||||
28, // 37: desktop.DesktopService.StartService:output_type -> google.protobuf.Empty
|
||||
12, // 38: desktop.DesktopService.GetWorkingDirectory:output_type -> desktop.WorkingDirectoryInfo
|
||||
28, // 39: desktop.DesktopService.DestroyWorkingDirectory:output_type -> google.protobuf.Empty
|
||||
13, // 40: desktop.DesktopService.ListCrashReports:output_type -> desktop.CrashReportList
|
||||
17, // 41: desktop.DesktopService.ReadCrashReport:output_type -> desktop.CrashReportContent
|
||||
28, // 42: desktop.DesktopService.MarkCrashReportRead:output_type -> google.protobuf.Empty
|
||||
19, // 43: desktop.DesktopService.ExportCrashReport:output_type -> desktop.CrashReportArchive
|
||||
28, // 44: desktop.DesktopService.DeleteCrashReport:output_type -> google.protobuf.Empty
|
||||
28, // 45: desktop.DesktopService.DeleteAllCrashReports:output_type -> google.protobuf.Empty
|
||||
20, // 46: desktop.DesktopService.ListOOMReports:output_type -> desktop.OOMReportList
|
||||
24, // 47: desktop.DesktopService.ReadOOMReport:output_type -> desktop.OOMReportContent
|
||||
28, // 48: desktop.DesktopService.MarkOOMReportRead:output_type -> google.protobuf.Empty
|
||||
19, // 49: desktop.DesktopService.ExportOOMReport:output_type -> desktop.CrashReportArchive
|
||||
28, // 50: desktop.DesktopService.DeleteOOMReport:output_type -> google.protobuf.Empty
|
||||
28, // 51: desktop.DesktopService.DeleteAllOOMReports:output_type -> google.protobuf.Empty
|
||||
27, // 52: desktop.DesktopService.InstallUpdate:output_type -> desktop.InstallUpdateResponse
|
||||
28, // 53: desktop.ApplicationService.CheckConfig:output_type -> google.protobuf.Empty
|
||||
9, // 54: desktop.ApplicationService.FormatConfig:output_type -> desktop.ConfigContent
|
||||
11, // 55: desktop.ApplicationService.EncodeProfile:output_type -> desktop.ProfileData
|
||||
10, // 56: desktop.ApplicationService.DecodeProfile:output_type -> desktop.ProfileContent
|
||||
28, // 57: desktop.ApplicationService.ArchiveReport:output_type -> google.protobuf.Empty
|
||||
29, // 58: desktop.ApplicationService.StartStandaloneNetworkQualityTest:output_type -> daemon.NetworkQualityTestProgress
|
||||
30, // 59: desktop.ApplicationService.StartStandaloneSTUNTest:output_type -> daemon.STUNTestProgress
|
||||
34, // [34:60] is the sub-list for method output_type
|
||||
8, // [8:34] is the sub-list for method input_type
|
||||
30, // 25: desktop.DesktopService.DeleteAllOOMReports:input_type -> google.protobuf.Empty
|
||||
28, // 26: desktop.DesktopService.InstallUpdate:input_type -> desktop.InstallUpdateRequest
|
||||
30, // 27: desktop.DesktopService.GetSecuritySettings:input_type -> google.protobuf.Empty
|
||||
27, // 28: desktop.DesktopService.SetInsecureModeEnabled:input_type -> desktop.SetInsecureModeEnabledRequest
|
||||
9, // 29: desktop.ApplicationService.CheckConfig:input_type -> desktop.ConfigContent
|
||||
9, // 30: desktop.ApplicationService.FormatConfig:input_type -> desktop.ConfigContent
|
||||
10, // 31: desktop.ApplicationService.EncodeProfile:input_type -> desktop.ProfileContent
|
||||
11, // 32: desktop.ApplicationService.DecodeProfile:input_type -> desktop.ProfileData
|
||||
3, // 33: desktop.ApplicationService.ArchiveReport:input_type -> desktop.ArchiveReportRequest
|
||||
4, // 34: desktop.ApplicationService.StartStandaloneNetworkQualityTest:input_type -> desktop.StandaloneNetworkQualityTestRequest
|
||||
5, // 35: desktop.ApplicationService.StartStandaloneSTUNTest:input_type -> desktop.StandaloneSTUNTestRequest
|
||||
6, // 36: desktop.DesktopService.GetDaemonInfo:output_type -> desktop.DaemonInfo
|
||||
30, // 37: desktop.DesktopService.ClaimService:output_type -> google.protobuf.Empty
|
||||
30, // 38: desktop.DesktopService.TakeOverService:output_type -> google.protobuf.Empty
|
||||
30, // 39: desktop.DesktopService.StartService:output_type -> google.protobuf.Empty
|
||||
12, // 40: desktop.DesktopService.GetWorkingDirectory:output_type -> desktop.WorkingDirectoryInfo
|
||||
30, // 41: desktop.DesktopService.DestroyWorkingDirectory:output_type -> google.protobuf.Empty
|
||||
13, // 42: desktop.DesktopService.ListCrashReports:output_type -> desktop.CrashReportList
|
||||
17, // 43: desktop.DesktopService.ReadCrashReport:output_type -> desktop.CrashReportContent
|
||||
30, // 44: desktop.DesktopService.MarkCrashReportRead:output_type -> google.protobuf.Empty
|
||||
19, // 45: desktop.DesktopService.ExportCrashReport:output_type -> desktop.CrashReportArchive
|
||||
30, // 46: desktop.DesktopService.DeleteCrashReport:output_type -> google.protobuf.Empty
|
||||
30, // 47: desktop.DesktopService.DeleteAllCrashReports:output_type -> google.protobuf.Empty
|
||||
20, // 48: desktop.DesktopService.ListOOMReports:output_type -> desktop.OOMReportList
|
||||
24, // 49: desktop.DesktopService.ReadOOMReport:output_type -> desktop.OOMReportContent
|
||||
30, // 50: desktop.DesktopService.MarkOOMReportRead:output_type -> google.protobuf.Empty
|
||||
19, // 51: desktop.DesktopService.ExportOOMReport:output_type -> desktop.CrashReportArchive
|
||||
30, // 52: desktop.DesktopService.DeleteOOMReport:output_type -> google.protobuf.Empty
|
||||
30, // 53: desktop.DesktopService.DeleteAllOOMReports:output_type -> google.protobuf.Empty
|
||||
29, // 54: desktop.DesktopService.InstallUpdate:output_type -> desktop.InstallUpdateResponse
|
||||
26, // 55: desktop.DesktopService.GetSecuritySettings:output_type -> desktop.SecuritySettings
|
||||
30, // 56: desktop.DesktopService.SetInsecureModeEnabled:output_type -> google.protobuf.Empty
|
||||
30, // 57: desktop.ApplicationService.CheckConfig:output_type -> google.protobuf.Empty
|
||||
9, // 58: desktop.ApplicationService.FormatConfig:output_type -> desktop.ConfigContent
|
||||
11, // 59: desktop.ApplicationService.EncodeProfile:output_type -> desktop.ProfileData
|
||||
10, // 60: desktop.ApplicationService.DecodeProfile:output_type -> desktop.ProfileContent
|
||||
30, // 61: desktop.ApplicationService.ArchiveReport:output_type -> google.protobuf.Empty
|
||||
31, // 62: desktop.ApplicationService.StartStandaloneNetworkQualityTest:output_type -> daemon.NetworkQualityTestProgress
|
||||
32, // 63: desktop.ApplicationService.StartStandaloneSTUNTest:output_type -> daemon.STUNTestProgress
|
||||
36, // [36:64] is the sub-list for method output_type
|
||||
8, // [8:36] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
@@ -1779,7 +1888,7 @@ func file_experimental_boxdd_desktop_service_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_experimental_boxdd_desktop_service_proto_rawDesc), len(file_experimental_boxdd_desktop_service_proto_rawDesc)),
|
||||
NumEnums: 3,
|
||||
NumMessages: 25,
|
||||
NumMessages: 27,
|
||||
NumExtensions: 0,
|
||||
NumServices: 2,
|
||||
},
|
||||
|
||||
@@ -26,6 +26,8 @@ service DesktopService {
|
||||
rpc DeleteOOMReport(OOMReportRequest) returns (google.protobuf.Empty) {}
|
||||
rpc DeleteAllOOMReports(google.protobuf.Empty) returns (google.protobuf.Empty) {}
|
||||
rpc InstallUpdate(InstallUpdateRequest) returns (InstallUpdateResponse) {}
|
||||
rpc GetSecuritySettings(google.protobuf.Empty) returns (SecuritySettings) {}
|
||||
rpc SetInsecureModeEnabled(SetInsecureModeEnabledRequest) returns (google.protobuf.Empty) {}
|
||||
}
|
||||
|
||||
service ApplicationService {
|
||||
@@ -173,6 +175,15 @@ message OOMReportFile {
|
||||
bool is_profile = 3;
|
||||
}
|
||||
|
||||
message SecuritySettings {
|
||||
bool available = 1;
|
||||
bool insecure_mode_enabled = 2;
|
||||
}
|
||||
|
||||
message SetInsecureModeEnabledRequest {
|
||||
bool enabled = 1;
|
||||
}
|
||||
|
||||
message InstallUpdateRequest {
|
||||
string installer_path = 1;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ const (
|
||||
DesktopService_DeleteOOMReport_FullMethodName = "/desktop.DesktopService/DeleteOOMReport"
|
||||
DesktopService_DeleteAllOOMReports_FullMethodName = "/desktop.DesktopService/DeleteAllOOMReports"
|
||||
DesktopService_InstallUpdate_FullMethodName = "/desktop.DesktopService/InstallUpdate"
|
||||
DesktopService_GetSecuritySettings_FullMethodName = "/desktop.DesktopService/GetSecuritySettings"
|
||||
DesktopService_SetInsecureModeEnabled_FullMethodName = "/desktop.DesktopService/SetInsecureModeEnabled"
|
||||
)
|
||||
|
||||
// DesktopServiceClient is the client API for DesktopService service.
|
||||
@@ -61,6 +63,8 @@ type DesktopServiceClient interface {
|
||||
DeleteOOMReport(ctx context.Context, in *OOMReportRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
DeleteAllOOMReports(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
InstallUpdate(ctx context.Context, in *InstallUpdateRequest, opts ...grpc.CallOption) (*InstallUpdateResponse, error)
|
||||
GetSecuritySettings(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SecuritySettings, error)
|
||||
SetInsecureModeEnabled(ctx context.Context, in *SetInsecureModeEnabledRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
}
|
||||
|
||||
type desktopServiceClient struct {
|
||||
@@ -261,6 +265,26 @@ func (c *desktopServiceClient) InstallUpdate(ctx context.Context, in *InstallUpd
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *desktopServiceClient) GetSecuritySettings(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SecuritySettings, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SecuritySettings)
|
||||
err := c.cc.Invoke(ctx, DesktopService_GetSecuritySettings_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *desktopServiceClient) SetInsecureModeEnabled(ctx context.Context, in *SetInsecureModeEnabledRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, DesktopService_SetInsecureModeEnabled_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DesktopServiceServer is the server API for DesktopService service.
|
||||
// All implementations must embed UnimplementedDesktopServiceServer
|
||||
// for forward compatibility.
|
||||
@@ -284,6 +308,8 @@ type DesktopServiceServer interface {
|
||||
DeleteOOMReport(context.Context, *OOMReportRequest) (*emptypb.Empty, error)
|
||||
DeleteAllOOMReports(context.Context, *emptypb.Empty) (*emptypb.Empty, error)
|
||||
InstallUpdate(context.Context, *InstallUpdateRequest) (*InstallUpdateResponse, error)
|
||||
GetSecuritySettings(context.Context, *emptypb.Empty) (*SecuritySettings, error)
|
||||
SetInsecureModeEnabled(context.Context, *SetInsecureModeEnabledRequest) (*emptypb.Empty, error)
|
||||
mustEmbedUnimplementedDesktopServiceServer()
|
||||
}
|
||||
|
||||
@@ -369,6 +395,14 @@ func (UnimplementedDesktopServiceServer) DeleteAllOOMReports(context.Context, *e
|
||||
func (UnimplementedDesktopServiceServer) InstallUpdate(context.Context, *InstallUpdateRequest) (*InstallUpdateResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method InstallUpdate not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedDesktopServiceServer) GetSecuritySettings(context.Context, *emptypb.Empty) (*SecuritySettings, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetSecuritySettings not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedDesktopServiceServer) SetInsecureModeEnabled(context.Context, *SetInsecureModeEnabledRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SetInsecureModeEnabled not implemented")
|
||||
}
|
||||
func (UnimplementedDesktopServiceServer) mustEmbedUnimplementedDesktopServiceServer() {}
|
||||
func (UnimplementedDesktopServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
@@ -732,6 +766,42 @@ func _DesktopService_InstallUpdate_Handler(srv interface{}, ctx context.Context,
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DesktopService_GetSecuritySettings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(emptypb.Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DesktopServiceServer).GetSecuritySettings(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: DesktopService_GetSecuritySettings_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DesktopServiceServer).GetSecuritySettings(ctx, req.(*emptypb.Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _DesktopService_SetInsecureModeEnabled_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SetInsecureModeEnabledRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DesktopServiceServer).SetInsecureModeEnabled(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: DesktopService_SetInsecureModeEnabled_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DesktopServiceServer).SetInsecureModeEnabled(ctx, req.(*SetInsecureModeEnabledRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// DesktopService_ServiceDesc is the grpc.ServiceDesc for DesktopService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -815,6 +885,14 @@ var DesktopService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "InstallUpdate",
|
||||
Handler: _DesktopService_InstallUpdate_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetSecuritySettings",
|
||||
Handler: _DesktopService_GetSecuritySettings_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SetInsecureModeEnabled",
|
||||
Handler: _DesktopService_SetInsecureModeEnabled_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "experimental/boxdd/desktop_service.proto",
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/tailscale/atomicfile"
|
||||
)
|
||||
|
||||
const securitySettingsFileName = "security.json"
|
||||
|
||||
type securitySettings struct {
|
||||
InsecureModeEnabled bool `json:"insecure_mode_enabled"`
|
||||
}
|
||||
|
||||
func saveSecuritySettings(directory string, settings securitySettings) error {
|
||||
content, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return atomicfile.WriteFile(filepath.Join(directory, securitySettingsFileName), content, 0o600)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build !windows
|
||||
|
||||
package main
|
||||
|
||||
import "context"
|
||||
|
||||
func registerSecurityPolicy(ctx context.Context, daemon *Daemon) {
|
||||
}
|
||||
|
||||
func insecureModeAvailable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *Daemon) insecureModeEnabled() bool {
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
//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)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/experimental/locale"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
func setLocaleFromContext(ctx context.Context) {
|
||||
requestMetadata, loaded := metadata.FromIncomingContext(ctx)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
for _, localeID := range requestMetadata.Get("accept-language") {
|
||||
if locale.Set(localeID) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func unaryLocaleInterceptor(ctx context.Context, request any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
setLocaleFromContext(ctx)
|
||||
return handler(ctx, request)
|
||||
}
|
||||
|
||||
func streamLocaleInterceptor(server any, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||
setLocaleFromContext(stream.Context())
|
||||
return handler(server, stream)
|
||||
}
|
||||
@@ -52,6 +52,7 @@ func newDaemon() (*Daemon, error) {
|
||||
if platformInterface != nil {
|
||||
service.MustRegister[adapter.PlatformInterface](ctx, platformInterface)
|
||||
}
|
||||
registerSecurityPolicy(ctx, d)
|
||||
d.startedService = daemon.NewStartedService(daemon.ServiceOptions{
|
||||
Context: ctx,
|
||||
LogMaxLines: 3000,
|
||||
@@ -65,8 +66,8 @@ func newDaemon() (*Daemon, error) {
|
||||
})
|
||||
authorizer := newAuthorizer(d)
|
||||
serverOptions := []grpc.ServerOption{
|
||||
grpc.ChainUnaryInterceptor(newUnaryAuthorizeInterceptor(authorizer), daemon.UnaryErrorInterceptor),
|
||||
grpc.ChainStreamInterceptor(newStreamAuthorizeInterceptor(authorizer), daemon.StreamErrorInterceptor),
|
||||
grpc.ChainUnaryInterceptor(newUnaryAuthorizeInterceptor(authorizer), unaryLocaleInterceptor),
|
||||
grpc.ChainStreamInterceptor(newStreamAuthorizeInterceptor(authorizer), streamLocaleInterceptor),
|
||||
}
|
||||
platformOptions, err := platformServerOptions(d)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user