diff --git a/README.md b/README.md index b1c1bb8..56197cc 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,12 @@ GOOS=linux GOARCH=amd64 go build -o super-frpc For detailed API documentation, please see [docs/api.md](docs/api.md) +## TODO + +- [x] Add Windows boot service support +- [ ] Add session management API +- [ ] Add codes per file documentation + ## License GPL-3.0 diff --git a/database.db b/database.db index 06b00c9..5e4106e 100644 Binary files a/database.db and b/database.db differ diff --git a/os.go b/os.go index e7c3ba8..f538720 100644 --- a/os.go +++ b/os.go @@ -6,7 +6,10 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "super-frpc/postLog" + + "golang.org/x/sys/windows/registry" ) func GetConfigDir() (string, error) { @@ -28,11 +31,16 @@ func GetFrpcPath() (string, error) { } func detectInitSystem() string { - if _, err := os.Stat("/run/systemd/system"); err == nil { - return "systemd" + if runtime.GOOS == "windows" { + return "windows" } - if _, err := os.Stat("/etc/init.d"); err == nil { - return "init.d" + if runtime.GOOS == "linux" { + if _, err := os.Stat("/run/systemd/system"); err == nil { + return "systemd" + } + if _, err := os.Stat("/etc/init.d"); err == nil { + return "init.d" + } } return "unknown" } @@ -45,6 +53,8 @@ func createBootService(username, instanceName, configPath, runUser string) error return createSystemdService(username, instanceName, configPath, runUser) case "init.d": return createInitDService(username, instanceName, configPath, runUser) + case "windows": + return createWindowsBootService(username, instanceName, configPath) default: return errors.New("unsupported init system") } @@ -221,6 +231,28 @@ exit 0 return nil } +func createWindowsBootService(username, instanceName, configPath string) error { + frpcPath, err := GetFrpcPath() + if err != nil { + return err + } + + serviceName := fmt.Sprintf("superfrpc_%s_%s", username, instanceName) + command := fmt.Sprintf("\"%s\" -c \"%s\"", frpcPath, configPath) + + key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows\CurrentVersion\Run`, registry.WRITE|registry.WOW64_64KEY) + if err != nil { + return fmt.Errorf("failed to open registry key: %w", err) + } + defer key.Close() + + if err := key.SetStringValue(serviceName, command); err != nil { + return fmt.Errorf("failed to set registry value: %w", err) + } + + return nil +} + func removeBootService(username, instanceName string) error { initSystem := detectInitSystem() @@ -243,6 +275,19 @@ func removeBootService(username, instanceName string) error { servicePath := filepath.Join("/etc/init.d", serviceName) os.Remove(servicePath) + + case "windows": + key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows\CurrentVersion\Run`, registry.WRITE|registry.WOW64_64KEY) + if err != nil { + postLog.Error(fmt.Sprintf("[removeBootService] Failed to open registry key: %v", err)) + } else { + defer key.Close() + if err := key.DeleteValue(serviceName); err != nil { + postLog.Error(fmt.Sprintf("[removeBootService] Failed to delete registry value: %v", err)) + } + } + default: + postLog.Error(fmt.Sprintf("[removeBootService] Unsupported init system: %s", initSystem)) } return nil