osp 0.1.0.pre.dev.1 → 0.1.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.
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
-