passman 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +35 -5
- data/bin/passman +36 -15
- data/lib/passman.rb +2 -39
- data/lib/passman/crypto.rb +11 -2
- data/lib/passman/manager.rb +78 -0
- data/lib/passman/password_generator.rb +1 -1
- data/lib/passman/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fd80581c44a6b45f671dee954c907546c1d0070
|
4
|
+
data.tar.gz: a6b7bb2c53cc7f49dbd46d780c2e8eeb98c1a569
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8843144a6727eb8d50eeddedcd98d5527da66f79ec892970acce16374b16036b655948d6a63f8ff60539c5b131b0194c72791d22b18c7f9993f65568c99b12c
|
7
|
+
data.tar.gz: ad5c45e1a5e9d802d73ee20a55689cb359bcadfec480b39c7624924ac792b2ab3aaa6daa48e51a1e64f83093bffe3d5cc5ffac54bd71bb0378e6a668b494d9a7
|
data/README.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# PassMan - Password Manager
|
2
|
-
[![Gem Version](https://badge.fury.io/rb/passman.svg)]()
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/passman.svg)](https://badge.fury.io/rb/passman)
|
3
3
|
[![Dependency Status](https://gemnasium.com/badges/github.com/alebian/passman.svg)](https://gemnasium.com/github.com/alebian/passman)
|
4
4
|
[![Build Status](https://travis-ci.org/alebian/passman.svg)](https://travis-ci.org/alebian/passman)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/alebian/passman/badges/gpa.svg)](https://codeclimate.com/github/alebian/passman)
|
6
6
|
[![Test Coverage](https://codeclimate.com/github/alebian/passman/badges/coverage.svg)](https://codeclimate.com/github/alebian/passman/coverage)
|
7
7
|
[![Inline docs](http://inch-ci.org/github/alebian/passman.svg)](http://inch-ci.org/github/alebian/passman)
|
8
8
|
|
9
|
-
PassMan is a command line application that stores your passwords
|
9
|
+
PassMan is a command line application that stores your passwords encrypted with AES 256 symmetric-key algorithm. It also let's you save more information about your accounts such as recovery information and more.
|
10
10
|
|
11
11
|
## Installation
|
12
12
|
|
@@ -16,16 +16,46 @@ Run this in your terminal:
|
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
-
|
19
|
+
PassMan will save your passwords in a file called 'passman.json' by default, you can tell PassMan to store the passwords in different files.
|
20
|
+
|
21
|
+
First of all you will need a 32 bit (or more) symmetric key. This will be used in the future to encrypt and decrypt your passwords but PassMan will not store that value. Everytime PassMan needs to encrypt or decrypt your passwords it will ask you for one key. You can tell PassMan to create a new secure random key if you want to:
|
22
|
+
|
23
|
+
```
|
24
|
+
passman -g 32
|
25
|
+
# => c50647a4dde91848fb5edda217149258
|
26
|
+
```
|
27
|
+
|
28
|
+
Once you have your key, write it down on paper or try to remember it. Now you can start saving your passwords.
|
29
|
+
|
30
|
+
```
|
31
|
+
passman -a Twitter -u alebian -p MySuperPassword
|
32
|
+
```
|
33
|
+
|
34
|
+
You will be prompted to insert you key and then PassMan will store your password.
|
35
|
+
|
36
|
+
Now you can retreive your passwords:
|
20
37
|
|
21
38
|
```
|
22
|
-
passman
|
39
|
+
passman -r Twitter
|
23
40
|
```
|
24
41
|
|
25
|
-
|
42
|
+
You can tell Passman to store your password in a different file:
|
26
43
|
|
27
44
|
```
|
45
|
+
passman -a Twitter -u alebian -p MySuperPassword -f ~/my_database
|
46
|
+
```
|
47
|
+
|
48
|
+
You can list the stored accounts:
|
28
49
|
|
50
|
+
```
|
51
|
+
passman -l
|
52
|
+
```
|
53
|
+
|
54
|
+
You can delete your accounts:
|
55
|
+
|
56
|
+
```
|
57
|
+
passman -d Twitter
|
58
|
+
```
|
29
59
|
|
30
60
|
## Contributing
|
31
61
|
|
data/bin/passman
CHANGED
@@ -5,7 +5,7 @@ require 'optparse'
|
|
5
5
|
require 'colorize'
|
6
6
|
require 'io/console'
|
7
7
|
|
8
|
-
options = {}
|
8
|
+
options = { length: 32 }
|
9
9
|
|
10
10
|
begin
|
11
11
|
|
@@ -39,7 +39,7 @@ begin
|
|
39
39
|
end
|
40
40
|
|
41
41
|
opts.on('-g', '--generate [N]', Integer, 'Generates a new random password of N characters, or default if N is not provided') do |length|
|
42
|
-
options[:length] = length
|
42
|
+
options[:length] = length unless length.nil? || length.empty?
|
43
43
|
options[:generate] = true
|
44
44
|
end
|
45
45
|
|
@@ -48,7 +48,7 @@ begin
|
|
48
48
|
end
|
49
49
|
|
50
50
|
opts.on('-v', '--version', 'Displays version') do
|
51
|
-
puts "PassMan Version: #{Passman::VERSION}"
|
51
|
+
puts "PassMan Version: #{Passman::VERSION}".colorize(:yellow)
|
52
52
|
exit
|
53
53
|
end
|
54
54
|
|
@@ -60,52 +60,73 @@ begin
|
|
60
60
|
|
61
61
|
parser.parse!
|
62
62
|
|
63
|
+
manager = Passman::Manager.new(options[:file])
|
64
|
+
key = ''
|
65
|
+
password = ''
|
66
|
+
|
63
67
|
if options[:account]
|
64
68
|
|
65
|
-
raise ArgumentError, 'No username provided.' unless options[:username]
|
66
|
-
password = ''
|
67
69
|
if options[:password]
|
68
70
|
password = options[:password]
|
69
71
|
else
|
70
|
-
password =
|
72
|
+
password = manager.generate_password(options[:length])
|
73
|
+
puts "Password generated: #{password}".colorize(:yellow)
|
71
74
|
end
|
72
75
|
|
73
|
-
if
|
76
|
+
if manager.exist?(options[:account])
|
74
77
|
print 'There is a username already stored. Do you want to overwrite it? [Y/n] '
|
75
78
|
overwrite = gets
|
76
79
|
exit unless overwrite == 'Y'
|
77
80
|
puts ''
|
78
81
|
end
|
79
82
|
|
80
|
-
print 'Insert your symmetric-key:
|
83
|
+
print 'Insert your symmetric-key:'
|
81
84
|
key = STDIN.noecho(&:gets)
|
85
|
+
raise ArgumentError, 'Key cannot be empty' if key.empty?
|
82
86
|
puts ''
|
83
|
-
Passman.add(options[:account], options[:username], Passman::Crypto.encrypt(password, key.chomp), options[:file])
|
84
87
|
|
88
|
+
manager.add(options[:account], options[:username], password, key)
|
85
89
|
puts 'Password successfully added'.colorize(:green)
|
86
90
|
|
87
91
|
elsif options[:delete]
|
88
92
|
|
89
|
-
|
93
|
+
manager.delete(options[:delete])
|
90
94
|
puts 'Password deleted'.colorize(:green)
|
91
95
|
|
92
96
|
elsif options[:list]
|
93
97
|
|
94
|
-
|
98
|
+
list = manager.list
|
99
|
+
puts 'No accounts stored' if list.empty?
|
100
|
+
list.each do |account, data|
|
95
101
|
puts account.colorize(:yellow) + ' -> ' + data['username']
|
96
102
|
end
|
97
103
|
|
98
104
|
elsif options[:generate]
|
99
105
|
|
100
|
-
puts
|
106
|
+
puts manager.generate_password(options[:length])
|
101
107
|
|
102
108
|
elsif options[:retreive]
|
103
109
|
|
104
|
-
|
105
|
-
|
110
|
+
unless manager.exist?(options[:retreive])
|
111
|
+
puts "The account doesn't exist"
|
112
|
+
exit
|
113
|
+
end
|
114
|
+
|
115
|
+
print 'Insert your symmetric-key:'
|
106
116
|
key = STDIN.noecho(&:gets)
|
117
|
+
raise ArgumentError, 'Key cannot be empty' if key.empty?
|
107
118
|
puts ''
|
108
|
-
|
119
|
+
account = manager.get(options[:retreive], key)
|
120
|
+
puts(
|
121
|
+
'Account: ' + "#{account[0]}".colorize(:yellow) +
|
122
|
+
', Username: ' + "#{account[1]['username']}".colorize(:yellow) +
|
123
|
+
', Password: ' + "#{account[1]['password']}".colorize(:yellow)
|
124
|
+
)
|
125
|
+
|
126
|
+
elsif options[:remove]
|
127
|
+
|
128
|
+
manager.delete(options[:remove])
|
129
|
+
puts 'Deleted account'.colorize(:red)
|
109
130
|
|
110
131
|
else
|
111
132
|
|
data/lib/passman.rb
CHANGED
@@ -1,44 +1,7 @@
|
|
1
|
-
|
1
|
+
require 'passman/crypto'
|
2
|
+
require 'passman/manager'
|
2
3
|
require 'passman/password_generator'
|
3
4
|
require 'passman/version'
|
4
|
-
require 'json'
|
5
5
|
|
6
6
|
module Passman
|
7
|
-
DEFAULT_FILE = 'passman.json'.freeze
|
8
|
-
|
9
|
-
def self.generate_password(length)
|
10
|
-
Passman::PasswordGenerator.generate(length / 2)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.add(account, username, encrypted_password, file = nil)
|
14
|
-
path = DEFAULT_FILE if file.nil?
|
15
|
-
db = database(path)
|
16
|
-
db[account.to_s] = { username: username, password: encrypted_password }
|
17
|
-
write_database(db, path)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.delete(account, file = nil)
|
21
|
-
path = DEFAULT_FILE if file.nil?
|
22
|
-
db = database(path)
|
23
|
-
db.delete(account.to_s)
|
24
|
-
write_database(db, path)
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.get(account, key, file = nil)
|
28
|
-
path = DEFAULT_FILE if file.nil?
|
29
|
-
db = database(path)
|
30
|
-
db[account.to_s]
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.database(file)
|
34
|
-
return JSON.parse(File.read(file)) if File.exist?(file)
|
35
|
-
{}
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.write_database(data, path)
|
39
|
-
File.delete(path) if File.exist?(path)
|
40
|
-
file = File.open(path, 'w+')
|
41
|
-
file.write(JSON.generate(data))
|
42
|
-
file.close
|
43
|
-
end
|
44
7
|
end
|
data/lib/passman/crypto.rb
CHANGED
@@ -3,11 +3,13 @@ require 'base64'
|
|
3
3
|
|
4
4
|
module Passman
|
5
5
|
class Crypto
|
6
|
+
MINIMUM_SIZE_KEY = 32
|
7
|
+
|
6
8
|
class << self
|
7
9
|
def encrypt(password, key)
|
8
10
|
cipher = new_cipher
|
9
11
|
cipher.encrypt
|
10
|
-
cipher.key = key
|
12
|
+
cipher.key = sanitize_key(key)
|
11
13
|
encrypted_password = cipher.update(password) + cipher.final
|
12
14
|
Base64.encode64(encrypted_password)
|
13
15
|
end
|
@@ -15,7 +17,7 @@ module Passman
|
|
15
17
|
def decrypt(encrypted_password, key)
|
16
18
|
cipher = new_cipher
|
17
19
|
cipher.decrypt
|
18
|
-
cipher.key = key
|
20
|
+
cipher.key = sanitize_key(key)
|
19
21
|
decrypted_password = cipher.update(Base64.decode64(encrypted_password))
|
20
22
|
decrypted_password << cipher.final
|
21
23
|
end
|
@@ -25,6 +27,13 @@ module Passman
|
|
25
27
|
def new_cipher
|
26
28
|
OpenSSL::Cipher::AES.new(256, 'CBC')
|
27
29
|
end
|
30
|
+
|
31
|
+
def sanitize_key(key)
|
32
|
+
raise ArgumentError, 'No key provided.' if key.nil? || key.empty?
|
33
|
+
sanitized = key
|
34
|
+
sanitized += key while sanitized.length < MINIMUM_SIZE_KEY
|
35
|
+
sanitized
|
36
|
+
end
|
28
37
|
end
|
29
38
|
end
|
30
39
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'passman/crypto'
|
2
|
+
require 'passman/password_generator'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Passman
|
6
|
+
class Manager
|
7
|
+
DEFAULT_PATH = 'passman.json'.freeze
|
8
|
+
|
9
|
+
def initialize(file = nil)
|
10
|
+
@file_path = DEFAULT_PATH
|
11
|
+
@file_path = file unless file.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate_password(length = 32)
|
15
|
+
Passman::PasswordGenerator.generate(length)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(account, username, password, key)
|
19
|
+
validate_add_arguments(account, username, password, key)
|
20
|
+
db = database
|
21
|
+
db[account.to_s] = { username: username, password: Passman::Crypto.encrypt(password, key) }
|
22
|
+
store_data(db)
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete(account)
|
26
|
+
raise ArgumentError, 'No account provided.' unless valid?(account)
|
27
|
+
db = database
|
28
|
+
db.delete(account.to_s)
|
29
|
+
store_data(db)
|
30
|
+
end
|
31
|
+
|
32
|
+
def get(account, key)
|
33
|
+
validate_get_arguments(account, key)
|
34
|
+
data = database[account.to_s]
|
35
|
+
[account.to_s, { 'username' => data['username'],
|
36
|
+
'password' => Passman::Crypto.decrypt(data['password'], key) }]
|
37
|
+
end
|
38
|
+
|
39
|
+
def exist?(account)
|
40
|
+
raise ArgumentError, 'No account provided.' unless valid?(account)
|
41
|
+
!(!database[account.to_s])
|
42
|
+
end
|
43
|
+
|
44
|
+
def list
|
45
|
+
database
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def validate_add_arguments(account, username, password, key)
|
51
|
+
raise ArgumentError, 'No account provided.' unless valid?(account)
|
52
|
+
raise ArgumentError, 'No username provided.' unless valid?(username)
|
53
|
+
raise ArgumentError, 'No password provided.' unless valid?(password)
|
54
|
+
raise ArgumentError, 'No key provided.' unless valid?(key)
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_get_arguments(account, key)
|
58
|
+
raise ArgumentError, 'No account provided.' unless valid?(account)
|
59
|
+
raise ArgumentError, 'No key provided.' unless valid?(key)
|
60
|
+
end
|
61
|
+
|
62
|
+
def valid?(argument)
|
63
|
+
!(argument.nil? || argument.empty?)
|
64
|
+
end
|
65
|
+
|
66
|
+
def database
|
67
|
+
return JSON.parse(File.read(@file_path)) if File.exist?(@file_path)
|
68
|
+
{}
|
69
|
+
end
|
70
|
+
|
71
|
+
def store_data(data)
|
72
|
+
File.delete(@file_path) if File.exist?(@file_path)
|
73
|
+
file = File.open(@file_path, 'w+')
|
74
|
+
file.write(JSON.generate(data))
|
75
|
+
file.close
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/passman/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alejandro Bezdjian
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- bin/passman
|
104
104
|
- lib/passman.rb
|
105
105
|
- lib/passman/crypto.rb
|
106
|
+
- lib/passman/manager.rb
|
106
107
|
- lib/passman/password_generator.rb
|
107
108
|
- lib/passman/version.rb
|
108
109
|
- passman.gemspec
|