Skip to content

Commit

Permalink
Merge pull request #139 from threez/ui
Browse files Browse the repository at this point in the history
add simple searchable table view
  • Loading branch information
hazcod authored Oct 13, 2024
2 parents 059dbd4 + 9091ec7 commit cbb0933
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 2 deletions.
99 changes: 97 additions & 2 deletions cmd/enpasscli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (
"strconv"
"strings"

"github.com/gdamore/tcell/v2"
"github.com/hazcod/enpass-cli/pkg/clipboard"
"github.com/hazcod/enpass-cli/pkg/enpass"
"github.com/hazcod/enpass-cli/pkg/unlock"
"github.com/miquella/ask"
"github.com/rivo/tview"
"github.com/sirupsen/logrus"
)

Expand All @@ -26,6 +28,8 @@ const (
cmdShow = "show"
cmdCopy = "copy"
cmdPass = "pass"
cmdUi = "ui"

// defaults
defaultLogLevel = logrus.InfoLevel
pinMinLength = 8
Expand All @@ -36,8 +40,10 @@ var (
// overwritten by go build
version = "dev"
// set of all commands
commands = map[string]struct{}{cmdVersion: {}, cmdHelp: {}, cmdDryRun: {}, cmdList: {},
cmdShow: {}, cmdCopy: {}, cmdPass: {}}
commands = map[string]struct{}{
cmdVersion: {}, cmdHelp: {}, cmdDryRun: {}, cmdList: {},
cmdShow: {}, cmdCopy: {}, cmdPass: {}, cmdUi: {},
}
)

type Args struct {
Expand Down Expand Up @@ -198,6 +204,93 @@ func entryPassword(logger *logrus.Logger, vault *enpass.Vault, args *Args) {
}
}

func ui(logger *logrus.Logger, vault *enpass.Vault, args *Args) {
cards, err := vault.GetEntries(*args.cardType, args.filters)
if err != nil {
logger.WithError(err).Fatal("could not retrieve cards")
}
if *args.sort {
sortEntries(cards)
}

app := tview.NewApplication()
flex := tview.NewFlex().SetDirection(tview.FlexRow)
table := tview.NewTable().SetBorders(false)
flex.AddItem(table, 0, 1, true)

var visibleCards []enpass.Card
render := func(filter string) {
filter = strings.ToLower(filter)
visibleCards = []enpass.Card{}

table.Clear()
table.SetCell(0, 0, tview.NewTableCell("Title").SetBackgroundColor(tcell.ColorGray))
table.SetCell(0, 1, tview.NewTableCell("Subtitle").SetBackgroundColor(tcell.ColorGray))
table.SetCell(0, 2, tview.NewTableCell("Category").SetBackgroundColor(tcell.ColorGray))

i := 0
for _, card := range cards {
if card.IsTrashed() && !*args.trashed {
continue
}
if !strings.Contains(strings.ToLower(card.Title+" "+card.Subtitle), filter) {
continue
}

table.SetCell(i+1, 0, tview.NewTableCell(card.Title))
table.SetCell(i+1, 1, tview.NewTableCell(card.Subtitle))
table.SetCell(i+1, 2, tview.NewTableCell(card.Category))
i += 1
visibleCards = append(visibleCards, card)
}
}
render("") // render ininital table without filter

statusText := tview.NewTextView().SetChangedFunc(func() {
app.Draw()
})

inputField := tview.NewInputField()
inputField.SetLabel("Search: ").
SetFieldWidth(30).
SetDoneFunc(func(key tcell.Key) {
render(inputField.GetText())
app.SetFocus(table)
statusText.SetText(fmt.Sprintf("found %d", len(visibleCards)))
})

status := tview.NewFlex()
status.AddItem(inputField, 0, 1, false)
status.AddItem(statusText, 0, 1, false)
flex.AddItem(status, 1, 1, false)

table.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Rune() == '/' {
app.SetFocus(inputField)
}
return event
})

table.Select(0, 0).SetFixed(1, 1)
table.SetSelectable(true, false)
table.SetSelectedFunc(func(row int, column int) {
card := visibleCards[row-1]
if decrypted, err := card.Decrypt(); err != nil {
logger.WithError(err).Fatal("could not decrypt card")
} else {
if err := clipboard.WriteAll(decrypted); err != nil {
logger.WithError(err).Fatal("could not copy password to clipboard")
} else {
statusText.SetText("copied password for " + card.Title)
}
}
})

if err := app.SetRoot(flex, true).SetFocus(inputField).Run(); err != nil {
panic(err)
}
}

func assembleVaultCredentials(logger *logrus.Logger, args *Args, store *unlock.SecureStore) *enpass.VaultCredentials {
credentials := &enpass.VaultCredentials{
Password: os.Getenv("MASTERPW"),
Expand Down Expand Up @@ -313,6 +406,8 @@ func main() {
copyEntry(logger, vault, args)
case cmdPass:
entryPassword(logger, vault, args)
case cmdUi:
ui(logger, vault, args)
default:
logger.WithField("command", args.command).Fatal("unknown command")
}
Expand Down
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@ go 1.17

require (
github.com/atotto/clipboard v0.1.4
github.com/gdamore/tcell/v2 v2.7.1
github.com/miquella/ask v1.0.0
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f
github.com/pkg/errors v0.9.1
github.com/rivo/tview v0.0.0-20240921122403-a64fc48d7654
github.com/sirupsen/logrus v1.9.3
golang.org/x/crypto v0.21.0
)

require (
github.com/gdamore/encoding v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
)
16 changes: 16 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.7.1 h1:TiCcmpWHiAU7F0rA2I3S2Y4mmLmO9KHxJ7E1QhYzQbc=
github.com/gdamore/tcell/v2 v2.7.1/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/miquella/ask v1.0.0 h1:QrFtpgA7tbDSlPUUwCMaAzZLnWseFZtryAn/pnvd3d8=
github.com/miquella/ask v1.0.0/go.mod h1:5hBixDZi2issKiqBf4oQ5c8BauqAYOOrkFOjG4eiUWk=
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f h1:hd3r+uv9DNLScbOrnlj82rBldHQf3XWmCeXAWbw8euQ=
Expand All @@ -11,6 +19,12 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/tview v0.0.0-20240921122403-a64fc48d7654 h1:oa+fljZiaJUVyiT7WgIM3OhirtwBm0LJA97LvWUlBu8=
github.com/rivo/tview v0.0.0-20240921122403-a64fc48d7654/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down Expand Up @@ -53,12 +67,14 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
Expand Down

0 comments on commit cbb0933

Please sign in to comment.