v0.0.1 is now done.

Cleaned up file naming/organization, optimized some things like using preallocated indexed slices instead of
appends, etc.
This commit is contained in:
brent s 2021-11-21 18:07:52 -05:00
parent a6f4afe491
commit 5975b5ed5c
Signed by: bts
GPG Key ID: 8C004C2F93481F6B
19 changed files with 644 additions and 442 deletions

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)


Copyright (c) 2016 Goran Sterjov Copyright (c) 2021 Brent Saner


Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.


62
README.adoc Normal file
View File

@ -0,0 +1,62 @@
= libsecret/gosecret
Brent Saner <bts@square-r00t.net>
Last updated {localdatetime}
:doctype: book
:docinfo: shared
:data-uri:
:imagesdir: images
:sectlinks:
:sectnums:
:sectnumlevels: 7
:toc: preamble
:toc2: left
:idprefix:
:toclevels: 7
:source-highlighter: rouge

This project is originally forked from https://github.com/gsterjov/go-libsecret[go-libsecret^] due to:

* Lack of response from the developer
* Complete lack of documentation
* Poor, ineffecient, or just plain antipattern design
* Missing functionality

and as such, hopefully this library should serve as a more effective libsecret/SecretService interface.

== Backwards Compatability/Drop-In Replacement Support
Version series `v0.X.X` of this library promises full and non-breaking backwards support of API interaction with the original project. The only changes should be internal optimizations, adding documentation, some file reorganizing, adding Golang module support, etc. -- all transparent from the library API itself.

To use this library as a replacement without significantly modifying your code, you can simply use a `replace` directive:

// TODO: did I do this correctly? I never really use replacements so someone PR if this is incorrect.
.go.mod
[source]
----
# ...
replace (
github.com/gsterjov/go-libsecret dev => r00t2.io/gosecret v0
)
----

and then run `go mod tidy`.

== New Developer API
Starting from `v1.0.0` onwards, entirely breaking changes can be assumed from the original project.

To use the new version,

[source,go]
----
import (
`r00t2.io/gosecret/v1`
)
----

To reflect the absolute breaking changes, the module name changes as well from `libsecret` to `gosecret`.

== Usage
Full documentation can be found via inline documentation. Either via the https://pkg.go.dev/r00t2.io/gosecret[pkg.go.dev documentation^] or https://pkg.go.dev/golang.org/x/tools/cmd/godoc[`godoc`^] (or `go doc`) in the source root.

////
However, here's a quick demonstration.
////

View File

@ -1,124 +0,0 @@
package libsecret

import "github.com/godbus/dbus"


type Collection struct {
conn *dbus.Conn
dbus dbus.BusObject
}


func NewCollection(conn *dbus.Conn, path dbus.ObjectPath) *Collection {
return &Collection{
conn: conn,
dbus: conn.Object(DBusServiceName, path),
}
}


func (collection Collection) Path() dbus.ObjectPath {
return collection.dbus.Path()
}


// READ Array<ObjectPath> Items;
func (collection *Collection) Items() ([]Item, error) {
val, err := collection.dbus.GetProperty("org.freedesktop.Secret.Collection.Items")
if err != nil {
return []Item{}, err
}

items := []Item{}
for _, path := range val.Value().([]dbus.ObjectPath) {
items = append(items, *NewItem(collection.conn, path))
}

return items, nil
}


// Delete (OUT ObjectPath prompt);
func (collection *Collection) Delete() error {
var prompt dbus.ObjectPath

err := collection.dbus.Call("org.freedesktop.Secret.Collection.Delete", 0).Store(&prompt)
if err != nil {
return err
}

if isPrompt(prompt) {
prompt := NewPrompt(collection.conn, prompt)

_, err := prompt.Prompt()
if err != nil {
return err
}
}

return nil
}


// SearchItems (IN Dict<String,String> attributes, OUT Array<ObjectPath> results);
func (collection *Collection) SearchItems(profile string) ([]Item, error) {
attributes := make(map[string]string)
attributes["profile"] = profile

var paths []dbus.ObjectPath

err := collection.dbus.Call("org.freedesktop.Secret.Collection.SearchItems", 0, attributes).Store(&paths)
if err != nil {
return []Item{}, err
}

items := []Item{}
for _, path := range paths {
items = append(items, *NewItem(collection.conn, path))
}

return items, nil
}


