oro 1.0.0.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.
@@ -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: []