ppg 0.0.1.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: 8cfd70a8672f3df6fe2516af336b97f686aa3001
4
+ data.tar.gz: 82bfb856d6a3cfe78bbfcbcd70066abfd6a00d8a
5
+ SHA512:
6
+ metadata.gz: db880f29757216f42134cb11376b231931a2bb1ada582d7dc1771bafd2c36f1d110efaccf551852b2fbb28f2ccf78457f2a4ea521209e6c7994fcf534e036819
7
+ data.tar.gz: 6fb661bc2b099fbf6b15aad50b16484f5907e21d702e2b57927863561e3aec3e7ac2b451c408bbdf67c9d2cd286e4ef4f3bd0062412cb8648c2f211802ca6cf2
data/bin/ppg ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'ppg'
5
+
6
+ require 'getoptlong'
7
+
8
+ DEFAULT_PASSWORD_LENGTH = 8
9
+
10
+ opts = GetoptLong.new(
11
+ ['--help', '-h', GetoptLong::NO_ARGUMENT],
12
+ ['--digits', '-d', GetoptLong::OPTIONAL_ARGUMENT],
13
+ ['--upcase', '-u', GetoptLong::OPTIONAL_ARGUMENT],
14
+ ['--length', '-l', GetoptLong::REQUIRED_ARGUMENT],
15
+ ['--verbous', '-v', GetoptLong::NO_ARGUMENT]
16
+ )
17
+
18
+ def print_help
19
+ puts <<-EOF
20
+ generator.rb [OPTIONS]
21
+
22
+ -h --help: prints this help
23
+
24
+ -d N include N digits in password
25
+ --digits N 1 by default
26
+
27
+ -u N Include N letters in upper case
28
+ --upcase N 1 by default
29
+
30
+ -l N make password of N characters
31
+ --length N
32
+
33
+ -v turns on additional output
34
+ --verbous
35
+
36
+ EOF
37
+
38
+ end
39
+
40
+ begin
41
+
42
+ mutators = {}
43
+ password_length = DEFAULT_PASSWORD_LENGTH
44
+
45
+ opts.each do |opt, arg|
46
+ case opt
47
+ when '--help'
48
+ print_help
49
+ exit
50
+ when '--digits'
51
+
52
+ mutators[:Digits] = Proc.new { Random.rand(10).to_s },
53
+ arg.empty? ? 1 : arg.to_i
54
+
55
+ when '--upcase'
56
+ mutators[:Upcase] = Proc.new { |c| c.upcase },
57
+ arg.empty? ? 1 : arg.to_i
58
+
59
+ when '--length'
60
+ password_length = arg.to_i
61
+ raise "password length must be greater than 0" if password_length <= 0
62
+
63
+ when '--verbous'
64
+ class Password
65
+ def to_s
66
+ "\n" \
67
+ "password: #{password}\n" \
68
+ "pattern: #{password_pattern.to_s}\n"
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+
75
+ pwgen = PwGen.new(password_length)
76
+ mutators.each { |name, mutator|
77
+ puts "enabling #{name} mutator for #{mutator.last} character(s)"
78
+ pwgen.add_mutator(*mutator)
79
+ }
80
+
81
+ puts pwgen.generate_password
82
+
83
+ rescue GetoptLong::MissingArgument
84
+ puts
85
+ print_help
86
+ exit
87
+
88
+ end
89
+
data/lib/ppg.rb ADDED
@@ -0,0 +1 @@
1
+ require_relative 'ppg/pwgen'
@@ -0,0 +1,18 @@
1
+ class Password
2
+ attr_accessor :password, :password_pattern
3
+ attr_reader :PASSWORD_LENGTH
4
+
5
+ def initialize (password_length, password_pattern = nil)
6
+ @PASSWORD_LENGTH = password_length.freeze
7
+ @password = String.new
8
+ #TODO: make password_pattern validation check method
9
+ @password_pattern ||= []
10
+ end
11
+
12
+ def length= (length)
13
+ @PASSWORD_LENGTH = length.freeze
14
+ end
15
+
16
+ alias :to_s :password
17
+
18
+ end
@@ -0,0 +1,41 @@
1
+ $ENGLISH_PHONEMES_HASH = {
2
+
3
+ :vowels => [ "a","e","i","o","u" ],
4
+
5
+ :consonants => [ "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n",
6
+ "p", "r", "s", "t", "v", "w", "x", "y", "z" ],
7
+
8
+ :dipthongs => {
9
+ :vowel => ["ae", "oh", "oo", "ah", "ai", "ee", "ei", "ie"],
10
+ :consonant => ["ng", "gh", "ch", "ph", "qu", "sh", "th"]
11
+ }
12
+
13
+ }.freeze
14
+
15
+ $ENGLISH_DOWNCASE_REGEXP = /[a-z]/.freeze
16
+
17
+ class Phonemes
18
+ attr_reader :downcase_regexp
19
+
20
+ def initialize(
21
+ vowels = nil,
22
+ consonants = nil,
23
+ dipthongs = nil,
24
+ downcase_regexp = $ENGLISH_DOWNCASE_REGEXP
25
+ )
26
+
27
+ @phonemes = { :vowel => vowels || $ENGLISH_PHONEMES_HASH[:vowels],
28
+ :consonant => consonants || $ENGLISH_PHONEMES_HASH[:consonants],
29
+ :dipthong => dipthongs || $ENGLISH_PHONEMES_HASH[:dipthongs]
30
+ }
31
+ @downcase_regexp = downcase_regexp
32
+ end
33
+
34
+ def keys
35
+ @phonemes.keys
36
+ end
37
+
38
+ def [](index)
39
+ @phonemes[index]
40
+ end
41
+ end
data/lib/ppg/pwgen.rb ADDED
@@ -0,0 +1,143 @@
1
+ # coding: utf-8
2
+ require_relative 'password'
3
+ require_relative 'phonemes'
4
+
5
+ require 'securerandom'
6
+
7
+ class MutatorError < Exception; end
8
+
9
+ class PwGen
10
+ attr_reader :password
11
+ attr_writer :phonemes
12
+
13
+ def initialize(length, phonemes = nil)
14
+ @password = Password.new(length)
15
+ @phonemes = phonemes || Phonemes.new
16
+ @mutators = {}
17
+
18
+ #TODO: избавиться от константы
19
+ @dipthong_length = 2
20
+ end
21
+
22
+ def add_mutator(proc, count)
23
+ @mutated_chars ||= []
24
+ @clean_chars_left ||= @password.PASSWORD_LENGTH
25
+
26
+ return false if count == 0
27
+
28
+ if @clean_chars_left == 0
29
+ count = 0
30
+ raise MutatorError, "nothing left to mutate, rejecting!"
31
+ end
32
+
33
+ unless proc.respond_to? :call
34
+ raise MutatorError, "mutator's not callable, rejecting!"
35
+ end
36
+
37
+ if count > @clean_chars_left
38
+ error_string = "can't mutate #{count} characters, decreasing to #{@clean_chars_left}!\n"
39
+ count = @clean_chars_left
40
+ raise MutatorError, error_string
41
+ end
42
+
43
+ @clean_chars_left -= count
44
+ @mutators[proc] = count
45
+ true
46
+
47
+ rescue MutatorError
48
+ STDERR << $!.message
49
+ retry
50
+
51
+ end
52
+
53
+ def generate_password
54
+ generate_password_pattern!
55
+ .fill_in_password_pattern!
56
+ .mutate!
57
+ @password
58
+ end
59
+
60
+ def fill_in_password_pattern!
61
+ @password.password_pattern.each do |pattern|
62
+ if pattern.kind_of?(Symbol)
63
+ elem = @phonemes[pattern][SecureRandom.random_number(@phonemes[pattern].length)]
64
+ else pattern.kind_of?(Array)
65
+ # most definitely is dipthong
66
+ length = @phonemes[pattern[0]][pattern[1]].length
67
+ elem = @phonemes[pattern[0]][pattern[1]][SecureRandom.random_number(length)]
68
+ end
69
+ @password.password << elem
70
+ end
71
+ self
72
+ end
73
+
74
+ def generate_password_pattern!
75
+ length_left = @password.PASSWORD_LENGTH
76
+ next_pattern = previous_pattern = nil
77
+ can_be_next_patterns = @phonemes.keys
78
+ selector_block = Proc.new { |pattern|
79
+ pattern if pattern != next_pattern || pattern == :dipthong
80
+ }
81
+ while length_left > 0 do
82
+ loop do
83
+ next_pattern = generate_random_pattern(can_be_next_patterns)
84
+ break unless requirements_not_met?(next_pattern,
85
+ previous_pattern, length_left)
86
+ end
87
+
88
+ can_be_next_patterns.select! &selector_block
89
+
90
+ can_be_next_patterns << previous_pattern if previous_pattern != nil
91
+
92
+ if next_pattern == :dipthong
93
+ if @password.password_pattern.empty? #first element
94
+ auxiliary_pattern = generate_random_pattern([:vowel, :consonant])
95
+ else
96
+ auxiliary_pattern =
97
+ case previous_pattern
98
+ when :vowel then :consonant
99
+ when :consonant then :vowel
100
+ end
101
+ end
102
+ next_pattern = next_pattern, auxiliary_pattern
103
+ can_be_next_patterns -= [auxiliary_pattern]
104
+ length_left -= @dipthong_length
105
+ previous_pattern = auxiliary_pattern
106
+
107
+ else
108
+ length_left -= 1
109
+ previous_pattern = next_pattern
110
+
111
+ end
112
+ @password.password_pattern << next_pattern
113
+ end
114
+ self
115
+ end
116
+
117
+ def mutate!
118
+ @mutators.each_pair do |mutator, count|
119
+ while count > 0
120
+ loop do
121
+ index = SecureRandom.random_number(@password.PASSWORD_LENGTH)
122
+ next unless @password.password[index] =~ @phonemes.downcase_regexp
123
+ @password.password[index] = (mutator.call @password.password[index])
124
+ break
125
+ end
126
+ count -= 1
127
+ end
128
+ end
129
+ end
130
+
131
+ def requirements_not_met?(next_pattern, previous_pattern, length_left)
132
+ return true if next_pattern == :dipthong && length_left < @dipthong_length
133
+ return true if next_pattern == previous_pattern
134
+ false
135
+ end
136
+
137
+ def generate_random_pattern(patterns)
138
+ patterns [ SecureRandom.random_number(patterns.length) ]
139
+ end
140
+
141
+ private :generate_random_pattern, :requirements_not_met?
142
+
143
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ppg
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - enoch0x5a
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A simple password generator with pronunciation in mind
14
+ email:
15
+ executables:
16
+ - ppg
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/ppg
21
+ - lib/ppg.rb
22
+ - lib/ppg/password.rb
23
+ - lib/ppg/phonemes.rb
24
+ - lib/ppg/pwgen.rb
25
+ homepage:
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.2.2
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Phonetic Password Generator
49
+ test_files: []