// CreateItem (IN Dict<String,Variant> properties, IN Secret secret, IN Boolean replace, OUT ObjectPath item, OUT ObjectPath prompt);
func (collection *Collection) CreateItem(label string, secret *Secret, replace bool) (*Item, error) {
properties := make(map[string]dbus.Variant)
attributes := make(map[string]string)

attributes["profile"] = label
properties["org.freedesktop.Secret.Item.Label"] = dbus.MakeVariant(label)
properties["org.freedesktop.Secret.Item.Attributes"] = dbus.MakeVariant(attributes)

var path dbus.ObjectPath
var prompt dbus.ObjectPath

err := collection.dbus.Call("org.freedesktop.Secret.Collection.CreateItem", 0, properties, secret, replace).Store(&path, &prompt)
if err != nil {
return &Item{}, err
}

if isPrompt(prompt) {
prompt := NewPrompt(collection.conn, prompt)

result, err := prompt.Prompt()
if err != nil {
return &Item{}, err
}

path = result.Value().(dbus.ObjectPath)
}

return NewItem(collection.conn, path), nil
}


// READ Boolean Locked;
func (collection *Collection) Locked() (bool, error) {
val, err := collection.dbus.GetProperty("org.freedesktop.Secret.Collection.Locked")
if err != nil {
return true, err
}

return val.Value().(bool), nil
}

138
collection_funcs.go Normal file
View File

@ -0,0 +1,138 @@
package libsecret

import (
`github.com/godbus/dbus`
)

// NewCollection returns a pointer to a new Collection based on a Dbus connection and a Dbus path.
func NewCollection(conn *dbus.Conn, path dbus.ObjectPath) (coll *Collection) {

coll = &Collection{
Conn: conn,
Dbus: conn.Object(DBusServiceName, path),
}

return
}

// Path returns the dbus.ObjectPath of the Collection.
func (c Collection) Path() (coll dbus.ObjectPath) {

// Remove this method in V1. It's bloat since we now have an exported Dbus.
coll = c.Dbus.Path()

return
}

// Items returns a slice of Item items in the Collection.
func (c *Collection) Items() (items []Item, err error) {

var variant dbus.Variant
var paths []dbus.ObjectPath

if variant, err = c.Dbus.GetProperty("org.freedesktop.Secret.Collection.Items"); err != nil {
return
}

paths = variant.Value().([]dbus.ObjectPath)

items = make([]Item, len(paths))

for idx, path := range paths {
items[idx] = *NewItem(c.Conn, path)
}

return
}

// Delete removes a Collection.
func (c *Collection) Delete() (err error) {

var promptPath dbus.ObjectPath
var prompt *Prompt

if err = c.Dbus.Call("org.freedesktop.Secret.Collection.Delete", 0).Store(&promptPath); err != nil {
return
}

if isPrompt(promptPath) {

prompt = NewPrompt(c.Conn, promptPath)
if _, err = prompt.Prompt(); err != nil {
return
}
}

return
}

// SearchItems searches a Collection for a matching profile string.
func (c *Collection) SearchItems(profile string) (items []Item, err error) {

var paths []dbus.ObjectPath
var attrs map[string]string = make(map[string]string, 0)

attrs["profile"] = profile

if err = c.Dbus.Call("org.freedesktop.Secret.Collection.SearchItems", 0, attrs).Store(&paths); err != nil {
return
}

items = make([]Item, len(paths))

for idx, path := range paths {
items[idx] = *NewItem(c.Conn, path)
}

return
}

// CreateItem returns a pointer to an Item based on a label, a Secret, and whether any existing secret should be replaced or not.
func (c *Collection) CreateItem(label string, secret *Secret, replace bool) (item *Item, err error) {

var prompt *Prompt
var path dbus.ObjectPath
var promptPath dbus.ObjectPath
var variant *dbus.Variant
var props map[string]dbus.Variant = make(map[string]dbus.Variant)
var attrs map[string]string = make(map[string]string)

attrs["profile"] = label
props["org.freedesktop.Secret.Item.Label"] = dbus.MakeVariant(label)
props["org.freedesktop.Secret.Item.Attributes"] = dbus.MakeVariant(attrs)

if err = c.Dbus.Call(
"org.freedesktop.Secret.Collection.CreateItem", 0, props, secret, replace,
).Store(&path, &promptPath); err != nil {
return
}

if isPrompt(promptPath) {
prompt = NewPrompt(c.Conn, promptPath)

if variant, err = prompt.Prompt(); err != nil {
return
}

path = variant.Value().(dbus.ObjectPath)
}

item = NewItem(c.Conn, path)

return
}

