add kdialog for kubuntu key escrow (#24405)

This commit is contained in:
Tim Lee
2024-12-05 08:44:16 -07:00
committed by GitHub
parent 2b071a9e5a
commit e3d9801f6d
13 changed files with 416 additions and 52 deletions
+1
View File
@@ -0,0 +1 @@
* added support for kdialog linux key escrow prompts for compatibility with kubuntu systems
+1 -2
View File
@@ -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{
+2 -3
View File
@@ -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)
+12 -1
View File
@@ -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).
//
+10 -1
View File
@@ -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()
+129
View File
@@ -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
}
+195
View File
@@ -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)
})
}
}
+2 -3
View File
@@ -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,
}
}
+30 -7
View File
@@ -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,
+10 -11
View File
@@ -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
+6 -17
View File
@@ -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)
})
}
+16 -5
View File
@@ -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,
+2 -2
View File
@@ -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,