keepass-cli/models/database.go

171 lines
4.0 KiB
Go

/*
Copyright © 2024 Brian Buller <brian@bullercodeworks.com>
*/
package models
import (
"errors"
"os"
"strings"
"github.com/tobischo/gokeepasslib"
kp "github.com/tobischo/gokeepasslib"
)
type KeePassDB struct {
path string
db *gokeepasslib.Database
}
func NewKeePassDB(filename string, auth string) (*KeePassDB, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
ret := KeePassDB{
path: filename,
db: kp.NewDatabase(),
}
ret.db.Credentials = kp.NewPasswordCredentials(auth)
err = kp.NewDecoder(file).Decode(ret.db)
if err != nil {
return nil, err
}
ret.db.UnlockProtectedEntries()
return &ret, nil
}
func (db *KeePassDB) GetAllEntriesFromRoot() [][]string {
var res [][]string
groups := db.db.Content.Root.Groups
for _, g := range groups {
grpRes := db.GetAllEntriesInGroup(g)
res = append(res, grpRes...)
}
return res
}
func (db *KeePassDB) GetAllEntriesInGroup(group kp.Group) [][]string {
var res [][]string
for _, g := range group.Groups {
grpRes := db.GetAllEntriesInGroup(g)
for _, r := range grpRes {
res = append(res, append([]string{group.Name}, r...))
}
}
for _, e := range group.Entries {
res = append(res, []string{group.Name, e.GetTitle()})
}
return res
}
func (db *KeePassDB) GetGroupsAndEntriesFromRoot(path []string) [][]string {
var res [][]string
groups := db.db.Content.Root.Groups
if len(path) == 0 {
// Return all groups/entries at this level
for _, g := range groups {
res = append(res, []string{g.Name})
}
return res
} else {
useCase := strings.ToLower(path[0]) != path[0]
for _, g := range groups {
var match bool
if useCase {
match = strings.HasPrefix(g.Name, path[0])
} else {
match = strings.HasPrefix(strings.ToLower(g.Name), path[0])
}
if match {
grpRes := db.GetGroupsAndEntries(g, path[1:])
for _, r := range grpRes {
res = append(res, append([]string{path[0]}, r...))
}
}
}
}
return res
}
func (db *KeePassDB) GetGroupsAndEntries(group kp.Group, path []string) [][]string {
var res [][]string
if len(path) == 0 {
// Return all groups/entries at this level
for _, g := range group.Groups {
res = append(res, []string{g.Name})
}
for _, e := range group.Entries {
res = append(res, []string{e.GetTitle()})
}
} else {
useCase := strings.ToLower(path[0]) != path[0]
for _, g := range group.Groups {
var match bool
if useCase {
match = strings.HasPrefix(g.Name, path[0])
} else {
match = strings.HasPrefix(strings.ToLower(g.Name), path[0])
}
if match {
grpRes := db.GetGroupsAndEntries(g, path[1:])
for _, r := range grpRes {
res = append(res, append([]string{path[0]}, r...))
}
}
}
for _, e := range group.Entries {
var match bool
if useCase {
match = strings.HasPrefix(e.GetTitle(), path[0])
} else {
match = strings.HasPrefix(strings.ToLower(e.GetTitle()), path[0])
}
if match {
res = append(res, []string{e.GetTitle()})
}
}
}
return res
}
func (db *KeePassDB) GetEntryPassword(path []string) (string, error) {
entry, err := db.FindEntryFromRoot(path)
if err != nil {
return "", err
}
return entry.GetPassword(), nil
}
func (db *KeePassDB) FindEntryFromRoot(path []string) (*kp.Entry, error) {
if len(path) < 2 {
return nil, errors.New("Invalid Path")
}
groups := db.db.Content.Root.Groups
for _, g := range groups {
if g.Name == path[0] {
return db.FindEntryInGroup(g, path[1:])
}
}
return nil, errors.New("Invalid Path")
}
func (db *KeePassDB) FindEntryInGroup(group kp.Group, path []string) (*kp.Entry, error) {
if len(path) == 0 {
return nil, errors.New("Invalid Path")
} else if len(path) == 1 {
// Looking for an entry in this group
for _, e := range group.Entries {
if e.GetTitle() == path[0] {
return &e, nil
}
}
return nil, errors.New("Invalid Path")
}
for _, g := range group.Groups {
if g.Name == path[0] {
return db.FindEntryInGroup(g, path[1:])
}
}
return nil, errors.New("Invalid Path")
}