lockr 0.3.0 → 0.4.2

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.
@@ -4,7 +4,7 @@ require 'lockr/pwdstore'
4
4
  class AddAction < AesAction
5
5
 
6
6
  def initialize(id,url,username,pwd,keyfile,vault)
7
- keyfilehash = calculate_hash( keyfile)
7
+ keyfilehash = FileUtils.calculate_sha512_hash( keyfile)
8
8
 
9
9
  pwd_directory = load_from_vault( vault)
10
10
 
@@ -1,47 +1,12 @@
1
1
  require 'openssl'
2
2
  require 'lockr/encryption/aes'
3
+ require 'lockr/fileutils'
3
4
 
4
5
  class BaseAction
5
- def calculate_hash( filename)
6
- sha1 = OpenSSL::Digest::SHA512.new
7
-
8
- File.open( filename) do |file|
9
- buffer = ''
10
-
11
- # Read the file 512 bytes at a time
12
- while not file.eof
13
- file.read(512, buffer)
14
- sha1.update(buffer)
15
- end
16
- end
17
-
18
- sha1.to_s
19
- end
6
+ include FileUtils
20
7
 
21
8
  def save_to_vault( storelist, vault)
22
- rotate_vault( vault)
23
-
24
- File.open( vault, 'w') do |f|
25
- f.write( storelist.to_yaml)
26
- end
27
- end
28
-
29
- def rotate_vault( vault)
30
- return unless File.exists?(vault)
31
-
32
- # move old files first
33
- max_files = 2 # = 3 - 1
34
- max_files.downto( 0) { |i|
35
-
36
- if i == 0
37
- File.rename( vault, "#{vault}_#{i}")
38
- else
39
- j = i - 1
40
- if File.exists?("#{vault}_#{j}")
41
- File.rename( "#{vault}_#{j}", "#{vault}_#{i}")
42
- end
43
- end
44
- }
9
+ FileUtils.store_obj_yaml( vault, storelist)
45
10
  end
46
11
 
47
12
  # loads the datastructure for the password sets from the file
@@ -58,14 +23,6 @@ class BaseAction
58
23
  # :username => PasswordStore
59
24
  # }
60
25
  def load_from_vault( vault)
61
- storelist = {}
62
-
63
- if File.exist?( vault)
64
- File.open( vault, 'r') do |f|
65
- storelist = YAML::load(f)
66
- end
67
- end
68
-
69
- storelist
26
+ FileUtils.load_obj_yaml( vault)
70
27
  end
71
28
  end
@@ -12,7 +12,7 @@ class ListAction < AesAction
12
12
  out << "Id: #{id}"
13
13
  }
14
14
  else
