folder mostly done, types (partially) stubbed out.

This commit is contained in:
brent s. 2021-12-20 04:02:48 -05:00
parent d76746d79e
commit 8ab14af06c
Signed by: bts
GPG Key ID: 8C004C2F93481F6B
11 changed files with 605 additions and 35 deletions

51
blob_funcs.go Normal file
View File

@ -0,0 +1,51 @@
package gokwallet

/*
NewBlob returns a Blob. It requires a RecurseOpts
(you can use DefaultRecurseOpts, call NewRecurseOpts, or provide your own RecurseOpts struct).
It also requires a Folder.
*/
func NewBlob(f *Folder, keyName string, recursion *RecurseOpts) (blob *Blob, err error) {

if !f.isInit {
err = ErrNotInitialized
return
}

blob = &Blob{
DbusObject: f.DbusObject,
Name: keyName,
// Value: "",
Recurse: recursion,
wm: f.wallet.wm,
wallet: f.wallet,
folder: f,
isInit: false,
}

if blob.Recurse.AllWalletItems || blob.Recurse.Blobs {
if err = blob.Update(); err != nil {
return
}
}

blob.isInit = true

return
}

// Update fetches a Blob's Blob.Value.
func (b *Blob) Update() (err error) {

// TODO.

return
}

// isWalletItem is needed for interface membership.
func (b *Blob) isWalletItem() (isWalletItem bool) {

isWalletItem = true

return
}

View File

@ -8,10 +8,10 @@ const (


// KwalletD Dbus enums for WalletItem types. // KwalletD Dbus enums for WalletItem types.
const ( const (
kwalletdEnumTypeUnknown = iota // UnknownItem kwalletdEnumTypeUnknown int32 = iota // UnknownItem (0)
kwalletdEnumTypePassword // Password kwalletdEnumTypePassword // Password (1)
kwalletdEnumTypeStream // Blob kwalletdEnumTypeStream // Blob (2)
kwalletdEnumTypeMap // Map kwalletdEnumTypeMap // Map (3)
kwalletdEnumTypeUnused = 0xffff // 65535 kwalletdEnumTypeUnused = 0xffff // 65535
) )



View File

@ -17,4 +17,10 @@ var (
ErrOperationFailed is a generic failure message that will occur of a Dbus operation returns non-success. ErrOperationFailed is a generic failure message that will occur of a Dbus operation returns non-success.
*/ */
ErrOperationFailed error = errors.New("a Dbus operation has failed to execute successfully") ErrOperationFailed error = errors.New("a Dbus operation has failed to execute successfully")
/*
ErrNoCreate is triggered if attempting to create an item (Folder, Password, etc.) but it fails.
*/
ErrNoCreate error = errors.New("failed to create an object")
// ErrNoDisconnect can occur if trying to disconnect a Wallet from a WalletManager/application and a failure occurs.
ErrNoDisconnect error = errors.New("failed to disconnect wallet from application")
) )

View File

@ -1,9 +1,13 @@
package gokwallet package gokwallet


import (
"github.com/godbus/dbus/v5"
)

