oro 1.0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|