oro 1.0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
1
+ # ('0'..'9').to_a
2
+
3
+ ---
4
+ - "0"
5
+ - "1"
6
+ - "2"
7
+ - "3"
8
+ - "4"
9
+ - "5"
10
+ - "6"
11
+ - "7"
12
+ - "8"
13
+ - "9"
@@ -0,0 +1,34 @@
1
+ # %w(~ ` ! @ # $ % ^ & * ( ) _ - + = { } [ ] | / : ; ' < > , . ?)
2
+ # Bad: \ "
3
+
4
+ ---
5
+ - "~"
6
+ - "`"
7
+ - "!"
8
+ - "@"
9
+ - "#"
10
+ - "$"
11
+ - "%"
12
+ - "^"
13
+ - "&"
14
+ - "*"
15
+ - "("
16
+ - ")"
17
+ - "_"
18
+ - "-"
19
+ - "+"
20
+ - "="
21
+ - "{"
22
+ - "}"
23
+ - "["
24
+ - "]"
25
+ - "|"
26
+ - "/"
27
+ - ":"
28
+ - ";"
29
+ - "'"
30
+ - "<"
31
+ - ">"
32
+ - ","
33
+ - "."
34
+ - "?"
@@ -0,0 +1,114 @@
1
+ require_relative 'parts'
2
+ require_relative 'helpers'
3
+ require_relative 'settings'
4
+ require_relative 'errors'
5
+ require_relative 'settings_parser'
6
+
7
+ # A class epresenting a complete password
8
+ class Password
9
+ include SettingsAccessors
10
+ attr_accessor :settings
11
+ attr_reader :virgin_settings
12
+
13
+ # Class methods
14
+
15
+ # Singleton helper returning classes required by password
16
+ def self.components_for(settings)
17
+ parts = []
18
+ settings.plan.each { |part| parts << Object.const_get(part[0]) }
19
+ parts.uniq
20
+ end
21
+
22
+ # Returns classes for all installed parts
23
+ def self.installed_part_classes
24
+ Part.descendants
25
+ end
26
+
27
+ # Returns string names for all installed parts
28
+ def self.installed_parts
29
+ Part.descendants.map(&:name)
30
+ end
31
+
32
+ # Returns a hash of "short" => "long" part identifiers
33
+ def self.installed_part_switches
34
+ switches = {} # FIXME: This apparently can't be memoized (?)
35
+ installed_parts.each do |part|
36
+ part.downcase.chars.each { |char| switches.key?(char) ? next : (switches[char] = part; break) }
37
+ end
38
+ switches
39
+ end
40
+
41
+ # Returns a help message for all installed parts
42
+ def self.installed_parts_help
43
+ help = []
44
+ installed_part_switches.each_pair do |s, l|
45
+ help << " #{s}[n] #{l} part" # FIXME: There has to be a string format approach for making this match up.
46
+ end
47
+ help.join("\n")
48
+ end
49
+
50
+ # Returns a text list of metadata about all installed parts
51
+ def self.installed_parts_summary
52
+ count = 0
53
+ Password.installed_part_classes.each do |klass|
54
+ klass.listify
55
+ count += klass.count
56
+ puts klass.to_s
57
+ end
58
+ "Total list members: #{count}"
59
+ end
60
+
61
+ # Instance methods
62
+
63
+ def initialize(clio = '')
64
+ # Parse clio for Config and Actions
65
+ @settings = SettingsParser.parse(clio)
66
+
67
+ # Parse, manually, remaining non-switch plan parts
68
+ clio.each do |part|
69
+ match = (/\b([a-zA-Z]{1})([0-9]*)\b/).match(part)
70
+ if match
71
+ @settings.plan.push([Password.installed_part_switches[match[1]], match[2] == '' ? nil : match[2].to_i]) # nil behaves better with --prefs
72
+ raise NoMatchingListError.new("No matching dictionary for '#{match[1]}'") unless Password.installed_part_switches.keys.include?(match[1])
73
+ end
74
+ end
75
+
76
+ # Add help for installed parts if needed
77
+ @settings.actions[:help].gsub!(/INSTALLED_PARTS_HELP/, Password.installed_parts_help) if @settings.actions[:help]
78
+
79
+ # Save virgin parsed settings
80
+ @virgin_settings = @settings.dup
81
+
82
+ # Use saved preferences plan, then defaults plan, if no plan provided in clio
83
+ # FIXME: Will require updating to reflect the approach above.
84
+ @settings.plan = (Preferences.instance.plan.empty? ? Defaults.instance.plan : Preferences.instance.plan) if @settings.plan.empty?
85
+
86
+ # Settings merged with Preferences, that merged with Defaults
87
+ @settings.config = Defaults.instance.config.merge(Preferences.instance.config.merge(@settings.config))
88
+
89
+ # Add lists for required part classes only, check for non-contiguous lists
90
+ Password.components_for(@settings).each do |klass|
91
+ klass.listify
92
+ fail ListIsNonContiguousError, "Dictionary #{klass.name} is noncontiguous and requires at least one entry for each range member\n#{klass.to_s}" unless klass.contiguous?
93
+ end
94
+ end
95
+
96
+ def length
97
+ length = 0
98
+ @settings.plan.each { |part| length += part[1].nil? ? Object.const_get(part[0]).middle : part[1] }
99
+ @settings.config.key?(:l33t) && @settings.config[:l33t] == true ? "#{length}+" : length.to_s # Precision is out the window with l33t; && likely uneeded
100
+ end
101
+
102
+ def result
103
+ current_password = []
104
+
105
+ @settings.plan.each do |plan_part|
106
+ part_klass = self.class.const_get(plan_part[0]) # The part descriptor from oro settings
107
+ plan_part[1] = part_klass.middle if plan_part[1].nil?
108
+ current_password << part_klass.get(plan_part[1], @settings.config) # Passing config, Parts don't currently rely on the Preferences singleton
109
+ end
110
+
111
+ current_password.shuffle! if @settings.config[:shuffle]
112
+ current_password.join
113
+ end
114
+ end
@@ -0,0 +1,44 @@
1
+ require 'singleton'
2
+ require 'yaml'
3
+ require 'ostruct'
4
+ require_relative 'settings_parser'
5
+ require_relative 'helpers'
6
+
7
+ # Singleton class representing default settings
8
+ class Defaults
9
+ include ClioHelper, SettingsAccessors, SettingsInspector, Singleton
10
+ FILE = File.join(File.dirname(__FILE__), 'defaults.yml')
11
+
12
+ def initialize
13
+ settings
14
+ end
15
+
16
+ def settings
17
+ @settings ||= YAML.load(File.read(FILE))
18
+ end
19
+ end
20
+
21
+ # Singleton class representing preferred settings
22
+ class Preferences
23
+ include ClioHelper, SettingsAccessors, SettingsInspector, Singleton
24
+ FILE = File.join(Dir.home, '.oro')
25
+
26
+ def initialize
27
+ reset_defaults unless FileTest.readable?(FILE) # Create preference file if missing
28
+ settings
29
+ end
30
+
31
+ def settings
32
+ @settings ||= YAML.load(File.read(FILE))
33
+ end
34
+
35
+ def settings=(settings)
36
+ settings.delete_field('actions') if settings.actions
37
+ File.open(FILE, 'w') { |f| f.write YAML.dump(settings) }
38
+ @settings = settings
39
+ end
40
+
41
+ def reset_defaults
42
+ self.settings = Defaults.instance.settings
43
+ end
44
+ end
@@ -0,0 +1,105 @@
1
+ require 'ostruct'
2
+ require 'optparse'
3
+
4
+ # One job, recieves String command line settings, parses them and returns OpenStruct structured settings.
5
+ class SettingsParser
6
+ def self.parse(argv) # Ie: an ARGV-style array of the clio
7
+ settings = OpenStruct.new(:plan => [], :config => {}, :actions => {})
8
+
9
+ clio_parser = OptionParser.new do |clio_parser_config|
10
+ clio_parser_config.program_name = 'Oro'
11
+ clio_parser_config.release = 'Command Line Version'
12
+ clio_parser_config.version = %w(1 0 0)
13
+ clio_parser_config.banner = 'Usage: oro [settings]'
14
+ clio_parser_config.separator ''
15
+
16
+ # Parts
17
+ clio_parser_config.separator 'Part settings (all lengths optional)'
18
+ clio_parser_config.separator 'INSTALLED_PARTS_HELP'
19
+
20
+ # Config
21
+ clio_parser_config.separator ''
22
+ clio_parser_config.separator 'Config settings'
23
+
24
+ clio_parser_config.on('-iMANDATORY', '--iterations=MANDATORY', Integer, 'The number of passwords to generate') do |val|
25
+ settings.config[:iterations] = val
26
+ end
27
+
28
+ clio_parser_config.on('-c', '--[no-]capitalize', 'Capitalize every word part') do |val|
29
+ settings.config[:capitalize] = val
30
+ end
31
+
32
+ clio_parser_config.on('-r', '--[no-]capitalize-random', 'Randomly capitalize one letter in every word part') do |val|
33
+ settings.config[:capitalize_random] = val
34
+ end
35
+
36
+ clio_parser_config.on('-l', '--[no-]l33t', 'Make one l33t-style replacement per word part') do |val|
37
+ settings.config[:l33t] = val
38
+ end
39
+
40
+ clio_parser_config.on('-s', '--[no-]shuffle', 'Randomize map parts') do |val|
41
+ settings.config[:shuffle] = val
42
+ end
43
+
44
+ clio_parser_config.on('-f', '--format=MANDATORY', %w(json yml yaml string), 'Results format: string, json, yaml') do |val|
45
+ settings.config[:format] = val
46
+ end
47
+
48
+ clio_parser_config.on('-e', '--separator[=OPTIONAL]', 'Separator characters') do |val|
49
+ settings.config[:separator] = eval("val=\"#{val}\"") # FIXME: The horror, but how else to take \n as an option and retain it's control nature? The eval should be removed.
50
+ end
51
+
52
+ # Actions
53
+ clio_parser_config.separator ''
54
+ clio_parser_config.separator 'Action settings'
55
+ clio_parser_config.on('--lists', 'Show all available lists') do |val|
56
+ settings.actions[:lists] = val
57
+ end
58
+
59
+ clio_parser_config.on('--prefs', '--preferences', 'Show your current preferences') do |val|
60
+ settings.actions[:preferences] = val
61
+ end
62
+
63
+ clio_parser_config.on('--defaults', 'Show system defaults') do |val|
64
+ settings.actions[:defaults] = val
65
+ end
66
+
67
+ clio_parser_config.on('--set', 'Set passed settings as your preferences') do |val|
68
+ settings.actions[:set] = val
69
+ end
70
+
71
+ clio_parser_config.on('--reset', 'Reset your preferences to system defaults') do |val|
72
+ settings.actions[:reset] = val
73
+ end
74
+
75
+ clio_parser_config.on('-v', '--verbose', 'Provide verbose feedback, dictionary metadata, and statistics when run') do |val|
76
+ settings.actions[:verbose] = val
77
+ end
78
+
79
+ clio_parser_config.on('-h', '--help', 'Print this dialog') do
80
+ settings.actions[:help] = clio_parser_config.to_s
81
+ end
82
+
83
+ clio_parser_config.on('--version', 'Show version') do
84
+ settings.actions[:version] = clio_parser_config.ver
85
+ end
86
+
87
+ # Examples
88
+ clio_parser_config.separator ''
89
+ clio_parser_config.separator 'Examples'
90
+ clio_parser_config.separator ' oro e9 p1 n3 -s --set'
91
+ clio_parser_config.separator ' oro n4 -e"-" -i4'
92
+ clio_parser_config.separator ' oro n99 -i10'
93
+ clio_parser_config.separator ' oro e10 n5 -fjson'
94
+
95
+ clio_parser_config.separator ''
96
+ clio_parser_config.separator 'See dictionary source files for associated licence attributions.'
97
+ clio_parser_config.separator ''
98
+ end # end clio_parser
99
+
100
+ argv = argv.is_a?(Array) ? argv : argv.split
101
+ clio_parser.parse!(argv)
102
+
103
+ settings
104
+ end # end parse
105
+ end # end class
@@ -0,0 +1,16 @@
1
+ require 'rake' # Provide FileList class
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'oro'
5
+ s.version = '1.0.0.2'
6
+ s.date = '2016-03-02'
7
+ s.summary = 'Oro for passwords...'
8
+ s.description = 'A flexible, command-line utility which generates memorable passwords. The enemy knows the system -- Claude Shannon / Auguste Kerckhoffs'
9
+ s.authors = ['Joel Wagener']
10
+ s.email = 'bayou.marcus@gmail.com'
11
+ s.executables = ['oro']
12
+ s.files = FileList['**/**/*']
13
+ s.homepage = 'https://github.com/bayou-marcus/oro'
14
+ s.license = 'The MIT License.' # http://choosealicense.com
15
+ s.required_ruby_version = '~> 2.2'
16
+ end
@@ -0,0 +1,40 @@
1
+ require 'minitest/autorun'
2
+ # require 'yaml'
3
+ # require_relative '../lib/oro/settings' # FIXME Should this even be needed? See Rakefile for the fail.
4
+ # require_relative '../lib/oro/settings_parser' # FIXME Should this even be needed? See Rakefile for the fail.
5
+
6
+ class TestPreference < Minitest::Test
7
+
8
+ def setup
9
+ @clio = '-w7 -p -n3 -i10 -c -dDeutsch'
10
+ @PREFERENCE_FILE = Preference::PREFERENCE_FILE
11
+ @prfs = Preference.instance # Creates preference file
12
+ end
13
+
14
+ def test_that_preference_file_exists
15
+ assert FileTest.readable?(@PREFERENCE_FILE), "#{@PREFERENCE_FILE} is missing"
16
+ end
17
+
18
+ def test_reset_defaults_sets_defaults
19
+ @prfs.reset_defaults
20
+ assert_equal @prfs.get, YAML.load(File.read(Preference::DEFAULTS_FILE))
21
+ end
22
+
23
+ def test_get_returns_open_struct_with_format_and_config
24
+ @prfs.set(@clio)
25
+ structured_options = @prfs.get
26
+ assert (structured_options.class.name == 'OpenStruct' and structured_options.to_h.has_key?(:format) and structured_options.to_h.has_key?(:config)), 'get_structured not OpenStruct or missing format or config'
27
+ end
28
+
29
+ def test_get_defaults_equals_defaults
30
+ assert_equal @prfs.get_defaults, YAML.load(File.read(Preference::DEFAULTS_FILE))
31
+ end
32
+
33
+ def teardown
34
+ remove_instance_variable(:@clio)
35
+ remove_instance_variable(:@PREFERENCE_FILE)
36
+ remove_instance_variable(:@prfs)
37
+ # File.delete(@PREFERENCE_FILE) # FIXME "setup and teardown runs before/after each test" doesn't manage the preference file accurately so unable to test its creation; perhaps what the filesystem reports is out of sync
38
+ end
39
+
40
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oro
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Joel Wagener
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A flexible, command-line utility which generates memorable passwords.
14
+ The enemy knows the system -- Claude Shannon / Auguste Kerckhoffs
15
+ email: bayou.marcus@gmail.com
16
+ executables:
17
+ - oro
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE.textile
22
+ - README.md
23
+ - Rakefile
24
+ - bin/oro
25
+ - lib/oro.rb
26
+ - lib/oro/defaults.yml
27
+ - lib/oro/errors.rb
28
+ - lib/oro/helpers.rb
29
+ - lib/oro/parts.rb
30
+ - lib/oro/parts/braille.yml
31
+ - lib/oro/parts/emoticon.yml
32
+ - lib/oro/parts/english.yml
33
+ - lib/oro/parts/german.yml
34
+ - lib/oro/parts/latin.yml
35
+ - lib/oro/parts/linnaeus.yml
36
+ - lib/oro/parts/number.yml
37
+ - lib/oro/parts/punctuation.yml
38
+ - lib/oro/password.rb
39
+ - lib/oro/settings.rb
40
+ - lib/oro/settings_parser.rb
41
+ - oro.gemspec
42
+ - test/preference_test.rb
43
+ homepage: https://github.com/bayou-marcus/oro
44
+ licenses:
45
+ - The MIT License.
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '2.2'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project:
63
+ rubygems_version: 2.4.8
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: Oro for passwords...
67
+ test_files: []