15
- keyfilehash = calculate_hash( keyfile)
15
+ keyfilehash = FileUtils.calculate_sha512_hash( keyfile)
16
16
  pwd_directory.each { |oid,value|
17
17
  pwd_directory_id = YAML::load(decrypt( value[:enc], keyfilehash, value[:salt]))
18
18
  pwd_directory_id.each { |username, pwdstore|
@@ -4,7 +4,7 @@ require 'lockr/pwdstore'
4
4
  class RemoveAction < AesAction
5
5
 
6
6
  def initialize(id,username,keyfile,vault)
7
- keyfilehash = calculate_hash( keyfile)
7
+ keyfilehash = FileUtils.calculate_sha512_hash( keyfile)
8
8
  pwd_directory = load_from_vault( vault)
9
9
 
10
10
  unless pwd_directory.has_key?( id)
@@ -3,7 +3,7 @@ require 'lockr/action/aes'
3
3
  class ShowAction < AesAction
4
4
 
5
5
  def initialize(id,username,keyfile, vault)
6
- keyfilehash = calculate_hash( keyfile)
6
+ keyfilehash = FileUtils.calculate_sha512_hash( keyfile)
7
7
 
8
8
  pwd_directory = load_from_vault( vault)
9
9
 
@@ -0,0 +1,74 @@
1
+ module FileUtils
2
+
3
+ # rotate the provided file with a maximum of 'limit' backups
4
+ # renamed filed will be named file_0, file_1, ...
5
+ def FileUtils.rotate_file( file, limit)
6
+ return unless File.exists?(file)
7
+
8
+ # move old files first
9
+ max_files = limit - 1
10
+ max_files.downto( 0) { |i|
11
+
12
+ if i == 0
13
+ FileUtils.copy( file, "#{file}_#{i}")
14
+ else
15
+ j = i - 1
16
+ if File.exists?("#{file}_#{j}")
17
+ FileUtils.copy( "#{file}_#{j}", "#{file}_#{i}")
18
+ end
19
+ end
20
+ }
21
+
22
+ puts "Rotated local vault file(s)"
23
+ end
24
+
25
+ # copy file_src to file_target
26
+ def FileUtils.copy( file_src, file_target)
27
+ return unless File.exists?( file_src)
28
+
29
+ dst = File.new( file_target, 'w')
30
+ File.open( file_src, 'r') do |src|
31
+ dst.write( src.read)
32
+ end
33
+ dst.close
34
+ end
35
+
36
+ # store an object as yaml to file
37
+ def FileUtils.store_obj_yaml( file, object)
38
+ File.open( file, 'w') do |f|
39
+ f.write( object.to_yaml)
40
+ end
41
+ end
42
+
43
+ # load an yaml object from file
44
+ def FileUtils.load_obj_yaml( file)
45
+ object = {}
46
+
47
+ unless File.exist?( file)
48
+ return object
49
+ end
50
+
51
+ File.open( file, 'r') do |f|
52
+ object = YAML::load(f)
53
+ end
54
+
55
+ object
56
+ end
57
+
58
+ # calculate the sha512 hash of a file
59
+ def FileUtils.calculate_sha512_hash( filename)
60
+ sha512 = OpenSSL::Digest::SHA512.new
61
+
62
+ File.open( filename) do |file|
63
+ buffer = ''
64
+
65
+ # Read the file 512 bytes at a time
66
+ while not file.eof
67
+ file.read(512, buffer)
68
+ sha512.update(buffer)
69
+ end
70
+ end
71
+
72
+ sha512.to_s
73
+ end
74
+ end
data/lib/lockr/sftp.rb ADDED
@@ -0,0 +1,100 @@
1
+ require 'lockr/config'
2
+ require 'net/sftp'
3
+ require 'set'
4
+ require 'lockr/fileutils'
5
+
6
+ class SFTP
7
+ include FileUtils
8
+
9
+ # upload the vault via sftp to the location specified in the configuration
10
+ def upload( config, vault)
11
+ cfg_sftp = get_sftp_config( config)
12
+ remote_file = File.join( cfg_sftp[:directory], File.basename(vault))
13
+ Net::SFTP.start( cfg_sftp[:hostname], cfg_sftp[:username]) do |sftp|
14
+
15
+ # TODO check remote checksum to make sure upload is necessary
16
+ rotate_sftp_file( sftp, remote_file, 3)
17
+
18
+ # upload a file or directory to the remote host
19
+ sftp.upload!( vault, remote_file)
20
+ puts "Uploaded vault to host '#{cfg_sftp[:hostname]}' by SFTP"
21
+ end
22
+ end
23
+
24
+ # rotate the provided file with a maximum of 'limit' backups
25
+ # renamed filed will be named file_0, file_1, ...
26
+ def rotate_sftp_file( sftp, file, limit)
27
+ return unless file_exists( sftp, file)
28
+
29
+ # move old files first
30
+ max_files = limit - 1
31
+ max_files.downto( 0) { |i|
32
+
33
+ if i == 0
34
+ sftp.rename( file, "#{file}_#{i}")
35
+ else
36
+ j = i - 1
37
+ next unless file_exists( sftp, "#{file}_#{j}")
38
+ sftp.rename( "#{file}_#{j}", "#{file}_#{i}")
39
+ end
40
+ }
41
+
42
+ puts "Rotated remote vault file(s)"
43
+ end
44
+
45
+ # check if the file exists on the given sftp connection
46
+ def file_exists( sftp, file)
47
+ files = get_dir_listing( sftp, File.dirname(file))
48
+ files.include?( File.basename(file))
49
+ end
50
+
51
+ # get the file listing of a remote directory
52
+ def get_dir_listing( sftp, dir)
53
+ list = []
54
+
55
+ sftp.dir.foreach(dir) do |entry|
56
+ list << entry.name
57
+ end
58
+
59
+ Set.new(list)
60
+ end
61
+
62
+ # download the vault via sftp to the location specified in the configuration
63
+ def download( config, vault)
64
+ cfg_sftp = get_sftp_config( config)
65
+
66
+ Net::SFTP.start( cfg_sftp[:hostname], cfg_sftp[:username]) do |sftp|
67
+
68
+ # TODO check if remote file is same as local (checksum?)
69
+ rotate_file( vault, 3)
70
+
71
+ # upload a file or directory to the remote host
72
+ sftp.download!( File.join( cfg_sftp[:directory], File.basename(vault)), vault)
73
+ puts "Downloaded vault from host '#{cfg_sftp[:hostname]}' by SFTP"
74
+ end
75
+ end
76
+
77
+ # check config for section lockr and subsection sftp. then check for keys
78
+ # :hostname, :username and :directory. if anything is missing, raise ArgumentError
79
+ # returns sftp configuration hash
80
+ def get_sftp_config( config)
81
+ unless config.config.has_key?( :lockr)
82
+ raise ArgumentError, 'config has no "lockr" section'
83
+ end
84
+
85
+ cfg = config.config[:lockr]
86
+
87
+ unless cfg.has_key?( :sftp)
88
+ raise ArgumentError, 'config has no "sftp" section'
89
+ end
90
+
91
+ cfg_sftp = cfg[:sftp]
92
+
93
+ unless cfg_sftp.has_key?( :hostname) and cfg_sftp.has_key?( :username) and cfg_sftp.has_key?( :directory)
94
+ raise ArgumentError, 'config "sftp" section must have keys :host, :username and :directory'
95
+ end
96
+
97
+ cfg_sftp
98
+ end
99
+
100
+ end
data/lib/lockr/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module LockrVer
2
- VERSION = "0.3.0"
3
- DATE = "2012-08-13"
2
+ VERSION = "0.4.2"
3
+ DATE = "2012-08-19"
4
4
  end
data/lib/lockr.rb CHANGED
@@ -10,16 +10,19 @@ require 'lockr/action/remove'
10
10
  require 'lockr/action/show'
11
11
  require 'lockr/config'
12
12
  require 'lockr/pwdgen'
13
+ require 'lockr/sftp'
13
14
  require 'lockr/version'
15
+ require 'lockr/fileutils'
14
16
 
15
17
  class Lockr
16
18
 
17
19
  def run()
18
20
  options = parse_options()
19
- merge_config( options)
21
+ configfile = Configuration.new()
22
+ merge_config( configfile, options)
20
23
  validate_options( options)
21
24
  acquire_additional_input( options)
22
- process_actions( options)
25
+ process_actions( configfile, options)
23
26
  end
24
27
 
25
28
  def parse_options()
@@ -55,7 +58,17 @@ class Lockr
55
58
  opts.on( '-g', '--genpwd PARAMS', 'generate a random password (based on the optional PARAMS)') do |params|
56
59
  options[:generatepwd] = params
57
60
  end
61
+
62
+ options[:download] = nil
63
+ opts.on( '-d', '--download', 'download latest vault from configured sftp location before executing action') do |d|
64
+ options[:download] = true
65
+ end
58
66
 
67
+ options[:upload] = nil
68
+ opts.on( '-u', '--upload', 'upload vault to configured sftp location after executing action') do |d|
69
+ options[:upload] = true
70
+ end
71
+
59
72
  # This displays the help screen, all programs are
60
73
  # assumed to have this option.
61
74
  opts.on( '-h', '--help', 'Display this screen' ) do
@@ -82,9 +95,7 @@ class Lockr
82
95
  options
83
96
  end
84
97
 
85
- def merge_config( options)
86
- configfile = Configuration.new()
87
-
98
+ def merge_config( configfile, options)
88
99
  if configfile.config.nil?
89
100
  return
90
101
  end
@@ -138,7 +149,15 @@ class Lockr
138
149
  end
139
150
  end
140
151
 
141
- def process_actions( options)
152
+ def process_actions( configfile, options)
153
+ rotate_required = ( ! options[:download].nil? ) || ( ! %w{a add r remove}.index( options[:action]).nil? )
154
+ FileUtils.rotate_file( options[:vault], 3) if rotate_required
155
+
156
+ unless options[:download].nil?
157
+ sftp = SFTP.new
158
+ sftp.download( configfile, options[:vault])
159
+ end
160
+
142
161
  begin
143
162
  case options[:action]
144
163
  when 'a', 'add'
@@ -162,5 +181,10 @@ class Lockr
162
181
  say( "<%= color('Invalid keyfile', :red) %>")
163
182
  exit 42
164
183
  end
184
+
185
+ unless options[:upload].nil?
186
+ sftp = SFTP.new
187
+ sftp.upload( configfile, options[:vault])
188
+ end
165
189
  end
166
190
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lockr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,31 +9,43 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-13 00:00:00.000000000 Z
12
+ date: 2012-08-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: highline
16
- requirement: &70208522621980 !ruby/object:Gem::Requirement
16
+ requirement: &70292937547480 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: '0'
21
+ version: 1.6.13
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70208522621980
24
+ version_requirements: *70292937547480
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bundler
27
- requirement: &70208522620300 !ruby/object:Gem::Requirement
27
+ requirement: &70292937546980 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
31
31
  - !ruby/object:Gem::Version
32
- version: '0'
32
+ version: 1.1.4
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70208522620300
36
- description: Store your passwords AES encrypted in a simple yaml file
35
+ version_requirements: *70292937546980
36
+ - !ruby/object:Gem::Dependency
37
+ name: net-sftp
38
+ requirement: &70292937546520 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 2.0.5
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70292937546520
47
+ description: Lockr is a command line based password manager. Passwords are stored
48
+ AES-encrypted in a file on your own system.
37
49
  email: info@byteblues.com
38
50
  executables:
39
51
  - lockr
@@ -49,8 +61,10 @@ files:
49
61
  - lib/lockr/action/show.rb
50
62
  - lib/lockr/encryption/aes.rb
51
63
  - lib/lockr/config.rb
64
+ - lib/lockr/fileutils.rb
52
65
  - lib/lockr/pwdgen.rb
53
66
  - lib/lockr/pwdstore.rb
67
+ - lib/lockr/sftp.rb
54
68
  - lib/lockr/version.rb
55
69
  - !binary |-
56
70
  YmluL2xvY2ty
@@ -77,5 +91,5 @@ rubyforge_project:
77
91
  rubygems_version: 1.8.10
78
92
  signing_key:
79
93
  specification_version: 3
80
- summary: Safe password storage
94
+ summary: Command line based password manager
81
95
  test_files: []