osp 0.1.0.pre.dev.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91fa1ed62524c4d5a625fc41b705e53ec07c1025
4
- data.tar.gz: 4953a9cc50c9ae298912a8829ad040caa0a273e1
3
+ metadata.gz: 765b0bc1616f91a2da8a4ec9bb41e46146fe0e58
4
+ data.tar.gz: d7ea9546689038040a86571bd05c5d4be2da1f90
5
5
  SHA512:
6
- metadata.gz: a3b038055e9eabb2b95739973349a846db72e4dab13fb75d02eac627284acd91e4d640804edc42158ddad3933cbe80f272d5a57e7308280a15cad09aa7edc188
7
- data.tar.gz: 10ed0c220116da7cb8f1b4d72d5dcdd27e9eafb55a8a222032e82e22bc673c7ac3b66263215337dc37caf58c68dd19a63ed66025a015c082407c1b630d019fe9
6
+ metadata.gz: 9e6211266c619d2ebaa89907e1f6f8581f1d26c7bb58c2288a87106b91b836b66c80807e87fc5ae470810ed96601b12742c9d83bd0b804b9270957ba5e4ae3df
7
+ data.tar.gz: 0632221c03282e0a437a07fcb2333169ded00eea8a446f396a09330e0ae6656b8dbc263087b0d977974a83e8e3efba32561c0b751d91af65d51833de42208997
@@ -1,10 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- osp (0.1.0.pre.dev.1)
4
+ osp (0.1.0)
5
5
  highline (~> 1.7)
6
6
  msgpack (~> 0.7)
7
- rainbow (~> 2.0)
8
7
  thefox-ext (~> 1.2)
9
8
 
10
9
  GEM
@@ -13,7 +12,6 @@ GEM
13
12
  highline (1.7.8)
14
13
  minitest (5.8.3)
15
14
  msgpack (0.7.1)
16
- rainbow (2.0.0)
17
15
  thefox-ext (1.2.0)
18
16
 
19
17
  PLATFORMS
data/README.md CHANGED
@@ -1,7 +1,19 @@
1
- # One Shall Pass for Command Line
1
+ # One Shall Pass for Command-line
2
+
3
+ ## Install
4
+
5
+ The preferred method of installation is via RubyGems.org:
6
+ <https://rubygems.org/gems/osp>
7
+
8
+ gem install osp
9
+
10
+ or via `Gemfile`:
11
+
12
+ gem 'osp', '~>0.1'
2
13
 
3
14
  ## Project Links
4
15
 