// Locked indicates that a Collection is locked (true) or unlocked (false).
func (c *Collection) Locked() (isLocked bool, err error) {

var variant dbus.Variant

if variant, err = c.Dbus.GetProperty("org.freedesktop.Secret.Collection.Locked"); err != nil {
isLocked = true
return
}

isLocked = variant.Value().(bool)

return
}

7
consts.go Normal file
View File

@ -0,0 +1,7 @@
package libsecret

const (
DBusServiceName string = "org.freedesktop.secrets"
DBusPath string = "/org/freedesktop/secrets"
PromptPrefix string = DBusPath + "/prompt/"
)

16
funcs.go Normal file
View File

@ -0,0 +1,16 @@
package libsecret

import (
`strings`

`github.com/godbus/dbus`
)

// isPrompt returns a boolean that is true if path is/requires a prompt(ed path) and false if it is/does not.
func isPrompt(path dbus.ObjectPath) (prompt bool) {

prompt = strings.HasPrefix(string(path), PromptPrefix)

return

}

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module r00t2.io/gosecret

go 1.17

require github.com/godbus/dbus v4.1.0+incompatible

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4=
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=

77
item.go
View File

@ -1,77 +0,0 @@
package libsecret

import "github.com/godbus/dbus"


type Item struct {
conn *dbus.Conn
dbus dbus.BusObject
}


func NewItem(conn *dbus.Conn, path dbus.ObjectPath) *Item {
return &Item{
conn: conn,
dbus: conn.Object(DBusServiceName, path),
}
}


func (item Item) Path() dbus.ObjectPath {
return item.dbus.Path()
}


// READWRITE String Label;
func (item *Item) Label() (string, error) {
val, err := item.dbus.GetProperty("org.freedesktop.Secret.Item.Label")
if err != nil {
return "", err
}

return val.Value().(string), nil
}


// READ Boolean Locked;
func (item *Item) Locked() (bool, error) {
val, err := item.dbus.GetProperty("org.freedesktop.Secret.Item.Locked")
if err != nil {
return true, err
}

return val.Value().(bool), nil
}


// GetSecret (IN ObjectPath session, OUT Secret secret);
func (item *Item) GetSecret(session *Session) (*Secret, error) {
secret := Secret{}

err := item.dbus.Call("org.freedesktop.Secret.Item.GetSecret", 0, session.Path()).Store(&secret)
if err != nil {
return &Secret{}, err
}

return &secret, nil
}


// Delete (OUT ObjectPath Prompt);
func (item *Item) Delete() error {
var prompt dbus.ObjectPath

err := item.dbus.Call("org.freedesktop.Secret.Item.Delete", 0).Store(&prompt)
if err != nil {
return err
}

if isPrompt(prompt) {
prompt := NewPrompt(item.conn, prompt)
if _, err := prompt.Prompt(); err != nil {
return err
}
}

return nil
}

89
item_funcs.go Normal file
View File

@ -0,0 +1,89 @@
package libsecret

import (
`github.com/godbus/dbus`
)

// NewItem returns a pointer to a new Item based on a Dbus connection and a Dbus path.
func NewItem(conn *dbus.Conn, path dbus.ObjectPath) (item *Item) {

item = &Item{
Conn: conn,
Dbus: conn.Object(DBusServiceName, path),
}

return
}

// Path returns the path of the underlying Dbus connection.
func (i Item) Path() (path dbus.ObjectPath) {

// Remove this method in V1. It's bloat since we now have an exported Dbus.
path = i.Dbus.Path()

return
}

// Label returns the label ("name") of an Item.
func (i *Item) Label() (label string, err error) {

var variant dbus.Variant

if variant, err = i.Dbus.GetProperty("org.freedesktop.Secret.Item.Label"); err != nil {
return
}

label = variant.Value().(string)

return
}

// Locked indicates that an Item is locked (true) or unlocked (false).
func (i *Item) Locked() (isLocked bool, err error) {

var variant dbus.Variant

if variant, err = i.Dbus.GetProperty("org.freedesktop.Secret.Item.Locked"); err != nil {
isLocked = true
return
}

isLocked = variant.Value().(bool)

return
}

