passw3rd 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/passw3rd/password_client.rb +4 -9
- data/lib/passw3rd/password_service.rb +31 -23
- data/lib/passw3rd/version.rb +1 -1
- data/test/password_service_test.rb +33 -10
- metadata +39 -22
@@ -31,19 +31,14 @@ module Passw3rd
|
|
31
31
|
opts.on('-p', '--password-dir PATH', 'Read and write password files to this directory (default is ~/)') do |opt|
|
32
32
|
password_dir = opt
|
33
33
|
::Passw3rd::PasswordService.password_file_dir = password_dir
|
34
|
-
|
34
|
+
unless File.directory?(File.expand_path(password_dir))
|
35
35
|
raise "#{password_dir} must be a directory"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
opts.on('-g', '--generate-key [PATH]', 'generate key/iv and store in PATH, defaults to the home directory') do |opt|
|
40
40
|
gen_key_path = opt
|
41
|
-
|
42
|
-
gen_key_path = ENV["HOME"]
|
43
|
-
end
|
44
|
-
if !File.directory?(File.expand_path(gen_key_path))
|
45
|
-
raise "#{opt} is not a directory"
|
46
|
-
end
|
41
|
+
gen_key_path ||= ::Passw3rd::PasswordService.key_file_dir
|
47
42
|
end
|
48
43
|
|
49
44
|
opts.on_tail("-h", "--help", "Show this message") do
|
@@ -55,8 +50,8 @@ module Passw3rd
|
|
55
50
|
|
56
51
|
# generate key/IV
|
57
52
|
if gen_key_path
|
58
|
-
|
59
|
-
puts "generated keys in #{
|
53
|
+
path = ::Passw3rd::PasswordService.create_key_iv_file(gen_key_path)
|
54
|
+
puts "generated keys in #{path}"
|
60
55
|
end
|
61
56
|
|
62
57
|
# decrypt password_file using the key/IV in key_path
|
@@ -11,17 +11,17 @@ module Passw3rd
|
|
11
11
|
class << self
|
12
12
|
attr_writer :password_file_dir
|
13
13
|
def password_file_dir
|
14
|
-
|
14
|
+
@password_file_dir || ENV['passw3rd-password_file_dir'] || Dir.getwd
|
15
15
|
end
|
16
16
|
|
17
17
|
attr_writer :key_file_dir
|
18
18
|
def key_file_dir
|
19
|
-
|
19
|
+
@key_file_dir || ENV['passw3rd-key_file_dir'] || Dir.getwd
|
20
20
|
end
|
21
21
|
|
22
22
|
def cipher_name= (cipher_name)
|
23
23
|
raise "Hey man, you can only use #{APPROVED_CIPHERS}, you supplied #{cipher_name}" if cipher_name.nil? || !APPROVED_CIPHERS.include?(cipher_name)
|
24
|
-
@cipher_name = cipher_name
|
24
|
+
@cipher_name = ENV['passw3rd-cipher_name'] || cipher_name
|
25
25
|
end
|
26
26
|
|
27
27
|
def cipher_name
|
@@ -33,23 +33,23 @@ module Passw3rd
|
|
33
33
|
instance_eval &block
|
34
34
|
end
|
35
35
|
|
36
|
-
def self.get_password (password_file, options = {:key_path => key_file_dir, :force =>
|
36
|
+
def self.get_password (password_file, options = {:key_path => self.key_file_dir, :force => true})
|
37
37
|
uri = _parse_uri(password_file)
|
38
|
-
encoded_password =
|
38
|
+
encoded_password = read_file(uri)
|
39
39
|
decrypt(encoded_password, options[:key_path])
|
40
40
|
rescue => e
|
41
41
|
raise ArgumentError, "Could not decrypt passw3rd file #{password_file} - #{e}" if options[:force]
|
42
42
|
end
|
43
43
|
|
44
|
-
def self.write_password_file(password, output_path, key_path = key_file_dir)
|
44
|
+
def self.write_password_file(password, output_path, key_path = self.key_file_dir)
|
45
45
|
enc_password = encrypt(password, key_path)
|
46
46
|
base64pw = Base64.encode64(enc_password)
|
47
47
|
path = File.join(password_file_dir, output_path)
|
48
|
-
|
48
|
+
write_file(path, base64pw)
|
49
49
|
path
|
50
50
|
end
|
51
51
|
|
52
|
-
def self.encrypt(password, key_path = key_file_dir)
|
52
|
+
def self.encrypt(password, key_path = self.key_file_dir)
|
53
53
|
raise ArgumentError, "password cannot be blank" if password.to_s.empty?
|
54
54
|
|
55
55
|
cipher = cipher_setup(:encrypt, key_path)
|
@@ -62,7 +62,7 @@ module Passw3rd
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def self.decrypt(cipher_text, key_path = key_file_dir)
|
65
|
+
def self.decrypt(cipher_text, key_path = self.key_file_dir)
|
66
66
|
cipher = cipher_setup(:decrypt, key_path)
|
67
67
|
begin
|
68
68
|
d = cipher.update(cipher_text)
|
@@ -102,9 +102,9 @@ module Passw3rd
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
-
def self.create_key_iv_file(path=nil)
|
105
|
+
def self.create_key_iv_file(path = nil)
|
106
106
|
unless path
|
107
|
-
path = ::Passw3rd::PasswordService.key_file_dir
|
107
|
+
path = ::Passw3rd::PasswordService.key_file_dir
|
108
108
|
end
|
109
109
|
|
110
110
|
# d'oh!
|
@@ -113,8 +113,8 @@ module Passw3rd
|
|
113
113
|
key = cipher.random_key
|
114
114
|
|
115
115
|
begin
|
116
|
-
File.open(key_path, 'w') {|f| f.write(key.unpack("H*").join) }
|
117
|
-
File.open(iv_path, 'w') {|f| f.write(iv.unpack("H*").join) }
|
116
|
+
File.open(self.key_path(path), 'w') {|f| f.write(key.unpack("H*").join) }
|
117
|
+
File.open(self.iv_path(path), 'w') {|f| f.write(iv.unpack("H*").join) }
|
118
118
|
rescue
|
119
119
|
puts "Couldn't write key/IV to #{path}\n"
|
120
120
|
raise $!
|
@@ -122,23 +122,23 @@ module Passw3rd
|
|
122
122
|
path
|
123
123
|
end
|
124
124
|
|
125
|
-
def self.key_path
|
126
|
-
File.join(
|
125
|
+
def self.key_path(path= self.key_file_dir)
|
126
|
+
File.join(path || self.key_file_dir, KEY_FILE)
|
127
127
|
end
|
128
128
|
|
129
|
-
def self.iv_path
|
130
|
-
File.join(
|
129
|
+
def self.iv_path(path = ::Passw3rd::PasswordService.key_file_dir)
|
130
|
+
File.join(path || self.key_file_dir, IV_FILE)
|
131
131
|
end
|
132
132
|
|
133
133
|
protected
|
134
134
|
|
135
|
-
def self.load_key(path
|
135
|
+
def self.load_key(path = ::Passw3rd::PasswordService.key_file_dir)
|
136
136
|
begin
|
137
|
-
key = IO.readlines(File.expand_path(self.key_path))[0]
|
138
|
-
iv = IO.readlines(self.iv_path)[0]
|
139
|
-
rescue
|
140
|
-
puts "Couldn't read key/iv from #{path}. Have they been generated?\n"
|
141
|
-
raise
|
137
|
+
key = IO.readlines(File.expand_path(self.key_path(path)))[0]
|
138
|
+
iv = IO.readlines(File.expand_path(self.iv_path(path)))[0]
|
139
|
+
rescue StandardError => e
|
140
|
+
puts "Couldn't read key/iv from #{self.key_path(path)}. Have they been generated?\n"
|
141
|
+
raise e
|
142
142
|
end
|
143
143
|
|
144
144
|
{:key => [key].pack("H*"), :iv => [iv].pack("H*")}
|
@@ -160,5 +160,13 @@ module Passw3rd
|
|
160
160
|
File.join(password_file_dir, password_file)
|
161
161
|
end
|
162
162
|
end
|
163
|
+
|
164
|
+
def self.read_file uri
|
165
|
+
Base64.decode64(open(uri) { |f| f.read })
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.write_file path, value
|
169
|
+
open(path, 'w') { |f| f.write value }
|
170
|
+
end
|
163
171
|
end
|
164
172
|
end
|
data/lib/passw3rd/version.rb
CHANGED
@@ -7,12 +7,16 @@ require File.expand_path('../../lib/passw3rd.rb', __FILE__)
|
|
7
7
|
class PasswordServiceTest < Test::Unit::TestCase
|
8
8
|
def setup
|
9
9
|
@random_string = sudorandumb
|
10
|
-
|
11
|
-
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup_sandbox(path = Dir.tmpdir)
|
13
|
+
::Passw3rd::PasswordService.key_file_dir = path
|
14
|
+
::Passw3rd::PasswordService.password_file_dir = path
|
12
15
|
::Passw3rd::PasswordService.create_key_iv_file
|
13
16
|
end
|
14
17
|
|
15
18
|
def test_enc_dec
|
19
|
+
setup_sandbox
|
16
20
|
enc = ::Passw3rd::PasswordService.encrypt(@random_string)
|
17
21
|
dec = ::Passw3rd::PasswordService.decrypt(enc)
|
18
22
|
|
@@ -28,6 +32,7 @@ class PasswordServiceTest < Test::Unit::TestCase
|
|
28
32
|
end
|
29
33
|
|
30
34
|
def test_set_and_get_password
|
35
|
+
setup_sandbox
|
31
36
|
password_file = ::Passw3rd::PasswordService.write_password_file(@random_string, "test")
|
32
37
|
decrypted = ::Passw3rd::PasswordService.get_password("test")
|
33
38
|
assert_equal(@random_string, decrypted)
|
@@ -35,18 +40,22 @@ class PasswordServiceTest < Test::Unit::TestCase
|
|
35
40
|
|
36
41
|
def test_set_and_get_password_custom_dir
|
37
42
|
dir = "#{Dir.tmpdir}/#{sudorandumb}"
|
38
|
-
|
39
|
-
FileUtils.mkdir_p(dir)
|
40
43
|
::Passw3rd::PasswordService.password_file_dir = dir
|
44
|
+
::Passw3rd::PasswordService.key_file_dir = dir
|
41
45
|
|
42
|
-
|
43
|
-
assert_match(Regexp.new(dir), password_file_path)
|
44
|
-
|
45
|
-
decrypted = ::Passw3rd::PasswordService.get_password("test2")
|
46
|
-
assert_equal(@random_string, decrypted)
|
47
|
-
FileUtils.rm_rf(dir)
|
46
|
+
assert_passw3rd_cycle(dir)
|
48
47
|
end
|
49
48
|
|
49
|
+
def test_with_env_vars
|
50
|
+
::Passw3rd::PasswordService.key_file_dir = nil
|
51
|
+
::Passw3rd::PasswordService.password_file_dir = nil
|
52
|
+
dir = "#{Dir.tmpdir}/#{sudorandumb}"
|
53
|
+
ENV['passw3rd-password_file_dir'] = dir
|
54
|
+
ENV['passw3rd-key_file_dir'] = dir
|
55
|
+
|
56
|
+
assert_passw3rd_cycle(dir)
|
57
|
+
end
|
58
|
+
|
50
59
|
def test_configure_with_block
|
51
60
|
::Passw3rd::PasswordService.configure do |c|
|
52
61
|
c.password_file_dir = Dir.tmpdir
|
@@ -60,4 +69,18 @@ class PasswordServiceTest < Test::Unit::TestCase
|
|
60
69
|
def sudorandumb
|
61
70
|
Digest::SHA1.hexdigest(Time.now.to_s.split(//).sort_by{rand}.join)
|
62
71
|
end
|
72
|
+
|
73
|
+
def assert_passw3rd_cycle dir
|
74
|
+
FileUtils.mkdir_p(dir)
|
75
|
+
path = ::Passw3rd::PasswordService.create_key_iv_file
|
76
|
+
|
77
|
+
id = sudorandumb
|
78
|
+
password_file_path = ::Passw3rd::PasswordService.write_password_file(@random_string, "test#{id}")
|
79
|
+
assert_match(Regexp.new(dir), password_file_path)
|
80
|
+
|
81
|
+
decrypted = ::Passw3rd::PasswordService.get_password("test#{id}")
|
82
|
+
assert_equal(@random_string, decrypted)
|
83
|
+
|
84
|
+
FileUtils.rm_rf(dir)
|
85
|
+
end
|
63
86
|
end
|
metadata
CHANGED
@@ -1,25 +1,33 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: passw3rd
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 3
|
10
|
+
version: 0.2.3
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Neil Matatall
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
17
|
+
|
18
|
+
date: 2011-11-16 00:00:00 Z
|
13
19
|
dependencies: []
|
14
|
-
|
15
|
-
|
16
|
-
email:
|
20
|
+
|
21
|
+
description: Generate a key/iv file, generate passwords, and store encrypted files in source control, keep the key/iv safe!
|
22
|
+
email:
|
17
23
|
- neil.matatall@gmail.com
|
18
|
-
executables:
|
24
|
+
executables:
|
19
25
|
- passw3rd
|
20
26
|
extensions: []
|
27
|
+
|
21
28
|
extra_rdoc_files: []
|
22
|
-
|
29
|
+
|
30
|
+
files:
|
23
31
|
- README.md
|
24
32
|
- LICENSE
|
25
33
|
- EXAMPLES.md
|
@@ -34,27 +42,36 @@ files:
|
|
34
42
|
- spec/spec_helper.rb
|
35
43
|
homepage: https://github.com/oreoshake/passw3rd
|
36
44
|
licenses: []
|
45
|
+
|
37
46
|
post_install_message:
|
38
47
|
rdoc_options: []
|
39
|
-
|
48
|
+
|
49
|
+
require_paths:
|
40
50
|
- lib
|
41
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
52
|
none: false
|
43
|
-
requirements:
|
44
|
-
- -
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
|
47
|
-
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
61
|
none: false
|
49
|
-
requirements:
|
50
|
-
- -
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
hash: 3
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
53
69
|
requirements: []
|
70
|
+
|
54
71
|
rubyforge_project:
|
55
72
|
rubygems_version: 1.8.10
|
56
73
|
signing_key:
|
57
74
|
specification_version: 3
|
58
75
|
summary: A simple "keep the passwords out of source code and config files".
|
59
76
|
test_files: []
|
60
|
-
|
77
|
+
|