skeletonkey 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7248579cc226d9cb384f36a30a94f438036140cc
4
+ data.tar.gz: 9fdc1c0cc5aa4d1e3de85487788bf2f149e4ee9a
5
+ SHA512:
6
+ metadata.gz: 32e54091eb0e1d65fab248cb73bf61d4dd4ed7ec0af279e5ad83b9592add31138463fa74729a2a5e70b6ffc1c912e5da781bf597054e98ccc9a1871a820500b0
7
+ data.tar.gz: 1cca1778429025ca6309fbdb25b8d30f66b3bfc3cec47bd053f1446ef4f05d317e0a614d0b393c86bd515a3c9a6cfdd64c16113f1872dc99068c458ba6e0264e
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.dirname(File.realpath(__FILE__)) + '/../lib')
4
+
5
+ require 'skeletonkey/cli'
6
+
7
+ Lockbox::Cli.start(ARGV)
@@ -0,0 +1,54 @@
1
+ require 'thor'
2
+ require 'clipboard'
3
+ require 'io/console'
4
+ require 'skeletonkey/safe'
5
+ require 'skeletonkey/password'
6
+
7
+ module Lockbox
8
+ class Cli < Thor
9
+ def initialize(*args)
10
+ super(*args)
11
+
12
+ @safe ||= Safe.new
13
+ end
14
+
15
+ desc "add KEY", "add a new password for KEY"
16
+ def add(key)
17
+ STDIN.noecho do |io|
18
+ puts "Please Enter a Password for #{key}: "
19
+ first_attempt = io.gets.chomp
20
+
21
+ puts "Please confirm your password: "
22
+ second_attempt = io.gets.chomp
23
+
24
+ on_invalid = ->(message){ puts message }
25
+
26
+ if Password.valid?(first_attempt, second_attempt, &on_invalid)
27
+ @safe.add(key, Password.fromString(first_attempt))
28
+ end
29
+ end
30
+ end
31
+
32
+ desc "remove KEY", "remove a password for KEY"
33
+ def remove(key)
34
+ @safe.remove(key)
35
+ end
36
+
37
+ desc "get KEY", "retrieve a password for KEY"
38
+ option :copy, :type => :boolean
39
+ def get(key)
40
+ password = @safe.get(key).to_str
41
+
42
+ if options[:copy]
43
+ Clipboard.copy(password)
44
+ else
45
+ puts password
46
+ end
47
+ end
48
+
49
+ desc "list", "list all KEYs"
50
+ def list
51
+ puts @safe.list
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ module Lockbox
2
+ class KeyPair
3
+ class << self
4
+ def generate
5
+ return if File.exists?(private_key_path) && File.exists?(public_key_path)
6
+
7
+ key = OpenSSL::PKey::RSA.new 2048
8
+
9
+ File.open(private_key_path, 'w', 0600) do |file|
10
+ file.write(key.to_pem)
11
+ end
12
+
13
+ File.open(public_key_path, 'w', 0600) do |file|
14
+ file.write(key.public_key.to_pem)
15
+ end
16
+ end
17
+
18
+ def public_encrypt(data)
19
+ generate
20
+ key = OpenSSL::PKey::RSA.new(File.read(public_key_path))
21
+ key.public_encrypt(data)
22
+ end
23
+
24
+ def private_decrypt(data)
25
+ generate
26
+ key = OpenSSL::PKey::RSA.new(File.read(private_key_path))
27
+ key.private_decrypt(data)
28
+ end
29
+
30
+ private
31
+
32
+ def private_key_path
33
+ File.join(Lockbox::DIRECTORY, "private_key.pem")
34
+ end
35
+
36
+ def public_key_path
37
+ File.join(Lockbox::DIRECTORY, "public_key.pem")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,79 @@
1
+ require 'openssl'
2
+ require 'skeletonkey/key_pair'
3
+
4
+ module Lockbox
5
+ class Password
6
+ attr_accessor :contents, :encrypted_contents, :iv, :key
7
+
8
+ class << self
9
+ def valid?(password, confirmed_password, &on_invalid)
10
+ valid = true
11
+
12
+ if password != confirmed_password
13
+ on_invalid.call("Your passwords do not match! Please try again")
14
+ valid = false
15
+ elsif password === ''
16
+ on_invalid.call("Your password cannot be empty! Please try again")
17
+ valid = false
18
+ end
19
+
20
+ valid
21
+ end
22
+
23
+ def fromHash(password_hash)
24
+ password = new
25
+ password.encrypted_contents = password_hash[:encrypted_contents]
26
+ password.key = password_hash[:key]
27
+ password.iv = password_hash[:iv]
28
+
29
+ password.decrypt
30
+ password
31
+ end
32
+
33
+ def fromString(password_str)
34
+ password = new
35
+ password.contents = password_str
36
+
37
+ password.encrypt
38
+ password
39
+ end
40
+ end
41
+
42
+ def to_str
43
+ @contents
44
+ end
45
+
46
+ def to_hash
47
+ {
48
+ :encrypted_contents => @encrypted_contents,
49
+ :iv => @iv,
50
+ :key => @key
51
+ }
52
+ end
53
+
54
+ def encrypt
55
+ cipher.encrypt
56
+
57
+ # set random key/iv on cipher, return for public encryption
58
+ # and store encrypted key/iv in instance variables
59
+ @key = KeyPair.public_encrypt(cipher.random_key)
60
+ @iv = KeyPair.public_encrypt(cipher.random_iv)
61
+
62
+ @encrypted_contents = cipher.update(@contents) + cipher.final
63
+ end
64
+
65
+ def decrypt
66
+ decipher = cipher
67
+ decipher.decrypt
68
+
69
+ decipher.key = KeyPair.private_decrypt(@key)
70
+ decipher.iv = KeyPair.private_decrypt(@iv)
71
+
72
+ @contents = decipher.update(@encrypted_contents) + decipher.final
73
+ end
74
+
75
+ def cipher
76
+ @cipher ||= OpenSSL::Cipher.new('AES-256-CBC')
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,50 @@
1
+ module Lockbox
2
+ DIRECTORY = File.join(Dir.home, ".lockbox")
3
+
4
+ class Safe
5
+ def initialize()
6
+ Dir.mkdir(Lockbox::DIRECTORY) unless Dir.exists?(Lockbox::DIRECTORY)
7
+
8
+ @file = File.join(Lockbox::DIRECTORY, "safe")
9
+ @storage = {}
10
+
11
+ reload
12
+ end
13
+
14
+ def add(key, password)
15
+ @storage[key] = password.to_hash
16
+ update
17
+ end
18
+
19
+ def get(key)
20
+ Password.fromHash(@storage[key])
21
+ end
22
+
23
+ def remove(key)
24
+ @storage.delete(key)
25
+ update
26
+ end
27
+
28
+ def list
29
+ @storage.keys * "\n"
30
+ end
31
+
32
+ private
33
+
34
+ def reload
35
+ @storage = {}
36
+
37
+ return if !File.exists?(@file)
38
+
39
+ File.open(@file, 'r') do |file|
40
+ @storage = Marshal.load(file)
41
+ end
42
+ end
43
+
44
+ def update
45
+ File.open(@file, 'w', 0600) do |file|
46
+ file << Marshal.dump(@storage)
47
+ end
48
+ end
49
+ end
50
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skeletonkey
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Dennis Heckman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Simple password storage and retrieval
14
+ email: denheck@gmail.com
15
+ executables:
16
+ - skeletonkey
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/skeletonkey
21
+ - lib/skeletonkey/cli.rb
22
+ - lib/skeletonkey/key_pair.rb
23
+ - lib/skeletonkey/password.rb
24
+ - lib/skeletonkey/safe.rb
25
+ homepage: http://rubygems.org/gems/skeletonkey
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.2.2
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Password Protection
49
+ test_files: []