// GetSecret returns the Secret in an Item using a Session.
func (i *Item) GetSecret(session *Session) (secret *Secret, err error) {

secret = new(Secret)

if err = i.Dbus.Call(
"org.freedesktop.Secret.Item.GetSecret", 0, session.Path(),
).Store(&secret); err != nil {
return
}

return
}

// Delete removes an Item from a Collection.
func (i *Item) Delete() (err error) {

var prompt *Prompt
var promptPath dbus.ObjectPath

if err = i.Dbus.Call("org.freedesktop.Secret.Item.Delete", 0).Store(&promptPath); err != nil {
return
}

if isPrompt(promptPath) {
prompt = NewPrompt(i.Conn, promptPath)

if _, err = prompt.Prompt(); err != nil {
return
}
}

return
}

View File

@ -1,55 +0,0 @@
package libsecret

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


type Prompt struct {
conn *dbus.Conn
dbus dbus.BusObject
}


func NewPrompt(conn *dbus.Conn, path dbus.ObjectPath) *Prompt {
return &Prompt{
conn: conn,
dbus: conn.Object(DBusServiceName, path),
}
}


func (prompt Prompt) Path() dbus.ObjectPath {
return prompt.dbus.Path()
}


func isPrompt(path dbus.ObjectPath) bool {
promptPath := DBusPath + "/prompt/"
return strings.HasPrefix(string(path), promptPath)
}


// Prompt (IN String window-id);
func (prompt *Prompt) Prompt() (*dbus.Variant, error) {
// prompts are asynchronous so we connect to the signal
// and block with a channel until we get a response
c := make(chan *dbus.Signal, 10)
defer close(c)

prompt.conn.Signal(c)
defer prompt.conn.RemoveSignal(c)

err := prompt.dbus.Call("org.freedesktop.Secret.Prompt.Prompt", 0, "").Store()
if err != nil {
return &dbus.Variant{}, err
}

for {
if result := <-c; result.Path == prompt.Path() {
value := result.Body[1].(dbus.Variant)
return &value, nil
}
}
}

50
prompt_funcs.go Normal file
View File

@ -0,0 +1,50 @@
package libsecret

import (
`github.com/godbus/dbus`
)

// NewPrompt returns a pointer to a new Prompt based on a Dbus connection and a Dbus path.
func NewPrompt(conn *dbus.Conn, path dbus.ObjectPath) (prompt *Prompt) {

prompt = &Prompt{
Conn: conn,
Dbus: conn.Object(DBusServiceName, path),
}

return
}

// Path returns the path of the underlying Dbus connection.
func (p Prompt) Path() (path dbus.ObjectPath) {

// Remove this method in V1. It's bloat since we now have an exported Dbus.
path = p.Dbus.Path()

return
}

// Prompt issues/waits for a prompt for unlocking a Locked Collection or Secret / Item.
func (p *Prompt) Prompt() (promptValue *dbus.Variant, err error) {

var c chan *dbus.Signal
var result *dbus.Signal

// Prompts are asynchronous; we connect to the signal and block with a channel until we get a response.
c = make(chan *dbus.Signal, 10)
defer close(c)

p.Conn.Signal(c)
defer p.Conn.RemoveSignal(c)

if err = p.Dbus.Call("org.freedesktop.Secret.Prompt.Prompt", 0, "").Store(); err != nil {
return
}

for {
if result = <-c; result.Path == p.Path() {
*promptValue = result.Body[1].(dbus.Variant)
return
}
}
}

View File

@ -1,21 +0,0 @@
package libsecret

import "github.com/godbus/dbus"


type Secret struct {
Session dbus.ObjectPath
Parameters []byte
Value []byte
ContentType string
}


func NewSecret(session *Session, params []byte, value []byte, contentType string) *Secret {
return &Secret{
Session: session.Path(),
Parameters: params,
Value: value,
ContentType: contentType,
}
}

14
secret_funcs.go Normal file
View File

@ -0,0 +1,14 @@
package libsecret

// NewSecret returns a pointer to a new Secret based on a Session, parameters, (likely an empty byte slice), a value, and the MIME content type.
func NewSecret(session *Session, params []byte, value []byte, contentType string) (secret *Secret) {

secret = &Secret{
Session: session.Path(),
Parameters: params,
Value: value,
ContentType: contentType,
}

return
}

View File

@ -1,141 +0,0 @@
package libsecret

