passwordsafe 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in passwordsafe.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ passwordsafe (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.2)
10
+ rspec (2.3.0)
11
+ rspec-core (~> 2.3.0)
12
+ rspec-expectations (~> 2.3.0)
13
+ rspec-mocks (~> 2.3.0)
14
+ rspec-core (2.3.1)
15
+ rspec-expectations (2.3.0)
16
+ diff-lcs (~> 1.1.2)
17
+ rspec-mocks (2.3.0)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ passwordsafe!
24
+ rspec
data/README.md ADDED
@@ -0,0 +1,5 @@
1
+ == Password Safe
2
+ A command line application that can store and retrieve passwords from an encrypted file.
3
+
4
+ Based on 'Tutorial: Build your own password safe with Ruby!' at http://rbjl.net/41-tutorial-build-your-own-password-safe-with-ruby
5
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,27 @@
1
+ require 'openssl'
2
+
3
+ module PasswordSafe
4
+ module Encryptor; extend self;
5
+
6
+ def decrypt(data, pwhash)
7
+ crypt :decrypt, data, pwhash
8
+ end
9
+
10
+ def encrypt(data, pwhash)
11
+ crypt :encrypt, data, pwhash
12
+ end
13
+
14
+ def hash (plain)
15
+ Digest::SHA512.digest(plain)
16
+ end
17
+
18
+ private
19
+ def crypt(mode, data, pwhash)
20
+ cipher = OpenSSL::Cipher.new 'AES256'
21
+ cipher.send mode.to_sym
22
+ cipher.key = pwhash
23
+ cipher.update(data) << cipher.final
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,44 @@
1
+ require 'passwordsafe/safe'
2
+
3
+ module PasswordSafe
4
+ class Keyring
5
+
6
+ def initialize safe = nil
7
+ @safe = safe
8
+ @ring = load_from_safe
9
+ end
10
+
11
+ def has_a_safe?
12
+ @safe.is_a? PasswordSafe::Safe
13
+ end
14
+
15
+ def length
16
+ @ring.length
17
+ end
18
+
19
+ def add name, password
20
+ raise KeyExistsException, "Key already exists in keyring, if you'd like to add it remove the existing key", caller if @ring.has_key?(name)
21
+ @ring.store(name, password)
22
+ @safe.write_safe @ring
23
+ end
24
+
25
+ def get name
26
+ @ring[name]
27
+ end
28
+
29
+ def list
30
+ @ring.keys
31
+ end
32
+
33
+ def remove name
34
+ @ring.delete(name)
35
+ @safe.write_safe @ring
36
+ end
37
+
38
+ private
39
+ def load_from_safe
40
+ @safe.read_safe
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,30 @@
1
+ require 'passwordsafe/encryptor'
2
+
3
+ module PasswordSafe
4
+ class Safe
5
+ include PasswordSafe::Encryptor
6
+
7
+ def initialize filename, masterpass
8
+ @safefile = File.expand_path(filename)
9
+ @mphash = hash(masterpass)
10
+ end
11
+
12
+ def access_safe
13
+ unless File.file? @safefile
14
+ FileUtils.touch @safefile
15
+ write_safe
16
+ end
17
+ end
18
+ def write_safe data = {}
19
+ dump = Marshal.dump(data)
20
+ access_safe
21
+ encrypted_data = encrypt(dump, @mphash)
22
+ File.open(@safefile, 'w') {|f| f.write encrypted_data}
23
+ end
24
+ def read_safe
25
+ access_safe
26
+ Marshal.load decrypt(File.read(@safefile), @mphash) || {}
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,3 @@
1
+ module Passwordsafe
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,3 @@
1
+ module Passwordsafe
2
+ # Your code goes here...
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "passwordsafe/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "passwordsafe"
7
+ s.version = Passwordsafe::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["thecatwasnot"]
10
+ s.email = ["thecatwasnot@gmail.com"]
11
+ s.homepage = "http://rubygems.org/gems/passwordsafe"
12
+ s.summary = %q{Small command line app for storing passwords}
13
+ s.description = %q{Small command line app for storing passwords}
14
+
15
+ s.rubyforge_project = "passwordsafe"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency('rspec')
23
+ end
24
+
data/safefile ADDED
@@ -0,0 +1 @@
1
+ �������U�vZ�H�
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'passwordsafe/encryptor'
3
+
4
+ describe PasswordSafe::Encryptor do
5
+
6
+ before(:each) do
7
+ klass = Class.new { include PasswordSafe::Encryptor}
8
+ @encryptor = klass.new
9
+ end
10
+ context "hash" do
11
+ it "creates a password hash" do
12
+ @encryptor.should respond_to(:hash).with(1).argument
13
+ @encryptor.hash("test").should be_a(String)
14
+ end
15
+
16
+ it "creates the same hash given the same text" do
17
+ @encryptor.hash("test").should eq(@encryptor.hash("test"))
18
+ end
19
+
20
+ it "creates a different hash given different text" do
21
+ @encryptor.hash("test").should_not eq(@encryptor.hash("another"))
22
+ end
23
+ end
24
+ context "encrypt" do
25
+ before(:each) do
26
+ @string = "teststring"
27
+ @hash = @encryptor.hash("hashstring")
28
+ end
29
+
30
+ it "encrypts a string" do
31
+ @encryptor.should respond_to(:encrypt).with(2).arguments
32
+ @encryptor.encrypt(@string, @hash).should be_a(String)
33
+ end
34
+ it "creates the same string given the same text" do
35
+ @encryptor.encrypt(@string, @hash).should eq(@encryptor.encrypt(@string, @hash))
36
+ end
37
+ it "creates a different string given different text" do
38
+ @encryptor.encrypt(@string, @hash).should_not eq(@encryptor.encrypt("anotherstring", @hash))
39
+ end
40
+ end
41
+ context "decrypt" do
42
+ before(:each) do
43
+ @string = "teststring"
44
+ @hash = @encryptor.hash("hashstring")
45
+ @data = @encryptor.encrypt(@string, @hash)
46
+ end
47
+ it "decrypts a string" do
48
+ @encryptor.should respond_to(:decrypt).with(2).arguments
49
+ @encryptor.decrypt(@data, @hash).should be_a(String)
50
+ end
51
+ it "decrypts an encrypted string" do
52
+ @encryptor.decrypt(@data, @hash).should eq(@string)
53
+ end
54
+ end
55
+ end # describe PasswordSafe::Encryptor
56
+
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+ require 'passwordsafe/keyring'
3
+
4
+ describe PasswordSafe::Keyring do
5
+ before(:each) do
6
+ #set up a safe that will clear initilaization and send empty data
7
+ @safe = mock PasswordSafe::Safe
8
+ @safe.stub(:read_safe).and_return({})
9
+ @safe.stub(:write_safe)
10
+ end
11
+
12
+ it "expects to get a Safe to read/write" do
13
+ @safe.should_receive(:is_a?).and_return(true)
14
+ PasswordSafe::Keyring.should respond_to(:new).with(1).argument
15
+ keyring = PasswordSafe::Keyring.new(@safe)
16
+ keyring.should have_a_safe
17
+ end
18
+
19
+ context "length" do
20
+ it "returns the number of keys in the keyring" do
21
+ keyring = PasswordSafe::Keyring.new(@safe)
22
+ keyring.should respond_to(:length)
23
+ keyring.length.should be_a(Integer)
24
+ end
25
+ end
26
+
27
+ context "add" do
28
+ before(:each) do
29
+ @keyring = PasswordSafe::Keyring.new(@safe)
30
+ end
31
+ it "adds a key to the keyring" do
32
+ @keyring.should respond_to(:add).with(2).arguments
33
+ @keyring.add("name", "password")
34
+ @keyring.length.should eq(1)
35
+ end
36
+ it "throws an error when adding a duplicate key name" do
37
+ @keyring.add("name", "password")
38
+ expect{@keyring.add("name", "password")}.to raise_error()
39
+ end
40
+ it "saves the modified keyring to the safe" do
41
+ @safe.should_receive(:write_safe).with({"name" => "password"})
42
+ @keyring.add("name", "password")
43
+ end
44
+ end
45
+
46
+ context "get" do
47
+ it "gets a key from the keyring" do
48
+ @safe.stub(:read_safe).and_return({"name" => "password"})
49
+ @keyring = PasswordSafe::Keyring.new(@safe)
50
+ @keyring.get("name").should eq("password")
51
+ end
52
+ end
53
+
54
+ context "list" do
55
+ it "returns a list of existing key names" do
56
+ @safe.should_receive(:read_safe).and_return({"first" => "password", "second" => "password"})
57
+ @keyring = PasswordSafe::Keyring.new(@safe)
58
+ @keyring.list.should eq(["first", "second"])
59
+ end
60
+ it "returns an empty array if there are no keys" do
61
+ @keyring = PasswordSafe::Keyring.new(@safe)
62
+ @keyring.list.should eq([])
63
+ end
64
+ end
65
+
66
+ context "remove" do
67
+ it "removes an existing key" do
68
+ @safe.should_receive(:read_safe).and_return({"first" => "password", "second" => "password"})
69
+ @keyring = PasswordSafe::Keyring.new(@safe)
70
+ @keyring.remove("first")
71
+ @keyring.get("first").should eq(nil)
72
+ end
73
+ it "saves the modified keyring to the safe" do
74
+ @safe.should_receive(:read_safe).and_return({"first" => "password", "second" => "password"})
75
+ @safe.should_receive(:write_safe).with({"second" => "password"})
76
+ @keyring = PasswordSafe::Keyring.new(@safe)
77
+ @keyring.remove("first")
78
+ end
79
+ end
80
+ end
81
+
data/spec/safe_spec.rb ADDED
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'passwordsafe/safe'
3
+
4
+ describe PasswordSafe::Safe do
5
+ before (:each) do
6
+ @file = 'passwordsafe'
7
+ @filename = File.expand_path(@file)
8
+ @masterpass = 'masterpass'
9
+ end
10
+
11
+ it "takes a safe filename and master password at initilaization" do
12
+ PasswordSafe::Safe.should respond_to(:new).with(2).arguments
13
+ end
14
+
15
+ context "access_safe" do
16
+ before(:each) do
17
+ @safe = PasswordSafe::Safe.new(@file, @masterpass)
18
+ end
19
+ it "creates a safe if none exists" do
20
+ @safe.access_safe
21
+ File.file?(@filename).should be_true
22
+ end
23
+ it "doesn't modify an existing safe" do
24
+ content = "some existing file content"
25
+ File.open(@filename, 'w') {|f| f.write content}
26
+ @safe.access_safe
27
+ File.read(@filename).should eq(content)
28
+ end
29
+ end
30
+
31
+ context "write_safe" do
32
+ before(:each) do
33
+ @safe = PasswordSafe::Safe.new(@file, @masterpass)
34
+ klass = Class.new { include PasswordSafe::Encryptor}
35
+ @encryptor = klass.new
36
+ @data = {"data" => "encrypt"}
37
+ end
38
+
39
+ it "creates a safe file to write to" do
40
+ @safe.write_safe(@data)
41
+ File.file?(@filename).should be_true
42
+ end
43
+
44
+ it "writes encrypted data to a safe" do
45
+ @safe.write_safe(@data)
46
+
47
+ #we'll use our encryptor to check the contents
48
+ hash = @encryptor.hash(@masterpass)
49
+ Marshal.load(@encryptor.decrypt(File.read(@filename), hash)).should eq(@data)
50
+ end
51
+ end
52
+
53
+ context "read_safe" do
54
+ it "reads encrypted data out of an existing safe" do
55
+ @safe = PasswordSafe::Safe.new(@file, @masterpass)
56
+ data = {"data" => "encrypt"}
57
+ @safe.write_safe(data)
58
+ #got data into an existing safe...now read it out again
59
+ @safe.read_safe.should eq(data)
60
+ end
61
+ end
62
+
63
+ after(:each) do
64
+ #We check on the existance of files when we expect them to exist so this seems ok
65
+ File.delete @filename if File.file?(@filename)
66
+ end
67
+ end # describe PasswordSafe::Safe
68
+
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'passwordsafe' # and any other gems you need
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
9
+
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: passwordsafe
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - thecatwasnot
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-22 00:00:00 -06:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ description: Small command line app for storing passwords
34
+ email:
35
+ - thecatwasnot@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - .gitignore
44
+ - .rspec
45
+ - Gemfile
46
+ - Gemfile.lock
47
+ - README.md
48
+ - Rakefile
49
+ - lib/passwordsafe.rb
50
+ - lib/passwordsafe/encryptor.rb
51
+ - lib/passwordsafe/keyring.rb
52
+ - lib/passwordsafe/safe.rb
53
+ - lib/passwordsafe/version.rb
54
+ - passwordsafe.gemspec
55
+ - safefile
56
+ - spec/encryptor_spec.rb
57
+ - spec/keyring_spec.rb
58
+ - spec/safe_spec.rb
59
+ - spec/spec_helper.rb
60
+ has_rdoc: true
61
+ homepage: http://rubygems.org/gems/passwordsafe
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options: []
66
+
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project: passwordsafe
88
+ rubygems_version: 1.3.7
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Small command line app for storing passwords
92
+ test_files: []
93
+