// This runs the prompt. // // The prompt will timeout after 1 minute func (p Prompt) Prompt(window_id string) (dbus.Variant, error) { // spec: Prompt(IN String window-id); empty := dbus.Variant{} conn, err := dbus.SessionBus() if err != nil { return empty, err } cmp := make(chan *dbus.Signal, 5) conn.Signal(cmp) call := p.Call(_PromptPrompt, 0, window_id) if call.Err != nil { return empty, call.Err } for { select { case sig := <-cmp: if sig.Name == _PromptCompleted { if sig.Body[0].(bool) { return empty, PromptDismissed } return sig.Body[1].(dbus.Variant), nil } case <-time.After(time.Duration(time.Minute)): err := p.Dismiss() if err != nil { panic(err) } return empty, Timeout } } }
// The first argument is the Label for the collection, and the second is an (optional) alias. func (s Service) CreateCollection(label, alias string) (Collection, error) { // spec: CreateCollection(IN Dict<String,Variant> properties, IN String alias, OUT ObjectPath collection, OUT ObjectPath prompt); var collectionPath, promptPath dbus.ObjectPath conn, err := dbus.SessionBus() if err != nil { return Collection{}, err } properties := map[string]dbus.Variant{ _CollectionLabel: dbus.MakeVariant(label), } call := s.Call(_ServiceCreateCollection, 0, properties, alias) if call.Err != nil { return Collection{}, call.Err } err = call.Store(&collectionPath, &promptPath) if err != nil { return Collection{}, err } if dbus.ObjectPath("/") != collectionPath { return Collection{conn.Object(ServiceName, collectionPath)}, nil } v, err := checkPrompt(promptPath) if err != nil { return Collection{}, err } return Collection{conn.Object(ServiceName, dbus.ObjectPath(v.Value().(string)))}, fmt.Errorf("unable to create collection") }
func DialCollection(path string) (Collection, error) { conn, err := dbus.SessionBus() if err != nil { return Collection{}, err } obj := conn.Object(ServiceName, dbus.ObjectPath(path)) return Collection{obj}, nil }
func DialService() (Service, error) { conn, err := dbus.SessionBus() if err != nil { return Service{}, err } obj := conn.Object(ServiceName, ServicePath) return Service{obj}, nil }
func (c Collection) Items() []Item { // How did we get here if we can't get on the bus now? conn, _ := dbus.SessionBus() p, _ := c.GetProperty(_CollectionItems) objs := p.Value().([]dbus.ObjectPath) i := make([]Item, len(objs)) for idx, objPath := range objs { i[idx] = Item{conn.Object(ServiceName, objPath)} } return i }
func checkPrompt(promptPath dbus.ObjectPath) (dbus.Variant, error) { // if we don't need to prompt, just return. empty := dbus.Variant{} if promptPath == noPrompt { return empty, nil } conn, err := dbus.SessionBus() if err != nil { return empty, err } pr := Prompt{conn.Object(ServiceName, promptPath)} return pr.Prompt("secretservice.go") }
// List Colletions func (s Service) Collections() []Collection { conn, err := dbus.SessionBus() if err != nil { panic(err) } v, err := s.GetProperty(_ServiceCollections) if err != nil { panic(err) } paths := v.Value().([]dbus.ObjectPath) out := make([]Collection, len(paths)) for i, path := range paths { out[i] = Collection{conn.Object(ServiceName, path)} } return out }
func (c Collection) Unlock() error { conn, _ := dbus.SessionBus() var prompt dbus.ObjectPath u := make([]dbus.ObjectPath, 1) srv := conn.Object(ServiceName, ServicePath) call := srv.Call(_ServiceUnlock, 0, []dbus.ObjectPath{c.Path()}) if call.Err != nil { return call.Err } if err := call.Store(&u, &prompt); err != nil { return err } if _, err := checkPrompt(prompt); err != nil { return err } return nil }
func (s Service) ReadAlias(a string) (Collection, error) { // spec: ReadAlias(IN String name, OUT ObjectPath collection); var path dbus.ObjectPath conn, err := dbus.SessionBus() if err != nil { return Collection{}, err } call := s.Call(_ServiceReadAlias, 0, a) if call.Err != nil { return Collection{}, call.Err } err = call.Store(&path) if err != nil { return Collection{}, err } return Collection{conn.Object(ServiceName, path)}, nil }
// First argument is the algorithm used. "plain" (AlgoPlain) and // "dh-ietf1024-sha256-aes128-cbc-pkcs7" (AlgoDH) are supported. // // The dbus api has the caller supply their DH public key and returns // the other side's public key, but this implementation generates a // new keypair, does the exchange, derives the encryption key, and then // stores it in the returned Session. func (s Service) OpenSession(algo string, args ...interface{}) (Session, error) { // spec: OpenSession(IN String algorithm, IN Variant input, OUT Variant output, OUT ObjectPath result); var ret Session conn, err := dbus.SessionBus() if err != nil { return ret, err } switch algo { case AlgoPlain: var discard dbus.Variant var sessionPath dbus.ObjectPath err = s.Call(_ServiceOpenSession, 0, algo, dbus.MakeVariant("")).Store(&discard, &sessionPath) if err != nil { return ret, err } ret = Session{conn.Object(ServiceName, sessionPath), algo, nil} case AlgoDH: // see http://standards.freedesktop.org/secret-service/ch07s03.html var sessionPath dbus.ObjectPath var srvReply dbus.Variant var srvPub []byte symKey := make([]byte, aes.BlockSize) grp, err := dhkx.GetGroup(2) if err != nil { return ret, err } privKey, err := grp.GeneratePrivateKey(rand.Reader) if err != nil { return ret, err } err = s.Call(_ServiceOpenSession, 0, algo, dbus.MakeVariant(privKey.Bytes())).Store(&srvReply, &sessionPath) if err != nil { return ret, err } srvPub = srvReply.Value().([]byte) sharedKey, err := grp.ComputeKey(dhkx.NewPublicKey(srvPub), privKey) if err != nil { return ret, err } _, err = io.ReadFull(hkdf.New(sha256.New, sharedKey.Bytes(), nil, nil), symKey) ret = Session{conn.Object(ServiceName, sessionPath), algo, symKey} default: err = InvalidAlgorithm } return ret, err }
func (c Collection) SearchItems(attr map[string]string) ([]Item, error) { // spec: SearchItems(IN Dict<String,String> attributes, OUT Array<ObjectPath> results); i := []Item{} conn, err := dbus.SessionBus() if err != nil { return i, err } call := c.Call(_CollectionSearchItems, 0, attr) if call.Err != nil { return i, call.Err } var value []dbus.ObjectPath call.Store(&value) for _, objPath := range value { i = append(i, Item{conn.Object(ServiceName, objPath)}) } return i, nil }
func init() { conn, err := dbus.SessionBus() if err != nil { fmt.Fprintln(os.Stderr, "keyring/dbus: Error connecting to dbus session, not registering SecretService provider") return } srv := conn.Object(ssServiceName, ssServicePath) p := &ssProvider{conn, srv} // Everything should implement dbus peer, so ping to make sure we have an object... if session, err := p.openSession(); err != nil { fmt.Fprintf(os.Stderr, "Unable to open dbus session %s: %s\n", srv, err) return } else { session.Call(fmt.Sprint(ssSessionIface, "Close"), 0) } defaultProvider = p }
func simpleCall(path dbus.ObjectPath, method string, args ...interface{}) error { var call *dbus.Call var promptPath dbus.ObjectPath conn, err := dbus.SessionBus() if err != nil { return err } obj := conn.Object(ServiceName, path) if args == nil { call = obj.Call(method, 0) } else { call = obj.Call(method, 0, args...) } if call.Err != nil { return call.Err } call.Store(&promptPath) _, err = checkPrompt(promptPath) return err }
func (s Service) SearchItems(attrs map[string]string) ([]Item, []Item, error) { // spec: SearchItems(IN Dict<String,String> attributes, OUT Array<ObjectPath> unlocked, OUT Array<ObjectPath> locked); var unlocked, locked []dbus.ObjectPath conn, err := dbus.SessionBus() if err != nil { return []Item{}, []Item{}, err } call := s.Call(_ServiceSearchItems, 0, attrs) err = call.Store(&unlocked, &locked) if err != nil { return []Item{}, []Item{}, err } retUnlocked := make([]Item, len(unlocked)) retLocked := make([]Item, len(locked)) for i, v := range unlocked { retUnlocked[i] = Item{conn.Object(ServiceName, v)} } for i, v := range locked { retLocked[i] = Item{conn.Object(ServiceName, v)} } return retUnlocked, retLocked, nil }
func (c Collection) CreateItem(label string, attr map[string]string, s Secret, replace bool) (Item, error) { // spec: CreateItem(IN Dict<String,Variant> properties, IN Secret secret, IN Boolean replace, OUT ObjectPath item, OUT ObjectPath prompt); i := Item{} conn, err := dbus.SessionBus() if err != nil { return i, err } prop := make(map[string]dbus.Variant) prop[_ItemLabel] = dbus.MakeVariant(label) prop[_ItemAttributes] = dbus.MakeVariant(attr) call := c.Call(_CollectionCreateItem, 0, prop, s, replace) if call.Err != nil { return i, call.Err } var newItem dbus.ObjectPath call.Store(&newItem) i = Item{conn.Object(ServiceName, newItem)} return i, nil }
func getConn() *dbus.Conn { if conn == nil { conn, _ = dbus.SessionBus() } return conn }