/* /*
NewF returns a Wallet. It requires a RecurseOpts NewFolder returns a Folder. It requires a RecurseOpts
(you can use DefaultRecurseOpts, call NewRecurseOpts, or provide your own RecurseOpts struct). (you can use DefaultRecurseOpts, call NewRecurseOpts, or provide your own RecurseOpts struct).
It also requires a WalletManager and wallet name. It also requires a Wallet.
*/ */
func NewFolder(w *Wallet, name string, recursion *RecurseOpts) (folder *Folder, err error) { func NewFolder(w *Wallet, name string, recursion *RecurseOpts) (folder *Folder, err error) {


@ -22,15 +26,14 @@ func NewFolder(w *Wallet, name string, recursion *RecurseOpts) (folder *Folder,
Recurse: recursion, Recurse: recursion,
wm: w.wm, wm: w.wm,
wallet: w, wallet: w,
// handle: 0,
isInit: false, isInit: false,
} }


if err = folder.folderCheck(); err != nil { if folder.Recurse.AllWalletItems ||
return folder.Recurse.Passwords ||
} folder.Recurse.Maps ||

folder.Recurse.Blobs ||
if folder.Recurse.All || folder.Recurse.Wallets { folder.Recurse.UnknownItems {
if err = folder.Update(); err != nil { if err = folder.Update(); err != nil {
return return
} }
@ -41,16 +44,212 @@ func NewFolder(w *Wallet, name string, recursion *RecurseOpts) (folder *Folder,
return return
} }


// Update runs all of the configured Update[type] methods for a Folder, depending on Folder.Recurse configuration.
func (f *Folder) Update() (err error) { func (f *Folder) Update() (err error) {


// TODO. var errs []error = make([]error, 0)

if f.Recurse.AllWalletItems || f.Recurse.Passwords {
if err = f.UpdatePasswords(); err != nil {
errs = append(errs, err)
err = nil
}
}
if f.Recurse.AllWalletItems || f.Recurse.Maps {
if err = f.UpdateMaps(); err != nil {
errs = append(errs, err)
err = nil
}
}
if f.Recurse.AllWalletItems || f.Recurse.Blobs {
if err = f.UpdateBlobs(); err != nil {
errs = append(errs, err)
err = nil
}
}
if f.Recurse.AllWalletItems || f.Recurse.UnknownItems {
if err = f.UpdateUnknowns(); err != nil {
errs = append(errs, err)
err = nil
}
}

if errs != nil && len(errs) > 0 {
err = NewErrors(errs...)
}


return return
} }


func (f *Folder) folderCheck() (err error) { // UpdatePasswords updates (populates) a Folder's Folder.Passwords.
func (f *Folder) UpdatePasswords() (err error) {


// TODO. var mapKeys []string
var variant dbus.Variant
var errs []error = make([]error, 0)

if !f.isInit {
err = ErrNotInitialized
return
}

if err = f.Dbus.Call(
DbusWMPasswordList, 0, f.wallet.handle, f.Name, f.wallet.wm.AppID,
).Store(&variant); err != nil {
return
}

mapKeys = bytemapKeys(variant)

f.Passwords = make(map[string]*Password, len(mapKeys))

for _, k := range mapKeys {
if f.Passwords[k], err = NewPassword(f, k, f.Recurse); err != nil {
errs = append(errs, err)
err = nil
}
}

if errs != nil && len(errs) > 0 {
err = NewErrors(errs...)
}

return
}

// UpdateMaps updates (populates) a Folder's Folder.Maps.
func (f *Folder) UpdateMaps() (err error) {

var mapKeys []string
var variant dbus.Variant
var errs []error = make([]error, 0)

if err = f.Dbus.Call(
DbusWMMapList, 0, f.wallet.handle, f.Name, f.wallet.wm.AppID,
).Store(&variant); err != nil {
return
}

mapKeys = bytemapKeys(variant)

f.Maps = make(map[string]*Map, len(mapKeys))

for _, k := range mapKeys {
if f.Maps[k], err = NewMap(f, k, f.Recurse); err != nil {
errs = append(errs, err)
err = nil
}
}

if errs != nil && len(errs) > 0 {
err = NewErrors(errs...)
}

return
}

// UpdateBlobs updates (populates) a Folder's Folder.BinaryData.
func (f *Folder) UpdateBlobs() (err error) {

var mapKeys []string
var isBlob bool
var variant dbus.Variant
var errs []error = make([]error, 0)

if !f.isInit {
err = ErrNotInitialized
return
}

if err = f.Dbus.Call(
DbusWMEntriesList, 0, f.wallet.handle, f.Name, f.wallet.wm.AppID,
).Store(&variant); err != nil {
return
}

mapKeys = bytemapKeys(variant)

f.BinaryData = make(map[string]*Blob, len(mapKeys))

for _, k := range mapKeys {
if isBlob, err = f.isType(k, kwalletdEnumTypeStream); err != nil {
errs = append(errs, err)
err = nil
continue
}
if !isBlob {
continue
}

if f.BinaryData[k], err = NewBlob(f, k, f.Recurse); err != nil {
errs = append(errs, err)
err = nil
}
}

if errs != nil && len(errs) > 0 {
err = NewErrors(errs...)
}

return
}

// UpdateUnknowns updates (populates) a Folder's Folder.Unknown.
func (f *Folder) UpdateUnknowns() (err error) {

var mapKeys []string
var isUnknown bool
var variant dbus.Variant
var errs []error = make([]error, 0)

if !f.isInit {
err = ErrNotInitialized
return
}

if err = f.Dbus.Call(
DbusWMEntriesList, 0, f.wallet.handle, f.Name, f.wallet.wm.AppID,
).Store(&variant); err != nil {
return
}

mapKeys = bytemapKeys(variant)

f.Unknown = make(map[string]*UnknownItem, len(mapKeys))

for _, k := range mapKeys {
if isUnknown, err = f.isType(k, kwalletdEnumTypeUnknown); err != nil {
errs = append(errs, err)
err = nil
continue
}
if !isUnknown {
continue
}

if f.Unknown[k], err = NewUnknownItem(f, k, f.Recurse); err != nil {
errs = append(errs, err)
err = nil
}
}

if errs != nil && len(errs) > 0 {
err = NewErrors(errs...)
}

return
}

// isType checks if a certain key keyName is of type typeCheck (via kwalletdEnumType*).
func (f *Folder) isType(keyName string, typeCheck int32) (isOfType bool, err error) {

var entryType int32

if err = f.Dbus.Call(
DbusWMEntryType, 0, f.wallet.handle, f.Name, keyName, f.wallet.wm.AppID,
).Store(&entryType); err != nil {
return
}


return return
} }

51
map_funcs.go Normal file
View File

@ -0,0 +1,51 @@
package gokwallet

/*
NewMap returns a Map. It requires a RecurseOpts
(you can use DefaultRecurseOpts, call NewRecurseOpts, or provide your own RecurseOpts struct).
It also requires a Folder.
*/
func NewMap(f *Folder, keyName string, recursion *RecurseOpts) (m *Map, err error) {

if !f.isInit {
err = ErrNotInitialized
return
}

m = &Map{
DbusObject: f.DbusObject,
Name: keyName,
// Value: "",
Recurse: recursion,
wm: f.wallet.wm,
wallet: f.wallet,
folder: f,
isInit: false,
}

if m.Recurse.AllWalletItems || m.Recurse.Maps {
if err = m.Update(); err != nil {
return
}
}

m.isInit = true

return
}

// Update fetches a Map's Map.Value.
func (m *Map) Update() (err error) {

// TODO.

return
}

// isWalletItem is needed for interface membership.
func (m *Map) isWalletItem() (isWalletItem bool) {

isWalletItem = true

return
}

51
password_funcs.go Normal file
View File

@ -0,0 +1,51 @@
package gokwallet

/*
NewPassword returns a Password. It requires a RecurseOpts
(you can use DefaultRecurseOpts, call NewRecurseOpts, or provide your own RecurseOpts struct).
It also requires a Folder.
*/
func NewPassword(f *Folder, keyName string, recursion *RecurseOpts) (password *Password, err error) {

if !f.isInit {
err = ErrNotInitialized
return
}

password = &Password{
DbusObject: f.DbusObject,
Name: keyName,
// Value: "",
Recurse: recursion,
wm: f.wallet.wm,
wallet: f.wallet,
folder: f,
isInit: false,
}

if password.Recurse.AllWalletItems || password.Recurse.Passwords {
if err = password.Update(); err != nil {
return
}
}

password.isInit = true

return
}

// Update fetches a Password's Password.Value.
func (p *Password) Update() (err error) {

// TODO.

return
}

// isWalletItem is needed for interface membership.
func (p *Password) isWalletItem() (isWalletItem bool) {

isWalletItem = true

return
}

View File

@ -121,8 +121,6 @@ type Folder struct {
wm *WalletManager wm *WalletManager
// wallet is the parent Wallet this Folder was fetched from. // wallet is the parent Wallet this Folder was fetched from.
wallet *Wallet wallet *Wallet
// handle is this Folder's handler number.
handle int32
// isInit flags whether this is "properly" set up (i.e. has a handle). // isInit flags whether this is "properly" set up (i.e. has a handle).
isInit bool isInit bool
} }
@ -142,8 +140,6 @@ type Password struct {
wallet *Wallet wallet *Wallet
// folder is the parent Folder this Password was fetched from. // folder is the parent Folder this Password was fetched from.
folder *Folder folder *Folder
// handle is this Password's handler number.
handle int32
// isInit flags whether this is "properly" set up (i.e. has a handle). // isInit flags whether this is "properly" set up (i.e. has a handle).
isInit bool isInit bool
} }
@ -163,8 +159,6 @@ type Map struct {
wallet *Wallet wallet *Wallet
// folder is the parent Folder this Map was fetched from. // folder is the parent Folder this Map was fetched from.
folder *Folder folder *Folder
// handle is this Map's handler number.
handle int32
// isInit flags whether this is "properly" set up (i.e. has a handle). // isInit flags whether this is "properly" set up (i.e. has a handle).
isInit bool isInit bool
} }
@ -184,8 +178,6 @@ type Blob struct {
wallet *Wallet wallet *Wallet
// folder is the parent Folder this Blob was fetched from. // folder is the parent Folder this Blob was fetched from.
folder *Folder folder *Folder
// handle is this Blob's handler number.
handle int32
// isInit flags whether this is "properly" set up (i.e. has a handle). // isInit flags whether this is "properly" set up (i.e. has a handle).
isInit bool isInit bool
} }
@ -209,8 +201,6 @@ type UnknownItem struct {
wallet *Wallet wallet *Wallet
// folder is the parent Folder this UnknownItem was fetched from. // folder is the parent Folder this UnknownItem was fetched from.
folder *Folder folder *Folder
// handle is this UnknownItem's handler number.
handle int32
// isInit flags whether this is "properly" set up (i.e. has a handle). // isInit flags whether this is "properly" set up (i.e. has a handle).
isInit bool isInit bool
} }

