2024-05-15 18:49:50 +00:00
|
|
|
/*
|
|
|
|
Copyright © 2024 Brian Buller <brian@bullercodeworks.com>
|
|
|
|
*/
|
2024-05-15 18:42:38 +00:00
|
|
|
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")
|
|
|
|
}
|