summaryrefslogtreecommitdiff
path: root/internal/keepass/search.go
blob: e34570364892b9f032825f2cb2aeac21399eb63c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package keepass

import (
	"context"
	"fmt"
	"path/filepath"
	"sort"

	"codeberg.org/snonux/foostore/internal/store"
)

// Search collects all indexes matching searchTerm, sorts by Description,
// calls onMatch and actionFn per entry, and returns the sorted list.
func (b *Backend) Search(
	ctx context.Context,
	searchTerm string,
	action store.Action,
	actionFn func(context.Context, *store.Index, *store.Data) error,
	onMatch func(*store.Index),
) ([]*store.Index, error) {
	var indexes store.IndexSlice
	if err := b.WalkIndexes(ctx, searchTerm, func(idx *store.Index) error {
		indexes = append(indexes, idx)
		return nil
	}); err != nil {
		return nil, err
	}
	sort.Sort(indexes)

	for _, idx := range indexes {
		if onMatch != nil {
			onMatch(idx)
		}
		if err := b.applyAction(ctx, idx, action, actionFn); err != nil {
			return indexes, err
		}
	}
	return indexes, nil
}

// applyAction executes the requested action for a single matching Index.
// File-level actions (cat, export) are handled directly; external-tool actions
// (paste, open, edit) are delegated to the caller-supplied actionFn.
func (b *Backend) applyAction(ctx context.Context, idx *store.Index, action store.Action, actionFn func(context.Context, *store.Index, *store.Data) error) error {
	switch action {
	case store.ActionNone:
		return nil
	case store.ActionCat:
		return b.actionCat(ctx, idx)
	case store.ActionExport:
		return b.actionExport(ctx, idx, false)
	case store.ActionPathExport:
		return b.actionExport(ctx, idx, true)
	default:
		if actionFn != nil {
			d, err := b.LoadData(ctx, idx)
			if err != nil {
				return err
			}
			return actionFn(ctx, idx, d)
		}
	}
	return nil
}

// actionCat prints the decrypted content of an index entry to stdout.
// Binary entries are skipped with a warning.
func (b *Backend) actionCat(ctx context.Context, idx *store.Index) error {
	if idx.IsBinary() {
		fmt.Println("Not displaying/pasting binary data!")
		return nil
	}
	d, err := b.LoadData(ctx, idx)
	if err != nil {
		return err
	}
	fmt.Print(d.String())
	return nil
}

// actionExport writes the decrypted content to cfg.ExportDir.
// When fullPath is true the full description path is used; when false only the
// basename is used (matching the :export vs :pathexport behaviour).
func (b *Backend) actionExport(ctx context.Context, idx *store.Index, fullPath bool) error {
	d, err := b.LoadData(ctx, idx)
	if err != nil {
		return err
	}
	destFile := idx.Description
	if !fullPath {
		destFile = filepath.Base(idx.Description)
	}
	return d.Export(ctx, b.cfg.ExportDir, destFile)
}