import "github.com/godbus/dbus"


const (
DBusServiceName = "org.freedesktop.secrets"
DBusPath = "/org/freedesktop/secrets"
)

type DBusObject interface {
Path() dbus.ObjectPath
}


type Service struct {
conn *dbus.Conn
dbus dbus.BusObject
}


func NewService() (*Service, error) {
conn, err := dbus.SessionBus()
if err != nil {
return &Service{}, err
}

return &Service{
conn: conn,
dbus: conn.Object(DBusServiceName, DBusPath),
}, nil
}


func (service Service) Path() dbus.ObjectPath {
return service.dbus.Path()
}


// OpenSession (IN String algorithm, IN Variant input, OUT Variant output, OUT ObjectPath result);
func (service *Service) Open() (*Session, error) {
var output dbus.Variant
var path dbus.ObjectPath

err := service.dbus.Call("org.freedesktop.Secret.Service.OpenSession", 0, "plain", dbus.MakeVariant("")).Store(&output, &path)
if err != nil {
return &Session{}, err
}

return NewSession(service.conn, path), nil
}


// READ Array<ObjectPath> Collections;
func (service *Service) Collections() ([]Collection, error) {
val, err := service.dbus.GetProperty("org.freedesktop.Secret.Service.Collections")
if err != nil {
return []Collection{}, err
}

collections := []Collection{}
for _, path := range val.Value().([]dbus.ObjectPath) {
collections = append(collections, *NewCollection(service.conn, path))
}

return collections, nil
}


// CreateCollection (IN Dict<String,Variant> properties, IN String alias, OUT ObjectPath collection, OUT ObjectPath prompt);
func (service *Service) CreateCollection(label string) (*Collection, error) {
properties := make(map[string]dbus.Variant)
properties["org.freedesktop.Secret.Collection.Label"] = dbus.MakeVariant(label)

var path dbus.ObjectPath
var prompt dbus.ObjectPath

err := service.dbus.Call("org.freedesktop.Secret.Service.CreateCollection", 0, properties, "").Store(&path, &prompt)
if err != nil {
return &Collection{}, err
}

if isPrompt(prompt) {
prompt := NewPrompt(service.conn, prompt)

result, err := prompt.Prompt()
if err != nil {
return &Collection{}, err
}

path = result.Value().(dbus.ObjectPath)
}

return NewCollection(service.conn, path), nil
}


// Unlock (IN Array<ObjectPath> objects, OUT Array<ObjectPath> unlocked, OUT ObjectPath prompt);
func (service *Service) Unlock(object DBusObject) error {
objects := []dbus.ObjectPath{object.Path()}

var unlocked []dbus.ObjectPath
var prompt dbus.ObjectPath

err := service.dbus.Call("org.freedesktop.Secret.Service.Unlock", 0, objects).Store(&unlocked, &prompt)
if err != nil {
return err
}

if isPrompt(prompt) {
prompt := NewPrompt(service.conn, prompt)
if _, err := prompt.Prompt(); err != nil {
return err
}
}

return nil
}


// Lock (IN Array<ObjectPath> objects, OUT Array<ObjectPath> locked, OUT ObjectPath Prompt);
func (service *Service) Lock(object DBusObject) error {
objects := []dbus.ObjectPath{object.Path()}

var locked []dbus.ObjectPath
var prompt dbus.ObjectPath

err := service.dbus.Call("org.freedesktop.Secret.Service.Lock", 0, objects).Store(&locked, &prompt)
if err != nil {
return err
}

if isPrompt(prompt) {
prompt := NewPrompt(service.conn, prompt)
if _, err := prompt.Prompt(); err != nil {
return err
}
}

return nil
}

147
service_funcs.go Normal file
View File

@ -0,0 +1,147 @@
package libsecret

import (
`github.com/godbus/dbus`
)

// NewService returns a pointer to a new Service.
func NewService() (service *Service, err error) {

service = &Service{
Conn: nil,
Dbus: nil,
}

if service.Conn, err = dbus.SessionBus(); err != nil {
return
}
service.Dbus = service.Conn.Object(DBusServiceName, dbus.ObjectPath(DBusPath))

return
}

// Path returns the path of the underlying Dbus connection.
func (s Service) Path() (path dbus.ObjectPath) {

// Remove this method in V1. It's bloat since we now have an exported Dbus.
path = s.Dbus.Path()

return
}

