osp 0.1.0.pre.dev.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 91fa1ed62524c4d5a625fc41b705e53ec07c1025
4
+ data.tar.gz: 4953a9cc50c9ae298912a8829ad040caa0a273e1
5
+ SHA512:
6
+ metadata.gz: a3b038055e9eabb2b95739973349a846db72e4dab13fb75d02eac627284acd91e4d640804edc42158ddad3933cbe80f272d5a57e7308280a15cad09aa7edc188
7
+ data.tar.gz: 10ed0c220116da7cb8f1b4d72d5dcdd27e9eafb55a8a222032e82e22bc673c7ac3b66263215337dc37caf58c68dd19a63ed66025a015c082407c1b630d019fe9
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ /.bundle/
2
+ .setup
3
+ CHANGELOG-*.txt
4
+ /releases/
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1
4
+ - 2.2
5
+ before_install:
6
+ - ruby --version
7
+ script:
8
+ - make test
9
+ - make install
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+
2
+ source 'https://rubygems.org'
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ osp (0.1.0.pre.dev.1)
5
+ highline (~> 1.7)
6
+ msgpack (~> 0.7)
7
+ rainbow (~> 2.0)
8
+ thefox-ext (~> 1.2)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ highline (1.7.8)
14
+ minitest (5.8.3)
15
+ msgpack (0.7.1)
16
+ rainbow (2.0.0)
17
+ thefox-ext (1.2.0)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ bundler (~> 1.10)
24
+ minitest (~> 5.8)
25
+ osp!
26
+
27
+ BUNDLED WITH
28
+ 1.10.2
data/Makefile ADDED
@@ -0,0 +1,8 @@
1
+
2
+ GEM_NAME = osp
3
+
4
+ include Makefile.common
5
+
6
+ .PHONY: test
7
+ test:
8
+ RUBYOPT=-w ./tests/ts_all.rb
data/Makefile.common ADDED
@@ -0,0 +1,51 @@
1
+
2
+ # Ruby Common Big
3
+ # 2015-12-15
4
+
5
+ MV = mv -nv
6
+ RM = rm -rf
7
+ MKDIR = mkdir -p
8
+ BUNDLER = bundle
9
+ BUNDLER_OPTIONS = --jobs=5 --retry=3
10
+ GEMSPEC_FILE = $(GEM_NAME).gemspec
11
+
12
+ .PHONY: all $(ALL_TARGETS_EXT)
13
+ all: setup
14
+
15
+ .PHONY: setup
16
+ setup: .setup
17
+
18
+ .setup:
19
+ $(BUNDLER) install $(BUNDLER_OPTIONS)
20
+ touch $@
21
+
22
+ .PHONY: install
23
+ install:
24
+ gem_file=$$(gem build $(GEMSPEC_FILE) | grep 'File:' | tail -1 | awk '{ print $$2 }'); \
25
+ sudo gem install $$gem_file; \
26
+ $(RM) $$gem_file
27
+
28
+ .PHONY: uninstall
29
+ uninstall:
30
+ sudo gem uninstall $(GEM_NAME)
31
+
32
+ .PHONY: update
33
+ update:
34
+ $(BUNDLER) update
35
+
36
+ .PHONY: clean
37
+ clean:
38
+ $(RM) .setup
39
+
40
+ .PHONY: release
41
+ release: | releases
42
+ set -e; \
43
+ gem_file=$$(gem build $(GEMSPEC_FILE) | grep 'File:' | tail -1 | awk '{ print $$2 }'); \
44
+ dst="releases/$$gem_file"; \
45
+ [ ! -f $$dst ]; \
46
+ $(MV) $$gem_file releases; \
47
+ gem push $$dst; \
48
+ echo 'done'
49
+
50
+ releases:
51
+ $(MKDIR) $@
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # One Shall Pass for Command Line
2
+
3
+ ## Project Links
4
+
5
+ - [Gem](https://rubygems.org/gems/osp)
6
+ - [Travis CI Repository](https://travis-ci.org/TheFox/osp)
7
+
8
+ ## Weblinks
9
+
10
+ - [maxtaco/oneshallpass](https://github.com/maxtaco/oneshallpass)
11
+ - [Ruby OpenSSL HMAC](http://ruby-doc.org/stdlib-2.2.4/libdoc/openssl/rdoc/OpenSSL/HMAC.html)
12
+ - [Ruby OpenSSL PKCS5](http://ruby-doc.org/stdlib-2.2.2/libdoc/openssl/rdoc/OpenSSL/PKCS5.html)
13
+ - [Ruby AES Encryption using OpenSSL](https://gist.github.com/byu/99651)
14
+
15
+ ## License
16
+ Copyright (C) 2015 Christian Mayer <http://fox21.at>
17
+
18
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
19
+
20
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
data/bin/catmp ADDED
@@ -0,0 +1,56 @@
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
+
data/bin/osp ADDED
@@ -0,0 +1,384 @@
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 'fileutils'
8
+ #require 'securerandom'
9
+ #require 'openssl'
10
+ #require 'base64'
11
+ # require 'yaml/store'
12
+ require 'pp'
13
+
14
+ require 'bundler/setup'
15
+ #require 'highline/import'
16
+ require 'highline'
17
+ require 'rainbow'
18
+ require 'msgpack'
19
+ require 'osp'
20
+
21
+ #msg = [1,2,3].to_msgpack
22
+ #MessagePack.unpack(msg)
23
+
24
+
25
+ options = {
26
+ :database_path => "#{Dir.home}/.osp",
27
+ }
28
+ opts = OptionParser.new do |opts|
29
+ opts.banner = 'Usage: osp'
30
+ opts.separator('')
31
+
32
+ opts.on('-d', '--database <path>', 'Path to the database file.') do |path|
33
+ options[:database_path] = path
34
+ end
35
+
36
+ opts.on_tail('-h', '--help', 'Show this message.') do
37
+ puts opts
38
+ puts
39
+ exit 3
40
+ end
41
+ end
42
+ #ARGV << '-h' if ARGV.count == 0
43
+ args = opts.parse(ARGV)
44
+
45
+
46
+ @cli = HighLine.new
47
+
48
+ puts "OSP - OneShallPass #{TheFox::OSP::VERSION}"
49
+ puts TheFox::OSP::HOMEPAGE
50
+ puts
51
+
52
+ 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'
58
+
59
+ Console.cursor_jump_to_column
60
+ Console.cursor_up(2)
61
+ Console.screen_clear_to_bottom
62
+
63
+ puts ' Email: *****'
64
+ puts 'Password: *****'
65
+ puts
66
+
67
+ email = 'xyz@example.com'
68
+ password = 'xyz'
69
+
70
+ database = {
71
+ 'meta' => {
72
+ 'version' => 1,
73
+ 'created_at' => DateTime.now.to_s,
74
+ 'updated_at' => DateTime.now.to_s,
75
+ },
76
+ 'hosts' => {}
77
+ }
78
+ has_database = false
79
+ has_database_changes = false
80
+ if File.exist?(options[:database_path])
81
+ puts "Found database file: #{options[:database_path]}",
82
+ 'Try to open it ...'
83
+
84
+ 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
87
+ rescue Exception => e
88
+ puts "FATAL ERROR: couldn't open database:"
89
+ puts "'#{e}'"
90
+
91
+ exit
92
+ end
93
+ end
94
+
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
+ def password_callback_method(step, pw)
104
+ printf '.'
105
+ end
106
+ osp.password_callback_method = self.method('password_callback_method')
107
+
108
+ def host_show(host, regenerate_password = false)
109
+ if !host.has_generated_password? || regenerate_password
110
+ print 'Generate password '
111
+ host.generate_password(regenerate_password)
112
+ puts ' done'
113
+ end
114
+
115
+ puts
116
+ puts " Name: #{host.name}"
117
+ puts "Generation: #{host.generation}"
118
+ puts " Length: #{host.length}"
119
+ puts " Symbols: #{host.symbols}"
120
+ puts " Hashes: #{host.hashes}"
121
+ puts " Password: #{host.password}"
122
+ end
123
+
124
+ def host_edit(osp, host = nil)
125
+ host = TheFox::OSP::Host.new(osp) if host.nil?
126
+
127
+ tmp = @cli.ask(' Name: ' + (!host.name.nil? ? "[#{host.name}]" : '') + ' ').strip.to_s
128
+ # puts "name: '#{tmp}' #{tmp.class}"
129
+
130
+ host.name = tmp if tmp != ''
131
+ # puts "name: '#{host.name}' #{host.name.class}"
132
+
133
+ host.name = nil if host.name == ''
134
+ # puts "name: '#{host.name}' #{host.name.class}"
135
+
136
+ if host.name.nil?
137
+ # puts "No host input."
138
+ return nil
139
+ end
140
+
141
+ host.generation = @cli.ask("Generation: [#{host.generation}] ", Integer){ |q|
142
+ q.default = host.generation
143
+ q.in = 1..99 }.to_i
144
+
145
+ host.length = @cli.ask(" Length: [#{host.length}] ", Integer){ |q|
146
+ q.default = host.length
147
+ q.in = TheFox::OSP::PASSWORD_MIN_SIZE..TheFox::OSP::PASSWORD_MAX_SIZE }.to_i
148
+
149
+ host.symbols = @cli.ask(" Symbols: [#{host.symbols}] ", Integer){ |q|
150
+ q.default = host.symbols
151
+ q.in = 0..3 }.to_i
152
+
153
+ host.updated_at = DateTime.now
154
+
155
+ host
156
+ end
157
+
158
+ actions = ['begin']
159
+ while true
160
+ case actions.pop
161
+ when 'begin'
162
+ puts
163
+ puts "Type '?' for help."
164
+ when 'n'
165
+ puts
166
+ host = host_edit(osp)
167
+ if !host.nil?
168
+ host_show(host)
169
+ puts
170
+
171
+ add = @cli.ask('Add to database? [yN] ', String){ |q| q.character = true }.strip.downcase
172
+ add = 'n' if add == ''
173
+ puts "Answer: '#{add}'"
174
+
175
+ if add == 'y'
176
+ has_database_changes = true
177
+
178
+ database['hosts'][host.name] = host
179
+ end
180
+ else
181
+ puts "ERROR: hostname can't be nothing."
182
+ end
183
+ when 'l'
184
+ puts
185
+ puts 'List Hosts'
186
+ puts
187
+
188
+ hosts_n = database['hosts'].count
189
+ format = '%' + hosts_n.to_s.length.to_s + 'd'
190
+
191
+ # puts "format: '#{format}'"
192
+
193
+ n = 0
194
+ database['hosts'].values.each do |host|
195
+ n += 1
196
+ # pp host
197
+ printf "#{format}. %s\n", n, host.name
198
+ end
199
+ when 's'
200
+ found_hosts = []
201
+
202
+ search_actions = ['begin']
203
+ while true
204
+ case search_actions.pop
205
+ when 'begin'
206
+ puts
207
+ puts 'Entering search submenu.'
208
+
209
+ search_actions << 's'
210
+ when 's'
211
+ puts
212
+
213
+ host_name = @cli.ask('Search host names: ', String).strip.downcase
214
+ re = Regexp.new(host_name, Regexp::IGNORECASE)
215
+
216
+ found_hosts = database['hosts'].select{ |name, host| re.match(host.name) }
217
+
218
+ search_actions << 'l'
219
+ when 'l'
220
+ puts
221
+ if found_hosts.count > 0
222
+ puts "#{found_hosts.count} host(s) found:"
223
+
224
+ hosts_n = found_hosts.count
225
+ format = '%' + hosts_n.to_s.length.to_s + 'd'
226
+ n = 0
227
+ found_hosts.each do |name, host|
228
+ n += 1
229
+ printf "#{format}. %s\n", n, host.name
230
+ end
231
+ else
232
+ puts 'No hosts found.'
233
+ end
234
+ when 'i'
235
+ puts
236
+ if found_hosts.count > 0
237
+ index = @cli.ask('Show host, select by number: ', Integer){ |q|
238
+ q.character = true if found_hosts.count < 10
239
+ q.in = 1..(found_hosts.count) }.to_i
240
+
241
+ puts
242
+ puts "Host ##{index} selected:"
243
+ index -= 1
244
+ selected_host = nil
245
+ begin
246
+ selected_host = found_hosts.values[index]
247
+ rescue Exception => e
248
+ puts "ERROR: #{e}"
249
+ end
250
+
251
+ if !selected_host.nil?
252
+ host_show(selected_host)
253
+ end
254
+ else
255
+ puts 'No hosts found.'
256
+ end
257
+ when 'e'
258
+ puts
259
+ if found_hosts.count > 0
260
+ index = @cli.ask('Edit, select host by number: ', Integer){ |q|
261
+ q.character = true if found_hosts.count < 10
262
+ q.in = 1..(found_hosts.count) }.to_i
263
+
264
+ puts
265
+ puts "Host ##{index} selected:"
266
+ index -= 1
267
+ selected_host = nil
268
+ begin
269
+ selected_host = found_hosts.values[index].clone
270
+ rescue Exception => e
271
+ puts "ERROR: #{e}"
272
+ end
273
+
274
+ if !selected_host.nil?
275
+ host_edit(osp, selected_host)
276
+ host_show(selected_host)
277
+
278
+ database['hosts'][selected_host.name] = selected_host
279
+
280
+ has_database_changes = true
281
+ end
282
+ else
283
+ puts 'No hosts found.'
284
+ end
285
+ # when 'd'
286
+ # puts
287
+ # if found_hosts.count > 0
288
+ # puts 'Delete'
289
+ # puts
290
+ # else
291
+ # puts 'No hosts found.'
292
+ # end
293
+ when 'q'
294
+ break
295
+ when '?'
296
+ puts
297
+ puts 'Search-menu help:'
298
+ puts "\ts - New search."
299
+ puts "\tl - List found hosts."
300
+ puts "\ti - Print informations about a host found by a search."
301
+ puts "\te - Edit a host found by search."
302
+ # puts "\td - Delete a host found by search."
303
+ puts "\tq - Quit search."
304
+ puts "\t? - Print help."
305
+ else
306
+ puts "WARNING: invalid input. Type '?' for help."
307
+ end
308
+
309
+ next if search_actions.count > 0
310
+
311
+ puts
312
+ search_actions << @cli.ask('[slieq?] >> '){ |q| q.character = true }.downcase
313
+ end
314
+ when 'x'
315
+ actions << 'q'
316
+ actions << 'w'
317
+ when 'w'
318
+ if has_database_changes
319
+ tmp = "#{options[:database_path]}~"
320
+ backup = "#{options[:database_path]}~backup"
321
+
322
+ database['meta']['updated_at'] = DateTime.now.to_s
323
+
324
+ if File.exist?(options[:database_path])
325
+ puts "Backup old file to '#{backup}'."
326
+ FileUtils.mv(options[:database_path], backup)
327
+ end
328
+
329
+ puts "Write temp file to '#{tmp}'."
330
+ db_c = database.clone
331
+ db_c['hosts'] = db_c['hosts'].map{ |name, host| [name, host.to_h] }.to_h
332
+ File.binwrite(tmp, db_c.to_msgpack)
333
+
334
+ puts "Finally move temp file to '#{options[:database_path]}'."
335
+ FileUtils.mv(tmp, options[:database_path])
336
+
337
+ has_database_changes = false
338
+ else
339
+ puts 'Nothing changed, nothing written.'
340
+ end
341
+ when 'q'
342
+ if has_database_changes
343
+ puts
344
+ puts 'You have unsaved database changes.'
345
+
346
+ save = @cli.ask('Would you like to save the database? [Yn] ', String){ |q| q.character = true }.strip.downcase
347
+ save = 'y' if save == ''
348
+ puts "Answer: '#{save}'"
349
+
350
+ if save == 'y'
351
+ actions << 'x'
352
+ else
353
+ really = @cli.ask('Really? [yN] ', String){ |q| q.character = true }.strip.downcase
354
+ really = 'y' if really == ''
355
+ puts "Answer: '#{really}'"
356
+
357
+ if really == 'y'
358
+ has_database_changes = false
359
+ actions << 'q'
360
+ end
361
+ end
362
+ else
363
+ puts 'Quit.'
364
+ break
365
+ end
366
+ when '?'
367
+ puts
368
+ puts 'Main-menu help:'
369
+ puts "\tn - New password."
370
+ puts "\tl - List hosts from database."
371
+ puts "\ts - Search submenu."
372
+ puts "\tx - Same as wq."
373
+ puts "\tw - Write database to file."
374
+ puts "\tq - Quit."
375
+ puts "\t? - Print help."
376
+ else
377
+ puts "WARNING: invalid input. Type '?' for help."
378
+ end
379
+
380
+ next if actions.count > 0
381
+
382
+ puts
383
+ actions << @cli.ask('[nlsxwq?] > '){ |q| q.character = true }.downcase
384
+ end
data/lib/ext/string.rb ADDED
@@ -0,0 +1,8 @@
1
+
2
+ require 'thefox-ext'
3
+
4
+ class String
5
+ def is_valid?
6
+ is_upper? || is_lower? || is_digit?
7
+ end
8
+ end