From 1d9145bcf24ff49fe125094bf55788c3562c77ec Mon Sep 17 00:00:00 2001 From: brent s Date: Tue, 30 Nov 2021 02:33:07 -0500 Subject: [PATCH] adding some funcs for Service. still need two or three more, then Service is done (but untested). --- collection_funcs.go | 12 ++- consts.go | 4 +- errs.go | 2 + service_funcs.go | 258 +++++++++++++++++++++++++++++--------------- session_funcs.go | 8 +- 5 files changed, 186 insertions(+), 98 deletions(-) diff --git a/collection_funcs.go b/collection_funcs.go index 9f11d53..5029d62 100644 --- a/collection_funcs.go +++ b/collection_funcs.go @@ -1,10 +1,10 @@ package gosecret import ( - `strings` - `time` + "strings" + "time" - `github.com/godbus/dbus` + "github.com/godbus/dbus" ) /* @@ -38,8 +38,10 @@ func NewCollection(conn *dbus.Conn, path dbus.ObjectPath) (coll *Collection, err } coll = &Collection{ - Conn: conn, - Dbus: conn.Object(DbusService, path), + DbusObject: &DbusObject{ + Conn: conn, + Dbus: conn.Object(DbusService, path), + }, // lastModified: time.Now(), } diff --git a/consts.go b/consts.go index 90c189c..9243c0d 100644 --- a/consts.go +++ b/consts.go @@ -27,13 +27,13 @@ const ( // DbusServiceCreateCollection is used to create a new Collection via Service.CreateCollection. DbusServiceCreateCollection string = DbusInterfaceService + ".CreateCollection" - // DbusServiceGetSecrets is used to fetch all Secret / Item items in a given Collection (via Service.GetSecrets). + // DbusServiceGetSecrets is used to fetch multiple Secret values from multiple Item items in a given Collection (via Service.GetSecrets). DbusServiceGetSecrets string = DbusInterfaceService + ".GetSecrets" // DbusServiceLock is used by Service.Lock. DbusServiceLock string = DbusInterfaceService + ".Lock" - // DbusServiceLockService is [FUNCTION UNKNOWN; TODO.] + // DbusServiceLockService is [FUNCTION UNKNOWN/UNDOCUMENTED; TODO.] DbusServiceLockService string = DbusInterfaceService + ".LockService" // DbusServiceOpenSession is used by Service.Open. diff --git a/errs.go b/errs.go index e685895..7569eac 100644 --- a/errs.go +++ b/errs.go @@ -12,6 +12,8 @@ var ( ErrInvalidProperty error = errors.New("invalid variant type; cannot convert") // ErrNoDbusConn gets triggered if a connection to Dbus can't be detected. ErrNoDbusConn error = errors.New("no valid dbus connection") + // ErrMissingPaths gets triggered if one or more Dbus object paths are expected but non/not enough are received. + ErrMissingPaths error = errors.New("one or more Dbus object paths were expected but an insufficient amount were received") ) /* diff --git a/service_funcs.go b/service_funcs.go index af5e2c0..e43befb 100644 --- a/service_funcs.go +++ b/service_funcs.go @@ -14,7 +14,7 @@ func NewService() (service *Service, err error) { } svc.Dbus = service.Conn.Object(DbusService, dbus.ObjectPath(DbusPath)) - if svc.Session, err = svc.Open(); err != nil { + if svc.Session, _, err = svc.Open(); err != nil { return } @@ -23,6 +23,152 @@ func NewService() (service *Service, err error) { return } +// Collections returns a slice of Collection items accessible to this Service. +func (s *Service) Collections() (collections []Collection, err error) { + + var paths []dbus.ObjectPath + var variant dbus.Variant + var coll *Collection + var errs []error = make([]error, 0) + + if variant, err = s.Dbus.GetProperty(DbusServiceCollections); err != nil { + return + } + + paths = variant.Value().([]dbus.ObjectPath) + + collections = make([]Collection, len(paths)) + + for idx, path := range paths { + if coll, err = NewCollection(s.Conn, path); err != nil { + // return + errs = append(errs, err) + err = nil + } + collections[idx] = *coll + } + err = NewErrors(err) + + return +} + +/* + CreateAliasedCollection creates a new Collection (keyring) via a Service with the name specified by label, + aliased to the name specified by alias, and returns the new Collection. +*/ +func (s *Service) CreateAliasedCollection(label, alias string) (collection *Collection, err error) { + + var variant *dbus.Variant + var path dbus.ObjectPath + var promptPath dbus.ObjectPath + var prompt *Prompt + var props map[string]dbus.Variant = make(map[string]dbus.Variant) + + props[DbusCollectionLabel] = dbus.MakeVariant(label) + + if err = s.Dbus.Call( + DbusServiceCreateCollection, 0, props, alias, + ).Store(&path, &promptPath); err != nil { + return + } + + if isPrompt(promptPath) { + + prompt = NewPrompt(s.Conn, promptPath) + + if variant, err = prompt.Prompt(); err != nil { + return + } + + path = variant.Value().(dbus.ObjectPath) + } + + collection, err = NewCollection(s.Conn, path) + + return +} + +/* + CreateCollection creates a new Collection (keyring) via a Service with the name specified by label and returns the new Collection. + It is a *very* thin wrapper around Service.CreateAliasedCollection, but with a blank alias. +*/ +func (s *Service) CreateCollection(label string) (collection *Collection, err error) { + + collection, err = s.CreateAliasedCollection(label, "") + + return +} + +/* + GetSecrets allows you to fetch values (Secret) from multiple Item object paths using this Service's Session. + An ErrMissingPaths will be returned for err if itemPaths is nil or empty. + The returned secrets is a map with itemPaths as the keys and their corresponding Secret as the value. +*/ +func (s *Service) GetSecrets(itemPaths ...dbus.ObjectPath) (secrets map[dbus.ObjectPath]*Secret, err error) { + + if itemPaths == nil || len(itemPaths) == 0 { + err = ErrMissingPaths + return + } + + secrets = make(map[dbus.ObjectPath]*Secret, len(itemPaths)) + + // TODO: trigger a Service.Unlock for any locked items? + /* + // TODO: make any errs in here a MultiError instead. + for _, secretPath := range itemPaths { + if err = s.Dbus.Call( + DbusServiceGetSecrets, 0, secretPath, + ).Store(&result); err != nil { + return + } + } + */ + if err = s.Dbus.Call( + DbusServiceGetSecrets, 0, itemPaths, + ).Store(&secrets); err != nil { + return + } + + return +} + +/* + Lock locks an Unlocked Service, Collection, etc. + You can usually get objectPath for the object(s) to unlock via .Dbus.Path(). + If objectPaths is nil or empty, the Service's own path will be used. +*/ +func (s *Service) Lock(objectPaths ...dbus.ObjectPath) (err error) { + + var locked []dbus.ObjectPath + var prompt *Prompt + var resultPath dbus.ObjectPath + + if objectPaths == nil || len(objectPaths) == 0 { + objectPaths = []dbus.ObjectPath{s.Dbus.Path()} + } + + // TODO: make any errs in here a MultiError instead. + for _, p := range objectPaths { + if err = s.Dbus.Call( + DbusServiceLock, 0, p, + ).Store(&locked, &resultPath); err != nil { + return + } + + if isPrompt(resultPath) { + + prompt = NewPrompt(s.Conn, resultPath) + + if _, err = prompt.Prompt(); err != nil { + return + } + } + } + + return +} + // Open returns a pointer to a Session from the Service. func (s *Service) Open() (session *Session, output dbus.Variant, err error) { @@ -43,101 +189,37 @@ func (s *Service) Open() (session *Session, output dbus.Variant, err error) { return } -// Collections returns a slice of Collection items accessible to this Service. -func (s *Service) Collections() (collections []Collection, err error) { - - var paths []dbus.ObjectPath - var variant dbus.Variant - - if variant, err = s.Dbus.GetProperty("org.freedesktop.Secret.Service.Collections"); err != nil { - return - } - - paths = variant.Value().([]dbus.ObjectPath) - - collections = make([]Collection, len(paths)) - - for idx, path := range paths { - collections[idx] = *NewCollection(s.Conn, path) - } - - return -} - -// CreateCollection creates a new Collection (keyring) via a Service with the name specified by label and returns the new Collection. -func (s *Service) CreateCollection(label string) (collection *Collection, err error) { - - var variant *dbus.Variant - var path dbus.ObjectPath - var promptPath dbus.ObjectPath - var prompt *Prompt - var props map[string]dbus.Variant = make(map[string]dbus.Variant) - - props["org.freedesktop.Secret.Collection.Label"] = dbus.MakeVariant(label) - - if err = s.Dbus.Call("org.freedesktop.Secret.Service.CreateCollection", 0, props, "").Store(&path, &promptPath); err != nil { - return - } - - if isPrompt(promptPath) { - - prompt = NewPrompt(s.Conn, promptPath) - - if variant, err = prompt.Prompt(); err != nil { - return - } - - path = variant.Value().(dbus.ObjectPath) - } - - collection = NewCollection(s.Conn, path) - - return -} - -// Unlock unlocks a Locked Service. -func (s *Service) Unlock(object DBusObject) (err error) { +/* + Unlock unlocks a Locked Service, Collection, etc. + You can usually get objectPath for the object(s) to unlock via .Dbus.Path(). + If objectPaths is nil or empty, the Service's own path will be used. +*/ +func (s *Service) Unlock(objectPaths ...dbus.ObjectPath) (err error) { var unlocked []dbus.ObjectPath var prompt *Prompt - var promptPath dbus.ObjectPath - var paths []dbus.ObjectPath = []dbus.ObjectPath{object.Path()} + var resultPath dbus.ObjectPath - if err = s.Dbus.Call("org.freedesktop.Secret.Service.Unlock", 0, paths).Store(&unlocked, &promptPath); err != nil { - return + if objectPaths == nil || len(objectPaths) == 0 { + objectPaths = []dbus.ObjectPath{s.Dbus.Path()} } - if isPrompt(promptPath) { - - prompt = NewPrompt(s.Conn, promptPath) - - if _, err = prompt.Prompt(); err != nil { - return - } - } - - return -} - -// Lock locks an Unlocked Service. -func (s *Service) Lock(object DBusObject) (err error) { - - var locked []dbus.ObjectPath - var prompt *Prompt - var promptPath dbus.ObjectPath - var paths []dbus.ObjectPath = []dbus.ObjectPath{object.Path()} - - if err = s.Dbus.Call("org.freedesktop.Secret.Service.Lock", 0, paths).Store(&locked, &promptPath); err != nil { - return - } - - if isPrompt(promptPath) { - - prompt = NewPrompt(s.Conn, promptPath) - - if _, err = prompt.Prompt(); err != nil { + // TODO: make any errs in here a MultiError instead. + for _, p := range objectPaths { + if err = s.Dbus.Call( + DbusServiceUnlock, 0, p, + ).Store(&unlocked, &resultPath); err != nil { return } + + if isPrompt(resultPath) { + + prompt = NewPrompt(s.Conn, resultPath) + + if _, err = prompt.Prompt(); err != nil { + return + } + } } return diff --git a/session_funcs.go b/session_funcs.go index 02791b9..642dc35 100644 --- a/session_funcs.go +++ b/session_funcs.go @@ -1,15 +1,17 @@ package gosecret import ( - `github.com/godbus/dbus` + "github.com/godbus/dbus" ) // NewSession returns a pointer to a new Session based on a Dbus connection and a Dbus path. func NewSession(conn *dbus.Conn, path dbus.ObjectPath) (session *Session) { session = &Session{ - Conn: conn, - Dbus: conn.Object(DbusService, path), + &DbusObject{ + Conn: conn, + Dbus: conn.Object(DbusService, path), + }, } return