51
unknownitem_funcs.go Normal file
View File

@ -0,0 +1,51 @@
package gokwallet

/*
NewUnknownItem returns an UnknownItem. It requires a RecurseOpts
(you can use DefaultRecurseOpts, call NewRecurseOpts, or provide your own RecurseOpts struct).
It also requires a Folder.
*/
func NewUnknownItem(f *Folder, keyName string, recursion *RecurseOpts) (unknown *UnknownItem, err error) {

if !f.isInit {
err = ErrNotInitialized
return
}

unknown = &UnknownItem{
DbusObject: f.DbusObject,
Name: keyName,
// Value: "",
Recurse: recursion,
wm: f.wallet.wm,
wallet: f.wallet,
folder: f,
isInit: false,
}

if unknown.Recurse.AllWalletItems || unknown.Recurse.UnknownItems {
if err = unknown.Update(); err != nil {
return
}
}

unknown.isInit = true

return
}

// Update fetches an UnknownItem's UnknownItem.Value.
func (u *UnknownItem) Update() (err error) {

// TODO.

return
}

// isWalletItem is needed for interface membership.
func (u *UnknownItem) isWalletItem() (isWalletItem bool) {

isWalletItem = true

return
}

View File

@ -1,5 +1,9 @@
package gokwallet package gokwallet


