diff --git a/orbit/changes/23697-kubuntu-luks b/orbit/changes/23697-kubuntu-luks new file mode 100644 index 0000000000..d7ef70f483 --- /dev/null +++ b/orbit/changes/23697-kubuntu-luks @@ -0,0 +1 @@ +* added support for kdialog linux key escrow prompts for compatibility with kubuntu systems \ No newline at end of file diff --git a/orbit/cmd/orbit/orbit.go b/orbit/cmd/orbit/orbit.go index 1be45d7cfb..2cf8138045 100644 --- a/orbit/cmd/orbit/orbit.go +++ b/orbit/cmd/orbit/orbit.go @@ -39,7 +39,6 @@ import ( "github.com/fleetdm/fleet/v4/orbit/pkg/update" "github.com/fleetdm/fleet/v4/orbit/pkg/update/filestore" "github.com/fleetdm/fleet/v4/orbit/pkg/user" - "github.com/fleetdm/fleet/v4/orbit/pkg/zenity" "github.com/fleetdm/fleet/v4/pkg/certificate" "github.com/fleetdm/fleet/v4/pkg/file" retrypkg "github.com/fleetdm/fleet/v4/pkg/retry" @@ -938,7 +937,7 @@ func main() { orbitClient.RegisterConfigReceiver(update.ApplyWindowsMDMEnrollmentFetcherMiddleware(windowsMDMEnrollmentCommandFrequency, orbitHostInfo.HardwareUUID, orbitClient)) orbitClient.RegisterConfigReceiver(update.ApplyWindowsMDMBitlockerFetcherMiddleware(windowsMDMBitlockerCommandFrequency, orbitClient)) case "linux": - orbitClient.RegisterConfigReceiver(luks.New(orbitClient, zenity.New())) + orbitClient.RegisterConfigReceiver(luks.New(orbitClient)) } flagUpdateReceiver := update.NewFlagReceiver(orbitClient.TriggerOrbitRestart, update.FlagUpdateOptions{ diff --git a/orbit/pkg/dialog/dialog.go b/orbit/pkg/dialog/dialog.go index 5a1244a155..b0155c269b 100644 --- a/orbit/pkg/dialog/dialog.go +++ b/orbit/pkg/dialog/dialog.go @@ -1,7 +1,6 @@ package dialog import ( - "context" "errors" "time" ) @@ -20,10 +19,10 @@ var ( type Dialog interface { // ShowEntry displays a dialog that accepts end user input. It returns the entered // text or errors ErrCanceled, ErrTimeout, or ErrUnknown. - ShowEntry(ctx context.Context, opts EntryOptions) ([]byte, error) + ShowEntry(opts EntryOptions) ([]byte, error) // ShowInfo displays a dialog that displays information. It returns an error if the dialog // could not be displayed. - ShowInfo(ctx context.Context, opts InfoOptions) error + ShowInfo(opts InfoOptions) error // Progress displays a dialog that shows progress. It waits until the // context is cancelled. ShowProgress(opts ProgressOptions) (cancelFunc func() error, err error) diff --git a/orbit/pkg/execuser/execuser.go b/orbit/pkg/execuser/execuser.go index 9a6222b121..3687163218 100644 --- a/orbit/pkg/execuser/execuser.go +++ b/orbit/pkg/execuser/execuser.go @@ -2,12 +2,16 @@ // SYSTEM service on Windows) as the current login user. package execuser -import "io" +import ( + "io" + "time" +) type eopts struct { env [][2]string args [][2]string stderrPath string //nolint:structcheck,unused + timeout time.Duration } // Option allows configuring the application. @@ -27,6 +31,13 @@ func WithArg(name, value string) Option { } } +// WithTimeout sets the timeout for the application. Currently only supported on Linux. +func WithTimeout(duration time.Duration) Option { + return func(a *eopts) { + a.timeout = duration + } +} + // Run runs an application as the current login user. // It assumes the caller is running with high privileges (root on Unix, SYSTEM on Windows). // diff --git a/orbit/pkg/execuser/execuser_linux.go b/orbit/pkg/execuser/execuser_linux.go index cbcb222b13..a23c5ccf6d 100644 --- a/orbit/pkg/execuser/execuser_linux.go +++ b/orbit/pkg/execuser/execuser_linux.go @@ -64,7 +64,16 @@ func runWithOutput(path string, opts eopts) (output []byte, exitCode int, err er } } - cmd := exec.Command("sudo", args...) + // Prefix with "timeout" and "sudo" if applicable + var cmdArgs []string + if opts.timeout > 0 { + cmdArgs = append(cmdArgs, "timeout", fmt.Sprintf("%ds", int(opts.timeout.Seconds()))) + } + cmdArgs = append(cmdArgs, "sudo") + cmdArgs = append(cmdArgs, args...) + + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) // #nosec G204 + log.Printf("cmd=%s", cmd.String()) output, err = cmd.Output() diff --git a/orbit/pkg/kdialog/kdialog.go b/orbit/pkg/kdialog/kdialog.go new file mode 100644 index 0000000000..c688b8f60a --- /dev/null +++ b/orbit/pkg/kdialog/kdialog.go @@ -0,0 +1,129 @@ +package kdialog + +import ( + "errors" + "strings" + "time" + + "github.com/fleetdm/fleet/v4/orbit/pkg/dialog" + "github.com/fleetdm/fleet/v4/orbit/pkg/execuser" + "github.com/fleetdm/fleet/v4/orbit/pkg/platform" +) + +const kdialogProcessName = "kdialog" + +type KDialog struct { + cmdWithOutput func(timeout time.Duration, args ...string) ([]byte, int, error) + cmdWithCancel func(args ...string) (cancelFunc func() error, err error) +} + +func New() *KDialog { + return &KDialog{ + cmdWithOutput: execCmdWithOutput, + cmdWithCancel: execCmdWithCancel, + } +} + +func (k *KDialog) ShowEntry(opts dialog.EntryOptions) ([]byte, error) { + args := []string{"--password"} + if opts.Text != "" { + args = append(args, opts.Text) + } + if opts.Title != "" { + args = append(args, "--title", opts.Title) + } + + output, statusCode, err := k.cmdWithOutput(opts.TimeOut, args...) + if err != nil { + switch statusCode { + case 1: + return nil, dialog.ErrCanceled + case 124: + return nil, dialog.ErrTimeout + default: + return nil, errors.Join(dialog.ErrUnknown, err) + } + } + + output = []byte(strings.TrimSuffix(string(output), "\n")) + + return output, nil +} + +func (k *KDialog) ShowProgress(opts dialog.ProgressOptions) (func() error, error) { + args := []string{"--msgbox"} + if opts.Text != "" { + args = append(args, opts.Text) + } + if opts.Title != "" { + args = append(args, "--title", opts.Title) + } + + cancel, err := k.cmdWithCancel(args...) + if err != nil { + return nil, err + } + + return cancel, nil +} + +func (k *KDialog) ShowInfo(opts dialog.InfoOptions) error { + args := []string{"--msgbox"} + if opts.Text != "" { + args = append(args, opts.Text) + } + if opts.Title != "" { + args = append(args, "--title", opts.Title) + } + + _, statusCode, err := k.cmdWithOutput(opts.TimeOut, args...) + if err != nil { + switch statusCode { + case 124: + return dialog.ErrTimeout + default: + return errors.Join(dialog.ErrUnknown, err) + } + } + + return nil +} + +func execCmdWithOutput(timeout time.Duration, args ...string) ([]byte, int, error) { + var opts []execuser.Option + for _, arg := range args { + opts = append(opts, execuser.WithArg(arg, "")) // using empty value for positional args + } + + if timeout > 0 { + opts = append(opts, execuser.WithTimeout(timeout)) + } + + output, exitCode, err := execuser.RunWithOutput(kdialogProcessName, opts...) + if err != nil { + return nil, exitCode, err + } + + return output, exitCode, nil +} + +func execCmdWithCancel(args ...string) (func() error, error) { + var opts []execuser.Option + for _, arg := range args { + opts = append(opts, execuser.WithArg(arg, "")) // using empty value for positional args + } + + _, err := execuser.Run(kdialogProcessName, opts...) + if err != nil { + return nil, err + } + + killFunc := func() error { + if _, err := platform.KillAllProcessByName(kdialogProcessName); err != nil { + return err + } + return nil + } + + return killFunc, nil +} diff --git a/orbit/pkg/kdialog/kdialog_test.go b/orbit/pkg/kdialog/kdialog_test.go new file mode 100644 index 0000000000..17cd4444d4 --- /dev/null +++ b/orbit/pkg/kdialog/kdialog_test.go @@ -0,0 +1,195 @@ +package kdialog + +import ( + "os/exec" + "testing" + "time" + + "github.com/fleetdm/fleet/v4/orbit/pkg/dialog" + "github.com/stretchr/testify/assert" +) + +type mockExecCmd struct { + output []byte + exitCode int + capturedArgs []string + err error +} + +func (m *mockExecCmd) runWithOutput(timeout time.Duration, args ...string) ([]byte, int, error) { + m.capturedArgs = append(m.capturedArgs, args...) + + if m.exitCode != 0 { + return nil, m.exitCode, &exec.ExitError{} + } + + if m.err != nil { + return nil, m.exitCode, m.err + } + + return m.output, m.exitCode, nil +} + +func (m *mockExecCmd) runWithCancel(args ...string) (cancelFunc func() error, err error) { + m.capturedArgs = append(m.capturedArgs, args...) + + if m.err != nil { + return nil, m.err + } + + return nil, nil +} + +func TestShowEntryArgs(t *testing.T) { + testCases := []struct { + name string + opts dialog.EntryOptions + expectedArgs []string + }{ + { + name: "Basic Entry", + opts: dialog.EntryOptions{ + Title: "A Title", + Text: "Some text", + }, + expectedArgs: []string{"--password", "Some text", "--title", "A Title"}, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + mock := &mockExecCmd{ + output: []byte("some output"), + } + k := &KDialog{ + cmdWithOutput: mock.runWithOutput, + } + output, err := k.ShowEntry(tt.opts) + assert.NoError(t, err) + assert.Equal(t, tt.expectedArgs, mock.capturedArgs) + assert.Equal(t, []byte("some output"), output) + }) + } +} + +func TestShowEntryError(t *testing.T) { + mock := &mockExecCmd{ + exitCode: 1, + } + k := &KDialog{ + cmdWithOutput: mock.runWithOutput, + } + _, err := k.ShowEntry(dialog.EntryOptions{}) + assert.Error(t, err) + assert.ErrorIs(t, err, dialog.ErrCanceled) + + mock = &mockExecCmd{ + exitCode: 124, + } + k = &KDialog{ + cmdWithOutput: mock.runWithOutput, + } + _, err = k.ShowEntry(dialog.EntryOptions{}) + assert.Error(t, err) + assert.ErrorIs(t, err, dialog.ErrTimeout) + + mock = &mockExecCmd{ + exitCode: 2, + } + k = &KDialog{ + cmdWithOutput: mock.runWithOutput, + } + _, err = k.ShowEntry(dialog.EntryOptions{}) + assert.Error(t, err) + assert.ErrorIs(t, err, dialog.ErrUnknown) +} + +func TestShowInfoArgs(t *testing.T) { + testCases := []struct { + name string + opts dialog.InfoOptions + expectedArgs []string + }{ + { + name: "Basic Info", + opts: dialog.InfoOptions{ + Title: "A Title", + Text: "Some text", + }, + expectedArgs: []string{"--msgbox", "Some text", "--title", "A Title"}, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + mock := &mockExecCmd{} + k := &KDialog{ + cmdWithOutput: mock.runWithOutput, + } + err := k.ShowInfo(tt.opts) + assert.NoError(t, err) + assert.Equal(t, tt.expectedArgs, mock.capturedArgs) + }) + } +} + +func TestShowInfoError(t *testing.T) { + testcases := []struct { + name string + exitCode int + expectedErr error + }{ + { + name: "Dialog Timed Out", + exitCode: 124, + expectedErr: dialog.ErrTimeout, + }, + { + name: "Unknown Error", + exitCode: 99, + expectedErr: dialog.ErrUnknown, + }, + } + + for _, tt := range testcases { + t.Run(tt.name, func(t *testing.T) { + mock := &mockExecCmd{ + exitCode: tt.exitCode, + } + k := &KDialog{ + cmdWithOutput: mock.runWithOutput, + } + err := k.ShowInfo(dialog.InfoOptions{}) + assert.ErrorIs(t, err, tt.expectedErr) + }) + } +} + +func TestShowProgressArgs(t *testing.T) { + testCases := []struct { + name string + opts dialog.ProgressOptions + expectedArgs []string + }{ + { + name: "Basic Progress", + opts: dialog.ProgressOptions{ + Title: "A Title", + Text: "Some text", + }, + expectedArgs: []string{"--msgbox", "Some text", "--title", "A Title"}, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + mock := &mockExecCmd{} + k := &KDialog{ + cmdWithCancel: mock.runWithCancel, + } + _, err := k.ShowProgress(tt.opts) + assert.NoError(t, err) + assert.Equal(t, tt.expectedArgs, mock.capturedArgs) + }) + } +} diff --git a/orbit/pkg/luks/luks.go b/orbit/pkg/luks/luks.go index 6376b24eaa..13f61bee4a 100644 --- a/orbit/pkg/luks/luks.go +++ b/orbit/pkg/luks/luks.go @@ -10,7 +10,7 @@ type KeyEscrower interface { type LuksRunner struct { escrower KeyEscrower - notifier dialog.Dialog + notifier dialog.Dialog //nolint:structcheck,unused } type LuksResponse struct { @@ -29,9 +29,8 @@ type LuksResponse struct { Err string } -func New(escrower KeyEscrower, notifier dialog.Dialog) *LuksRunner { +func New(escrower KeyEscrower) *LuksRunner { return &LuksRunner{ escrower: escrower, - notifier: notifier, } } diff --git a/orbit/pkg/luks/luks_linux.go b/orbit/pkg/luks/luks_linux.go index 9bea2759fb..89e3cbf968 100644 --- a/orbit/pkg/luks/luks_linux.go +++ b/orbit/pkg/luks/luks_linux.go @@ -14,7 +14,9 @@ import ( "time" "github.com/fleetdm/fleet/v4/orbit/pkg/dialog" + "github.com/fleetdm/fleet/v4/orbit/pkg/kdialog" "github.com/fleetdm/fleet/v4/orbit/pkg/lvm" + "github.com/fleetdm/fleet/v4/orbit/pkg/zenity" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/rs/zerolog/log" "github.com/siderolabs/go-blockdevice/v2/encryption" @@ -35,6 +37,14 @@ const ( var ErrKeySlotFull = regexp.MustCompile(`Key slot \d+ is full`) +func isInstalled(toolName string) bool { + path, err := exec.LookPath(toolName) + if err != nil { + return false + } + return path != "" +} + func (lr *LuksRunner) Run(oc *fleet.OrbitConfig) error { ctx := context.Background() @@ -42,6 +52,19 @@ func (lr *LuksRunner) Run(oc *fleet.OrbitConfig) error { return nil } + if !isInstalled("cryptsetup") { + return errors.New("cryptsetup is not installed") + } + + switch { + case isInstalled("zenity"): + lr.notifier = zenity.New() + case isInstalled("kdialog"): + lr.notifier = kdialog.New() + default: + return errors.New("No supported dialog tool found") + } + devicePath, err := lvm.FindRootDisk() if err != nil { return fmt.Errorf("Failed to find LUKS Root Partition: %w", err) @@ -81,7 +104,7 @@ func (lr *LuksRunner) Run(oc *fleet.OrbitConfig) error { } // Show error in dialog - if err := lr.infoPrompt(ctx, infoTitle, infoFailedText); err != nil { + if err := lr.infoPrompt(infoTitle, infoFailedText); err != nil { log.Info().Err(err).Msg("failed to show failed escrow key dialog") } @@ -89,14 +112,14 @@ func (lr *LuksRunner) Run(oc *fleet.OrbitConfig) error { } if response.Err != "" { - if err := lr.infoPrompt(ctx, infoTitle, response.Err); err != nil { + if err := lr.infoPrompt(infoTitle, response.Err); err != nil { log.Info().Err(err).Msg("failed to show response error dialog") } return fmt.Errorf("error getting linux escrow key: %s", response.Err) } // Show success dialog - if err := lr.infoPrompt(ctx, infoTitle, infoSuccessText); err != nil { + if err := lr.infoPrompt(infoTitle, infoSuccessText); err != nil { log.Info().Err(err).Msg("failed to show success escrow key dialog") } @@ -251,7 +274,7 @@ func generateRandomPassphrase() ([]byte, error) { } func (lr *LuksRunner) entryPrompt(ctx context.Context, title, text string) ([]byte, error) { - passphrase, err := lr.notifier.ShowEntry(ctx, dialog.EntryOptions{ + passphrase, err := lr.notifier.ShowEntry(dialog.EntryOptions{ Title: title, Text: text, HideText: true, @@ -264,7 +287,7 @@ func (lr *LuksRunner) entryPrompt(ctx context.Context, title, text string) ([]by return nil, nil case errors.Is(err, dialog.ErrTimeout): log.Debug().Msg("key escrow dialog timed out") - err := lr.infoPrompt(ctx, infoTitle, timeoutMessage) + err := lr.infoPrompt(infoTitle, timeoutMessage) if err != nil { log.Info().Err(err).Msg("failed to show timeout dialog") } @@ -279,8 +302,8 @@ func (lr *LuksRunner) entryPrompt(ctx context.Context, title, text string) ([]by return passphrase, nil } -func (lr *LuksRunner) infoPrompt(ctx context.Context, title, text string) error { - err := lr.notifier.ShowInfo(ctx, dialog.InfoOptions{ +func (lr *LuksRunner) infoPrompt(title, text string) error { + err := lr.notifier.ShowInfo(dialog.InfoOptions{ Title: title, Text: text, TimeOut: 1 * time.Minute, diff --git a/orbit/pkg/zenity/zenity.go b/orbit/pkg/zenity/zenity.go index d8dca21944..5887a3bf4d 100644 --- a/orbit/pkg/zenity/zenity.go +++ b/orbit/pkg/zenity/zenity.go @@ -2,19 +2,18 @@ package zenity import ( "bytes" - "context" + "errors" "fmt" "github.com/fleetdm/fleet/v4/orbit/pkg/dialog" "github.com/fleetdm/fleet/v4/orbit/pkg/execuser" - "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" ) const zenityProcessName = "zenity" type Zenity struct { // cmdWithOutput can be set in tests to mock execution of the dialog. - cmdWithOutput func(ctx context.Context, args ...string) ([]byte, int, error) + cmdWithOutput func(args ...string) ([]byte, int, error) // cmdWithWait can be set in tests to mock execution of the dialog. cmdWithCancel func(args ...string) (func() error, error) } @@ -30,7 +29,7 @@ func New() *Zenity { // ShowEntry displays an dialog that accepts end user input. It returns the entered // text or errors ErrCanceled, ErrTimeout, or ErrUnknown. -func (z *Zenity) ShowEntry(ctx context.Context, opts dialog.EntryOptions) ([]byte, error) { +func (z *Zenity) ShowEntry(opts dialog.EntryOptions) ([]byte, error) { args := []string{"--entry"} if opts.Title != "" { args = append(args, fmt.Sprintf("--title=%s", opts.Title)) @@ -45,7 +44,7 @@ func (z *Zenity) ShowEntry(ctx context.Context, opts dialog.EntryOptions) ([]byt args = append(args, fmt.Sprintf("--timeout=%d", int(opts.TimeOut.Seconds()))) } - output, statusCode, err := z.cmdWithOutput(ctx, args...) + output, statusCode, err := z.cmdWithOutput(args...) if err != nil { switch statusCode { case 1: @@ -53,7 +52,7 @@ func (z *Zenity) ShowEntry(ctx context.Context, opts dialog.EntryOptions) ([]byt case 5: return nil, dialog.ErrTimeout default: - return nil, ctxerr.Wrap(ctx, dialog.ErrUnknown, err.Error()) + return nil, errors.Join(dialog.ErrUnknown, err) } } @@ -61,7 +60,7 @@ func (z *Zenity) ShowEntry(ctx context.Context, opts dialog.EntryOptions) ([]byt } // ShowInfo displays an information dialog. It returns errors ErrTimeout or ErrUnknown. -func (z *Zenity) ShowInfo(ctx context.Context, opts dialog.InfoOptions) error { +func (z *Zenity) ShowInfo(opts dialog.InfoOptions) error { args := []string{"--info"} if opts.Title != "" { args = append(args, fmt.Sprintf("--title=%s", opts.Title)) @@ -73,13 +72,13 @@ func (z *Zenity) ShowInfo(ctx context.Context, opts dialog.InfoOptions) error { args = append(args, fmt.Sprintf("--timeout=%d", int(opts.TimeOut.Seconds()))) } - _, statusCode, err := z.cmdWithOutput(ctx, args...) + _, statusCode, err := z.cmdWithOutput(args...) if err != nil { switch statusCode { case 5: - return ctxerr.Wrap(ctx, dialog.ErrTimeout) + return dialog.ErrTimeout default: - return ctxerr.Wrap(ctx, dialog.ErrUnknown, err.Error()) + return errors.Join(dialog.ErrUnknown, err) } } @@ -114,7 +113,7 @@ func (z *Zenity) ShowProgress(opts dialog.ProgressOptions) (func() error, error) return cancel, nil } -func execCmdWithOutput(ctx context.Context, args ...string) ([]byte, int, error) { +func execCmdWithOutput(args ...string) ([]byte, int, error) { var opts []execuser.Option for _, arg := range args { opts = append(opts, execuser.WithArg(arg, "")) // Using empty value for positional args diff --git a/orbit/pkg/zenity/zenity_test.go b/orbit/pkg/zenity/zenity_test.go index 5d29d087bd..b38381b6ee 100644 --- a/orbit/pkg/zenity/zenity_test.go +++ b/orbit/pkg/zenity/zenity_test.go @@ -1,7 +1,6 @@ package zenity import ( - "context" "os/exec" "testing" "time" @@ -18,7 +17,7 @@ type mockExecCmd struct { } // MockCommandContext simulates exec.CommandContext and captures arguments -func (m *mockExecCmd) runWithOutput(ctx context.Context, args ...string) ([]byte, int, error) { +func (m *mockExecCmd) runWithOutput(args ...string) ([]byte, int, error) { m.capturedArgs = append(m.capturedArgs, args...) if m.exitCode != 0 { @@ -35,8 +34,6 @@ func (m *mockExecCmd) runWithStdin(args ...string) (func() error, error) { } func TestShowEntryArgs(t *testing.T) { - ctx := context.Background() - testCases := []struct { name string opts dialog.EntryOptions @@ -70,7 +67,7 @@ func TestShowEntryArgs(t *testing.T) { z := &Zenity{ cmdWithOutput: mock.runWithOutput, } - output, err := z.ShowEntry(ctx, tt.opts) + output, err := z.ShowEntry(tt.opts) assert.NoError(t, err) assert.Equal(t, tt.expectedArgs, mock.capturedArgs) assert.Equal(t, []byte("some output"), output) @@ -79,8 +76,6 @@ func TestShowEntryArgs(t *testing.T) { } func TestShowEntryError(t *testing.T) { - ctx := context.Background() - testcases := []struct { name string exitCode int @@ -111,7 +106,7 @@ func TestShowEntryError(t *testing.T) { z := &Zenity{ cmdWithOutput: mock.runWithOutput, } - output, err := z.ShowEntry(ctx, dialog.EntryOptions{}) + output, err := z.ShowEntry(dialog.EntryOptions{}) require.ErrorIs(t, err, tt.expectedErr) assert.Nil(t, output) }) @@ -119,22 +114,18 @@ func TestShowEntryError(t *testing.T) { } func TestShowEntrySuccess(t *testing.T) { - ctx := context.Background() - mock := &mockExecCmd{ output: []byte("some output"), } z := &Zenity{ cmdWithOutput: mock.runWithOutput, } - output, err := z.ShowEntry(ctx, dialog.EntryOptions{}) + output, err := z.ShowEntry(dialog.EntryOptions{}) assert.NoError(t, err) assert.Equal(t, []byte("some output"), output) } func TestShowInfoArgs(t *testing.T) { - ctx := context.Background() - testCases := []struct { name string opts dialog.InfoOptions @@ -162,7 +153,7 @@ func TestShowInfoArgs(t *testing.T) { z := &Zenity{ cmdWithOutput: mock.runWithOutput, } - err := z.ShowInfo(ctx, tt.opts) + err := z.ShowInfo(tt.opts) assert.NoError(t, err) assert.Equal(t, tt.expectedArgs, mock.capturedArgs) }) @@ -170,8 +161,6 @@ func TestShowInfoArgs(t *testing.T) { } func TestShowInfoError(t *testing.T) { - ctx := context.Background() - testcases := []struct { name string exitCode int @@ -197,7 +186,7 @@ func TestShowInfoError(t *testing.T) { z := &Zenity{ cmdWithOutput: mock.runWithOutput, } - err := z.ShowInfo(ctx, dialog.InfoOptions{}) + err := z.ShowInfo(dialog.InfoOptions{}) require.ErrorIs(t, err, tt.expectedErr) }) } diff --git a/tools/dialog/main.go b/tools/dialog/main.go index 036aadc369..90d59e93d3 100644 --- a/tools/dialog/main.go +++ b/tools/dialog/main.go @@ -4,19 +4,30 @@ package main // It will show an entry dialog, a progress dialog, and an info dialog import ( - "context" + "flag" "fmt" "time" "github.com/fleetdm/fleet/v4/orbit/pkg/dialog" + "github.com/fleetdm/fleet/v4/orbit/pkg/kdialog" "github.com/fleetdm/fleet/v4/orbit/pkg/zenity" ) func main() { - prompt := zenity.New() - ctx := context.Background() + dialogTool := flag.String("dialog", "zenity", "Dialog to use: zenity or kdialog") + flag.Parse() - output, err := prompt.ShowEntry(ctx, dialog.EntryOptions{ + var prompt dialog.Dialog + + if *dialogTool == "zenity" { + fmt.Println("Using zenity") + prompt = zenity.New() + } else { + fmt.Println("Using kdialog") + prompt = kdialog.New() + } + + output, err := prompt.ShowEntry(dialog.EntryOptions{ Title: "Zenity Test Entry Title", Text: "Zenity Test Entry Text", HideText: true, @@ -42,7 +53,7 @@ func main() { panic(err) } - err = prompt.ShowInfo(ctx, dialog.InfoOptions{ + err = prompt.ShowInfo(dialog.InfoOptions{ Title: "Zenity Test Info Title", Text: "Result: " + string(output), TimeOut: 10 * time.Second, diff --git a/tools/luks/luks/main.go b/tools/luks/luks/main.go index f20c28f4e2..f8e841c854 100644 --- a/tools/luks/luks/main.go +++ b/tools/luks/luks/main.go @@ -24,7 +24,7 @@ func main() { prompt := zenity.New() // Prompt existing passphrase from the user. - currentPassphrase, err := prompt.ShowEntry(context.Background(), dialog.EntryOptions{ + currentPassphrase, err := prompt.ShowEntry(dialog.EntryOptions{ Title: "Enter Existing LUKS Passphrase", Text: "Enter your existing LUKS passphrase:", HideText: true, @@ -49,7 +49,7 @@ func main() { if err := device.AddKey(context.Background(), devicePath, userKey, escrowKey); err != nil { if errors.Is(err, encryption.ErrEncryptionKeyRejected) { - currentPassphrase, err = prompt.ShowEntry(context.Background(), dialog.EntryOptions{ + currentPassphrase, err = prompt.ShowEntry(dialog.EntryOptions{ Title: "Enter Existing LUKS Passphrase", Text: "Bad password. Enter your existing LUKS passphrase:", HideText: true,