// Open returns a pointer to a Session from the Service.
func (s *Service) Open() (session *Session, err error) {

var output dbus.Variant
var path dbus.ObjectPath

if err = s.Dbus.Call(
"org.freedesktop.Secret.Service.OpenSession", 0, "plain", dbus.MakeVariant(""),
).Store(&output, &path); err != nil {
return
}

session = NewSession(s.Conn, path)

return
}

// Collections returns a slice of Collection keyrings 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.
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) {

var unlocked []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.Unlock", 0, paths).Store(&unlocked, &promptPath); err != nil {
return
}

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 {
return
}
}

return
}

View File

@ -1,22 +0,0 @@
package libsecret

import "github.com/godbus/dbus"


type Session struct {
conn *dbus.Conn
dbus dbus.BusObject
}


func NewSession(conn *dbus.Conn, path dbus.ObjectPath) *Session {
return &Session{
conn: conn,
dbus: conn.Object(DBusServiceName, path),
}
}


func (session Session) Path() dbus.ObjectPath {
return session.dbus.Path()
}

25
session_funcs.go Normal file
View File

@ -0,0 +1,25 @@
package libsecret

import (
`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(DBusServiceName, path),
}

return
}

// Path returns the path of the underlying Dbus connection.
func (s Session) Path() (path dbus.ObjectPath) {

// Remove this method in V1. It's bloat since we now have an exported Dbus.
path = s.Dbus.Path()

return
}

88
types.go Normal file
View File

@ -0,0 +1,88 @@
package libsecret

import (
`github.com/godbus/dbus`
)

// DBusObject is any type that has a Path method that returns a dbus.ObjectPath.
type DBusObject interface {
Path() dbus.ObjectPath
}

/*
Collection is an accessor for libsecret collections, which contain multiple Secret Item items.
Reference:
https://developer-old.gnome.org/libsecret/0.18/SecretCollection.html
https://specifications.freedesktop.org/secret-service/latest/ch03.html
*/
type Collection struct {
// Conn is an active connection to the Dbus.
Conn *dbus.Conn
// Dbus is the Dbus bus object.
Dbus dbus.BusObject
}

/*
Item is an entry in a Collection that contains a Secret.
https://developer-old.gnome.org/libsecret/0.18/SecretItem.html
https://specifications.freedesktop.org/secret-service/latest/re03.html
*/
type Item struct {
// Conn is an active connection to the Dbus.
Conn *dbus.Conn
// Dbus is the Dbus bus object.
Dbus dbus.BusObject
}

/*
Prompt is an interface to handling unlocking prompts.
https://developer-old.gnome.org/libsecret/0.18/SecretPrompt.html
https://specifications.freedesktop.org/secret-service/latest/ch09.html
*/
type Prompt struct {
// Conn is an active connection to the Dbus.
Conn *dbus.Conn
// Dbus is the Dbus bus object.
Dbus dbus.BusObject
}

/*
Secret is the "Good Stuff" - the actual secret content.
https://developer-old.gnome.org/libsecret/0.18/SecretValue.html
https://specifications.freedesktop.org/secret-service/latest/re03.html
https://specifications.freedesktop.org/secret-service/latest/ch14.html#type-Secret
*/
type Secret struct {
// Session is a Dbus object path for the associated Session.
Session dbus.ObjectPath
// Parameters are "algorithm dependent parameters for secret value encoding" - likely this will just be an empty byteslice.
Parameters []byte
// Value is the secret's content in []byte format.
Value []byte
// ContentType is the MIME type of Value.
ContentType string
}

/*
Service is a general SecretService interface, sort of handler for Dbus - it's used for fetching a Session, Collections, etc.
https://developer-old.gnome.org/libsecret/0.18/SecretService.html
https://specifications.freedesktop.org/secret-service/latest/re01.html
*/
type Service struct {
// Conn is an active connection to the Dbus.
Conn *dbus.Conn
// Dbus is the Dbus bus object.
Dbus dbus.BusObject
}

/*
Session is a session/instance/connection to SecretService.
https://developer-old.gnome.org/libsecret/0.18/SecretService.html
https://specifications.freedesktop.org/secret-service/latest/ch06.html
*/
type Session struct {
// Conn is an active connection to the Dbus.
Conn *dbus.Conn
// Dbus is the Dbus bus object.
Dbus dbus.BusObject
}