import (
"github.com/godbus/dbus/v5"
)

/* /*
resultCheck checks the result code from a Dbus call and returns an error if not successful. resultCheck checks the result code from a Dbus call and returns an error if not successful.
See also resultPassed. See also resultPassed.
@ -12,6 +16,8 @@ func resultCheck(result int32) (err error) {
err = nil err = nil
case DbusFailure: case DbusFailure:
err = ErrOperationFailed err = ErrOperationFailed
default:
err = ErrOperationFailed
} }


return return
@ -29,6 +35,26 @@ func resultPassed(result int32) (passed bool) {
passed = true passed = true
case DbusFailure: case DbusFailure:
passed = false passed = false
default:
passed = false
}

return
}

// bytemapKeys is used to parse out Map names when fetching from Dbus.
func bytemapKeys(variant dbus.Variant) (keyNames []string) {

var d map[string]dbus.Variant

d = variant.Value().(map[string]dbus.Variant)

keyNames = make([]string, len(d))

idx := 0
for k, _ := range d {
keyNames[idx] = k
idx++
} }


return return

View File

@ -1,5 +1,9 @@
package gokwallet package gokwallet


import (
"github.com/godbus/dbus/v5"
)

/* /*
NewWallet returns a Wallet. It requires a RecurseOpts NewWallet returns a Wallet. It requires a RecurseOpts
(you can use DefaultRecurseOpts, call NewRecurseOpts, or provide your own RecurseOpts struct). (you can use DefaultRecurseOpts, call NewRecurseOpts, or provide your own RecurseOpts struct).
@ -27,7 +31,7 @@ func NewWallet(wm *WalletManager, name string, recursion *RecurseOpts) (wallet *
return return
} }


if wallet.Recurse.All || wallet.Recurse.Wallets { if wallet.Recurse.All || wallet.Recurse.Folders {
if err = wallet.Update(); err != nil { if err = wallet.Update(); err != nil {
return return
} }
@ -38,13 +42,73 @@ func NewWallet(wm *WalletManager, name string, recursion *RecurseOpts) (wallet *
return return
} }


// Disconnect disconnects this Wallet from its parent WalletManager.
func (w *Wallet) Disconnect() (err error) {

var ok bool

if err = w.walletCheck(); err != nil {
return
}

if err = w.Dbus.Call(
DbusWMDisconnectApp, 0, w.Name, w.wm.AppID,
).Store(&ok); err != nil {
return
}

if !ok {
err = ErrNoDisconnect
}

return
}

// DisconnectApplication disconnects this Wallet from a specified WalletManager/application (see Wallet.Connections).
func (w *Wallet) DisconnectApplication(appName string) (err error) {

var ok bool

if err = w.walletCheck(); err != nil {
return
}

if err = w.Dbus.Call(
DbusWMDisconnectApp, 0, appName, w.wm.AppID,
).Store(&ok); err != nil {
return
}

if !ok {
err = ErrNoDisconnect
}

return
}

/*
ChangePassword will change (or set) the password for a Wallet.
Note that this *must* be done via the windowing layer.
*/
func (w *Wallet) ChangePassword() (err error) {

var call *dbus.Call

call = w.Dbus.Call(
DbusWMChangePassword, 0, w.Name, DefaultWindowID, w.wm.AppID,
)

err = call.Err

return
}

