passwordsafe 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rvmrc +2 -1
- data/Gemfile.lock +1 -1
- data/README.md +4 -2
- data/features/get.feature +0 -1
- data/features/list.feature +17 -0
- data/features/step_definitions/safe_steps.rb +10 -0
- data/lib/passwordsafe/cli.rb +8 -0
- data/lib/passwordsafe/version.rb +1 -1
- data/spec/encryptor_spec.rb +21 -27
- data/spec/keyring_spec.rb +33 -42
- data/spec/safe_spec.rb +35 -39
- metadata +4 -3
data/.rvmrc
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
rvm ruby-1.9.2
|
1
|
+
rvm ruby-1.9.2@pws
|
2
|
+
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -6,16 +6,18 @@ Based on 'Tutorial: Build your own password safe with Ruby!' at http://rbjl.net/
|
|
6
6
|
## Currently implemented
|
7
7
|
**NOTE** This gem is currently in alpha, if you'd like to try it and make suggestions feel free but please do not store valuble information in it yet.
|
8
8
|
|
9
|
-
|
10
9
|
password add name password
|
11
10
|
Use passwordsafe to add a password with NAME to the safe. The utility will prompt for a master password to use to encrypt the file. *Do NOT loose your master password, it is unrecoverable!*
|
12
11
|
|
13
12
|
password get name
|
14
13
|
Use passwordsafe to retrive an existing password out of your safe. The utility will prompt for a master password.
|
15
14
|
|
15
|
+
password list
|
16
|
+
List all the existing password names in the safe.
|
17
|
+
|
18
|
+
|
16
19
|
## Not Implemented yet
|
17
20
|
|
18
|
-
password list
|
19
21
|
password remove name
|
20
22
|
password help
|
21
23
|
|
data/features/get.feature
CHANGED
@@ -9,7 +9,6 @@ Feature: Get
|
|
9
9
|
And I type "masterpa$$"
|
10
10
|
Then the output should contain "name: "
|
11
11
|
|
12
|
-
@announce
|
13
12
|
Scenario: Get a password with a name that does not exist
|
14
13
|
Given A safe exists with masterpassword "masterpa$$" and a "name" key
|
15
14
|
When I run "password get name2" interactively
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: List
|
2
|
+
In order to see what passwords I have stored
|
3
|
+
As a user
|
4
|
+
I want to be able to list existing password names
|
5
|
+
|
6
|
+
Scenario: No passwords stored
|
7
|
+
Given A safe exists with masterpassword "masterpa$$" and "0" keys
|
8
|
+
When I run "password list" interactively
|
9
|
+
And I type "masterpa$$"
|
10
|
+
Then the output should contain "List: (none)"
|
11
|
+
|
12
|
+
Scenario: One password stored
|
13
|
+
Given A safe exists with masterpassword "masterpa$$" and a "pass" key
|
14
|
+
When I run "password list" interactively
|
15
|
+
And I type "masterpa$$"
|
16
|
+
Then the output should contain "List: pass"
|
17
|
+
|
@@ -9,3 +9,13 @@ Given /^A safe exists with masterpassword "([^"]*)" and a "([^"]*)" key$/ do |ma
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
Given /^A safe exists with masterpassword "([^"]*)" and "([^"]*)" keys$/ do |masterpass, keys|
|
13
|
+
in_current_dir do
|
14
|
+
safe = PasswordSafe::Safe.new(PasswordSafe::CLI::DEFAULTSAFE, masterpass)
|
15
|
+
|
16
|
+
keys.to_i.times do |i|
|
17
|
+
PasswordSafe::Keyring.new(safe).add "pass#{i}", "dummypass"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
data/lib/passwordsafe/cli.rb
CHANGED
@@ -29,6 +29,14 @@ module PasswordSafe
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
desc "list", "List the names of all the existing passwords in the safe"
|
33
|
+
def list
|
34
|
+
safe = make_safe
|
35
|
+
keys = PasswordSafe::Keyring.new(safe).list
|
36
|
+
puts "List: (none)" if keys.empty?
|
37
|
+
puts "List: #{keys.join(", ")}"
|
38
|
+
end
|
39
|
+
|
32
40
|
no_tasks do
|
33
41
|
def make_safe filename = DEFAULTSAFE
|
34
42
|
masterpass = ask("Enter your master password: ") { |q| q.echo = "x" }
|
data/lib/passwordsafe/version.rb
CHANGED
data/spec/encryptor_spec.rb
CHANGED
@@ -2,54 +2,48 @@ require 'spec_helper'
|
|
2
2
|
require 'passwordsafe/encryptor'
|
3
3
|
|
4
4
|
describe PasswordSafe::Encryptor do
|
5
|
+
let(:encryptor) {(Class.new { include PasswordSafe::Encryptor}).new }
|
5
6
|
|
6
|
-
|
7
|
-
klass = Class.new { include PasswordSafe::Encryptor}
|
8
|
-
@encryptor = klass.new
|
9
|
-
end
|
10
|
-
context "hash" do
|
7
|
+
describe "hash" do
|
11
8
|
it "creates a password hash" do
|
12
|
-
|
13
|
-
|
9
|
+
encryptor.should respond_to(:hash).with(1).argument
|
10
|
+
encryptor.hash("test").should be_a(String)
|
14
11
|
end
|
15
12
|
|
16
13
|
it "creates the same hash given the same text" do
|
17
|
-
|
14
|
+
encryptor.hash("test").should eq(encryptor.hash("test"))
|
18
15
|
end
|
19
16
|
|
20
17
|
it "creates a different hash given different text" do
|
21
|
-
|
18
|
+
encryptor.hash("test").should_not eq(encryptor.hash("another"))
|
22
19
|
end
|
23
20
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@hash = @encryptor.hash("hashstring")
|
28
|
-
end
|
21
|
+
describe "encrypt" do
|
22
|
+
let(:string) { "teststring" }
|
23
|
+
let(:hash) { encryptor.hash("hashstring") }
|
29
24
|
|
30
25
|
it "encrypts a string" do
|
31
|
-
|
32
|
-
|
26
|
+
encryptor.should respond_to(:encrypt).with(2).arguments
|
27
|
+
encryptor.encrypt(string, hash).should be_a(String)
|
33
28
|
end
|
34
29
|
it "creates the same string given the same text" do
|
35
|
-
|
30
|
+
encryptor.encrypt(string, hash).should eq(encryptor.encrypt(string, hash))
|
36
31
|
end
|
37
32
|
it "creates a different string given different text" do
|
38
|
-
|
33
|
+
encryptor.encrypt(string, hash).should_not eq(encryptor.encrypt("anotherstring", hash))
|
39
34
|
end
|
40
35
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
36
|
+
describe "decrypt" do
|
37
|
+
let(:string) { "teststring" }
|
38
|
+
let(:hash) { encryptor.hash("hashstring") }
|
39
|
+
let(:data) { encryptor.encrypt(string, hash) }
|
40
|
+
|
47
41
|
it "decrypts a string" do
|
48
|
-
|
49
|
-
|
42
|
+
encryptor.should respond_to(:decrypt).with(2).arguments
|
43
|
+
encryptor.decrypt(data, hash).should be_a(String)
|
50
44
|
end
|
51
45
|
it "decrypts an encrypted string" do
|
52
|
-
|
46
|
+
encryptor.decrypt(data, hash).should eq(string)
|
53
47
|
end
|
54
48
|
end
|
55
49
|
end # describe PasswordSafe::Encryptor
|
data/spec/keyring_spec.rb
CHANGED
@@ -2,83 +2,74 @@ require 'spec_helper'
|
|
2
2
|
require 'passwordsafe/keyring'
|
3
3
|
|
4
4
|
describe PasswordSafe::Keyring do
|
5
|
-
|
6
|
-
|
7
|
-
@safe = mock PasswordSafe::Safe
|
8
|
-
@safe.stub(:read_safe).and_return({})
|
9
|
-
@safe.stub(:write_safe)
|
10
|
-
end
|
5
|
+
let(:safe) { mock PasswordSafe::Safe, :read_safe => {}, :write_safe => nil }
|
6
|
+
let(:keyring) { PasswordSafe::Keyring.new(safe) }
|
11
7
|
|
12
8
|
it "expects to get a Safe to read/write" do
|
13
|
-
|
9
|
+
safe.should_receive(:is_a?).and_return(true)
|
14
10
|
PasswordSafe::Keyring.should respond_to(:new).with(1).argument
|
15
|
-
keyring = PasswordSafe::Keyring.new(
|
11
|
+
keyring = PasswordSafe::Keyring.new(safe)
|
16
12
|
keyring.should have_a_safe
|
17
13
|
end
|
18
14
|
|
19
|
-
|
15
|
+
describe "length" do
|
16
|
+
|
20
17
|
it "returns the number of keys in the keyring" do
|
21
|
-
keyring = PasswordSafe::Keyring.new(@safe)
|
22
18
|
keyring.should respond_to(:length)
|
23
19
|
keyring.length.should be_a(Integer)
|
24
20
|
end
|
25
21
|
end
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
@keyring = PasswordSafe::Keyring.new(@safe)
|
30
|
-
end
|
23
|
+
describe "add" do
|
24
|
+
|
31
25
|
it "adds a key to the keyring" do
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
keyring.should respond_to(:add).with(2).arguments
|
27
|
+
keyring.add("name", "password")
|
28
|
+
keyring.length.should eq(1)
|
35
29
|
end
|
36
30
|
it "throws an error when adding a duplicate key name" do
|
37
|
-
|
38
|
-
expect{
|
31
|
+
keyring.add("name", "password")
|
32
|
+
expect{keyring.add("name", "password")}.to raise_error()
|
39
33
|
end
|
40
34
|
it "saves the modified keyring to the safe" do
|
41
|
-
|
42
|
-
|
35
|
+
safe.should_receive(:write_safe).with({"name" => "password"})
|
36
|
+
keyring.add("name", "password")
|
43
37
|
end
|
44
38
|
end
|
45
39
|
|
46
|
-
|
40
|
+
describe "get" do
|
41
|
+
|
47
42
|
it "gets a key from the keyring" do
|
48
|
-
|
49
|
-
|
50
|
-
@keyring.get("name").should eq("password")
|
43
|
+
safe.stub(:read_safe).and_return({"name" => "password"})
|
44
|
+
keyring.get("name").should eq("password")
|
51
45
|
end
|
52
46
|
it "returns nil if the key does not exist" do
|
53
|
-
|
54
|
-
@keyring.get("name").should be_nil
|
47
|
+
keyring.get("name").should be_nil
|
55
48
|
end
|
56
49
|
end
|
57
50
|
|
58
|
-
|
51
|
+
describe "list" do
|
52
|
+
|
59
53
|
it "returns a list of existing key names" do
|
60
|
-
|
61
|
-
|
62
|
-
@keyring.list.should eq(["first", "second"])
|
54
|
+
safe.should_receive(:read_safe).and_return({"first" => "password", "second" => "password"})
|
55
|
+
keyring.list.should eq(["first", "second"])
|
63
56
|
end
|
64
57
|
it "returns an empty array if there are no keys" do
|
65
|
-
|
66
|
-
@keyring.list.should eq([])
|
58
|
+
keyring.list.should eq([])
|
67
59
|
end
|
68
60
|
end
|
69
61
|
|
70
|
-
|
62
|
+
describe "remove" do
|
63
|
+
|
71
64
|
it "removes an existing key" do
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
@keyring.get("first").should eq(nil)
|
65
|
+
safe.should_receive(:read_safe).and_return({"first" => "password", "second" => "password"})
|
66
|
+
keyring.remove("first")
|
67
|
+
keyring.get("first").should eq(nil)
|
76
68
|
end
|
77
69
|
it "saves the modified keyring to the safe" do
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
@keyring.remove("first")
|
70
|
+
safe.should_receive(:read_safe).and_return({"first" => "password", "second" => "password"})
|
71
|
+
safe.should_receive(:write_safe).with({"second" => "password"})
|
72
|
+
keyring.remove("first")
|
82
73
|
end
|
83
74
|
end
|
84
75
|
end
|
data/spec/safe_spec.rb
CHANGED
@@ -2,67 +2,63 @@ require 'spec_helper'
|
|
2
2
|
require 'passwordsafe/safe'
|
3
3
|
|
4
4
|
describe PasswordSafe::Safe do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
5
|
+
let(:file) { 'passwordsafe' }
|
6
|
+
let(:filename) { File.expand_path(file) }
|
7
|
+
let(:masterpass) {'masterpass' }
|
8
|
+
let(:safe) { PasswordSafe::Safe.new(file, masterpass) }
|
10
9
|
|
11
10
|
it "takes a safe filename and master password at initilaization" do
|
12
11
|
PasswordSafe::Safe.should respond_to(:new).with(2).arguments
|
13
12
|
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
@safe = PasswordSafe::Safe.new(@file, @masterpass)
|
18
|
-
end
|
14
|
+
describe "access_safe" do
|
15
|
+
|
19
16
|
it "creates a safe if none exists" do
|
20
|
-
|
21
|
-
|
17
|
+
File.delete filename if File.file?(filename)
|
18
|
+
safe.access_safe
|
19
|
+
File.file?(filename).should be_true
|
22
20
|
end
|
23
21
|
it "doesn't modify an existing safe" do
|
24
22
|
content = "some existing file content"
|
25
|
-
File.open(
|
26
|
-
|
27
|
-
File.read(
|
23
|
+
File.open(filename, 'w') {|f| f.write content}
|
24
|
+
safe.access_safe
|
25
|
+
File.read(filename).should eq(content)
|
28
26
|
end
|
29
27
|
end
|
30
28
|
|
31
|
-
context "
|
32
|
-
|
33
|
-
@safe = PasswordSafe::Safe.new(@file, @masterpass)
|
34
|
-
klass = Class.new { include PasswordSafe::Encryptor}
|
35
|
-
@encryptor = klass.new
|
36
|
-
@data = {"data" => "encrypt"}
|
37
|
-
end
|
29
|
+
context "modifying file" do
|
30
|
+
let(:data) { ({"data" => "encrypt"}) }
|
38
31
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
32
|
+
describe "write_safe" do
|
33
|
+
|
34
|
+
it "creates a safe file to write to" do
|
35
|
+
File.delete filename if File.file?(filename)
|
36
|
+
safe.write_safe(data)
|
37
|
+
File.file?(filename).should be_true
|
38
|
+
end
|
43
39
|
|
44
|
-
|
45
|
-
|
40
|
+
it "writes encrypted data to a safe" do
|
41
|
+
encryptor = (Class.new { include PasswordSafe::Encryptor}).new
|
42
|
+
safe.write_safe(data)
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
#we'll use our encryptor to check the contents
|
45
|
+
hash = encryptor.hash(masterpass)
|
46
|
+
Marshal.load(encryptor.decrypt(File.read(filename), hash)).should eq(data)
|
47
|
+
end
|
50
48
|
end
|
51
|
-
end
|
52
49
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
@safe.read_safe.should eq(data)
|
50
|
+
describe "read_safe" do
|
51
|
+
|
52
|
+
it "reads encrypted data out of an existing safe" do
|
53
|
+
safe.write_safe(data)
|
54
|
+
safe.read_safe.should eq(data)
|
55
|
+
end
|
60
56
|
end
|
61
57
|
end
|
62
58
|
|
63
59
|
after(:each) do
|
64
60
|
#We check on the existance of files when we expect them to exist so this seems ok
|
65
|
-
File.delete
|
61
|
+
File.delete filename if File.file?(filename)
|
66
62
|
end
|
67
63
|
end # describe PasswordSafe::Safe
|
68
64
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 4
|
9
|
+
version: 0.0.4
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- thecatwasnot
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-01-04 00:00:00 -06:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -116,6 +116,7 @@ files:
|
|
116
116
|
- bin/password
|
117
117
|
- features/add.feature
|
118
118
|
- features/get.feature
|
119
|
+
- features/list.feature
|
119
120
|
- features/step_definitions/safe_steps.rb
|
120
121
|
- features/support/env.rb
|
121
122
|
- lib/passwordsafe.rb
|