-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit with first working version
- Loading branch information
1 parent
fc2672f
commit ecad6a1
Showing
8 changed files
with
287 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,4 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
env/ | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*,cover | ||
.hypothesis/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# IPython Notebook | ||
.ipynb_checkpoints | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# celery beat schedule file | ||
celerybeat-schedule | ||
|
||
# dotenv | ||
.env | ||
|
||
# virtualenv | ||
venv/ | ||
ENV/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
Crypto | ||
fuzzywuzzy | ||
*.dist-info | ||
*.egg-info |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
build: | ||
pip install --requirement requirements.txt --target=. | ||
|
||
link: | ||
@ln -fs `pwd` "/Users/sadovnychyi/Google Drive/Sync/Alfred.alfredpreferences/workflows" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,39 @@ | ||
# alfred-chrome-passwords | ||
Browse your passwords saved in Google Chrome using Alfred | ||
# Alfred Chrome Passwords | ||
|
||
Browse your passwords saved in Google Chrome using Alfred instead of https://password.google.com. | ||
|
||
# Demo | ||
|
||
![sample](https://cloud.githubusercontent.com/assets/193864/17643019/7d16b81c-618f-11e6-824a-784b678a4f50.gif) | ||
|
||
# Installation | ||
|
||
See [releases](https://github.com/sadovnychyi/alfred-chrome-passwords/releases) | ||
to download latest build. Simply open it with Alfred and follow instructions. | ||
|
||
# Usage | ||
|
||
Type `password` keyword to see the most frequent passwords you have used. | ||
Continue typing to filter them and press `Enter` to copy it. Note that by | ||
default you will be required to type your OS password to decrypt selected | ||
password. | ||
|
||
# Using non-default profile | ||
|
||
Provide `--profile` argument to `passwords.py` script. For example: | ||
```bash | ||
python passwords.py --query="$1" --profile="Profile 1" | ||
``` | ||
![image](https://cloud.githubusercontent.com/assets/193864/17643119/9ac8a2d2-6192-11e6-9763-b53ad6769a1c.png) | ||
|
||
# Security | ||
|
||
Chrome stores all your passwords inside of sqlite database named `Login Data`. | ||
All passwords are securely encrypted by a master password which is stored in | ||
your keychain. By default you have to use your OS password to access Chrome's | ||
safe storage password. If you feel super safe allowing anybody who has physical | ||
access to your Mac to access your passwords – you can remove that confirmation | ||
window. To do so, open `Keychain Access`, search for `Chrome Safe Storage`, go | ||
to `Access Control` and select `Allow all applications to access this item`. But... just don't! | ||
|
||
![image](https://cloud.githubusercontent.com/assets/193864/17643070/0f400788-6191-11e6-9c6e-02a0d411a05c.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from Crypto.Cipher import AES | ||
import hashlib | ||
import subprocess | ||
import sys | ||
|
||
|
||
def main(password): | ||
master_password = subprocess.check_output([ | ||
'/usr/bin/security', 'find-generic-password', '-w', '-s', | ||
'Chrome Safe Storage', '-a', 'Chrome']).strip() | ||
key = hashlib.pbkdf2_hmac(hash_name='sha1', password=master_password, | ||
salt=b'saltysalt', iterations=1003, dklen=16) | ||
cipher = AES.new(key, AES.MODE_CBC, IV=b' ' * 16) | ||
return sys.stdout.write(cipher.decrypt(password.decode('base64'))) | ||
|
||
|
||
if __name__ == '__main__': | ||
main(sys.argv[1] if len(sys.argv) > 1 else '') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>bundleid</key> | ||
<string>com.github.sadovnychyi.chromepasswords</string> | ||
<key>category</key> | ||
<string>Productivity</string> | ||
<key>connections</key> | ||
<dict> | ||
<key>049FB103-A748-4A6E-9B25-3CE43041BD8D</key> | ||
<array> | ||
<dict> | ||
<key>destinationuid</key> | ||
<string>9F1468CE-D107-4676-BC98-B66947DB9AE3</string> | ||
<key>modifiers</key> | ||
<integer>0</integer> | ||
<key>modifiersubtext</key> | ||
<string></string> | ||
<key>vitoclose</key> | ||
<false/> | ||
</dict> | ||
</array> | ||
<key>9F1468CE-D107-4676-BC98-B66947DB9AE3</key> | ||
<array> | ||
<dict> | ||
<key>destinationuid</key> | ||
<string>49F46A2B-E033-4214-9CC6-D84213949876</string> | ||
<key>modifiers</key> | ||
<integer>0</integer> | ||
<key>modifiersubtext</key> | ||
<string></string> | ||
<key>vitoclose</key> | ||
<false/> | ||
</dict> | ||
</array> | ||
</dict> | ||
<key>createdby</key> | ||
<string>Dmytro Sadovnychyi</string> | ||
<key>description</key> | ||
<string>Browse your passwords saved in Google Chrome</string> | ||
<key>disabled</key> | ||
<false/> | ||
<key>name</key> | ||
<string>Chrome Passwords</string> | ||
<key>objects</key> | ||
<array> | ||
<dict> | ||
<key>config</key> | ||
<dict> | ||
<key>alfredfiltersresults</key> | ||
<false/> | ||
<key>argumenttype</key> | ||
<integer>1</integer> | ||
<key>escaping</key> | ||
<integer>102</integer> | ||
<key>keyword</key> | ||
<string>password</string> | ||
<key>queuedelaycustom</key> | ||
<integer>3</integer> | ||
<key>queuedelayimmediatelyinitially</key> | ||
<true/> | ||
<key>queuedelaymode</key> | ||
<integer>0</integer> | ||
<key>queuemode</key> | ||
<integer>1</integer> | ||
<key>runningsubtext</key> | ||
<string>Reading database...</string> | ||
<key>script</key> | ||
<string>python passwords.py --query="$1"</string> | ||
<key>scriptargtype</key> | ||
<integer>1</integer> | ||
<key>scriptfile</key> | ||
<string></string> | ||
<key>subtext</key> | ||
<string>Browse your passwords saved in Google Chrome</string> | ||
<key>title</key> | ||
<string>Chrome Passwords</string> | ||
<key>type</key> | ||
<integer>0</integer> | ||
<key>withspace</key> | ||
<true/> | ||
</dict> | ||
<key>type</key> | ||
<string>alfred.workflow.input.scriptfilter</string> | ||
<key>uid</key> | ||
<string>049FB103-A748-4A6E-9B25-3CE43041BD8D</string> | ||
<key>version</key> | ||
<integer>2</integer> | ||
</dict> | ||
<dict> | ||
<key>config</key> | ||
<dict> | ||
<key>autopaste</key> | ||
<false/> | ||
<key>clipboardtext</key> | ||
<string>{query}</string> | ||
<key>transient</key> | ||
<false/> | ||
</dict> | ||
<key>type</key> | ||
<string>alfred.workflow.output.clipboard</string> | ||
<key>uid</key> | ||
<string>49F46A2B-E033-4214-9CC6-D84213949876</string> | ||
<key>version</key> | ||
<integer>2</integer> | ||
</dict> | ||
<dict> | ||
<key>config</key> | ||
<dict> | ||
<key>concurrently</key> | ||
<false/> | ||
<key>escaping</key> | ||
<integer>102</integer> | ||
<key>script</key> | ||
<string>python decrypt.py $1</string> | ||
<key>scriptargtype</key> | ||
<integer>1</integer> | ||
<key>scriptfile</key> | ||
<string></string> | ||
<key>type</key> | ||
<integer>0</integer> | ||
</dict> | ||
<key>type</key> | ||
<string>alfred.workflow.action.script</string> | ||
<key>uid</key> | ||
<string>9F1468CE-D107-4676-BC98-B66947DB9AE3</string> | ||
<key>version</key> | ||
<integer>2</integer> | ||
</dict> | ||
</array> | ||
<key>readme</key> | ||
<string>Browse your passwords saved in Google Chrome.</string> | ||
<key>uidata</key> | ||
<dict> | ||
<key>049FB103-A748-4A6E-9B25-3CE43041BD8D</key> | ||
<dict> | ||
<key>xpos</key> | ||
<integer>120</integer> | ||
<key>ypos</key> | ||
<integer>290</integer> | ||
</dict> | ||
<key>49F46A2B-E033-4214-9CC6-D84213949876</key> | ||
<dict> | ||
<key>xpos</key> | ||
<integer>730</integer> | ||
<key>ypos</key> | ||
<integer>290</integer> | ||
</dict> | ||
<key>9F1468CE-D107-4676-BC98-B66947DB9AE3</key> | ||
<dict> | ||
<key>xpos</key> | ||
<integer>510</integer> | ||
<key>ypos</key> | ||
<integer>290</integer> | ||
</dict> | ||
</dict> | ||
<key>version</key> | ||
<string>1.0.0</string> | ||
<key>webaddress</key> | ||
<string>https://github.com/sadovnychyi/alfred-chrome-passwords</string> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import argparse | ||
import base64 | ||
import codecs | ||
import fuzzywuzzy.process | ||
import json | ||
import os | ||
import sqlite3 | ||
import sys | ||
import tempfile | ||
try: | ||
from urlparse import urlparse | ||
except ImportError: | ||
from urllib.parse import urlparse | ||
|
||
HOME = os.path.expanduser('~') | ||
CHROME = 'Library/Application Support/Google/Chrome' | ||
PROFILE = 'Default' | ||
LOGIN_DATA = 'Login Data' | ||
|
||
|
||
def main(query, profile): | ||
with tempfile.NamedTemporaryFile() as tmp: | ||
with open(os.path.join(HOME, CHROME, profile, LOGIN_DATA), 'rb') as f: | ||
tmp.write(f.read()) | ||
cursor = sqlite3.connect(tmp.name).cursor() | ||
cursor.execute('''SELECT origin_url, username_value, password_value | ||
FROM logins ORDER BY times_used desc''') | ||
passwords = [] | ||
for origin_url, account, password in cursor.fetchall(): | ||
password = base64.b64encode(password[3:]).decode('utf8') | ||
url = urlparse(origin_url) | ||
title = codecs.decode(url.netloc.encode('utf8'), 'idna') | ||
if title.lower().startswith('www.'): | ||
title = title[4:] | ||
if url.scheme == 'android': | ||
title = '%s://%s' % (url.scheme, title.split('@')[1]) | ||
passwords.append({ | ||
'type': 'default', | ||
'title': title, | ||
'subtitle': account, | ||
'arg': password, | ||
'valid': 'true' if len(password) > 0 else 'false', | ||
'autocomplete': title, | ||
}) | ||
passwords = fuzzywuzzy.process.extractBests( | ||
query, passwords, processor=lambda x: '%s %s' % (x['title'], x['subtitle'])) | ||
json.dump({'items': [p[0] for p in passwords]}, sys.stdout, indent=2) | ||
sys.stdout.flush() | ||
|
||
|
||
if __name__ == '__main__': | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument('--query', default='') | ||
parser.add_argument('--profile', default=PROFILE) | ||
args = parser.parse_args() | ||
main(args.query, args.profile) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pycrypto | ||
fuzzywuzzy |