// Close closes a Wallet. // Close closes a Wallet.
func (w *Wallet) Close() (err error) { func (w *Wallet) Close() (err error) {


var rslt int32 var rslt int32


if !w.isInit { if err = w.walletCheck(); err != nil {
err = ErrNotInitialized
return return
} }


@ -60,6 +124,80 @@ func (w *Wallet) Close() (err error) {
return return
} }


// Connections lists the application names for connections to ("users of") this Wallet.
func (w *Wallet) Connections() (connList []string, err error) {

if err = w.walletCheck(); err != nil {
return
}

if err = w.Dbus.Call(
DbusWMUsers, 0, w.Name,
).Store(&connList); err != nil {
return
}

return
}

// CreateFolder creates a new Folder in a Wallet.
func (w *Wallet) CreateFolder(name string) (err error) {

var ok bool

if err = w.walletCheck(); err != nil {
return
}

if err = w.Dbus.Call(
DbusWMCreateFolder, 0, w.handle, name, w.wm.AppID,
).Store(&ok); err != nil {
return
}

if !ok {
err = ErrNoCreate
}

return
}

// Delete deletes a Wallet.
func (w *Wallet) Delete() (err error) {

var rslt int32

if err = w.walletCheck(); err != nil {
return
}

if err = w.Dbus.Call(
DbusWMDeleteWallet, 0, w.Name,
).Store(&rslt); err != nil {
return
}

err = resultCheck(rslt)

return
}

// FolderExists indicates if a Folder exists in a Wallet or not.
func (w *Wallet) FolderExists(folderName string) (exists bool, err error) {

var notExists bool

if err = w.Dbus.Call(
DbusWMFolderNotExist, 0, w.Name, folderName,
).Store(&notExists); err != nil {
return
}

exists = !notExists

return
}

/* /*
ForceClose is like Close but will still close a Wallet even if currently in use by the WalletManager. ForceClose is like Close but will still close a Wallet even if currently in use by the WalletManager.
(Despite the insinuation by the name, this should be a relatively safe operation). (Despite the insinuation by the name, this should be a relatively safe operation).
@ -83,8 +221,6 @@ func (w *Wallet) ForceClose() (err error) {
err = resultCheck(rslt) err = resultCheck(rslt)


return return

return
} }


// IsOpen returns whether a Wallet is open ("unlocked") or not (as well as updates Wallet.IsOpen). // IsOpen returns whether a Wallet is open ("unlocked") or not (as well as updates Wallet.IsOpen).
@ -124,6 +260,8 @@ func (w *Wallet) ListFolders() (folderList []string, err error) {
*/ */
func (w *Wallet) Open() (err error) { func (w *Wallet) Open() (err error) {


var handler *int32

if _, err = w.IsOpen(); err != nil { if _, err = w.IsOpen(); err != nil {
return return
} }
@ -131,11 +269,18 @@ func (w *Wallet) Open() (err error) {
if !w.IsUnlocked { if !w.IsUnlocked {
if err = w.Dbus.Call( if err = w.Dbus.Call(
DbusWMOpen, 0, DbusWMOpen, 0,
).Store(&w.handle); err != nil { ).Store(handler); err != nil {
return return
} }
} }


if handler == nil {
err = ErrOperationFailed
return
} else {
w.handle = *handler
}

w.IsUnlocked = true w.IsUnlocked = true


return return

View File

@ -104,7 +104,7 @@ func (wm *WalletManager) CloseWallet(walletName string) (err error) {
Unlike Wallet.ForceClose, this closes access for ALL applications/WalletManagers Unlike Wallet.ForceClose, this closes access for ALL applications/WalletManagers
for the specified Wallet - not just this WalletManager. for the specified Wallet - not just this WalletManager.
*/ */
func (wm *WalletManager) FprceCloseWallet(walletName string) (err error) { func (wm *WalletManager) ForceCloseWallet(walletName string) (err error) {


var rslt int32 var rslt int32


@ -202,7 +202,7 @@ func (wm *WalletManager) NetworkWallet() (w *Wallet, err error) {
return return
} }


// WalletNames returns a list of available Wallet names. // WalletNames returns a list of existing Wallet names.
func (wm *WalletManager) WalletNames() (wallets []string, err error) { func (wm *WalletManager) WalletNames() (wallets []string, err error) {


if err = wm.Dbus.Call( if err = wm.Dbus.Call(