16
+ - [Blog Post about OSP](http://blog.fox21.at/2015/12/19/one-shall-pass-for-command-line.html)
5
17
  - [Gem](https://rubygems.org/gems/osp)
6
18
  - [Travis CI Repository](https://travis-ci.org/TheFox/osp)
7
19
 
data/bin/osp CHANGED
@@ -5,22 +5,13 @@ raise 'Ruby >=2.1 required' unless RUBY_VERSION >= '2.1.0'
5
5
 
6
6
  require 'optparse'
7
7
  require 'fileutils'
8
- #require 'securerandom'
9
- #require 'openssl'
10
- #require 'base64'
11
- # require 'yaml/store'
12
8
  require 'pp'
13
9
 
14
10
  require 'bundler/setup'
15
- #require 'highline/import'
16
11
  require 'highline'
17
- require 'rainbow'
18
12
  require 'msgpack'
19
13
  require 'osp'
20
14
 
21
- #msg = [1,2,3].to_msgpack
22
- #MessagePack.unpack(msg)
23
-
24
15
 
25
16
  options = {
26
17
  :database_path => "#{Dir.home}/.osp",
@@ -39,7 +30,6 @@ opts = OptionParser.new do |opts|
39
30
  exit 3
40
31
  end
41
32
  end
42
- #ARGV << '-h' if ARGV.count == 0
43
33
  args = opts.parse(ARGV)
44
34
 
45
35
 
@@ -50,22 +40,20 @@ puts TheFox::OSP::HOMEPAGE
50
40
  puts
51
41
 
52
42
  puts 'Master Login'
53
-
54
- # email = @cli.ask(' Email: ')
55
- puts ' Email: xyz@example.com'
56
- # password = @cli.ask('Password: '){ |q| q.echo = '*' }
57
- puts 'Password: xyz'
43
+ email = @cli.ask(' Email: ')
44
+ password = @cli.ask('Password: '){ |q| q.echo = '*' }
58
45
 
59
46
  Console.cursor_jump_to_column
60
47
  Console.cursor_up(2)
61
48
  Console.screen_clear_to_bottom
62
-
63
49
  puts ' Email: *****'
64
50
  puts 'Password: *****'
65
51
  puts
66
52
 
67
- email = 'xyz@example.com'
68
- password = 'xyz'
53
+ printf "Calculating base hash: #{TheFox::OSP::HASHES_N} (#{TheFox::OSP::HASHES_EXP}-bit) - please wait ..."
54
+ osp = TheFox::OSP::OSP.new(email, password, TheFox::OSP::HASHES_N)
55
+ osp.key_derivation
56
+ puts ' done'
69
57
 
70
58
  database = {
71
59
  'meta' => {
@@ -78,28 +66,58 @@ database = {
78
66
  has_database = false
79
67
  has_database_changes = false
80
68
  if File.exist?(options[:database_path])
81
- puts "Found database file: #{options[:database_path]}",
69
+ puts "Use database file: #{options[:database_path]}",
82
70
  'Try to open it ...'
83
71
 
84
72
  begin
85
- database = MessagePack.unpack(File.binread(options[:database_path]))
86
- database['hosts'] = database['hosts'].map{ |name, host| [name, TheFox::OSP::Host.from_h(host)] }.to_h
73
+ puts "Read file '#{options[:database_path]}'."
74
+ db_meta = File.binread(options[:database_path])
75
+
76
+ puts 'Process metadata.'
77
+ db_meta = Base64.strict_decode64(db_meta)
78
+ db_meta = MessagePack.unpack(db_meta)
79
+
80
+ db_e = Base64.strict_decode64(db_meta['db'])
81
+ mac = OpenSSL::Digest::SHA256.digest(db_e)
82
+ if db_meta['mac'] == mac
83
+ puts 'Setup database encryption.'
84
+ dk_sha256 = OpenSSL::Digest::SHA256.digest(osp.dk)
85
+ iv = Base64.strict_decode64(db_meta['iv'])
86
+
87
+ aes = OpenSSL::Cipher::Cipher.new('AES-256-CBC')
88
+ aes.decrypt
89
+ aes.key = dk_sha256
90
+ aes.iv = iv
91
+
92
+ begin
93
+ puts 'Decrypt database.'
94
+ db_b64 = aes.update(db_e)
95
+ db_b64 << aes.final
96
+ rescue Exception => e
97
+ raise 'Incorrect email and password combination.'
98
+ end
99
+
100
+ puts 'Build database.'
101
+ database = MessagePack.unpack(Base64.strict_decode64(db_b64))
102
+
103
+ database['hosts'] = database['hosts'].map{ |name, host|
104
+ host_o = TheFox::OSP::Host.from_h(host)
105
+ host_o.osp = osp
106
+ [name, host_o]
107
+ }.to_h
108
+
109
+ puts 'Startup done.'
110
+ else
111
+ raise 'Integrity check failed.'
112
+ end
87
113
  rescue Exception => e
88
114
  puts "FATAL ERROR: couldn't open database:"
89
- puts "'#{e}'"
115
+ puts "#{e}"
90
116
 
91
- exit
117
+ exit 1
92
118
  end
93
119
  end
94
120
 
95
- printf "Calculating base hash: #{TheFox::OSP::HASHES_N} (#{TheFox::OSP::HASHES_EXP}-bit) - please wait ..."
96
-
97
- osp = TheFox::OSP::OSP.new(email, password, TheFox::OSP::HASHES_N)
98
- osp.key_derivation
99
- puts ' done'
100
-
101
- database['hosts'].each{ |name, host| host.osp = osp }
102
-
103
121
  def password_callback_method(step, pw)
104
122
  printf '.'
105
123
  end
@@ -125,16 +143,9 @@ def host_edit(osp, host = nil)
125
143
  host = TheFox::OSP::Host.new(osp) if host.nil?
126
144
 
127
145
  tmp = @cli.ask(' Name: ' + (!host.name.nil? ? "[#{host.name}]" : '') + ' ').strip.to_s
128
- # puts "name: '#{tmp}' #{tmp.class}"
129
-
130
146
  host.name = tmp if tmp != ''
131
- # puts "name: '#{host.name}' #{host.name.class}"
132
-
133
147
  host.name = nil if host.name == ''
134
- # puts "name: '#{host.name}' #{host.name.class}"
135
-
136
148
  if host.name.nil?
137
- # puts "No host input."
138
149
  return nil
139
150
  end
140
151
 
@@ -188,12 +199,9 @@ while true
188
199
  hosts_n = database['hosts'].count
189
200
  format = '%' + hosts_n.to_s.length.to_s + 'd'
190
201
 
191
- # puts "format: '#{format}'"
192
-
193
202
  n = 0
194
203
  database['hosts'].values.each do |host|
195
204
  n += 1
196
- # pp host
197
205
  printf "#{format}. %s\n", n, host.name
198
206
  end
199
207
  when 's'
@@ -273,7 +281,7 @@ while true
273
281
 
274
282
  if !selected_host.nil?
275
283
  host_edit(osp, selected_host)
276
- host_show(selected_host)
284
+ host_show(selected_host, true)
277
285
 
278
286
  database['hosts'][selected_host.name] = selected_host
279
287
 
@@ -317,21 +325,51 @@ while true
317
325
  when 'w'
318
326
  if has_database_changes
319
327
  tmp = "#{options[:database_path]}~"
320
- backup = "#{options[:database_path]}~backup"
321
328
 
322
329
  database['meta']['updated_at'] = DateTime.now.to_s
323
330
 
324
- if File.exist?(options[:database_path])
325
- puts "Backup old file to '#{backup}'."
326
- FileUtils.mv(options[:database_path], backup)
327
- end
331
+ # http://stackoverflow.com/questions/9049789/aes-encryption-key-versus-iv
332
+ # http://keepass.info/help/base/security.html
333
+ # https://gist.github.com/byu/99651
328
334
 
329
- puts "Write temp file to '#{tmp}'."
335
+ puts 'Make temp database.'
330
336
  db_c = database.clone
331
337
  db_c['hosts'] = db_c['hosts'].map{ |name, host| [name, host.to_h] }.to_h
332
- File.binwrite(tmp, db_c.to_msgpack)
333
338
 
334
- puts "Finally move temp file to '#{options[:database_path]}'."
339
+ puts 'Setup database encryption.'
340
+ dk_sha256 = OpenSSL::Digest::SHA256.digest(osp.dk)
341
+ iv = OpenSSL::Cipher::Cipher.new('AES-256-CBC').random_iv
342
+
343
+ aes = OpenSSL::Cipher::Cipher.new('AES-256-CBC')
344
+ aes.encrypt
345
+ aes.key = dk_sha256
346
+ aes.iv = iv
347
+
348
+ puts 'Encrypt database.'
349
+ db_e = aes.update(Base64.strict_encode64(db_c.to_msgpack))
350
+ db_e << aes.final
351
+
352
+ mac = OpenSSL::Digest::SHA256.digest(db_e)
353
+
354
+ db_out = {
355
+ 'version' => 1,
356
+ 'iv' => Base64.strict_encode64(iv),
357
+ 'db' => Base64.strict_encode64(db_e),
358
+ 'mac' => mac,
359
+ }
360
+ db_out = db_out.to_msgpack
361
+ db_out = Base64.strict_encode64(db_out)
362
+
363
+ puts "Write temp file to '#{tmp}'."
364
+ File.binwrite(tmp, db_out)
365
+
366
+ backup_dts = Time.now.strftime('%Y%m%d-%H%M%S')
367
+ backup = "#{options[:database_path]}~backup_#{backup_dts}_" + Digest::SHA256.file(tmp).hexdigest[0..7]
368
+
369
+ puts "Backup temp file to '#{backup}'."
370
+ FileUtils.cp(tmp, backup)
371
+
372
+ puts "Finally, move temp file to '#{options[:database_path]}'."
335
373
  FileUtils.mv(tmp, options[:database_path])
336
374
 
337
375
  has_database_changes = false
@@ -4,16 +4,8 @@ module TheFox
4
4
 
5
5
  class Host
6
6
 
7
- # attr_accessor :osp
8
- # attr_accessor :version
9
7
  attr_accessor :created_at
10
8
  attr_accessor :updated_at
11
- # attr_accessor :name
12
- # attr_accessor :generation
13
- # attr_accessor :length
14
- # attr_accessor :symbols
15
- # attr_accessor :hashes
16
- # attr_accessor :password
17
9
 
18
10
  def initialize(osp = nil)
19
11
  @osp = osp
@@ -48,14 +40,6 @@ module TheFox
48
40
  @version.to_i
49
41
  end
50
42
 
51
- # def created_at=(v)
52
- # @created_at = v
53
- # end
54
-
55
- # def created_at
56
- # @created_at
57
- # end
58
-
59
43
  def name=(v)
60
44
  v = nil if v == ''
61
45
  @name = v
@@ -99,7 +83,6 @@ module TheFox
99
83
 
100
84
  def generate_password(regenerate = false)
101
85
  if @password.nil? && !@osp.nil? || regenerate
102
- # puts "host name: '#{@name}'"
103
86
  @password = @osp.password(@name, @length, @generation, @symbols)
104
87
  end
105
88
  end
@@ -127,8 +110,6 @@ module TheFox
127
110
  'length' => @length,
128
111
  'symbols' => @symbols,
129
112
  'hashes' => @hashes,
130
-
131
- #'password' => @password,
132
113
  }
133
114
  end
134
115
 
@@ -18,6 +18,7 @@ module TheFox
18
18
 
19
19
  class OSP
20
20
 
21
+ attr_accessor :dk
21
22
  attr_accessor :hashes
22
23
 
23
24
  def initialize(email, password, hashes = HASHES_N)
@@ -29,14 +30,7 @@ module TheFox
29
30
  end
30
31
 
31
32
  def key_derivation
32
- # puts "password: #{@password}"
33
- # puts "email: #{@email}"
34
- # puts "hashes: #{@hashes}"
35
-
36
33
  @dk = OpenSSL::PKCS5.pbkdf2_hmac(@password, @email, @hashes, 64, OpenSSL::Digest::SHA512.new)
37
- # pp @dk.length
38
- # pp @dk.length * 8
39
- # pp @dk.to_hex
40
34
  end
41
35
 
42
36
  def password(host_name, length = 16, generation = 1, symbols = 1)
@@ -48,29 +42,23 @@ module TheFox
48
42
  step = 0
49
43
  while pw.nil?
50
44
  raw = [ID, @email, host_name, generation, step]
51
- # pp raw
52
45
  data = raw.to_msgpack
53
46
  hmac_p = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA512.new, @dk, data)
54
47
  hmac_b64 = Base64.strict_encode64(hmac_p)
55
48
  pw = hmac_b64 if is_ok_pw(hmac_b64)
56
49
 
57
- # pp hmac_b64[0..16]
58
- #sleep 0.1
59
-
60
50
  @password_callback_method.call(step, hmac_b64) if !@password_callback_method.nil?
61
51
  step += 1
62
52
  end
63
53
 
64
54
  if symbols > 0
65
55
  sub_method = find_method_to_sub(pw)
66
- #puts "sub_method = #{sub_method}"
67
56
 
68
57
  _b64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
69
58
 
70
59
  indices = []
71
60
  (0..PASSWORD_MIN_SIZE).each do |n|
72
61
  c = pw[n]
73
- #puts "#{n} = #{c}"
74
62
  if c.method(sub_method).call
75
63
  indices << n
76
64
  if indices.count >= symbols
@@ -79,8 +67,6 @@ module TheFox
79
67
  end
80
68
  end
81
69
 
82
- #pp indices
83
-
84
70
  _map = "`~!@#$%^&*()-_+={}[]|;:,<>.?/"
85
71
  _map_len = _map.length
86
72
 
@@ -93,15 +79,10 @@ module TheFox
93
79
  x = _map[i % _map_len]
94
80
  arr << x
95
81
  last = index + 1
96
-
97
- #puts "#{index} = '#{c}' '#{i}' '#{x}' #{last}"
98
82
  end
99
83
  arr << pw[last..-1]
100
- #pp arr
101
84
  pw = arr.join
102
85
  end
103
-
104
- #puts "length: #{length}"
105
86
  pw[0...length]
106
87
  end
107
88
 
@@ -119,8 +100,6 @@ module TheFox
119
100
  (0...PASSWORD_MIN_SIZE).each do |n|
120
101
  c = pw[n]
121
102
 
122
- # puts "#{n} = #{c}"
123
-
124
103
  if c.is_digit?
125
104
  digits += 1
126
105
  elsif c.is_upper?
@@ -135,7 +114,6 @@ module TheFox
135
114
  bad = lambda { |x| x == 0 || x > 5 }
136
115
 
137
116
  if bad.call(caps) || bad.call(lowers) || bad.call(digits)
138
- #puts 'return false'
139
117
  return false
140
118
  end
141
119
 
@@ -162,8 +140,6 @@ module TheFox
162
140
  elsif c.is_lower?
163
141
  lowers += 1
164
142
  end
165
-
166
- #puts "#{n} = #{c} #{digits} #{caps} #{lowers}"
167
143
  end
168
144
 
169
145
  rv = ''
@@ -174,7 +150,6 @@ module TheFox
174
150
  else
175
151
  rv = 'is_upper?'
176
152
  end
177
- #rv = 'is_upper?'
178
153
  rv
179
154
  end
180
155
 
@@ -2,8 +2,8 @@
2
2
  module TheFox
3
3
  module OSP
4
4
  RELEASE_ID = 0
5
- VERSION = '0.1.0-dev.1'
6
- DATE = '2015-12-17'
5
+ VERSION = '0.1.0'
6
+ DATE = '2015-12-19'
7
7
  HOMEPAGE = 'https://github.com/TheFox/osp'
8
8
  end
9
9
  end
@@ -13,23 +13,20 @@ Gem::Specification.new do |spec|
13
13
  spec.email = 'christian@fox21.at'
14
14
 
15
15
  spec.summary = %q{One Shall Pass}
16
- spec.description = %q{One Shall Pass}
16
+ spec.description = %q{One Shall Pass for Command Line.}
17
17
  spec.homepage = TheFox::OSP::HOMEPAGE
18
18
  spec.license = 'GPL-3.0'
19
19
 
20
20
  spec.files = `git ls-files -z`.split("\x0").reject{ |f| f.match(%r{^(test|spec|features)/}) }
21
21
  spec.bindir = 'bin'
22
- spec.executables = ['osp', 'catmp']
22
+ spec.executables = ['osp']
23
23
  spec.require_paths = ['lib']
24
24
  spec.required_ruby_version = '>=2.1.0'
25
25
 
26
- #spec.requirements << ''
27
-
28
26
  spec.add_development_dependency 'bundler', '~>1.10'
29
27
  spec.add_development_dependency 'minitest', '~>5.8'
30
28
 
31
29
  spec.add_dependency 'highline', '~>1.7'
32
- spec.add_dependency 'rainbow', '~>2.0'
33
30
  spec.add_dependency 'msgpack', '~>0.7'
34
31
 
35
32
  spec.add_dependency 'thefox-ext', '~>1.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: osp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.dev.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Mayer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-17 00:00:00.000000000 Z
11
+ date: 2015-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.7'
55
- - !ruby/object:Gem::Dependency
56
- name: rainbow
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '2.0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: msgpack
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,11 +80,10 @@ dependencies:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
82
  version: '1.2'
97
- description: One Shall Pass
83
+ description: One Shall Pass for Command Line.
98
84
  email: christian@fox21.at
99
85
  executables:
100
86
  - osp
101
- - catmp
102
87
  extensions: []
103
88
  extra_rdoc_files: []
104
89
  files:
@@ -109,7 +94,6 @@ files:
109
94
  - Makefile
110
95
  - Makefile.common
111
96
  - README.md
112
- - bin/catmp
113
97
  - bin/osp
114
98
  - lib/ext/string.rb
115
99
  - lib/osp.rb
@@ -136,9 +120,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
120
  version: 2.1.0
137
121
  required_rubygems_version: !ruby/object:Gem::Requirement
138
122
  requirements:
139
- - - ">"
123
+ - - ">="
140
124
  - !ruby/object:Gem::Version
141
- version: 1.3.1
125
+ version: '0'
142
126
  requirements: []
143
127
  rubyforge_project:
144
128
  rubygems_version: 2.4.7
data/bin/catmp DELETED
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # coding: UTF-8
3
-
4
- raise 'Ruby >=2.1 required' unless RUBY_VERSION >= '2.1.0'
5
-
6
- require 'optparse'
7
- require 'yaml'
8
- require 'pp'
9
-
10
- require 'bundler/setup'
11
- require 'msgpack'
12
-
13
-
14
- options = {
15
- :path => nil,
16
- :yaml => false,
17
- }
18
- opts = OptionParser.new do |opts|
19
- opts.banner = 'Usage: catmp'
20
- opts.separator('')
21
-
22
- # opts.on('-p', '--path <path>', 'Path msgpack file.') do |path|
23
- # options[:path] = path
24
- # end
25
-
26
- opts.on('-y', '--yaml', 'Output in YAML format.') do
27
- options[:yaml] = true
28
- end
29
-
30
- opts.on_tail('-h', '--help', 'Show this message.') do
31
- puts opts
32
- puts
33
- exit 3
34
- end
35
- end
36
- #ARGV << '-h' if ARGV.count == 0
37
- args = opts.parse(ARGV)
38
-
39
- if args.count > 0
40
- options[:path] = args.shift
41
-
42
- if !options[:path].nil?
43
- ar = MessagePack.unpack(File.binread(options[:path]))
44
-
45
- if options[:yaml]
46
- print YAML.dump(ar)
47
- else
48
- pp ar
49
- end
50
- else
51
- raise 'FATAL ERROR: path invalid.'
52
- end
53
- else
54
- opts.parse(['-h'])
55
- end
56
-