Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
David Poetzsch-Heffter committed May 6, 2017
2 parents aff9a04 + 51bf907 commit 5ef6225
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 43 deletions.
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
KeyMan
======
# KeyMan

A gnome shell extension to access the keyring in a convenient way.

Simply search for your password and copy it to clipboad by clicking it. After a
certain amount of time it will be removed automatically (default is 5 seconds).
As this only works if the keyrings are unlocked, this extension also provides
easy access to lock/unlock keyrings. Finally, this extension provides a history
of the last copied passwords.
Simply search for your password and copy it to clipboad by clicking it.
After a certain amount of time it will be removed automatically (default is 5 seconds).
As this only works if the keyrings are unlocked, this extension also provides easy access to lock/unlock keyrings.
Finally, this extension provides a history of the last copied passwords.

License
=======
# Contributing

(c) 2014 David Poetzsch-Heffter <[email protected]>
Contributions are always welcome.
However, keep in mind [the boy scout rule](http://programmer.97things.oreilly.com/wiki/index.php/The_Boy_Scout_Rule).

## Useful links

* A collection of useful tips and links for developing gnome shell extensions: [http://stackoverflow.com/a/13315324/3594403]()
* St library reference: [https://developer.gnome.org/st/stable/]()

# License

(c) 2014 David Poetzsch-Heffter <[email protected]>.
This file is distributed under the same licence as the KeyMan package.
See file LICENSE for details.
83 changes: 55 additions & 28 deletions keyman.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ const KeyMan = new Lang.Class({
Lang.bind(this, function(menu, open) {
// this is triggered when the keymanager menu is opened
if (open) {
this.searchEntry.grab_key_focus();
// if we do it immediately the focus gets lost again
Mainloop.timeout_add_seconds(0, () => {
this.searchEntry.grab_key_focus();
});
} else {
this.searchEntry.get_stage().set_key_focus(null);
}
Expand Down Expand Up @@ -141,13 +144,13 @@ const KeyMan = new Lang.Class({

_createSecretMenuItem: function(item) {
let pmi = new PopupMenu.PopupMenuItem(item.label);
pmi.connect('activate', Lang.bind(this, function() {
pmi.connect('activate', () => {
this._copySecret(item.path);
this._clearSearchResults();
this.history.add(item);
this._populateHistoryMenu();
this.menu.close();
}));
});
return pmi;
},

Expand Down Expand Up @@ -205,49 +208,73 @@ const KeyMan = new Lang.Class({
let bottomSection = new PopupMenu.PopupMenuSection();

this.searchResultsSection = new PopupMenu.PopupMenuSection();

const searchHint = _("Search...")

this.searchEntry = new St.Entry(
{
name: "searchEntry",
hint_text: _("Search..."),
hint_text: searchHint,
track_hover: true,
can_focus: true
});

let entrySearch = this.searchEntry.clutter_text;
entrySearch.set_max_length(MAX_LENGTH);
entrySearch.connect('key-press-event', Lang.bind(this, function(o, e) {
let symbol = e.get_key_symbol();
if (symbol == KEY_RETURN || symbol == KEY_ENTER) {
this._clearSearchResults();

//this.menu.close();
let searchStrs = o.get_text().trim().split(/\s+/);
searchStrs = searchStrs.filter(function(s) s != "");

if (searchStrs.length > 0) {
let items = this.keyring.getItems(searchStrs);

if (items.length > 0) {
for (let i in items) {
let item = items[i];
let mi = this._createSecretMenuItem(item);
this.searchResultsSection.addMenuItem(mi);
}
} else {
let it = new PopupMenu.PopupMenuItem(_("Nothing found."));
this.searchResultsSection.addMenuItem(it);
entrySearch.connect("text-changed", (obj, event) => {
const text1 = obj.get_text();

if (text1.trim().length === 0) {
// do nothing
} else if (text1.trim().length < 3) {
// here we want to wait a while because there
// are more chars comming for sure.
// However, if there not more input comming we
// still activate the search in order to not
// confuse the user!

Mainloop.timeout_add_seconds(1, () => {
const text2 = obj.get_text();

// if the text already changed again we
// don't need to search
if (text1 === text2) {
this._updateSearchResults(text1);
}
}
})
} else if (text1 !== searchHint) {
this._updateSearchResults(text1);
}

}));
});

bottomSection.actor.add_actor(this.searchEntry);
bottomSection.addMenuItem(this.searchResultsSection);
bottomSection.actor.add_style_class_name("searchSection");
this.menu.addMenuItem(bottomSection);
},

_updateSearchResults: function(text) {
this._clearSearchResults();

//this.menu.close();
let searchStrs = text.trim().split(/\s+/);
searchStrs = searchStrs.filter(s => s != "");

if (searchStrs.length > 0) {
let items = this.keyring.getItems(searchStrs);

if (items.length > 0) {
for (let i in items) {
let item = items[i];
let mi = this._createSecretMenuItem(item);
this.searchResultsSection.addMenuItem(mi);
}
} else {
let it = new PopupMenu.PopupMenuItem(_("Nothing found."));
this.searchResultsSection.addMenuItem(it);
}
}
},

_enable: function() {
},
Expand Down
18 changes: 15 additions & 3 deletions keyringDbus.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ const KeyringConnection = new Lang.Class({
this.session = result[1];

this.signalConnections = []; // array of tuples [signalProvider, signalID]

// maps item paths to item labels because fetching the label
// for a path is slow (around 5ms on my machine). We have to do
// this for *all* items, so searching can easily take a second or
// so. Using the cache we have a major performance gain that even
// allows searching as you type
this.labelCache = {}
},

close: function() {
Expand Down Expand Up @@ -111,8 +118,13 @@ const KeyringConnection = new Lang.Class({
* Fetch the label of an item with the specified path.
*/
_getItemLabelFromPath: function(path) {
let item = new Interfaces.SecretItemProxy(bus, secretBus, path);
return item.Label;
if (this.labelCache[path]) {
return this.labelCache[path];
} else {
const item = new Interfaces.SecretItemProxy(bus, secretBus, path);
this.labelCache[path] = item.Label;
return item.Label;
}
},

/**
Expand All @@ -122,7 +134,7 @@ const KeyringConnection = new Lang.Class({
* @return An array of matching secret items (see makeItem for details)
*/
getItems: function(searchStrs) {
searchStrs.map(function(s) s.toLowerCase());
searchStrs.map(s => s.toLowerCase());

let searchResult = this.service.SearchItemsSync([]);
let allItems = searchResult[0].concat(searchResult[1]);
Expand Down
4 changes: 2 additions & 2 deletions metadata.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"shell-version": ["3.10", "3.14", "3.16", "3.18", "3.20"],
"shell-version": ["3.10", "3.14", "3.16", "3.18", "3.20", "3.22"],
"original-authors": ["[email protected]"],
"uuid": "[email protected]",
"name": "KeyMan",
"description": "Access passwords from the gnome keyring in a convenient way:\nSimply search for your password and copy it to clipboad by clicking it. After a certain amount of time it will be removed automatically (default is 5 seconds). As this only works if the keyrings are unlocked, this extension also provides easy access to lock/unlock keyrings.",
"url": "https://github.com/dpoetzsch/keyman",
"version": 14,
"version": 15,
"settings-schema": "org.gnome.shell.extensions.keyman"
}

0 comments on commit 5ef6225

Please sign in to comment.