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.
- checksums.yaml +7 -0
- data/LICENSE.textile +21 -0
- data/README.md +72 -0
- data/Rakefile +19 -0
- data/bin/oro +3 -0
- data/lib/oro.rb +80 -0
- data/lib/oro/defaults.yml +19 -0
- data/lib/oro/errors.rb +18 -0
- data/lib/oro/helpers.rb +62 -0
- data/lib/oro/parts.rb +128 -0
- data/lib/oro/parts/braille.yml +259 -0
- data/lib/oro/parts/emoticon.yml +824 -0
- data/lib/oro/parts/english.yml +59645 -0
- data/lib/oro/parts/german.yml +29644 -0
- data/lib/oro/parts/latin.yml +35590 -0
- data/lib/oro/parts/linnaeus.yml +33511 -0
- data/lib/oro/parts/number.yml +13 -0
- data/lib/oro/parts/punctuation.yml +34 -0
- data/lib/oro/password.rb +114 -0
- data/lib/oro/settings.rb +44 -0
- data/lib/oro/settings_parser.rb +105 -0
- data/oro.gemspec +16 -0
- data/test/preference_test.rb +40 -0
- metadata +67 -0
@@ -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
|
+
- "?"
|
data/lib/oro/password.rb
ADDED
@@ -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
|
data/lib/oro/settings.rb
ADDED
@@ -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
|
data/oro.gemspec
ADDED
@@ -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: []
|